diff --git a/.mention-bot b/.mention-bot index 6508c7e8679..9893b57bb84 100644 --- a/.mention-bot +++ b/.mention-bot @@ -2,7 +2,7 @@ "maxReviewers": 2, "message": "Thanks @pullRequester for your pull request :+1:. By analyzing the blame information on this pull request, I identified @reviewers to be potential reviewers.", "requiredOrgs": ["discourse"], - "skipCollaboratorPR": true, - "delayed": true, - "delayedUntil": "6d" + "skipCollaboratorPR": false, + "delayed": false, + "delayedUntil": "1d" } diff --git a/.travis.yml b/.travis.yml index 0f46f1ebcad..ed1f7d20b12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,6 +41,7 @@ before_install: - git clone --depth=1 https://github.com/discourse/discourse-backup-uploads-to-s3.git plugins/discourse-backup-uploads-to-s3 - git clone --depth=1 https://github.com/discourse/discourse-spoiler-alert.git plugins/discourse-spoiler-alert - git clone --depth=1 https://github.com/discourse/discourse-cakeday.git plugins/discourse-cakeday + - git clone --depth=1 https://github.com/discourse/discourse-canned-replies.git plugins/discourse-canned-replies - npm i -g eslint babel-eslint - eslint app/assets/javascripts - eslint --ext .es6 app/assets/javascripts @@ -52,7 +53,7 @@ before_script: - bundle exec rake db:create db:migrate install: - - bash -c "if [ '$RAILS_MASTER' == '1' ]; then bundle update --retry=3 --jobs=3 arel rails rails-observers seed-fu; fi" + - bash -c "if [ '$RAILS_MASTER' == '1' ]; then bundle update --retry=3 --jobs=3 arel rails seed-fu; fi" - bash -c "if [ '$RAILS_MASTER' == '0' ]; then bundle install --without development --deployment --retry=3 --jobs=3; fi" script: "bundle exec rspec && bundle exec rake plugin:spec && bundle exec rake qunit:test['200000']" diff --git a/Gemfile b/Gemfile index abf697bb3b9..3d49f0dc3aa 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,6 @@ end if rails_master? gem 'arel', git: 'https://github.com/rails/arel.git' gem 'rails', git: 'https://github.com/rails/rails.git' - gem 'rails-observers', git: 'https://github.com/rails/rails-observers.git' gem 'seed-fu', git: 'https://github.com/SamSaffron/seed-fu.git', branch: 'discourse' else # Rails 5 is going to ship with Action Cable, we have no use for it as @@ -29,8 +28,6 @@ else # gem 'railties' # gem 'sprockets-rails' gem 'rails', '~> 4.2' - - gem 'rails-observers' gem 'seed-fu', '~> 2.3.5' end @@ -48,7 +45,8 @@ gem 'onebox' gem 'http_accept_language', '~>2.0.5', require: false gem 'ember-rails', '0.18.5' -gem 'ember-source', '2.4.6' +gem 'ember-source', '2.10.0' +gem 'ember-handlebars-template', '0.7.5' gem 'barber' gem 'babel-transpiler' @@ -107,7 +105,6 @@ gem 'sidekiq-statistic' gem 'sinatra', require: false gem 'execjs', require: false gem 'mini_racer' -gem 'thin', require: false gem 'highline', require: false gem 'rack-protection' # security @@ -138,8 +135,6 @@ group :test, :development do gem 'rb-inotify', '~> 0.9', require: RUBY_PLATFORM =~ /linux/i ? 'rb-inotify' : false gem 'rspec-rails', require: false gem 'shoulda', require: false - gem 'simplecov', require: false - gem 'rspec-given' gem 'rspec-html-matchers' gem 'spork-rails' gem 'pry-nav' @@ -168,44 +163,22 @@ gem 'htmlentities', require: false # If you want to amend mini profiler to do the monkey patches in the railties # we are open to it. by deferring require to the initializer we can configure discourse installs without it -gem 'fast_stack', require: false, platform: [:mri_20] gem 'flamegraph', require: false gem 'rack-mini-profiler', require: false gem 'unicorn', require: false gem 'puma', require: false gem 'rbtrace', require: false, platform: :mri +gem 'gc_tracer', require: false, platform: :mri # required for feed importing and embedding # gem 'ruby-readability', require: false - gem 'simple-rss', require: false -gem 'gctools', require: false, platform: :mri_21 - -begin - gem 'stackprof', require: false, platform: [:mri_21, :mri_22, :mri_23] - gem 'memory_profiler', require: false, platform: [:mri_21, :mri_22, :mri_23] -rescue Bundler::GemfileError - begin - STDERR.puts "You are running an old version of bundler, please upgrade bundler ASAP, if you are using Discourse docker, rebuild your container." - gem 'stackprof', require: false, platform: [:mri_21, :mri_22] - gem 'memory_profiler', require: false, platform: [:mri_21, :mri_22] - rescue Bundler::GemfileError - gem 'stackprof', require: false, platform: [:mri_21] - gem 'memory_profiler', require: false, platform: [:mri_21] - end -end +gem 'stackprof', require: false, platform: :mri +gem 'memory_profiler', require: false, platform: :mri gem 'rmmseg-cpp', require: false gem 'logster' - -# perftools only works on 1.9 atm -group :profile do - # travis refuses to install this, instead of fuffing, just avoid it for now - # - # if you need to profile, uncomment out this line - # gem 'rack-perftools_profiler', require: 'rack/perftools_profiler', platform: :mri_19 -end diff --git a/Gemfile.lock b/Gemfile.lock index f48e3ff72eb..76dc704feb6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -52,7 +52,7 @@ GEM babel-transpiler (0.7.0) babel-source (>= 4.0, < 6) execjs (~> 2.0) - barber (0.11.1) + barber (0.11.2) ember-source (>= 1.0, < 3) execjs (>= 1.2, < 3) better_errors (2.1.1) @@ -71,19 +71,17 @@ GEM concurrent-ruby (1.0.2) connection_pool (2.2.0) crass (1.0.2) - daemons (1.2.4) debug_inspector (0.0.2) diff-lcs (1.2.5) discourse-qunit-rails (0.0.9) railties discourse_fastimage (2.0.3) - docile (1.1.5) domain_name (0.5.25) unf (>= 0.0.5, < 1.0.0) email_reply_trimmer (0.1.6) ember-data-source (2.2.1) ember-source (>= 1.8, < 3.0) - ember-handlebars-template (0.7.4) + ember-handlebars-template (0.7.5) barber (>= 0.11.0) sprockets (>= 3.3, < 4) ember-rails (0.18.5) @@ -93,9 +91,8 @@ GEM ember-source (>= 1.1.0) jquery-rails (>= 1.0.17) railties (>= 3.1) - ember-source (2.4.6) + ember-source (2.10.0) erubis (2.7.0) - eventmachine (1.2.0.1) excon (0.53.0) execjs (2.7.0) exifr (1.2.4) @@ -104,23 +101,20 @@ GEM faraday (0.9.2) multipart-post (>= 1.2, < 3) fast_blank (1.0.0) - fast_stack (0.2.0) fast_xor (1.1.3) rake rake-compiler fast_xs (0.8.0) - ffi (1.9.10) + ffi (1.9.17) flamegraph (0.9.5) foreman (0.82.0) thor (~> 0.19.1) fspath (2.1.1) - gctools (0.2.3) - given_core (3.7.1) - sorcerer (>= 0.3.7) + gc_tracer (1.5.1) globalid (0.3.7) activesupport (>= 4.1.0) guess_html_encoding (0.0.11) - hashie (3.4.4) + hashie (3.4.6) highline (1.7.8) hiredis (0.6.1) htmlentities (4.3.4) @@ -141,10 +135,10 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (1.8.3) + json (1.8.6) jwt (1.5.2) kgio (2.10.0) - libv8 (5.3.332.38.1) + libv8 (5.3.332.38.3) listen (0.7.3) logster (1.2.5) loofah (2.0.3) @@ -152,7 +146,7 @@ GEM lru_redux (1.1.0) mail (2.6.4) mime-types (>= 1.16, < 4) - memory_profiler (0.9.6) + memory_profiler (0.9.7) message_bus (2.0.2) rack (>= 1.1.3) metaclass (0.0.4) @@ -165,8 +159,8 @@ GEM mocha (1.1.0) metaclass (~> 0.0.1) mock_redis (0.15.4) - moneta (0.8.0) - msgpack (0.7.6) + moneta (0.8.1) + msgpack (1.0.2) multi_json (1.12.1) multi_xml (0.5.5) multipart-post (2.0.0) @@ -176,7 +170,7 @@ GEM mini_portile2 (~> 2.1.0) nokogumbo (1.4.7) nokogiri - oauth (0.4.7) + oauth (0.5.1) oauth2 (1.0.0) faraday (>= 0.8, < 0.10) jwt (~> 1.0) @@ -209,15 +203,17 @@ GEM omniauth-openid (1.0.1) omniauth (~> 1.0) rack-openid (~> 1.3.1) - omniauth-twitter (1.2.1) - json (~> 1.3) + omniauth-twitter (1.3.0) omniauth-oauth (~> 1.1) - onebox (1.6.2) + rack + onebox (1.7.7) + fast_blank (>= 1.0.0) htmlentities (~> 4.3.4) moneta (~> 0.8) multi_json (~> 1.11) mustache nokogiri (~> 1.6.6) + sanitize openid-redis-store (0.0.2) redis ruby-openid @@ -233,7 +229,7 @@ GEM pry (>= 0.9.10) puma (3.6.0) r2 (0.2.6) - rack (1.6.4) + rack (1.6.5) rack-mini-profiler (0.10.1) rack (>= 1.2.0) rack-openid (1.3.1) @@ -262,8 +258,6 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - rails-observers (0.1.2) - activemodel (~> 4.0) rails_multisite (1.0.6) rails (> 4.2, < 5) railties (4.2.7.1) @@ -300,9 +294,6 @@ GEM rspec-expectations (3.4.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.4.0) - rspec-given (3.7.1) - given_core (= 3.7.1) - rspec (>= 2.14.0) rspec-html-matchers (0.7.0) nokogiri (~> 1) rspec (~> 3) @@ -340,7 +331,7 @@ GEM shoulda (3.5.0) shoulda-context (~> 1.0, >= 1.0.1) shoulda-matchers (>= 1.4.1, < 3.0) - shoulda-context (1.2.1) + shoulda-context (1.2.2) shoulda-matchers (2.8.0) activesupport (>= 3.0.0) sidekiq (4.2.4) @@ -351,17 +342,11 @@ GEM sidekiq-statistic (1.2.0) sidekiq (>= 3.3.4, < 5) simple-rss (1.3.1) - simplecov (0.11.1) - docile (~> 1.1.0) - json (~> 1.8) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.0) sinatra (1.4.6) rack (~> 1.4) rack-protection (~> 1.4) tilt (>= 1.3, < 3) slop (3.6.0) - sorcerer (1.0.2) spork (1.0.0rc4) spork-rails (4.0.0) rails (>= 3.0.0, < 5) @@ -374,10 +359,6 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) stackprof (0.2.10) - thin (1.7.0) - daemons (~> 1.0, >= 1.0.9) - eventmachine (~> 1.0, >= 1.0.4) - rack (>= 1, < 3) thor (0.19.1) thread_safe (0.3.5) tilt (2.0.5) @@ -412,19 +393,19 @@ DEPENDENCIES discourse-qunit-rails discourse_fastimage (= 2.0.3) email_reply_trimmer (= 0.1.6) + ember-handlebars-template (= 0.7.5) ember-rails (= 0.18.5) - ember-source (= 2.4.6) + ember-source (= 2.10.0) excon execjs fabrication (= 2.9.8) fakeweb (~> 1.3.0) fast_blank - fast_stack fast_xor fast_xs flamegraph foreman - gctools + gc_tracer highline hiredis htmlentities @@ -463,7 +444,6 @@ DEPENDENCIES rack-mini-profiler rack-protection rails (~> 4.2) - rails-observers rails_multisite rake rb-fsevent @@ -475,7 +455,6 @@ DEPENDENCIES rinku rmmseg-cpp rspec - rspec-given rspec-html-matchers rspec-rails rtlit @@ -488,15 +467,13 @@ DEPENDENCIES sidekiq sidekiq-statistic simple-rss - simplecov sinatra spork-rails stackprof - thin timecop uglifier unf unicorn BUNDLED WITH - 1.13.6 + 1.13.7 diff --git a/README.md b/README.md index 6cdf4c101b8..359c8189f14 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ To learn more about the philosophy and goals of the project, [visit **discourse. ## Screenshots - - - + + + -Atom   +Atom   Soylent Browse [lots more notable Discourse instances](http://www.discourse.org/faq/customers/). @@ -84,7 +84,7 @@ The original Discourse code contributors can be found in [**AUTHORS.MD**](docs/A ## Copyright / License -Copyright 2014 - 2016 Civilized Discourse Construction Kit, Inc. +Copyright 2014 - 2017 Civilized Discourse Construction Kit, Inc. Licensed under the GNU General Public License Version 2.0 (or later); you may not use this work except in compliance with the License. diff --git a/app/assets/javascripts/admin/components/ace-editor.js.es6 b/app/assets/javascripts/admin/components/ace-editor.js.es6 index 01773d2cbf8..a03865c40ce 100644 --- a/app/assets/javascripts/admin/components/ace-editor.js.es6 +++ b/app/assets/javascripts/admin/components/ace-editor.js.es6 @@ -36,6 +36,7 @@ export default Ember.Component.extend({ loadScript("/javascripts/ace/ace.js", { scriptTag: true }).then(() => { window.ace.require(['ace/ace'], loadedAce => { + if (!this.element || this.isDestroying || this.isDestroyed) { return; } const editor = loadedAce.edit(this.$('.ace')[0]); editor.setTheme("ace/theme/chrome"); diff --git a/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 index 7d11fc86226..7ddc6f3ac4e 100644 --- a/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 @@ -68,7 +68,7 @@ export default Ember.Controller.extend(BufferedContent, { this.get('model').save(data).then(() => { if (newBadge) { const adminBadges = this.get('adminBadges.model'); - if (!adminBadges.contains(model)) { + if (!adminBadges.includes(model)) { adminBadges.pushObject(model); } this.transitionToRoute('adminBadges.show', model.get('id')); diff --git a/app/assets/javascripts/admin/controllers/admin-group.js.es6 b/app/assets/javascripts/admin/controllers/admin-group.js.es6 index 71cb2c70328..6c3da11d7f7 100644 --- a/app/assets/javascripts/admin/controllers/admin-group.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-group.js.es6 @@ -1,5 +1,4 @@ import { popupAjaxError } from 'discourse/lib/ajax-error'; -import { propertyEqual } from 'discourse/lib/computed'; import computed from 'ember-addons/ember-computed-decorators'; export default Ember.Controller.extend({ @@ -7,19 +6,6 @@ export default Ember.Controller.extend({ disableSave: false, savingStatus: '', - currentPage: function() { - if (this.get("model.user_count") === 0) { return 0; } - return Math.floor(this.get("model.offset") / this.get("model.limit")) + 1; - }.property("model.limit", "model.offset", "model.user_count"), - - totalPages: function() { - if (this.get("model.user_count") === 0) { return 0; } - return Math.floor(this.get("model.user_count") / this.get("model.limit")) + 1; - }.property("model.limit", "model.user_count"), - - showingFirst: Em.computed.lte("currentPage", 1), - showingLast: propertyEqual("currentPage", "totalPages"), - aliasLevelOptions: function() { return [ { name: I18n.t("groups.alias_levels.nobody"), value: 0 }, @@ -47,38 +33,6 @@ export default Ember.Controller.extend({ }, actions: { - next() { - if (this.get("showingLast")) { return; } - - const group = this.get("model"), - offset = Math.min(group.get("offset") + group.get("limit"), group.get("user_count")); - - group.set("offset", offset); - - return group.findMembers(); - }, - - previous() { - if (this.get("showingFirst")) { return; } - - const group = this.get("model"), - offset = Math.max(group.get("offset") - group.get("limit"), 0); - - group.set("offset", offset); - - return group.findMembers(); - }, - - removeMember(member) { - const self = this, - message = I18n.t("admin.groups.delete_member_confirm", { username: member.get("username"), group: this.get("model.name") }); - return bootbox.confirm(message, I18n.t("no_value"), I18n.t("yes_value"), function(confirm) { - if (confirm) { - self.get("model").removeMember(member); - } - }); - }, - removeOwner(member) { const self = this, message = I18n.t("admin.groups.delete_owner_confirm", { username: member.get("username"), group: this.get("model.name") }); @@ -95,12 +49,6 @@ export default Ember.Controller.extend({ this.set("model.ownerUsernames", null); }, - addMembers() { - if (Em.isEmpty(this.get("model.usernames"))) { return; } - this.get("model").addMembers(this.get("model.usernames")).catch(popupAjaxError); - this.set("model.usernames", null); - }, - save() { const group = this.get('model'), groupsController = this.get("adminGroupsType"), diff --git a/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 b/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 index 5393a27c8f6..8238b1d5afe 100644 --- a/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 @@ -1,9 +1,16 @@ +import computed from 'ember-addons/ember-computed-decorators'; + export default Ember.Controller.extend({ - adminRoutes: function() { - return this.get('model').map(p => { - if (p.get('enabled')) { - return p.admin_route; + @computed('model.@each.enabled_setting') + adminRoutes() { + let routes = []; + + this.get('model').forEach(p => { + if (this.siteSettings[p.get('enabled_setting')] && p.get('admin_route')) { + routes.push(p.get('admin_route')); } - }).compact(); - }.property() + }); + + return routes; + } }); 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 0c1cb7abb37..14bc031c0a3 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 @@ -31,6 +31,29 @@ export default Ember.Controller.extend(CanCheckEmails, { }.property('model.user_fields.[]'), actions: { + + impersonate() { return this.get("model").impersonate(); }, + logOut() { return this.get("model").logOut(); }, + resetBounceScore() { return this.get("model").resetBounceScore(); }, + refreshBrowsers() { return this.get("model").refreshBrowsers(); }, + approve() { return this.get("model").approve(); }, + deactivate() { return this.get("model").deactivate(); }, + sendActivationEmail() { return this.get("model").sendActivationEmail(); }, + activate() { return this.get("model").activate(); }, + revokeAdmin() { return this.get("model").revokeAdmin(); }, + grantAdmin() { return this.get("model").grantAdmin(); }, + revokeModeration() { return this.get("model").revokeModeration(); }, + grantModeration() { return this.get("model").grantModeration(); }, + saveTrustLevel() { return this.get("model").saveTrustLevel(); }, + restoreTrustLevel() { return this.get("model").restoreTrustLevel(); }, + lockTrustLevel(locked) { return this.get("model").lockTrustLevel(locked); }, + unsuspend() { return this.get("model").unsuspend(); }, + unblock() { return this.get("model").unblock(); }, + block() { return this.get("model").block(); }, + deleteAllPosts() { return this.get("model").deleteAllPosts(); }, + anonymize() { return this.get('model').anonymize(); }, + destroy() { return this.get('model').destroy(); }, + toggleTitleEdit() { this.set('userTitleValue', this.get('model.title')); this.toggleProperty('editingTitle'); @@ -39,7 +62,7 @@ export default Ember.Controller.extend(CanCheckEmails, { saveTitle() { const self = this; - return ajax("/users/" + this.get('model.username').toLowerCase(), { + return ajax(`/users/${this.get('model.username').toLowerCase()}.json`, { data: {title: this.get('userTitleValue')}, type: 'PUT' }).catch(function(e) { @@ -107,14 +130,6 @@ export default Ember.Controller.extend(CanCheckEmails, { if (result) { self.get('model').revokeApiKey(); } } ); - }, - - anonymize() { - this.get('model').anonymize(); - }, - - destroy() { - this.get('model').destroy(); } } diff --git a/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 index 53d8370403b..28f93925127 100644 --- a/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 @@ -65,10 +65,16 @@ export default Ember.Controller.extend({ this.set('saved', false); const url = extractDomainFromUrl(this.get('model.payload_url')); const model = this.get('model'); + const isNew = model.get('isNew'); + const saveWebHook = () => { return model.save().then(() => { this.set('saved', true); this.get('adminWebHooks').get('model').addObject(model); + + if (isNew) { + this.transitionToRoute('adminWebHooks.show', model.get('id')); + } }).catch(popupAjaxError); }; diff --git a/app/assets/javascripts/admin/models/admin-user.js.es6 b/app/assets/javascripts/admin/models/admin-user.js.es6 index 411dac89b8a..48764b671d6 100644 --- a/app/assets/javascripts/admin/models/admin-user.js.es6 +++ b/app/assets/javascripts/admin/models/admin-user.js.es6 @@ -257,7 +257,7 @@ const AdminUser = Discourse.User.extend({ }); }, - log_out() { + logOut() { return ajax("/admin/users/" + this.id + "/log_out", { type: 'POST', data: { username_or_email: this.get('username') } diff --git a/app/assets/javascripts/admin/models/email-preview.js.es6 b/app/assets/javascripts/admin/models/email-preview.js.es6 index cfe96c6e0d5..acc7462b925 100644 --- a/app/assets/javascripts/admin/models/email-preview.js.es6 +++ b/app/assets/javascripts/admin/models/email-preview.js.es6 @@ -5,7 +5,7 @@ EmailPreview.reopenClass({ findDigest: function(lastSeenAt, username) { if (Em.isEmpty(lastSeenAt)) { - lastSeenAt = moment().subtract(7, 'days').format('YYYY-MM-DD'); + lastSeenAt = this.oneWeekAgo(); } if (Em.isEmpty(username)) { @@ -21,7 +21,7 @@ EmailPreview.reopenClass({ sendDigest: function(lastSeenAt, username, email) { if (Em.isEmpty(lastSeenAt)) { - lastSeenAt = moment().subtract(7, 'days').format('YYYY-MM-DD'); + lastSeenAt = this.oneWeekAgo(); } if (Em.isEmpty(username)) { @@ -31,6 +31,11 @@ EmailPreview.reopenClass({ return ajax("/admin/email/send-digest.json", { data: { last_seen_at: lastSeenAt, username: username, email: email } }); + }, + + oneWeekAgo() { + const en = moment().locale('en'); + return en.subtract(7, 'days').format('YYYY-MM-DD'); } }); diff --git a/app/assets/javascripts/admin/models/report.js.es6 b/app/assets/javascripts/admin/models/report.js.es6 index 3342323b467..03e3888f97b 100644 --- a/app/assets/javascripts/admin/models/report.js.es6 +++ b/app/assets/javascripts/admin/models/report.js.es6 @@ -81,7 +81,8 @@ const Report = Discourse.Model.extend({ switch (this.get("type")) { case "flags": return "flag"; case "likes": return "heart"; - default: return null; + case "bookmarks": return "bookmark"; + default: return null; } }.property("type"), diff --git a/app/assets/javascripts/admin/models/web-hook.js.es6 b/app/assets/javascripts/admin/models/web-hook.js.es6 index e688a4dd0a1..325d9310452 100644 --- a/app/assets/javascripts/admin/models/web-hook.js.es6 +++ b/app/assets/javascripts/admin/models/web-hook.js.es6 @@ -10,7 +10,6 @@ export default RestModel.extend({ verify_certificate: true, active: false, web_hook_event_types: null, - categoriesFilter: null, groupsFilterInName: null, @computed('wildcard_web_hook') @@ -23,9 +22,9 @@ export default RestModel.extend({ } }, - @observes('category_ids') - updateCategoriesFilter() { - this.set('categoriesFilter', Category.findByIds(this.get('category_ids'))); + @computed('category_ids') + categories(categoryIds) { + return Category.findByIds(categoryIds); }, @observes('group_ids') @@ -55,7 +54,8 @@ export default RestModel.extend({ createProperties() { const types = this.get('web_hook_event_types'); - const categories = this.get('categoriesFilter'); + const categoryIds = this.get('categories').map(c => c.id); + // Hack as {{group-selector}} accepts a comma-separated string as data source, but // we use an array to populate the datasource above. const groupsFilter = this.get('groupsFilterInName'); @@ -69,7 +69,7 @@ export default RestModel.extend({ verify_certificate: this.get('verify_certificate'), active: this.get('active'), web_hook_event_type_ids: Ember.isEmpty(types) ? [null] : types.map(type => type.id), - category_ids: Ember.isEmpty(categories) ? [null] : categories.map(c => c.id), + category_ids: Ember.isEmpty(categoryIds) ? [null] : categoryIds, group_ids: Ember.isEmpty(groupNames) || Ember.isEmpty(groupNames[0]) ? [null] : Discourse.Site.currentProp('groups') .reduce((groupIds, g) => { if (groupNames.includes(g.name)) { groupIds.push(g.id); } diff --git a/app/assets/javascripts/admin/templates/admin.hbs b/app/assets/javascripts/admin/templates/admin.hbs index 77904edc48b..7f34c00b772 100644 --- a/app/assets/javascripts/admin/templates/admin.hbs +++ b/app/assets/javascripts/admin/templates/admin.hbs @@ -23,7 +23,7 @@ {{nav-item route='admin.backups' label='admin.backups.title'}} {{/if}} {{nav-item route='adminPlugins' label='admin.plugins.title'}} - {{plugin-outlet "admin-menu" tagName="li"}} + {{plugin-outlet name="admin-menu" connectorTagName="li"}}
diff --git a/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs b/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs index d9286ef5800..cc6310768a0 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs @@ -4,8 +4,19 @@ {{/if}} {{report.title}} -{{report.todayCount}} -{{report.yesterdayCount}} {{fa-icon "caret-up" class="up"}} {{fa-icon "caret-down" class="down"}} -{{report.lastSevenDaysCount}} {{fa-icon "caret-up" class="up"}} {{fa-icon "caret-down" class="down"}} -{{report.lastThirtyDaysCount}} {{fa-icon "caret-up" class="up"}} {{fa-icon "caret-down" class="down"}} -{{report.total}} + +{{number report.todayCount}} + + + {{number report.yesterdayCount}} {{fa-icon "caret-up" class="up"}} {{fa-icon "caret-down" class="down"}} + + + + {{number report.lastSevenDaysCount}} {{fa-icon "caret-up" class="up"}} {{fa-icon "caret-down" class="down"}} + + + + {{number report.lastThirtyDaysCount}} {{fa-icon "caret-up" class="up"}} {{fa-icon "caret-down" class="down"}} + + +{{number report.total}} diff --git a/app/assets/javascripts/admin/templates/components/admin-report-trust-level-counts.hbs b/app/assets/javascripts/admin/templates/components/admin-report-trust-level-counts.hbs index c78e2630035..3db7af1daa2 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report-trust-level-counts.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report-trust-level-counts.hbs @@ -1,6 +1,6 @@ {{report.title}} -{{#link-to 'adminUsersList.show' 'newuser'}}{{value-at-tl report.data level="0"}}{{/link-to}} -{{#link-to 'adminUsersList.show' 'basic'}}{{value-at-tl report.data level="1"}}{{/link-to}} -{{#link-to 'adminUsersList.show' 'member'}}{{value-at-tl report.data level="2"}}{{/link-to}} -{{#link-to 'adminUsersList.show' 'regular'}}{{value-at-tl report.data level="3"}}{{/link-to}} -{{#link-to 'adminUsersList.show' 'leader'}}{{value-at-tl report.data level="4"}}{{/link-to}} +{{#link-to 'adminUsersList.show' 'newuser'}}{{number (value-at-tl report.data level="0")}}{{/link-to}} +{{#link-to 'adminUsersList.show' 'basic'}}{{number (value-at-tl report.data level="1")}}{{/link-to}} +{{#link-to 'adminUsersList.show' 'member'}}{{number (value-at-tl report.data level="2")}}{{/link-to}} +{{#link-to 'adminUsersList.show' 'regular'}}{{number (value-at-tl report.data level="3")}}{{/link-to}} +{{#link-to 'adminUsersList.show' 'leader'}}{{number (value-at-tl report.data level="4")}}{{/link-to}} diff --git a/app/assets/javascripts/admin/templates/components/permalink-form.hbs b/app/assets/javascripts/admin/templates/components/permalink-form.hbs index 987a1bc9185..c7942543316 100644 --- a/app/assets/javascripts/admin/templates/components/permalink-form.hbs +++ b/app/assets/javascripts/admin/templates/components/permalink-form.hbs @@ -2,4 +2,4 @@ {{text-field value=url disabled=formSubmitted class="permalink-url" placeholderKey="admin.permalink.url" autocorrect="off" autocapitalize="off"}} {{combo-box content=permalinkTypes value=permalinkType}} {{text-field value=permalink_type_value disabled=formSubmitted class="external-url" placeholderKey=permalinkTypePlaceholder autocorrect="off" autocapitalize="off"}} - +{{d-button action="submit" disabled=formSubmitted label="admin.permalink.form.add"}} diff --git a/app/assets/javascripts/admin/templates/dashboard.hbs b/app/assets/javascripts/admin/templates/dashboard.hbs index e02a5a925ca..fbb0eb46b13 100644 --- a/app/assets/javascripts/admin/templates/dashboard.hbs +++ b/app/assets/javascripts/admin/templates/dashboard.hbs @@ -1,4 +1,4 @@ -{{plugin-outlet "admin-dashboard-top"}} +{{plugin-outlet name="admin-dashboard-top"}} {{#conditional-loading-spinner condition=loading}}
@@ -228,7 +228,7 @@
- {{data.num_clicks}} + {{number data.num_clicks}} {{/each}} @@ -248,8 +248,8 @@ {{s.domain}} - {{s.num_clicks}} - {{s.num_topics}} + {{number s.num_clicks}} + {{number s.num_topics}} {{/each}} @@ -261,16 +261,16 @@ {{top_referrers.title}} ({{i18n 'admin.dashboard.reports.last_30_days'}}) - {{top_referrers.ytitles.num_clicks}} - {{top_referrers.ytitles.num_topics}} + {{number top_referrers.ytitles.num_clicks}} + {{number top_referrers.ytitles.num_topics}} {{#each top_referrers.data as |r|}} {{#link-to 'adminUser' r.user_id r.username}}{{unbound r.username}}{{/link-to}} - {{r.num_clicks}} - {{r.num_topics}} + {{number r.num_clicks}} + {{number r.num_topics}} {{/each}} diff --git a/app/assets/javascripts/admin/templates/emojis.hbs b/app/assets/javascripts/admin/templates/emojis.hbs index 8972e2ab276..6f35c097a96 100644 --- a/app/assets/javascripts/admin/templates/emojis.hbs +++ b/app/assets/javascripts/admin/templates/emojis.hbs @@ -18,7 +18,7 @@ {{#each sortedEmojis as |e|}} - + :{{e.name}}: diff --git a/app/assets/javascripts/admin/templates/group.hbs b/app/assets/javascripts/admin/templates/group.hbs index f66e0ca8557..095b3f5f4b8 100644 --- a/app/assets/javascripts/admin/templates/group.hbs +++ b/app/assets/javascripts/admin/templates/group.hbs @@ -11,6 +11,11 @@ {{#if model.id}} {{#unless model.automatic}} +
+ + {{input type='text' name='full_name' value=model.full_name class='group-edit-full-name'}} +
+
{{d-editor value=model.bio_raw}} @@ -33,26 +38,8 @@
{{/unless}}
- -
- - {{currentPage}}/{{totalPages}} - -
-
- {{#each model.members as |member|}} - {{group-member member=member automatic=model.automatic removeAction="removeMember"}} - {{/each}} -
+ {{group-members-input model=model}}
- - {{#unless model.automatic}} -
- - {{user-selector usernames=model.usernames placeholderKey="admin.groups.selector_placeholder" id="user-selector"}} - {{d-button action="addMembers" class="add" icon="plus" label="admin.groups.add"}} -
- {{/unless}} {{/if}}
@@ -121,7 +108,7 @@ {{#if siteSettings.email_in}} {{text-field name="incoming_email" value=model.incoming_email placeholderKey="admin.groups.incoming_email_placeholder"}} - {{plugin-outlet "group-email-in"}} + {{plugin-outlet name="group-email-in" args=(hash model=model)}} {{/if}} {{/unless}} diff --git a/app/assets/javascripts/admin/templates/groups-type.hbs b/app/assets/javascripts/admin/templates/groups-type.hbs index d1d2223c2b3..6c9986fcb39 100644 --- a/app/assets/javascripts/admin/templates/groups-type.hbs +++ b/app/assets/javascripts/admin/templates/groups-type.hbs @@ -6,7 +6,7 @@
  • {{#link-to "adminGroup" group.type group.name}}{{group.name}} {{#if group.userCountDisplay}} - {{group.userCountDisplay}} + {{number group.userCountDisplay}} {{/if}} {{/link-to}}
  • diff --git a/app/assets/javascripts/admin/templates/user-index.hbs b/app/assets/javascripts/admin/templates/user-index.hbs index 6c4c87afffc..9cc35a3dce3 100644 --- a/app/assets/javascripts/admin/templates/user-index.hbs +++ b/app/assets/javascripts/admin/templates/user-index.hbs @@ -9,16 +9,10 @@ {{/if}} {{#if model.active}} {{#if model.can_impersonate}} - + {{d-button class="btn-danger" action="impersonate" icon="crosshairs" label="admin.impersonate.title" title="admin.impersonate.help"}} {{/if}} {{#if currentUser.admin}} - + {{d-button action="logOut" icon="power-off" label="admin.user.log_out"}} {{/if}} {{/if}}
    @@ -49,7 +43,7 @@ {{#if model.email}} {{model.email}} {{else}} - + {{d-button action="checkEmail" actionParam=model icon="envelope-o" label="admin.users.check_email.text" title="admin.users.check_email.title"}} {{/if}} @@ -59,9 +53,7 @@
    {{model.bounceScore}}
    {{#if model.canResetBounceScore}} - + {{d-button action="resetBounceScore" label="admin.user.reset_bounce_score.label" title="admin.user.reset_bounce_score.title"}} {{/if}} {{model.bounceScoreExplanation}}
    @@ -73,7 +65,7 @@ {{#if model.associated_accounts}} {{model.associated_accounts}} {{else}} - + {{d-button action="checkEmail" actionParam=model icon="envelope-o" label="admin.users.check_email.text" title="admin.users.check_email.title"}} {{/if}} @@ -108,9 +100,7 @@
    {{model.ip_address}}
    {{#if currentUser.staff}} - + {{d-button action="refreshBrowsers" label="admin.user.refresh_browsers"}} {{ip-lookup ip=model.ip_address userId=model.id}} {{/if}}
    @@ -176,10 +166,7 @@ {{i18n 'admin.user.approve_success'}} {{else}} {{#if model.can_approve}} - + {{d-button action="approve" icon="check" label="admin.user.approve"}} {{/if}} {{/if}} @@ -188,31 +175,19 @@
    {{i18n 'admin.users.active'}}
    -
    - {{#if model.active}} - {{i18n 'yes_value'}} - {{else}} - {{i18n 'no_value'}} - {{/if}} -
    +
    {{i18n-yes-no model.active}}
    {{#if model.active}} {{#if model.can_deactivate}} - + {{d-button action="deactivate" label="admin.user.deactivate_account"}} {{i18n 'admin.user.deactivate_explanation'}} {{/if}} {{else}} {{#if model.can_send_activation_email}} - + {{d-button action="sendActivationEmail" icon="envelope" label="admin.user.send_activation_email"}} {{/if}} {{#if model.can_activate}} - + {{d-button action="activate" icon="check" label="admin.user.activate"}} {{/if}} {{/if}}
    @@ -240,38 +215,26 @@
    {{i18n 'admin.user.admin'}}
    -
    {{model.admin}}
    +
    {{i18n-yes-no model.admin}}
    {{#if model.can_revoke_admin}} - + {{d-button action="revokeAdmin" icon="shield" label="admin.user.revoke_admin"}} {{/if}} {{#if model.can_grant_admin}} - + {{d-button action="grantAdmin" icon="shield" label="admin.user.grant_admin"}} {{/if}}
    {{i18n 'admin.user.moderator'}}
    -
    {{model.moderator}}
    +
    {{i18n-yes-no model.moderator}}
    {{#if model.can_revoke_moderation}} - + {{d-button action="revokeModeration" icon="shield" label="admin.user.revoke_moderation"}} {{/if}} {{#if model.can_grant_moderation}} - + {{d-button action="grantModeration" icon="shield" label="admin.user.grant_moderation"}} {{/if}}
    @@ -282,17 +245,17 @@ {{combo-box content=site.trustLevels value=model.trust_level nameProperty="detailedName"}} {{#if model.dirty}}
    - - + {{d-button class="ok no-text" action="saveTrustLevel" icon="check"}} + {{d-button class="cancel no-text" action="restoreTrustLevel" icon="times"}}
    {{/if}}
    {{#if model.canLockTrustLevel}} {{#if model.trust_level_locked}} - + {{d-button action="lockTrustLevel" actionParam=false label="admin.user.unlock_trust_level"}} {{else}} - + {{d-button action="lockTrustLevel" actionParam=true label="admin.user.lock_trust_level"}} {{/if}} {{/if}} {{#if model.tl3Requirements}} @@ -303,21 +266,15 @@
    {{i18n 'admin.user.suspended'}}
    -
    {{model.isSuspended}}
    +
    {{i18n-yes-no model.isSuspended}}
    {{#if model.isSuspended}} - + {{d-button class="btn-danger" action="unsuspend" icon="ban" label="admin.user.unsuspend"}} {{suspendDuration}} {{i18n 'admin.user.suspended_explanation'}} {{else}} {{#if model.canSuspend}} - + {{d-button class="btn-danger" action="showSuspendModal" actionParam=model icon="ban" label="admin.user.suspend"}} {{i18n 'admin.user.suspended_explanation'}} {{/if}} {{/if}} @@ -340,20 +297,14 @@
    {{i18n 'admin.user.blocked'}}
    -
    {{model.blocked}}
    +
    {{i18n-yes-no model.blocked}}
    {{#conditional-loading-spinner size="small" condition=model.blockingUser}} {{#if model.blocked}} - + {{d-button action="unblock" icon="thumbs-o-up" label="admin.user.unblock"}} {{i18n 'admin.user.block_explanation'}} {{else}} - + {{d-button action="block" icon="ban" label="admin.user.block"}} {{i18n 'admin.user.block_explanation'}} {{/if}} {{/conditional-loading-spinner}} @@ -362,7 +313,7 @@
    {{i18n 'admin.user.staged'}}
    -
    {{model.staged}}
    +
    {{i18n-yes-no model.staged}}
    {{i18n 'admin.user.staged_explanation'}}
    @@ -423,10 +374,7 @@
    {{#if model.can_delete_all_posts}} {{#if model.post_count}} - + {{d-button class="btn-danger" action="deleteAllPosts" icon="trash-o" label="admin.user.delete_all_posts"}} {{/if}} {{else}} {{model.deleteAllPostsExplanation}} diff --git a/app/assets/javascripts/admin/templates/users-list-show.hbs b/app/assets/javascripts/admin/templates/users-list-show.hbs index 879161e3d48..f18ce56b4b7 100644 --- a/app/assets/javascripts/admin/templates/users-list-show.hbs +++ b/app/assets/javascripts/admin/templates/users-list-show.hbs @@ -55,8 +55,8 @@ {{unbound user.email}} {{{unbound user.last_emailed_age}}} {{{unbound user.last_seen_age}}} - {{{unbound user.topics_entered}}} - {{{unbound user.posts_read_count}}} + {{number user.topics_entered}} + {{number user.posts_read_count}} {{{unbound user.time_read}}} {{{unbound user.created_at_age}}} diff --git a/app/assets/javascripts/admin/templates/version-checks.hbs b/app/assets/javascripts/admin/templates/version-checks.hbs index 542020d8ebd..25c560ad6ae 100644 --- a/app/assets/javascripts/admin/templates/version-checks.hbs +++ b/app/assets/javascripts/admin/templates/version-checks.hbs @@ -1,7 +1,10 @@
    + + {{custom-html name="upgrade-header" versionCheck=versionCheck tagName="thead"}} +
    + - {{custom-html 'upgrade-header'}} diff --git a/app/assets/javascripts/admin/templates/web-hooks-show.hbs b/app/assets/javascripts/admin/templates/web-hooks-show.hbs index b0e0c0c0bfb..458a18c1e22 100644 --- a/app/assets/javascripts/admin/templates/web-hooks-show.hbs +++ b/app/assets/javascripts/admin/templates/web-hooks-show.hbs @@ -50,7 +50,7 @@
    - {{category-selector categories=model.categoriesFilter blacklist=model.categoriesFilter}} + {{category-selector categories=model.categories blacklist=model.categories}}
    {{i18n 'admin.web_hooks.categories_filter_instructions'}}
    diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 2a4085f785e..96a2066c414 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -89,7 +89,6 @@ //= require_tree ./discourse/models //= require_tree ./discourse/components //= require_tree ./discourse/raw-views -//= require_tree ./discourse/views //= require_tree ./discourse/helpers //= require_tree ./discourse/templates //= require_tree ./discourse/routes diff --git a/app/assets/javascripts/discourse-common/helpers/i18n.js.es6 b/app/assets/javascripts/discourse-common/helpers/i18n.js.es6 index 455cc65a355..40fd2893d52 100644 --- a/app/assets/javascripts/discourse-common/helpers/i18n.js.es6 +++ b/app/assets/javascripts/discourse-common/helpers/i18n.js.es6 @@ -1,3 +1,4 @@ import { registerUnbound } from 'discourse-common/lib/helpers'; registerUnbound('i18n', (key, params) => I18n.t(key, params)); +registerUnbound('i18n-yes-no', (value, params) => I18n.t(value ? 'yes_value' : 'no_value', params)); diff --git a/app/assets/javascripts/discourse-common/lib/raw-handlebars.js.es6 b/app/assets/javascripts/discourse-common/lib/raw-handlebars.js.es6 index 423d8e88352..4b547a68828 100644 --- a/app/assets/javascripts/discourse-common/lib/raw-handlebars.js.es6 +++ b/app/assets/javascripts/discourse-common/lib/raw-handlebars.js.es6 @@ -18,6 +18,10 @@ RawHandlebars.helpers['get'] = function(context, options) { var firstContext = options.contexts[0]; var val = firstContext[context]; + if (context.indexOf('controller') === 0) { + context = context.replace(/^controller\./, ''); + } + if (val && val.isDescriptor) { return Em.get(firstContext, context); } val = val === undefined ? Em.get(firstContext, context): val; return val; diff --git a/app/assets/javascripts/discourse-common/resolver.js.es6 b/app/assets/javascripts/discourse-common/resolver.js.es6 index a69efc4e30b..19247192086 100644 --- a/app/assets/javascripts/discourse-common/resolver.js.es6 +++ b/app/assets/javascripts/discourse-common/resolver.js.es6 @@ -10,19 +10,23 @@ export function setResolverOption(name, value) { _options[name] = value; } +export function getResolverOption(name) { + return _options[name]; +} + function parseName(fullName) { - const nameParts = fullName.split(":"), - type = nameParts[0], fullNameWithoutType = nameParts[1], - name = fullNameWithoutType, - namespace = get(this, 'namespace'), - root = namespace; + const nameParts = fullName.split(":"); + const type = nameParts[0]; + let fullNameWithoutType = nameParts[1]; + const namespace = get(this, 'namespace'); + const root = namespace; return { - fullName: fullName, - type: type, - fullNameWithoutType: fullNameWithoutType, - name: name, - root: root, + fullName, + type, + fullNameWithoutType, + name: fullNameWithoutType, + root, resolveMethodName: "resolve" + classify(type) }; } @@ -125,12 +129,21 @@ export function buildResolver(baseName) { } }, + findConnectorTemplate(parsedName) { + const full = parsedName.fullNameWithoutType.replace('components/', ''); + if (full.indexOf('connectors') === 0) { + return Ember.TEMPLATES[`javascripts/${full}`]; + } + + }, + resolveTemplate(parsedName) { return this.findPluginMobileTemplate(parsedName) || this.findPluginTemplate(parsedName) || this.findMobileTemplate(parsedName) || this.findTemplate(parsedName) || this.findLoadingTemplate(parsedName) || + this.findConnectorTemplate(parsedName) || Ember.TEMPLATES.not_found; }, diff --git a/app/assets/javascripts/discourse.js.es6 b/app/assets/javascripts/discourse.js.es6 index 9012e8301b2..5ca85473c5b 100644 --- a/app/assets/javascripts/discourse.js.es6 +++ b/app/assets/javascripts/discourse.js.es6 @@ -6,7 +6,7 @@ const _pluginCallbacks = []; const Discourse = Ember.Application.extend({ rootElement: '#main', _docTitle: document.title, - __TAGS_INCLUDED__: true, + RAW_TEMPLATES: {}, getURL(url) { if (!url) return url; @@ -137,7 +137,7 @@ const Discourse = Ember.Application.extend({ Discourse.instanceInitializer({ name: "_discourse_plugin_" + (++initCount), after: 'inject-objects', - initialize: function() { + initialize() { withPluginApi(cb.version, cb.code); } }); diff --git a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 index 539171bc9a1..fd5bac3c0e0 100644 --- a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 @@ -11,6 +11,10 @@ export default Em.Component.extend(UploadMixin, { return uploading ? I18n.t("uploading") : I18n.t("user.change_avatar.upload_picture"); }, + validateUploadedFilesOptions() { + return { imagesOnly: true }; + }, + uploadDone(upload) { this.setProperties({ imageIsNotASquare: upload.width !== upload.height, diff --git a/app/assets/javascripts/discourse/components/badge-selector.js.es6 b/app/assets/javascripts/discourse/components/badge-selector.js.es6 index 315f7398a78..8f0bd5ecfeb 100644 --- a/app/assets/javascripts/discourse/components/badge-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/badge-selector.js.es6 @@ -1,5 +1,5 @@ import { on, observes, default as computed } from 'ember-addons/ember-computed-decorators'; -import { getOwner } from 'discourse-common/lib/get-owner'; +import { findRawTemplate } from 'discourse/lib/raw-templates'; export default Ember.Component.extend({ @computed('placeholderKey') @@ -18,7 +18,6 @@ export default Ember.Component.extend({ var self = this; var selectedBadges; - var template = getOwner(this).lookup('template:badge-selector-autocomplete.raw'); self.$('input').autocomplete({ allowAny: false, items: _.isArray(this.get('badgeNames')) ? this.get('badgeNames') : [this.get('badgeNames')], @@ -43,7 +42,7 @@ export default Ember.Component.extend({ }); }); }, - template: template + template: findRawTemplate('badge-selector-autocomplete') }); } }); diff --git a/app/assets/javascripts/discourse/components/category-selector.js.es6 b/app/assets/javascripts/discourse/components/category-selector.js.es6 index 460a1dfdd65..9cb3eec14ae 100644 --- a/app/assets/javascripts/discourse/components/category-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/category-selector.js.es6 @@ -1,7 +1,7 @@ import { categoryBadgeHTML } from 'discourse/helpers/category-link'; import Category from 'discourse/models/category'; import { on, observes } from 'ember-addons/ember-computed-decorators'; -import { getOwner } from 'discourse-common/lib/get-owner'; +import { findRawTemplate } from 'discourse/lib/raw-templates'; export default Ember.Component.extend({ @observes('categories') @@ -13,7 +13,6 @@ export default Ember.Component.extend({ @on('didInsertElement') _initializeAutocomplete(opts) { const self = this, - template = getOwner(this).lookup('template:category-selector-autocomplete.raw'), regexp = new RegExp(`href=['\"]${Discourse.getURL('/c/')}([^'\"]+)`); this.$('input').autocomplete({ @@ -41,7 +40,7 @@ export default Ember.Component.extend({ self.set('categories', categories); }); }, - template, + template: findRawTemplate('category-selector-autocomplete'), transformComplete(category) { return categoryBadgeHTML(category, {allowUncategorized: true}); } diff --git a/app/assets/javascripts/discourse/components/composer-editor.js.es6 b/app/assets/javascripts/discourse/components/composer-editor.js.es6 index 55b69c64a1c..a851ae88609 100644 --- a/app/assets/javascripts/discourse/components/composer-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-editor.js.es6 @@ -6,7 +6,7 @@ import { linkSeenTagHashtags, fetchUnseenTagHashtags } from 'discourse/lib/link- import { load } from 'pretty-text/oneboxer'; import { ajax } from 'discourse/lib/ajax'; import InputValidation from 'discourse/models/input-validation'; -import { getOwner } from 'discourse-common/lib/get-owner'; +import { findRawTemplate } from 'discourse/lib/raw-templates'; import { tinyAvatar, displayErrorForUpload, getUploadMarkdown, @@ -62,10 +62,9 @@ export default Ember.Component.extend({ @on('didInsertElement') _composerEditorInit() { const topicId = this.get('topic.id'); - const template = getOwner(this).lookup('template:user-selector-autocomplete.raw'); const $input = this.$('.d-editor-input'); $input.autocomplete({ - template, + template: findRawTemplate('user-selector-autocomplete'), dataSource: term => userSearch({ term, topicId, includeGroups: true }), key: "@", transformComplete: v => v.username || v.name @@ -168,7 +167,7 @@ export default Ember.Component.extend({ post.set('refreshedPost', true); } - $oneboxes.each((_, o) => load(o, refresh, ajax)); + $oneboxes.each((_, o) => load(o, refresh, ajax, this.currentUser.id)); }, _warnMentionedGroups($preview) { diff --git a/app/assets/javascripts/discourse/components/composer-title.js.es6 b/app/assets/javascripts/discourse/components/composer-title.js.es6 index 1e0d6b75601..1a2eb1bea7c 100644 --- a/app/assets/javascripts/discourse/components/composer-title.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-title.js.es6 @@ -31,7 +31,7 @@ export default Ember.Component.extend({ } }, - @observes('composer.titleLength') + @observes('composer.titleLength', 'watchForLink') _titleChanged() { if (this.get('composer.titleLength') === 0) { this.set('autoPosted', false); } if (this.get('autoPosted') || !this.get('watchForLink')) { return; } @@ -51,15 +51,16 @@ export default Ember.Component.extend({ }, _checkForUrl() { + if (!this.element || this.isDestroying || this.isDestroyed) { return; } + if (this.get('isAbsoluteUrl') && (this.get('composer.reply')||"").length === 0) { // Try to onebox. If success, update post body and title. - this.set('composer.loading', true); const link = document.createElement('a'); link.href = this.get('composer.title'); - let loadOnebox = load(link, false, ajax); + let loadOnebox = load(link, false, ajax, this.currentUser.id, true); if (loadOnebox && loadOnebox.then) { loadOnebox.then( () => { @@ -82,15 +83,17 @@ export default Ember.Component.extend({ this.set('composer.featuredLink', this.get('composer.title')); const $h = $(html), - header = $h.find('h4').length > 0 ? $h.find('h4') : $h.find('h3'); + heading = $h.find('h3').length > 0 ? $h.find('h3') : $h.find('h4'); this.set('composer.reply', this.get('composer.title')); - if (header.length > 0 && header.text().length > 0) { - this.changeTitle(header.text()); + if (heading.length > 0 && heading.text().length > 0) { + this.changeTitle(heading.text()); } else { - const filename = (this.get('composer.featuredLink')||"").split("/").pop(); - this.changeTitle(filename); + const firstTitle = $h.attr('title') || $h.find("[title]").attr("title"); + if (firstTitle && firstTitle.length > 0) { + this.changeTitle(firstTitle); + } } } }, diff --git a/app/assets/javascripts/discourse/components/csv-uploader.js.es6 b/app/assets/javascripts/discourse/components/csv-uploader.js.es6 index d89aaae30b7..70637588687 100644 --- a/app/assets/javascripts/discourse/components/csv-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/csv-uploader.js.es6 @@ -6,6 +6,10 @@ export default Em.Component.extend(UploadMixin, { tagName: "span", uploadUrl: "/invites/upload_csv", + validateUploadedFilesOptions() { + return { csvOnly: true }; + }, + @computed("uploading") uploadButtonText(uploading) { return uploading ? I18n.t("uploading") : I18n.t("user.invited.bulk_invite.text"); diff --git a/app/assets/javascripts/discourse/components/custom-html.js.es6 b/app/assets/javascripts/discourse/components/custom-html.js.es6 new file mode 100644 index 00000000000..c5df7fb51ed --- /dev/null +++ b/app/assets/javascripts/discourse/components/custom-html.js.es6 @@ -0,0 +1,20 @@ +import { getCustomHTML } from 'discourse/helpers/custom-html'; +import { getOwner } from 'discourse-common/lib/get-owner'; + +export default Ember.Component.extend({ + init() { + this._super(); + const name = this.get('name'); + const html = getCustomHTML(name); + + if (html) { + this.set('html', html); + this.set('layoutName', 'components/custom-html-container'); + } else { + const template = getOwner(this).lookup(`template:${name}`); + if (template) { + this.set('layoutName', name); + } + } + } +}); diff --git a/app/assets/javascripts/discourse/components/d-editor.js.es6 b/app/assets/javascripts/discourse/components/d-editor.js.es6 index 6e43dfde817..d5228324966 100644 --- a/app/assets/javascripts/discourse/components/d-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/d-editor.js.es6 @@ -11,6 +11,8 @@ import { translations } from 'pretty-text/emoji/data'; import { emojiSearch } from 'pretty-text/emoji'; import { emojiUrlFor } from 'discourse/lib/text'; import { getRegister } from 'discourse-common/lib/get-owner'; +import { findRawTemplate } from 'discourse/lib/raw-templates'; +import { determinePostReplaceSelection } from 'discourse/lib/utilities'; import deprecated from 'discourse-common/lib/deprecated'; // Our head can be a static string or a function that returns a string @@ -297,11 +299,10 @@ export default Ember.Component.extend({ }, _applyCategoryHashtagAutocomplete() { - const template = this.register.lookup('template:category-tag-autocomplete.raw'); const siteSettings = this.siteSettings; this.$('.d-editor-input').autocomplete({ - template: template, + template: findRawTemplate('category-tag-autocomplete'), key: '#', transformComplete(obj) { if (obj.model) { @@ -323,11 +324,10 @@ export default Ember.Component.extend({ if (!this.siteSettings.enable_emoji) { return; } const register = this.register; - const template = this.register.lookup('template:emoji-selector-autocomplete.raw'); const self = this; $editorInput.autocomplete({ - template: template, + template: findRawTemplate('emoji-selector-autocomplete'), key: ":", afterComplete(text) { self.set('value', text); @@ -526,11 +526,27 @@ export default Ember.Component.extend({ _replaceText(oldVal, newVal) { const val = this.get('value'); - const loc = val.indexOf(oldVal); - if (loc !== -1) { - this.set('value', val.replace(oldVal, newVal)); - this._selectText(loc + newVal.length, 0); + const needleStart = val.indexOf(oldVal); + + if (needleStart === -1) { + // Nothing to replace. + return; } + + const textarea = this.$('textarea.d-editor-input')[0]; + + // Determine post-replace selection. + const newSelection = determinePostReplaceSelection({ + selection: { start: textarea.selectionStart, end: textarea.selectionEnd }, + needle: { start: needleStart, end: needleStart + oldVal.length }, + replacement: { start: needleStart, end: needleStart + newVal.length } + }); + + // Replace value (side effect: cursor at the end). + this.set('value', val.replace(oldVal, newVal)); + + // Restore cursor. + this._selectText(newSelection.start, newSelection.end - newSelection.start); }, _addText(sel, text) { @@ -553,6 +569,7 @@ export default Ember.Component.extend({ applySurround: (head, tail, exampleKey, opts) => this._applySurround(selected, head, tail, exampleKey, opts), applyList: (head, exampleKey) => this._applyList(selected, head, exampleKey), addText: text => this._addText(selected, text), + replaceText: text => this._addText({pre: '', post: ''}, text), getText: () => this.get('value'), }; diff --git a/app/assets/javascripts/discourse/components/discourse-topic.js.es6 b/app/assets/javascripts/discourse/components/discourse-topic.js.es6 index 5d5c6299337..17f40f3928b 100644 --- a/app/assets/javascripts/discourse/components/discourse-topic.js.es6 +++ b/app/assets/javascripts/discourse/components/discourse-topic.js.es6 @@ -5,16 +5,10 @@ import { selectedText } from 'discourse/lib/utilities'; import { observes } from 'ember-addons/ember-computed-decorators'; function highlight(postNumber) { - const $contents = $(`#post_${postNumber} .topic-body`), - origColor = $contents.data('orig-color') || $contents.css('backgroundColor'); + const $contents = $(`#post_${postNumber} .topic-body`); - $contents.data("orig-color", origColor) - .addClass('highlighted') - .stop() - .animate({ backgroundColor: origColor }, 2500, 'swing', function() { - $contents.removeClass('highlighted'); - $contents.css({'background-color': ''}); - }); + $contents.addClass('highlighted'); + $contents.on('animationend', () => $contents.removeClass('highlighted')); } export default Ember.Component.extend(AddArchetypeClass, Scrolling, { diff --git a/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 b/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 index b43bea04103..0afeb1a239c 100644 --- a/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 @@ -11,6 +11,10 @@ export default Em.Component.extend(UploadMixin, { return Ember.isBlank(this.get("name")) ? {} : { name: this.get("name") }; }.property("name"), + validateUploadedFilesOptions() { + return { imagesOnly: true }; + }, + uploadDone(upload) { this.set("name", null); this.sendAction("done", upload); diff --git a/app/assets/javascripts/admin/components/group-member.js.es6 b/app/assets/javascripts/discourse/components/group-member.js.es6 similarity index 100% rename from app/assets/javascripts/admin/components/group-member.js.es6 rename to app/assets/javascripts/discourse/components/group-member.js.es6 diff --git a/app/assets/javascripts/discourse/components/group-members-input.js.es6 b/app/assets/javascripts/discourse/components/group-members-input.js.es6 new file mode 100644 index 00000000000..1fb45f27bf6 --- /dev/null +++ b/app/assets/javascripts/discourse/components/group-members-input.js.es6 @@ -0,0 +1,69 @@ +import computed from 'ember-addons/ember-computed-decorators'; +import { popupAjaxError } from 'discourse/lib/ajax-error'; +import { propertyEqual } from 'discourse/lib/computed'; + +export default Ember.Component.extend({ + classNames: ["group-members-input"], + + @computed('model.limit', 'model.offset', 'model.user_count') + currentPage(limit, offset, userCount) { + if (userCount === 0) { return 0; } + + return Math.floor(offset / limit) + 1; + }, + + @computed('model.limit', 'model.user_count') + totalPages(limit, userCount) { + if (userCount === 0) { return 0; } + return Math.floor(userCount / limit) + 1; + }, + + @computed('model.usernames') + disableAddButton(usernames) { + return !usernames || !(usernames.length > 0); + }, + + showingFirst: Em.computed.lte("currentPage", 1), + showingLast: propertyEqual("currentPage", "totalPages"), + + actions: { + next() { + if (this.get("showingLast")) { return; } + + const group = this.get("model"); + const offset = Math.min(group.get("offset") + group.get("limit"), group.get("user_count")); + group.set("offset", offset); + + return group.findMembers(); + }, + + previous() { + if (this.get("showingFirst")) { return; } + + const group = this.get("model"); + const offset = Math.max(group.get("offset") - group.get("limit"), 0); + group.set("offset", offset); + + return group.findMembers(); + }, + + addMembers() { + if (Em.isEmpty(this.get("model.usernames"))) { return; } + this.get("model").addMembers(this.get("model.usernames")).catch(popupAjaxError); + this.set("model.usernames", null); + }, + + removeMember(member) { + const message = I18n.t("groups.edit.delete_member_confirm",{ + username: member.get("username"), + group: this.get("model.name") + }); + + return bootbox.confirm(message, I18n.t("no_value"), I18n.t("yes_value"), confirm => { + if (confirm) { + this.get("model").removeMember(member); + } + }); + } + } +}); diff --git a/app/assets/javascripts/discourse/components/group-membership-button.js.es6 b/app/assets/javascripts/discourse/components/group-membership-button.js.es6 new file mode 100644 index 00000000000..dba83c69dc2 --- /dev/null +++ b/app/assets/javascripts/discourse/components/group-membership-button.js.es6 @@ -0,0 +1,73 @@ +import { default as computed } from 'ember-addons/ember-computed-decorators'; +import { popupAjaxError } from 'discourse/lib/ajax-error'; +import Group from 'discourse/models/group'; + +export default Ember.Component.extend({ + @computed("model.public") + canJoinGroup(publicGroup) { + return publicGroup; + }, + + @computed('model.allow_membership_requests', 'model.alias_level') + canRequestMembership(allowMembershipRequests, aliasLevel) { + return allowMembershipRequests && aliasLevel === 99; + }, + + @computed("model.is_group_user", "model.id", "groupUserIds") + userIsGroupUser(isGroupUser, groupId, groupUserIds) { + if (isGroupUser) { + return isGroupUser; + } else { + return !!groupUserIds && groupUserIds.includes(groupId); + } + }, + + @computed + joinGroupAction() { + return this.currentUser ? 'joinGroup' : 'showLogin'; + }, + + @computed + requestMembershipAction() { + return this.currentUser ? 'requestMembership' : 'showLogin'; + }, + + actions: { + showLogin() { + this.sendAction('showLogin'); + }, + + joinGroup() { + this.set('updatingMembership', true); + const model = this.get('model'); + + model.addMembers(this.currentUser.get('username')).then(() => { + model.set('is_group_user', true); + }).catch(popupAjaxError).finally(() => { + this.set('updatingMembership', false); + }); + }, + + leaveGroup() { + this.set('updatingMembership', true); + const model = this.get('model'); + + model.removeMember(this.currentUser).then(() => { + model.set('is_group_user', false); + }).catch(popupAjaxError).finally(() => { + this.set('updatingMembership', false); + }); + }, + + requestMembership() { + const groupName = this.get('model.name'); + + Group.loadOwners(groupName).then(result => { + const names = result.map(owner => owner.username).join(","); + const title = I18n.t('groups.request_membership_pm.title'); + const body = I18n.t('groups.request_membership_pm.body', { groupName }); + this.sendAction("createNewMessageViaParams", names, title, body); + }); + } + } +}); diff --git a/app/assets/javascripts/discourse/components/group-selector.js.es6 b/app/assets/javascripts/discourse/components/group-selector.js.es6 index 4f4fa0f6a5e..4beb5a3a932 100644 --- a/app/assets/javascripts/discourse/components/group-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/group-selector.js.es6 @@ -1,5 +1,5 @@ import { on, observes, default as computed } from 'ember-addons/ember-computed-decorators'; -import { getOwner } from 'discourse-common/lib/get-owner'; +import { findRawTemplate } from 'discourse/lib/raw-templates'; export default Ember.Component.extend({ @computed('placeholderKey') @@ -19,7 +19,6 @@ export default Ember.Component.extend({ var selectedGroups; var groupNames = this.get('groupNames'); - var template = getOwner(this).lookup('template:group-selector-autocomplete.raw'); self.$('input').autocomplete({ allowAny: false, items: _.isArray(groupNames) ? groupNames : (Ember.isEmpty(groupNames)) ? [] : [groupNames], @@ -44,7 +43,7 @@ export default Ember.Component.extend({ }); }); }, - template: template + template: findRawTemplate('group-selector-autocomplete') }); } }); diff --git a/app/assets/javascripts/discourse/components/image-uploader.js.es6 b/app/assets/javascripts/discourse/components/image-uploader.js.es6 index afa00fcfb30..642ba03b3e8 100644 --- a/app/assets/javascripts/discourse/components/image-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/image-uploader.js.es6 @@ -10,6 +10,10 @@ export default Em.Component.extend(UploadMixin, { return `background-image: url(${imageUrl})`.htmlSafe(); }, + validateUploadedFilesOptions() { + return { imagesOnly: true }; + }, + uploadDone(upload) { this.set("imageUrl", upload.url); this.set("imageId", upload.id); diff --git a/app/assets/javascripts/discourse/components/mobile-nav.js.es6 b/app/assets/javascripts/discourse/components/mobile-nav.js.es6 index cee8a2111aa..deccf48ef2d 100644 --- a/app/assets/javascripts/discourse/components/mobile-nav.js.es6 +++ b/app/assets/javascripts/discourse/components/mobile-nav.js.es6 @@ -14,6 +14,7 @@ export default Ember.Component.extend({ }, tagName: 'ul', + selectedHtml: null, classNames: ['mobile-nav'], diff --git a/app/assets/javascripts/discourse/components/mount-widget.js.es6 b/app/assets/javascripts/discourse/components/mount-widget.js.es6 index 3c56961ff8c..3c41721fe63 100644 --- a/app/assets/javascripts/discourse/components/mount-widget.js.es6 +++ b/app/assets/javascripts/discourse/components/mount-widget.js.es6 @@ -23,8 +23,6 @@ export default Ember.Component.extend({ this._super(); const name = this.get('widget'); - (this.get('delegated') || []).forEach(m => this.set(m, m)); - this.register = getRegister(this); this._widgetClass = queryRegistry(name) || this.register.lookupFactory(`widget:${name}`); @@ -33,7 +31,6 @@ export default Ember.Component.extend({ console.error(`Error: Could not find widget: ${name}`); } - this._childEvents = []; this._connected = []; this._dispatched = []; diff --git a/app/assets/javascripts/discourse/components/plugin-connector.js.es6 b/app/assets/javascripts/discourse/components/plugin-connector.js.es6 new file mode 100644 index 00000000000..564ab139e72 --- /dev/null +++ b/app/assets/javascripts/discourse/components/plugin-connector.js.es6 @@ -0,0 +1,30 @@ +import { observes } from 'ember-addons/ember-computed-decorators'; + +export default Ember.Component.extend({ + + init() { + this._super(); + + const connector = this.get('connector'); + this.set('layoutName', connector.templateName); + + const args = this.get('args') || {}; + Object.keys(args).forEach(key => this.set(key, args[key])); + + const connectorClass = this.get('connector.connectorClass'); + connectorClass.setupComponent.call(this, args, this); + }, + + @observes('args') + _argsChanged() { + const args = this.get('args') || {}; + Object.keys(args).forEach(key => this.set(key, args[key])); + }, + + send(name, ...args) { + const connectorClass = this.get('connector.connectorClass'); + const action = connectorClass.actions[name]; + return action ? action.call(this, ...args) : this._super(name, ...args); + } + +}); diff --git a/app/assets/javascripts/discourse/components/plugin-outlet.js.es6 b/app/assets/javascripts/discourse/components/plugin-outlet.js.es6 new file mode 100644 index 00000000000..91bf45560e9 --- /dev/null +++ b/app/assets/javascripts/discourse/components/plugin-outlet.js.es6 @@ -0,0 +1,51 @@ +/** + A plugin outlet is an extension point for templates where other templates can + be inserted by plugins. + + ## Usage + + If your handlebars template has: + + ```handlebars + {{plugin-outlet name="evil-trout"}} + ``` + + Then any handlebars files you create in the `connectors/evil-trout` directory + will automatically be appended. For example: + + plugins/hello/assets/javascripts/discourse/templates/connectors/evil-trout/hello.hbs + + With the contents: + + ```handlebars + Hello World + ``` + + Will insert Hello World at that point in the template. + + ## Disabling + + If a plugin returns a disabled status, the outlets will not be wired up for it. + The list of disabled plugins is returned via the `Site` singleton. + +**/ +import { connectorsFor } from 'discourse/lib/plugin-connectors'; + +export default Ember.Component.extend({ + tagName: 'span', + connectors: null, + + init() { + this._super(); + const name = this.get('name'); + + if (name) { + const args = this.get('args'); + const connectors = connectorsFor(name).filter(con => { + return con.connectorClass.shouldRender(args, this); + }); + + this.set('connectors', connectors); + } + } +}); diff --git a/app/assets/javascripts/discourse/components/quote-button.js.es6 b/app/assets/javascripts/discourse/components/quote-button.js.es6 index 77a5c8192a2..a8c8f5cfa57 100644 --- a/app/assets/javascripts/discourse/components/quote-button.js.es6 +++ b/app/assets/javascripts/discourse/components/quote-button.js.es6 @@ -1,4 +1,3 @@ -import computed from 'ember-addons/ember-computed-decorators'; import { selectedText } from 'discourse/lib/utilities'; // we don't want to deselect when we click on buttons that use it @@ -10,17 +9,22 @@ function willQuote(e) { export default Ember.Component.extend({ classNames: ['quote-button'], classNameBindings: ['visible'], - - @computed('quoteState.buffer') - visible: buffer => buffer && buffer.length > 0, + visible: false, _isMouseDown: false, _reselected: false, + _hideButton() { + this.get('quoteState').clear(); + this.set('visible', false); + }, + _selectionChanged() { + const quoteState = this.get('quoteState'); + const selection = window.getSelection(); if (selection.isCollapsed) { - if (this.get("visible")) this.sendAction("deselectText"); + if (this.get("visible")) { this._hideButton(); } return; } @@ -28,18 +32,22 @@ export default Ember.Component.extend({ let firstRange, postId; for (let r = 0; r < selection.rangeCount; r++) { const range = selection.getRangeAt(r); + + if ($(range.endContainer).closest('.cooked').length === 0) return; + const $ancestor = $(range.commonAncestorContainer); firstRange = firstRange || range; postId = postId || $ancestor.closest('.boxed, .reply').data('post-id'); if ($ancestor.closest(".contents").length === 0 || !postId) { - if (this.get("visible")) this.sendAction("deselectText"); + if (this.get("visible")) { this._hideButton(); } return; } } - this.get("quoteState").setProperties({ postId, buffer: selectedText() }); + quoteState.selected(postId, selectedText()); + this.set('visible', quoteState.buffer.length > 0); // on Desktop, shows the button at the beginning of the selection // on Mobile, shows the button at the end of the selection @@ -97,11 +105,11 @@ export default Ember.Component.extend({ const wait = (isWinphone || isAndroid) ? 250 : 25; const onSelectionChanged = _.debounce(() => this._selectionChanged(), wait); - $(document).on("mousedown.quote-button", (e) => { + $(document).on("mousedown.quote-button", e => { this._isMouseDown = true; this._reselected = false; if (!willQuote(e)) { - this.sendAction("deselectText"); + this._hideButton(); } }).on("mouseup.quote-button", () => { this._isMouseDown = false; @@ -120,7 +128,8 @@ export default Ember.Component.extend({ }, click() { - this.sendAction("selectText"); + const { postId, buffer } = this.get('quoteState'); + this.attrs.selectText(postId, buffer).then(() => this._hideButton()); return false; } }); diff --git a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 index 51ec9b4483b..23bdac794b4 100644 --- a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 +++ b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 @@ -48,12 +48,15 @@ export default Em.Component.extend({ init() { this._super(); - this._init(); - this._update(); + Ember.run.scheduleOnce('afterRender', () => { + this._init(); + this._update(); + }); }, @observes('searchTerm') _updateOptions() { + this._update(); Ember.run.debounce(this, this._update, 250); }, diff --git a/app/assets/javascripts/discourse/components/site-header.js.es6 b/app/assets/javascripts/discourse/components/site-header.js.es6 index bf66453c67f..9285f5355b8 100644 --- a/app/assets/javascripts/discourse/components/site-header.js.es6 +++ b/app/assets/javascripts/discourse/components/site-header.js.es6 @@ -47,6 +47,12 @@ const SiteHeaderComponent = MountWidget.extend(Docking, { this.queueRerender(); }, + willRender() { + if (this.get('currentUser.staff')) { + $('body').addClass('staff'); + } + }, + didInsertElement() { this._super(); $(window).on('resize.discourse-menu-panel', () => this.afterRender()); diff --git a/app/assets/javascripts/discourse/components/tag-chooser.js.es6 b/app/assets/javascripts/discourse/components/tag-chooser.js.es6 index a8fa6bc1835..00fc2444879 100644 --- a/app/assets/javascripts/discourse/components/tag-chooser.js.es6 +++ b/app/assets/javascripts/discourse/components/tag-chooser.js.es6 @@ -1,17 +1,24 @@ import renderTag from 'discourse/lib/render-tag'; function formatTag(t) { - return renderTag(t.id, {count: t.count}); + return renderTag(t.id, {count: t.count, noHref: true}); } export default Ember.TextField.extend({ classNameBindings: [':tag-chooser'], attributeBindings: ['tabIndex', 'placeholderKey', 'categoryId'], - _initValue: function() { + init() { + this._super(); const tags = this.get('tags') || []; this.set('value', tags.join(", ")); - }.on('init'), + + if (this.get('allowCreate') !== false) { + this.set('allowCreate', this.site.get('can_create_tag')); + } + + this.set('termMatchesForbidden', false); + }, _valueChanged: function() { const tags = this.get('value').split(',').map(v => v.trim()).reject(v => v.length === 0).uniq(); @@ -32,18 +39,13 @@ export default Ember.TextField.extend({ } }.observes('tags'), - _initializeTags: function() { - const site = this.site, - self = this, - filterRegexp = new RegExp(this.site.tags_filter_regexp, "g"); + didInsertElement() { + this._super(); - var limit = this.siteSettings.max_tags_per_topic; + const self = this; + const filterRegexp = new RegExp(this.site.tags_filter_regexp, "g"); - if (this.get('allowCreate') !== false) { - this.set('allowCreate', site.get('can_create_tag')); - } - - this.set('termMatchesForbidden', false); + let limit = this.siteSettings.max_tags_per_topic; if (this.get('unlimitedTagCount')) { limit = null; @@ -77,7 +79,7 @@ export default Ember.TextField.extend({ callback(data); }, - createSearchChoice: function(term, data) { + createSearchChoice(term, data) { term = term.replace(filterRegexp, '').trim().toLowerCase(); // No empty terms, make sure the user has permission to create the tag @@ -89,14 +91,14 @@ export default Ember.TextField.extend({ return { id: term, text: term }; } }, - createSearchChoicePosition: function(list, item) { + createSearchChoicePosition(list, item) { // Search term goes on the bottom list.push(item); }, - formatSelection: function (data) { - return data ? renderTag(this.text(data)) : undefined; + formatSelection(data) { + return data ? renderTag(this.text(data), {noHref: true}) : undefined; }, - formatSelectionCssClass: function(){ + formatSelectionCssClass() { return "discourse-tag-select2"; }, formatResult: formatTag, @@ -127,10 +129,11 @@ export default Ember.TextField.extend({ } }, }); - }.on('didInsertElement'), + }, - _destroyTags: function() { + willDestroyElement() { + this._super(); this.$().select2('destroy'); - }.on('willDestroyElement') + } }); diff --git a/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 b/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 index aeb9db8baab..13473c0e0f0 100644 --- a/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 @@ -1,17 +1,11 @@ import computed from 'ember-addons/ember-computed-decorators'; -import DelegatedActions from 'discourse/mixins/delegated-actions'; -export default Ember.Component.extend(DelegatedActions, { +export default Ember.Component.extend({ elementId: 'topic-footer-buttons', // Allow us to extend it layoutName: 'components/topic-footer-buttons', - init() { - this._super(); - this.delegateAll(this.get('topicDelegated')); - }, - @computed('topic.details.can_invite_to') canInviteTo(result) { return !this.site.mobileView && result; diff --git a/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6 b/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6 index 3ed113419e5..07ab1269982 100644 --- a/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6 @@ -38,7 +38,6 @@ export default Combobox.extend({ @observes('value') _valueChanged() { const value = this.get('value'); - const controller = this.get('parentView.controller'); const topic = this.get('topic'); const refresh = () => { @@ -48,7 +47,7 @@ export default Combobox.extend({ switch(value) { case 'invite': - controller.send('showInvite'); + this.attrs.showInvite(); refresh(); break; case 'bookmark': @@ -59,7 +58,7 @@ export default Combobox.extend({ refresh(); break; case 'flag': - controller.send('showFlagTopic'); + this.attrs.showFlagTopic(); refresh(); break; } diff --git a/app/assets/javascripts/discourse/components/topic-list-item.js.es6 b/app/assets/javascripts/discourse/components/topic-list-item.js.es6 index a38dd9c8f4c..9fdd978cd6c 100644 --- a/app/assets/javascripts/discourse/components/topic-list-item.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-list-item.js.es6 @@ -1,6 +1,6 @@ import computed from 'ember-addons/ember-computed-decorators'; import { bufferedRender } from 'discourse-common/lib/buffered-render'; -import { getOwner } from 'discourse-common/lib/get-owner'; +import { findRawTemplate } from 'discourse/lib/raw-templates'; export function showEntrance(e) { let target = $(e.target); @@ -32,7 +32,7 @@ export default Ember.Component.extend(bufferedRender({ }, buildBuffer(buffer) { - const template = getOwner(this).lookup('template:list/topic-list-item.raw'); + const template = findRawTemplate('list/topic-list-item'); if (template) { buffer.push(template(this)); } @@ -128,14 +128,11 @@ export default Ember.Component.extend(bufferedRender({ highlight(opts = { isLastViewedTopic: false }) { const $topic = this.$(); - const originalCol = $topic.css('backgroundColor'); $topic .addClass('highlighted') - .attr('data-islastviewedtopic', opts.isLastViewedTopic) - .stop() - .animate({ backgroundColor: originalCol }, 2500, 'swing', function() { - $topic.removeClass('highlighted'); - }); + .attr('data-islastviewedtopic', opts.isLastViewedTopic); + + $topic.on('animationend', () => $topic.removeClass('highlighted')); }, _highlightIfNeeded: function() { diff --git a/app/assets/javascripts/discourse/components/topic-navigation.js.es6 b/app/assets/javascripts/discourse/components/topic-navigation.js.es6 index b18eb12e1fe..ecae615fc56 100644 --- a/app/assets/javascripts/discourse/components/topic-navigation.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-navigation.js.es6 @@ -1,4 +1,5 @@ import { observes } from 'ember-addons/ember-computed-decorators'; +import showModal from 'discourse/lib/show-modal'; export default Ember.Component.extend({ composerOpen: null, @@ -93,19 +94,13 @@ export default Ember.Component.extend({ }, keyboardTrigger(e) { - if(e.type === "jump") { - bootbox.prompt(I18n.t('topic.progress.jump_prompt_long'), postIndex => { - if (postIndex === null) { return; } - this.sendAction('jumpToIndex', postIndex); + if (e.type === "jump") { + const controller = showModal('jump-to-post'); + controller.setProperties({ + topic: this.get('topic'), + postNumber: 1, + jumpToIndex: this.attrs.jumpToIndex }); - - // this is insanely hacky, for some reason shown event never fires, - // something is bust in bootbox - // TODO upgrade bootbox to see if this hack can be removed - setTimeout(()=>{ - $('.bootbox.modal').trigger('shown'); - },50); - } }, diff --git a/app/assets/javascripts/discourse/components/topic-progress.js.es6 b/app/assets/javascripts/discourse/components/topic-progress.js.es6 index 85cb5209552..f20f47426d7 100644 --- a/app/assets/javascripts/discourse/components/topic-progress.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-progress.js.es6 @@ -3,17 +3,11 @@ import { default as computed, observes } from 'ember-addons/ember-computed-decor export default Ember.Component.extend({ elementId: 'topic-progress-wrapper', classNameBindings: ['docked'], - expanded: false, docked: false, progressPosition: null, postStream: Ember.computed.alias('topic.postStream'), _streamPercentage: null, - init() { - this._super(); - (this.get('delegated') || []).forEach(m => this.set(m, m)); - }, - @computed('progressPosition') jumpTopDisabled(progressPosition) { return progressPosition <= 3; @@ -43,6 +37,15 @@ export default Ember.Component.extend({ } }, + @computed('progressPosition', 'topic.last_read_post_id') + showBackButton(position, lastReadId) { + if (!lastReadId) { return; } + + const stream = this.get('postStream.stream'); + const readPos = stream.indexOf(lastReadId) || 0; + return (readPos < (stream.length - 1)) && (readPos > position); + }, + @observes('postStream.stream.[]') _updateBar() { Ember.run.scheduleOnce('afterRender', this, this._updateProgressBar); @@ -146,6 +149,10 @@ export default Ember.Component.extend({ actions: { toggleExpansion() { this.toggleProperty('expanded'); + }, + + goBack() { + this.attrs.jumpToPost(this.get('topic.last_read_post_number')); } }, 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 ccac108e9f0..81d7e5c93e8 100644 --- a/app/assets/javascripts/discourse/components/user-card-contents.js.es6 +++ b/app/assets/javascripts/discourse/components/user-card-contents.js.es6 @@ -12,7 +12,7 @@ const clickMention = "click.discourse-user-mention"; export default Ember.Component.extend(CleansUp, { elementId: 'user-card', - classNameBindings: ['visible:show', 'showBadges', 'hasCardBadgeImage'], + classNameBindings: ['visible:show', 'showBadges', 'hasCardBadgeImage', 'user.card_background::no-bg'], allowBackgrounds: setting('allow_profile_backgrounds'), postStream: Ember.computed.alias('topic.postStream'), @@ -71,18 +71,14 @@ export default Ember.Component.extend(CleansUp, { @observes('user.card_background') addBackground() { - const url = this.get('user.card_background'); - if (!this.get('allowBackgrounds')) { return; } const $this = this.$(); if (!$this) { return; } - if (Ember.isEmpty(url)) { - $this.css('background-image', '').addClass('no-bg'); - } else { - $this.css('background-image', `url(${Discourse.getURLWithCDN(url)})`).removeClass('no-bg'); - } + const url = this.get('user.card_background'); + const bg = Ember.isEmpty(url) ? '' : `url(${Discourse.getURLWithCDN(url)})`; + $this.css('background-image', bg); }, _show(username, $target) { diff --git a/app/assets/javascripts/discourse/components/user-selector.js.es6 b/app/assets/javascripts/discourse/components/user-selector.js.es6 index 94d6db9bfe4..5fda51dec6f 100644 --- a/app/assets/javascripts/discourse/components/user-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/user-selector.js.es6 @@ -1,7 +1,7 @@ import { observes } from 'ember-addons/ember-computed-decorators'; import TextField from 'discourse/components/text-field'; import userSearch from 'discourse/lib/user-search'; -import { getOwner } from 'discourse-common/lib/get-owner'; +import { findRawTemplate } from 'discourse/lib/raw-templates'; export default TextField.extend({ @observes('usernames') @@ -31,7 +31,7 @@ export default TextField.extend({ } this.$().val(this.get('usernames')).autocomplete({ - template: getOwner(this).lookup('template:user-selector-autocomplete.raw'), + template: findRawTemplate('user-selector-autocomplete'), disabled: this.get('disabled'), single: this.get('single'), allowAny: this.get('allowAny'), diff --git a/app/assets/javascripts/discourse/controllers/application.js.es6 b/app/assets/javascripts/discourse/controllers/application.js.es6 index dc9f45d3220..78402acd259 100644 --- a/app/assets/javascripts/discourse/controllers/application.js.es6 +++ b/app/assets/javascripts/discourse/controllers/application.js.es6 @@ -15,4 +15,10 @@ export default Ember.Controller.extend({ loginRequired() { return Discourse.SiteSettings.login_required && !Discourse.User.current(); }, + + actions: { + appRouteAction(name) { + return this.send(name); + } + } }); diff --git a/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 b/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 index c59c632e38a..ab30fef1572 100644 --- a/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 +++ b/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 @@ -1,5 +1,6 @@ import computed from "ember-addons/ember-computed-decorators"; import ModalFunctionality from "discourse/mixins/modal-functionality"; +import { ajax } from 'discourse/lib/ajax'; import { allowsImages } from 'discourse/lib/utilities'; @@ -34,8 +35,7 @@ export default Ember.Controller.extend(ModalFunctionality, { refreshGravatar() { this.set("gravatarRefreshDisabled", true); - return Discourse - .ajax(`/user_avatar/${this.get("username")}/refresh_gravatar.json`, { method: "POST" }) + return ajax(`/user_avatar/${this.get("username")}/refresh_gravatar.json`, { method: "POST" }) .then(result => this.setProperties({ gravatar_avatar_template: result.gravatar_avatar_template, gravatar_avatar_upload_id: result.gravatar_upload_id, diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index 9a8aa809d29..c5e69a45a17 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -404,7 +404,6 @@ export default Ember.Controller.extend({ save(force) { const composer = this.get('model'); - const self = this; // Clear the warning state if we're not showing the checkbox anymore if (!this.get('showWarning')) { @@ -437,10 +436,10 @@ export default Ember.Controller.extend({ buttons.push({ "label": I18n.t("composer.reply_here") + "
    " + currentTopic.get('fancyTitle') + "
    ", "class": "btn btn-reply-here", - "callback": function() { + callback: () => { composer.set('topic', currentTopic); composer.set('post', null); - self.save(true); + this.save(true); } }); } @@ -448,9 +447,7 @@ export default Ember.Controller.extend({ buttons.push({ "label": I18n.t("composer.reply_original") + "
    " + this.get('model.topic.fancyTitle') + "
    ", "class": "btn-primary btn-reply-on-original", - "callback": function() { - self.save(true); - } + callback: () => this.save(true) }); bootbox.dialog(message, buttons, { "classes": "reply-where-modal" }); @@ -471,29 +468,32 @@ export default Ember.Controller.extend({ } }); - const promise = composer.save({ imageSizes, editReason: this.get("editReason")}).then(function(result) { + const promise = composer.save({ imageSizes, editReason: this.get("editReason")}).then(result=> { if (result.responseJson.action === "enqueued") { - self.send('postWasEnqueued', result.responseJson); - self.destroyDraft(); - self.close(); - self.appEvents.trigger('post-stream:refresh'); + this.send('postWasEnqueued', result.responseJson); + this.destroyDraft(); + this.close(); + this.appEvents.trigger('post-stream:refresh'); return result; } // If user "created a new topic/post" or "replied as a new topic" successfully, remove the draft. - if (result.responseJson.action === "create_post" || self.get('replyAsNewTopicDraft')) { - self.destroyDraft(); + if (result.responseJson.action === "create_post" || this.get('replyAsNewTopicDraft')) { + this.destroyDraft(); } - if (self.get('model.action') === 'edit') { - self.appEvents.trigger('post-stream:refresh', { id: parseInt(result.responseJson.id) }); + if (this.get('model.action') === 'edit') { + this.appEvents.trigger('post-stream:refresh', { id: parseInt(result.responseJson.id) }); + if (result.responseJson.post.post_number === 1) { + this.appEvents.trigger('header:show-topic', composer.get('topic')); + } } else { - self.appEvents.trigger('post-stream:refresh'); + this.appEvents.trigger('post-stream:refresh'); } if (result.responseJson.action === "create_post") { - self.appEvents.trigger('post:highlight', result.payload.post_number); + this.appEvents.trigger('post:highlight', result.payload.post_number); } - self.close(); + this.close(); const currentUser = Discourse.User.current(); if (composer.get('creatingTopic')) { @@ -510,9 +510,9 @@ export default Ember.Controller.extend({ } } - }).catch(function(error) { + }).catch(error => { composer.set('disableDrafts', false); - self.appEvents.one('composer:will-open', () => bootbox.alert(error)); + this.appEvents.one('composer:will-open', () => bootbox.alert(error)); }); if (this.get('application.currentRouteName').split('.')[0] === 'topic' && diff --git a/app/assets/javascripts/discourse/controllers/create-account.js.es6 b/app/assets/javascripts/discourse/controllers/create-account.js.es6 index ea7dee44093..50bd0188021 100644 --- a/app/assets/javascripts/discourse/controllers/create-account.js.es6 +++ b/app/assets/javascripts/discourse/controllers/create-account.js.es6 @@ -114,7 +114,7 @@ export default Ember.Controller.extend(ModalFunctionality, { email = this.get("accountEmail"); - if (this.get('rejectedEmails').contains(email)) { + if (this.get('rejectedEmails').includes(email)) { return InputValidation.create({ failed: true, reason: I18n.t('user.email.invalid') @@ -314,7 +314,7 @@ export default Ember.Controller.extend(ModalFunctionality, { }); } - if (this.get('rejectedPasswords').contains(password)) { + if (this.get('rejectedPasswords').includes(password)) { return InputValidation.create({ failed: true, reason: I18n.t('user.password.common') diff --git a/app/assets/javascripts/discourse/controllers/group-posts.js.es6 b/app/assets/javascripts/discourse/controllers/group-activity-posts.js.es6 similarity index 100% rename from app/assets/javascripts/discourse/controllers/group-posts.js.es6 rename to app/assets/javascripts/discourse/controllers/group-activity-posts.js.es6 diff --git a/app/assets/javascripts/discourse/controllers/group-activity.js.es6 b/app/assets/javascripts/discourse/controllers/group-activity.js.es6 new file mode 100644 index 00000000000..955822ffcf5 --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/group-activity.js.es6 @@ -0,0 +1,10 @@ +import computed from 'ember-addons/ember-computed-decorators'; + +export default Ember.Controller.extend({ + application: Ember.inject.controller(), + + @computed('model.is_group_user') + showGroupMessages(isGroupUser) { + return isGroupUser || (this.currentUser && this.currentUser.admin); + } +}); diff --git a/app/assets/javascripts/discourse/controllers/edit-group.js.es6 b/app/assets/javascripts/discourse/controllers/group-edit.js.es6 similarity index 51% rename from app/assets/javascripts/discourse/controllers/edit-group.js.es6 rename to app/assets/javascripts/discourse/controllers/group-edit.js.es6 index 01db8c7ad47..32277430af5 100644 --- a/app/assets/javascripts/discourse/controllers/edit-group.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-edit.js.es6 @@ -1,16 +1,19 @@ import { popupAjaxError } from 'discourse/lib/ajax-error'; +import computed from 'ember-addons/ember-computed-decorators'; export default Ember.Controller.extend({ - saving: false, + @computed('saving') + savingText(saving) { + if (saving !== undefined) { + return saving ? I18n.t('saving') : I18n.t('saved'); + } + }, actions: { save() { this.set('saving', true); - this.get('model').save().then(() => { - this.transitionToRoute('group', this.get('model.name')); - this.send('closeModal'); - }).catch(error => { + this.get('model').save().catch(error => { popupAjaxError(error); }).finally(() => { this.set('saving', false); diff --git a/app/assets/javascripts/discourse/controllers/group-index.js.es6 b/app/assets/javascripts/discourse/controllers/group-index.js.es6 index ff1b32741e5..269ecab7cdb 100644 --- a/app/assets/javascripts/discourse/controllers/group-index.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-index.js.es6 @@ -10,24 +10,28 @@ export default Ember.Controller.extend({ limit: null, offset: null, isOwner: Ember.computed.alias('model.is_group_owner'), + showActions: false, @observes('order', 'desc') refreshMembers() { + this.set('loading', true); + this.get('model') && - this.get('model').findMembers({ order: this.get('order'), desc: this.get('desc') }); + this.get('model') + .findMembers({ order: this.get('order'), desc: this.get('desc') }) + .finally(() => this.set('loading', false)); }, - @computed("model.public") - canJoinGroup(publicGroup) { - return !!(this.currentUser) && publicGroup; - }, - - @computed('model.allow_membership_requests', 'model.alias_level') - canRequestMembership(allowMembershipRequests, aliasLevel) { - return !!(this.currentUser) && allowMembershipRequests && aliasLevel === 99; + @computed('model.members') + hasMembers(members) { + return members && members.length > 0; }, actions: { + toggleActions() { + this.toggleProperty("showActions"); + }, + removeMember(user) { this.get('model').removeMember(user); }, @@ -39,35 +43,6 @@ export default Ember.Controller.extend({ } }, - requestMembership() { - const groupName = this.get('model.name'); - const title = I18n.t('groups.request_membership_pm.title'); - const body = I18n.t('groups.request_membership_pm.body', { groupName }); - this.transitionToRoute(`/new-message?groupname=${groupName}&title=${title}&body=${body}`); - }, - - joinGroup() { - this.set('updatingMembership', true); - const model = this.get('model'); - - model.addMembers(this.currentUser.get('username')).then(() => { - model.set('is_group_user', true); - }).catch(popupAjaxError).finally(() => { - this.set('updatingMembership', false); - }); - }, - - leaveGroup() { - this.set('updatingMembership', true); - const model = this.get('model'); - - model.removeMember(this.currentUser).then(() => { - model.set('is_group_user', false); - }).catch(popupAjaxError).finally(() => { - this.set('updatingMembership', false); - }); - }, - loadMore() { if (this.get("loading")) { return; } if (this.get("model.members.length") >= this.get("model.user_count")) { return; } diff --git a/app/assets/javascripts/discourse/controllers/group.js.es6 b/app/assets/javascripts/discourse/controllers/group.js.es6 index 6f52622fa9a..126f8911dc8 100644 --- a/app/assets/javascripts/discourse/controllers/group.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group.js.es6 @@ -13,17 +13,18 @@ var Tab = Em.Object.extend({ }); export default Ember.Controller.extend({ + application: Ember.inject.controller(), counts: null, showing: 'members', + tabs: [ - Tab.create({ name: 'members', active: true, 'location': 'group.index' }), - Tab.create({ name: 'posts' }), - Tab.create({ name: 'topics' }), - Tab.create({ name: 'mentions' }), - Tab.create({ name: 'messages', requiresMembership: true }), + Tab.create({ name: 'members', 'location': 'group.index', icon: 'users' }), + Tab.create({ name: 'activity' }), Tab.create({ - name: 'logs', i18nKey: 'logs.title', icon: 'shield', - requiresMembership: true, requiresGroupAdmin: true + name: 'edit', i18nKey: 'edit.title', icon: 'pencil', requiresGroupAdmin: true + }), + Tab.create({ + name: 'logs', i18nKey: 'logs.title', icon: 'list-alt', requiresGroupAdmin: true }) ], @@ -32,9 +33,9 @@ export default Ember.Controller.extend({ return !automatic && isGroupOwner; }, - @computed('model.name', 'model.title') - groupName(name, title) { - return (title || name).capitalize(); + @computed('model.name', 'model.full_name') + groupName(name, fullName) { + return (fullName || name).capitalize(); }, @computed('model.name', 'model.flair_url', 'model.flair_bg_color', 'model.flair_color') @@ -52,31 +53,18 @@ export default Ember.Controller.extend({ this.get('tabs')[0].set('count', this.get('model.user_count')); }, - @observes('showing') - showingChanged() { - const showing = this.get('showing'); - - this.get('tabs').forEach(tab => { - tab.set('active', showing === tab.get('name')); - }); - }, - - @computed('model.is_group_user', 'model.is_group_owner') - getTabs(isGroupUser, isGroupOwner) { + @computed('model.is_group_user', 'model.is_group_owner', 'model.automatic') + getTabs(isGroupUser, isGroupOwner, automatic) { return this.get('tabs').filter(t => { - let isMember = false; + let display = true; - if (this.currentUser) { - let admin = this.currentUser.admin; - - if (t.get('requiresGroupAdmin')) { - isMember = admin || isGroupOwner; - } else { - isMember = admin || isGroupUser; - } + if (this.currentUser && t.get('requiresGroupAdmin')) { + display = automatic ? false : (this.currentUser.admin || isGroupOwner); + } else if (t.get('requiresGroupAdmin')) { + display = false; } - return isMember || !t.get('requiresMembership'); + return display; }); } }); diff --git a/app/assets/javascripts/discourse/controllers/groups.js.es6 b/app/assets/javascripts/discourse/controllers/groups.js.es6 new file mode 100644 index 00000000000..d8ce08f3227 --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/groups.js.es6 @@ -0,0 +1,16 @@ +import { observes } from 'ember-addons/ember-computed-decorators'; + +export default Ember.Controller.extend({ + application: Ember.inject.controller(), + + @observes("groups.canLoadMore") + _showFooter() { + this.set("application.showFooter", !this.get("groups.canLoadMore")); + }, + + actions: { + loadMore() { + this.get('groups').loadMore(); + } + } +}); diff --git a/app/assets/javascripts/discourse/controllers/history.js.es6 b/app/assets/javascripts/discourse/controllers/history.js.es6 index e94852cf3ec..b6e9a103777 100644 --- a/app/assets/javascripts/discourse/controllers/history.js.es6 +++ b/app/assets/javascripts/discourse/controllers/history.js.es6 @@ -109,6 +109,11 @@ export default Ember.Controller.extend(ModalFunctionality, { return !prevHidden && this.currentUser && this.currentUser.get('staff'); }, + @computed("model.wiki", "model.last_revision", "model.current_revision") + displayEdit(wiki, lastRevision, currentRevision) { + return wiki && (lastRevision === currentRevision); + }, + @computed() displayRevert() { return this.currentUser && this.currentUser.get('staff'); @@ -187,6 +192,11 @@ export default Ember.Controller.extend(ModalFunctionality, { hideVersion() { this.hide(this.get("model.post_id"), this.get("model.current_revision")); }, showVersion() { this.show(this.get("model.post_id"), this.get("model.current_revision")); }, + editWiki() { + this.get('topicController').send('editPost', this.get('post')); + this.send('closeModal'); + }, + revertToVersion() { this.revert(this.get("post"), this.get("model.current_revision")); }, displayInline() { this.set("viewMode", "inline"); }, diff --git a/app/assets/javascripts/discourse/controllers/jump-to-post.js.es6 b/app/assets/javascripts/discourse/controllers/jump-to-post.js.es6 new file mode 100644 index 00000000000..94ccc5595a4 --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/jump-to-post.js.es6 @@ -0,0 +1,18 @@ +import ModalFunctionality from 'discourse/mixins/modal-functionality'; + +export default Ember.Controller.extend(ModalFunctionality, { + model: null, + postNumber: null, + + actions: { + jump() { + let where = parseInt(this.get('postNumber')); + if (where < 1) { where = 1; } + const max = this.get('topic.postStream.filteredPostsCount'); + if (where > max) { where = max; } + + this.jumpToIndex(where); + this.send('closeModal'); + } + } +}); diff --git a/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 index 099e4a1e689..e125dd73f31 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 @@ -1,4 +1,7 @@ import { propertyEqual } from 'discourse/lib/computed'; +import InputValidation from 'discourse/models/input-validation'; +import { emailValid } from 'discourse/lib/utilities'; +import computed from 'ember-addons/ember-computed-decorators'; export default Ember.Controller.extend({ taken: false, @@ -8,7 +11,7 @@ export default Ember.Controller.extend({ newEmail: null, newEmailEmpty: Em.computed.empty('newEmail'), - saveDisabled: Em.computed.or('saving', 'newEmailEmpty', 'taken', 'unchanged'), + saveDisabled: Em.computed.or('saving', 'newEmailEmpty', 'taken', 'unchanged', 'invalidEmail'), unchanged: propertyEqual('newEmailLower', 'currentUser.email'), newEmailLower: function() { @@ -20,6 +23,21 @@ export default Ember.Controller.extend({ return I18n.t("user.change"); }.property('saving'), + @computed('newEmail') + invalidEmail(newEmail) { + return !emailValid(newEmail); + }, + + @computed('invalidEmail') + emailValidation(invalidEmail) { + if (invalidEmail) { + return InputValidation.create({ + failed: true, + reason: I18n.t('user.email.invalid') + }); + } + }, + actions: { changeEmail: function() { var self = this; diff --git a/app/assets/javascripts/discourse/controllers/tag-groups.js.es6 b/app/assets/javascripts/discourse/controllers/tag-groups.js.es6 index d4785f36aa7..7ea16868797 100644 --- a/app/assets/javascripts/discourse/controllers/tag-groups.js.es6 +++ b/app/assets/javascripts/discourse/controllers/tag-groups.js.es6 @@ -1,3 +1,5 @@ +import TagGroup from 'discourse/models/tag-group'; + export default Ember.Controller.extend({ actions: { selectTagGroup(tagGroup) { @@ -9,8 +11,7 @@ export default Ember.Controller.extend({ }, newTagGroup() { - const newTagGroup = this.store.createRecord('tag-group'); - newTagGroup.set('name', I18n.t('tagging.groups.new_name')); + const newTagGroup = TagGroup.create({ id: 'new', name: I18n.t('tagging.groups.new_name') }); this.get('model').pushObject(newTagGroup); this.send('selectTagGroup', newTagGroup); } diff --git a/app/assets/javascripts/discourse/controllers/tags-show.js.es6 b/app/assets/javascripts/discourse/controllers/tags-show.js.es6 index 0e8e15db508..1e8e0c2fa0b 100644 --- a/app/assets/javascripts/discourse/controllers/tags-show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/tags-show.js.es6 @@ -16,7 +16,7 @@ if (customNavItemHref) { if (navItem.get('tagId')) { var name = navItem.get('name'); - if ( !Discourse.Site.currentProp('filters').contains(name) ) { + if ( !Discourse.Site.currentProp('filters').includes(name) ) { return null; } diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index 4b9650fd98c..6bedd2b5f33 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -11,6 +11,7 @@ import { categoryBadgeHTML } from 'discourse/helpers/category-link'; import Post from 'discourse/models/post'; import debounce from 'discourse/lib/debounce'; import isElementInViewport from "discourse/lib/is-element-in-viewport"; +import QuoteState from 'discourse/lib/quote-state'; export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { composer: Ember.inject.controller(), @@ -32,30 +33,6 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { filter: null, quoteState: null, - topicDelegated: [ - 'toggleMultiSelect', - 'deleteTopic', - 'recoverTopic', - 'toggleClosed', - 'showAutoClose', - 'showFeatureTopic', - 'showChangeTimestamp', - 'toggleArchived', - 'toggleVisibility', - 'convertToPublicTopic', - 'convertToPrivateMessage', - 'jumpTop', - 'jumpToPost', - 'jumpToPostPrompt', - 'jumpToIndex', - 'jumpBottom', - 'replyToPost', - 'toggleArchiveMessage', - 'showInvite', - 'toggleBookmark', - 'showFlagTopic' - ], - updateQueryParams() { const postStream = this.get('model.postStream'); this.setProperties(postStream.get('streamFilters')); @@ -143,7 +120,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { this._super(); this.set('selectedPosts', []); this.set('selectedReplies', []); - this.set('quoteState', Ember.Object.create({ buffer: null, postId: null })); + this.set('quoteState', new QuoteState()); }, showCategoryChooser: Ember.computed.not("model.isPrivateMessage"), @@ -175,18 +152,29 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { actions: { - deselectText() { - this.get('quoteState').setProperties({ buffer: null, postId: null }); + showPostFlags(post) { + return this.send('showFlags', post); }, - selectText() { - const { postId, buffer } = this.get('quoteState'); + topicRouteAction(name, model) { + return this.send(name, model); + }, - this.send('deselectText'); + openAutoClose() { + this.send('showAutoClose'); + }, + + openFeatureTopic() { + this.send('showFeatureTopic'); + }, + + selectText(postId, buffer) { + return this.get('model.postStream').loadPost(postId).then(post => { + const composer = this.get('composer'); + const viewOpen = composer.get('model.viewOpen'); - this.get('model.postStream').loadPost(postId).then(post => { // If we can't create a post, delegate to reply as new topic - if (!this.get('model.details.can_create_post')) { + if ((!viewOpen) && (!this.get('model.details.can_create_post'))) { this.send('replyAsNewTopic', post); return; } @@ -203,16 +191,19 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { } // If the composer is associated with a different post, we don't change it. - const composer = this.get('composer'); - const composerPost = composer.get('content.post'); + const composerPost = composer.get('model.post'); if (composerPost && (composerPost.get('id') !== this.get('post.id'))) { composerOpts.post = composerPost; } const quotedText = Quote.build(post, buffer); composerOpts.quote = quotedText; - if (composer.get('content.viewOpen') || composer.get('content.viewDraft')) { + if (composer.get('model.viewOpen')) { this.appEvents.trigger('composer:insert-text', quotedText); + } else if (composer.get('model.viewDraft')) { + const model = composer.get('model'); + model.set('reply', model.get('reply') + quotedText); + composer.send('openIfDraft'); } else { composer.open(composerOpts); } @@ -322,9 +313,10 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { const quoteState = this.get('quoteState'); const postStream = this.get('model.postStream'); - const quotedPost = postStream.findLoadedPost(quoteState.get('postId')); - const quotedText = Quote.build(quotedPost, quoteState.get('buffer')); - this.send('deselectText'); + const quotedPost = postStream.findLoadedPost(quoteState.postId); + const quotedText = Quote.build(quotedPost, quoteState.buffer); + + quoteState.clear(); if (composerController.get('content.topic.id') === topic.get('id') && composerController.get('content.action') === Composer.REPLY) { @@ -462,7 +454,15 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { }, jumpToPost(postNumber) { - this._jumpToPostId(this.get('model.postStream').findPostIdForPostNumber(postNumber)); + const postStream = this.get('model.postStream'); + let postId = postStream.findPostIdForPostNumber(postNumber); + + // If we couldn't find the post, find the closest post to it + if (!postId) { + const closest = postStream.closestPostNumberFor(postNumber); + postId = postStream.findPostIdForPostNumber(closest); + } + this._jumpToPostId(postId); }, jumpTop() { @@ -652,10 +652,9 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { replyAsNewTopic(post) { const composerController = this.get('composer'); - const quoteState = this.get('quoteState'); - post = post || quoteState.get('post'); - const quotedText = Quote.build(post, quoteState.get('buffer')); - this.send('deselectText'); + const { quoteState } = this; + const quotedText = Quote.build(post, quoteState.buffer); + quoteState.clear(); composerController.open({ action: Composer.CREATE_TOPIC, @@ -818,7 +817,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { postSelected(post) { if (this.get('allPostsSelected')) { return true; } - if (this.get('selectedPosts').contains(post)) { return true; } + if (this.get('selectedPosts').includes(post)) { return true; } if (this.get('selectedReplies').findBy('post_number', post.get('reply_to_post_number'))) { return true; } return false; diff --git a/app/assets/javascripts/discourse/controllers/user.js.es6 b/app/assets/javascripts/discourse/controllers/user.js.es6 index 8ccef07c9ef..f12612b45c8 100644 --- a/app/assets/javascripts/discourse/controllers/user.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user.js.es6 @@ -87,7 +87,7 @@ export default Ember.Controller.extend(CanCheckEmails, { if (!Ember.isEmpty(siteUserFields)) { const userFields = this.get('model.user_fields'); return siteUserFields.filterBy('show_on_profile', true).sortBy('position').map(field => { - field.dasherized_name = field.get('name').dasherize(); + Ember.set(field, 'dasherized_name', field.get('name').dasherize()); const value = userFields ? userFields[field.get('id').toString()] : null; return Ember.isEmpty(value) ? null : Ember.Object.create({ value, field }); }).compact(); diff --git a/app/assets/javascripts/discourse/helpers/application.js.es6 b/app/assets/javascripts/discourse/helpers/application.js.es6 index 05306c0e62f..17f37e94557 100644 --- a/app/assets/javascripts/discourse/helpers/application.js.es6 +++ b/app/assets/javascripts/discourse/helpers/application.js.es6 @@ -11,9 +11,9 @@ registerUnbound('number', (orig, params) => { orig = parseInt(orig, 10); if (isNaN(orig)) { orig = 0; } - let title = orig; + let title = I18n.toNumber(orig, { precision: 0 }); if (params.numberKey) { - title = I18n.t(params.numberKey, { number: orig }); + title = I18n.t(params.numberKey, { number: title, count: parseInt(title) }); } let classNames = 'number'; diff --git a/app/assets/javascripts/discourse/helpers/category-badge.js.es6 b/app/assets/javascripts/discourse/helpers/category-badge.js.es6 index 74d28b745db..41aad35a597 100644 --- a/app/assets/javascripts/discourse/helpers/category-badge.js.es6 +++ b/app/assets/javascripts/discourse/helpers/category-badge.js.es6 @@ -2,6 +2,9 @@ import { categoryLinkHTML } from 'discourse/helpers/category-link'; import { registerUnbound } from 'discourse-common/lib/helpers'; registerUnbound('category-badge', function(cat, options) { - options.link = false; - return categoryLinkHTML(cat, options); + return categoryLinkHTML(cat, { + hideParent: options.hideParent, + allowUncategorized: options.allowUncategorized, + link: false + }); }); diff --git a/app/assets/javascripts/discourse/helpers/custom-html.js.es6 b/app/assets/javascripts/discourse/helpers/custom-html.js.es6 index 29b98c46cf6..1fbc94eb832 100644 --- a/app/assets/javascripts/discourse/helpers/custom-html.js.es6 +++ b/app/assets/javascripts/discourse/helpers/custom-html.js.es6 @@ -1,5 +1,3 @@ -const { registerKeyword } = Ember.__loader.require("ember-htmlbars/keywords"); -const { internal } = Ember.__loader.require('htmlbars-runtime'); import PreloadStore from 'preload-store'; let _customizations = {}; @@ -24,36 +22,3 @@ export function clearHTMLCache() { export function setCustomHTML(key, html) { _customizations[key] = html; } - -registerKeyword('custom-html', { - setupState(state, env, scope, params) { - return { htmlKey: env.hooks.getValue(params[0]) }; - }, - - render(renderNode, env, scope, params, hash, template, inverse, visitor) { - let state = renderNode.getState(); - if (!state.htmlKey) { return true; } - - const html = getCustomHTML(state.htmlKey); - if (html) { - const htmlHash = { html }; - env.hooks.component(renderNode, - env, - scope, - 'custom-html-container', - params, - htmlHash, - { default: template, inverse }, - visitor); - return true; - } - - template = env.owner.lookup(`template:${state.htmlKey}`); - if (template) { - internal.hostBlock(renderNode, env, scope, template.raw, null, null, visitor, function(options) { - options.templates.template.yield(); - }); - } - return true; - } -}); diff --git a/app/assets/javascripts/discourse/helpers/max-usernames.js.es6 b/app/assets/javascripts/discourse/helpers/max-usernames.js.es6 deleted file mode 100644 index 68d002db8fe..00000000000 --- a/app/assets/javascripts/discourse/helpers/max-usernames.js.es6 +++ /dev/null @@ -1,10 +0,0 @@ -import { registerUnbound } from 'discourse-common/lib/helpers'; - -registerUnbound('max-usernames', function(usernames, params) { - var maxLength = parseInt(params.max) || 3; - if (usernames.length > maxLength){ - return usernames.slice(0, maxLength).join(", ") + ", +" + (usernames.length - maxLength); - } else { - return usernames.join(", "); - } -}); diff --git a/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6 b/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6 deleted file mode 100644 index 32fd7d8bae9..00000000000 --- a/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6 +++ /dev/null @@ -1,138 +0,0 @@ -/** - A plugin outlet is an extension point for templates where other templates can - be inserted by plugins. - - ## Usage - - If your handlebars template has: - - ```handlebars - {{plugin-outlet "evil-trout"}} - ``` - - Then any handlebars files you create in the `connectors/evil-trout` directory - will automatically be appended. For example: - - plugins/hello/assets/javascripts/discourse/templates/connectors/evil-trout/hello.hbs - - With the contents: - - ```handlebars - Hello World - ``` - - Will insert Hello World at that point in the template. - - ## Disabling - - If a plugin returns a disabled status, the outlets will not be wired up for it. - The list of disabled plugins is returned via the `Site` singleton. - -**/ -let _connectorCache, _templateCache; - -function findOutlets(collection, callback) { - const disabledPlugins = Discourse.Site.currentProp('disabled_plugins') || []; - - Object.keys(collection).forEach(function(res) { - if (res.indexOf("/connectors/") !== -1) { - // Skip any disabled plugins - for (let i=0; i { - const connector = _connectorCache[outletName]; - (connector || []).forEach(s => { - _templateCache.push(s.template); - s.templateId = parseInt(_templateCache.length - 1); - }); - }); -} - -// unbound version of outlets, only has a template -Handlebars.registerHelper('plugin-outlet', function(name) { - if (!_connectorCache) { buildConnectorCache(); } - - const connector = _connectorCache[name]; - if (connector && connector.length) { - const output = connector.map(c => c.template({context: this})); - return new Handlebars.SafeString(output.join("")); - } -}); - -const { registerKeyword } = Ember.__loader.require("ember-htmlbars/keywords"); -const { internal } = Ember.__loader.require('htmlbars-runtime'); - -registerKeyword('plugin-outlet', { - setupState(state, env, scope, params) { - if (!_connectorCache) { buildConnectorCache(); } - return { outletName: env.hooks.getValue(params[0]) }; - }, - - render(renderNode, env, scope, params, hash, template, inverse, visitor) { - let state = renderNode.getState(); - if (!state.outletName) { return true; } - const connector = _connectorCache[state.outletName]; - if (!connector || connector.length === 0) { return true; } - - const listTemplate = Ember.TEMPLATES['outlet-list']; - listTemplate.raw.locals = ['templateId', 'outletClasses', 'tagName']; - - internal.hostBlock(renderNode, env, scope, listTemplate.raw, null, null, visitor, function(options) { - connector.forEach(source => { - const tid = source.templateId; - options.templates.template.yieldItem(`d-outlet-${tid}`, [ - tid, - source.classNames, - hash.tagName || 'div' - ]); - }); - }); - return true; - } -}); - -registerKeyword('connector', function(morph, env, scope, params, hash, template, inverse, visitor) { - template = _templateCache[parseInt(env.hooks.getValue(hash.templateId))]; - - env.hooks.component(morph, - env, - scope, - 'connector-container', - params, - hash, - { default: template.raw, inverse }, - visitor); - return true; -}); diff --git a/app/assets/javascripts/discourse/helpers/raw-plugin-outlet.js.es6 b/app/assets/javascripts/discourse/helpers/raw-plugin-outlet.js.es6 new file mode 100644 index 00000000000..aa8657464a9 --- /dev/null +++ b/app/assets/javascripts/discourse/helpers/raw-plugin-outlet.js.es6 @@ -0,0 +1,9 @@ +import { rawConnectorsFor } from 'discourse/lib/plugin-connectors'; + +Handlebars.registerHelper('raw-plugin-outlet', function(args) { + const connectors = rawConnectorsFor(args.hash.name); + if (connectors.length) { + const output = connectors.map(c => c.template({context: this})); + return new Handlebars.SafeString(output.join("")); + } +}); diff --git a/app/assets/javascripts/discourse/helpers/raw.js.es6 b/app/assets/javascripts/discourse/helpers/raw.js.es6 index a6cf56e31f9..7f3d8b247b0 100644 --- a/app/assets/javascripts/discourse/helpers/raw.js.es6 +++ b/app/assets/javascripts/discourse/helpers/raw.js.es6 @@ -1,8 +1,10 @@ import { registerUnbound } from 'discourse-common/lib/helpers'; +import { findRawTemplate } from 'discourse/lib/raw-templates'; let _injections; function renderRaw(ctx, container, template, templateName, params) { + params = jQuery.extend({}, params); params.parent = params.parent || ctx; if (!params.view) { @@ -32,9 +34,9 @@ registerUnbound('raw', function(templateName, params) { templateName = templateName.replace('.', '/'); const container = Discourse.__container__; - var template = container.lookup('template:' + templateName + '.raw'); + const template = findRawTemplate(templateName); if (!template) { - Ember.warn('Could not find raw template: ' + templateName); + console.warn('Could not find raw template: ' + templateName); return; } return renderRaw(this, container, template, templateName, params); diff --git a/app/assets/javascripts/discourse/initializers/post-decorations.js.es6 b/app/assets/javascripts/discourse/initializers/post-decorations.js.es6 index df6e8d8bc27..d17b2087acd 100644 --- a/app/assets/javascripts/discourse/initializers/post-decorations.js.es6 +++ b/app/assets/javascripts/discourse/initializers/post-decorations.js.es6 @@ -8,6 +8,18 @@ export default { withPluginApi('0.1', api => { api.decorateCooked(highlightSyntax); api.decorateCooked(lightbox); + + api.decorateCooked($elem => { + const players = $('audio', $elem); + if (players.length) { + players.on('play', () => { + const postId = parseInt($elem.closest('article').data('post-id')); + if (postId) { + api.preventCloak(postId); + } + }); + } + }); }); } }; diff --git a/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 b/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 index d3b6e12f125..3666df1b580 100644 --- a/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 +++ b/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 @@ -2,6 +2,7 @@ import groups from 'discourse/lib/emoji/groups'; import KeyValueStore from "discourse/lib/key-value-store"; import { emojiList } from 'pretty-text/emoji'; import { emojiUrlFor } from 'discourse/lib/text'; +import { findRawTemplate } from 'discourse/lib/raw-templates'; const keyValueStore = new KeyValueStore("discourse_emojis_"); const EMOJI_USAGE = "emojiUsage"; @@ -151,7 +152,7 @@ function render(page, offset, options) { }; $('.emoji-modal', options.appendTo).remove(); - const template = options.register.lookup('template:emoji-toolbar.raw'); + const template = findRawTemplate('emoji-toolbar'); options.appendTo.append(template(model)); bindEvents(page, offset, options); diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index 4edc9a452ac..cc24df86de8 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -5,13 +5,16 @@ const _loading = {}; function loadWithTag(path, cb) { const head = document.getElementsByTagName('head')[0]; + let finished = false; let s = document.createElement('script'); s.src = path; - if (Ember.Test) { Ember.Test.pendingAjaxRequests++; } + if (Ember.Test) { + Ember.Test.registerWaiter(() => finished); + } head.appendChild(s); s.onload = s.onreadystatechange = function(_, abort) { - if (Ember.Test) { Ember.Test.pendingAjaxRequests--; } + finished = true; if (abort || !s.readyState || s.readyState === "loaded" || s.readyState === "complete") { s = s.onload = s.onreadystatechange = null; if (!abort) { diff --git a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 index c4833d4b45e..b8beb0020d9 100644 --- a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 +++ b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 @@ -11,6 +11,7 @@ import { preventCloak } from 'discourse/widgets/post-stream'; import { h } from 'virtual-dom'; import { addFlagProperty } from 'discourse/components/site-header'; import { addPopupMenuOptionsCallback } from 'discourse/controllers/composer'; +import { extraConnectorClass } from 'discourse/lib/plugin-connectors'; class PluginApi { constructor(version, container) { @@ -330,15 +331,41 @@ class PluginApi { addStorePluralization(thing, plural) { this.container.lookup("store:main").addPluralization(thing, plural); } + + /** + * Register a Connector class for a particular outlet and connector. + * + * For example, if the outlet is `user-profile-primary` and your connector + * template is called `my-connector.hbs`: + * + * ```javascript + * api.registerConnectorClass('user-profile-primary', 'my-connector', { + * shouldRender(args, component) { + * return component.siteSettings.my_plugin_enabled; + * } + * }); + * ``` + * + * For more information on connector classes, see: + * https://meta.discourse.org/t/important-changes-to-plugin-outlets-for-ember-2-10/54136 + **/ + registerConnectorClass(outletName, connectorName, klass) { + extraConnectorClass(`${outletName}/${connectorName}`, klass); + } } let _pluginv01; function getPluginApi(version) { version = parseFloat(version); - if (version <= 0.5) { + if (version <= 0.6) { if (!_pluginv01) { _pluginv01 = new PluginApi(version, Discourse.__container__); } + + // We are recycling the compatible object, but let's update to the higher version + if (_pluginv01.version < version) { + _pluginv01.version = version; + } return _pluginv01; } else { console.warn(`Plugin API v${version} is not supported`); diff --git a/app/assets/javascripts/discourse/lib/plugin-connectors.js.es6 b/app/assets/javascripts/discourse/lib/plugin-connectors.js.es6 new file mode 100644 index 00000000000..61cdbab2554 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/plugin-connectors.js.es6 @@ -0,0 +1,98 @@ +let _connectorCache; +let _rawConnectorCache; +let _extraConnectorClasses = {}; +let _classPaths; + +export function resetExtraClasses() { + _extraConnectorClasses = {}; + _classPaths = undefined; +} + +// Note: In plugins, define a class by path and it will be wired up automatically +// eg: discourse/connectors//.js.es6 +export function extraConnectorClass(name, obj) { + _extraConnectorClasses[name] = obj; +} + +const DefaultConnectorClass = { + actions: {}, + shouldRender: () => true, + setupComponent() { } +}; + +function findOutlets(collection, callback) { + const disabledPlugins = Discourse.Site.currentProp('disabled_plugins') || []; + + Object.keys(collection).forEach(function(res) { + if (res.indexOf("/connectors/") !== -1) { + // Skip any disabled plugins + for (let i=0; i { + _classPaths[`${outlet}/${un}`] = require(res).default; + }); + } + + const id = `${outletName}/${uniqueName}`; + let foundClass = _extraConnectorClasses[id] || _classPaths[id]; + + return foundClass ? + jQuery.extend({}, DefaultConnectorClass, foundClass) : + DefaultConnectorClass; +} + +function buildConnectorCache() { + _connectorCache = {}; + + findOutlets(Ember.TEMPLATES, (outletName, resource, uniqueName) => { + _connectorCache[outletName] = _connectorCache[outletName] || []; + + _connectorCache[outletName].push({ + templateName: resource.replace('javascripts/', ''), + template: Ember.TEMPLATES[resource], + classNames: `${outletName}-outlet ${uniqueName}`, + connectorClass: findClass(outletName, uniqueName) + }); + }); +} + +function buildRawConnectorCache() { + _rawConnectorCache = {}; + findOutlets(Discourse.RAW_TEMPLATES, (outletName, resource) => { + _rawConnectorCache[outletName] = _rawConnectorCache[outletName] || []; + _rawConnectorCache[outletName].push({ + template: Discourse.RAW_TEMPLATES[resource] + }); + }); +} + +export function connectorsFor(outletName) { + if (!_connectorCache) { buildConnectorCache(); } + return _connectorCache[outletName] || []; +} + +export function rawConnectorsFor(outletName) { + if (!_rawConnectorCache) { buildRawConnectorCache(); } + return _rawConnectorCache[outletName] || []; +} diff --git a/app/assets/javascripts/discourse/lib/quote-state.js.es6 b/app/assets/javascripts/discourse/lib/quote-state.js.es6 new file mode 100644 index 00000000000..db1e1826fb1 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/quote-state.js.es6 @@ -0,0 +1,15 @@ +export default class QuoteState { + constructor() { + this.clear(); + } + + selected(postId, buffer) { + this.postId = postId; + this.buffer = buffer; + } + + clear() { + this.buffer = ''; + this.postId = null; + } +} diff --git a/app/assets/javascripts/discourse/lib/raw-templates.js.es6 b/app/assets/javascripts/discourse/lib/raw-templates.js.es6 new file mode 100644 index 00000000000..89734b18aed --- /dev/null +++ b/app/assets/javascripts/discourse/lib/raw-templates.js.es6 @@ -0,0 +1,13 @@ +import { getResolverOption } from 'discourse-common/resolver'; + +export function findRawTemplate(name) { + if (getResolverOption('mobileView')) { + return Discourse.RAW_TEMPLATES[`javascripts/mobile/${name}`] || + Discourse.RAW_TEMPLATES[`javascripts/${name}`] || + Discourse.RAW_TEMPLATES[`mobile/${name}`] || + Discourse.RAW_TEMPLATES[name]; + } + + return Discourse.RAW_TEMPLATES[`javascripts/${name}`] || + Discourse.RAW_TEMPLATES[name]; +} diff --git a/app/assets/javascripts/discourse/lib/render-tag.js.es6 b/app/assets/javascripts/discourse/lib/render-tag.js.es6 index 5b627985413..356ee4b2c22 100644 --- a/app/assets/javascripts/discourse/lib/render-tag.js.es6 +++ b/app/assets/javascripts/discourse/lib/render-tag.js.es6 @@ -5,7 +5,7 @@ export default function renderTag(tag, params) { tag = Handlebars.Utils.escapeExpression(tag); const classes = ['tag-' + tag, 'discourse-tag']; const tagName = params.tagName || "a"; - const href = tagName === "a" ? " href='" + Discourse.getURL("/tags/" + tag) + "' " : ""; + const href = (tagName === "a" && !params.noHref) ? " href='" + Discourse.getURL("/tags/" + tag) + "' " : ""; if (Discourse.SiteSettings.tag_style || params.style) { classes.push(params.style || Discourse.SiteSettings.tag_style); diff --git a/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 b/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 index 03b6dfff3a1..6df7abd0d4b 100644 --- a/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 +++ b/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 @@ -6,6 +6,23 @@ function applicable() { !navigator.userAgent.match(/Trident/g); } + +function calcHeight(composingTopic) { + const winHeight = window.innerHeight; + + // Hard code some known iOS resolutions + switch(winHeight) { + case 460: return composingTopic ? 250 : 260; + case 559: return composingTopic ? 325 : 308; + case 627: + case 628: return 360; + } + + const ratio = composingTopic ? 0.54 : 0.6; + const min = composingTopic ? 300 : 350; + return Math.max(parseInt(winHeight*ratio), min); +} + let workaroundActive = false; let composingTopic = false; @@ -86,19 +103,9 @@ function positioningWorkaround($fixedElement) { fixedElement.style.top = '0px'; - let ratio = 0.6; - let min = 350; + composingTopic = $('#reply-control select.category-combobox').length > 0; - composingTopic = false; - - if ($('#reply-control select.category-combobox').length > 0) { - composingTopic = true; - // creating a topic, less height - ratio = 0.54; - min = 300; - } - - const height = Math.max(parseInt(window.innerHeight*ratio), min); + const height = calcHeight(composingTopic); fixedElement.style.height = height + "px"; diff --git a/app/assets/javascripts/discourse/lib/show-modal.js.es6 b/app/assets/javascripts/discourse/lib/show-modal.js.es6 index c0a50a83044..ed2457e065f 100644 --- a/app/assets/javascripts/discourse/lib/show-modal.js.es6 +++ b/app/assets/javascripts/discourse/lib/show-modal.js.es6 @@ -11,26 +11,22 @@ export default function(name, opts) { const controllerName = opts.admin ? `modals/${name}` : name; - const viewClass = container.lookupFactory('view:' + name); const controller = container.lookup('controller:' + controllerName); - if (viewClass) { - route.render(name, { into: 'modal', outlet: 'modalBody' }); - } else { - const templateName = opts.templateName || Ember.String.dasherize(name); + const templateName = opts.templateName || Ember.String.dasherize(name); - const renderArgs = { into: 'modal', outlet: 'modalBody'}; - if (controller) { renderArgs.controller = controllerName; } + const renderArgs = { into: 'modal', outlet: 'modalBody'}; + if (controller) { renderArgs.controller = controllerName; } - if (opts.addModalBodyView) { - renderArgs.view = 'modal-body'; - } + if (opts.addModalBodyView) { + renderArgs.view = 'modal-body'; + } - const modalName = `modal/${templateName}`; - const fullName = opts.admin ? `admin/templates/${modalName}` : modalName; - route.render(fullName, renderArgs); - if (opts.title) { - modalController.set('title', I18n.t(opts.title)); - } + + const modalName = `modal/${templateName}`; + const fullName = opts.admin ? `admin/templates/${modalName}` : modalName; + route.render(fullName, renderArgs); + if (opts.title) { + modalController.set('title', I18n.t(opts.title)); } if (controller) { diff --git a/app/assets/javascripts/discourse/lib/text.js.es6 b/app/assets/javascripts/discourse/lib/text.js.es6 index 56f460852f2..dc3c1cdf971 100644 --- a/app/assets/javascripts/discourse/lib/text.js.es6 +++ b/app/assets/javascripts/discourse/lib/text.js.es6 @@ -29,8 +29,8 @@ function emojiOptions() { return { getURL: Discourse.getURLWithCDN, emojiSet: siteSettings.emoji_set }; } -export function emojiUnescape(string) { - const opts = emojiOptions(); +export function emojiUnescape(string, options) { + const opts = _.extend(emojiOptions(), options || {}); return opts ? performEmojiUnescape(string, opts) : string; } diff --git a/app/assets/javascripts/discourse/lib/url.js.es6 b/app/assets/javascripts/discourse/lib/url.js.es6 index 6aca579c130..8f1b1d3e133 100644 --- a/app/assets/javascripts/discourse/lib/url.js.es6 +++ b/app/assets/javascripts/discourse/lib/url.js.es6 @@ -7,9 +7,15 @@ const TOPIC_REGEXP = /\/t\/([^\/]+)\/(\d+)\/?(\d+)?/; // We can add links here that have server side responses but not client side. const SERVER_SIDE_ONLY = [ + /^\/assets\//, + /^\/uploads\//, + /^\/stylesheets\//, + /^\/site_customizations\//, + /^\/raw\//, /^\/posts\/\d+\/raw/, + /^\/raw\/\d+/, /\.rss$/, - /\.json/, + /\.json$/, ]; let _jumpScheduled = false; @@ -121,8 +127,9 @@ const DiscourseURL = Ember.Object.extend({ return; } + const pathname = path.replace(/(https?\:)?\/\/[^\/]+/, ''); const serverSide = SERVER_SIDE_ONLY.some(r => { - if (path.match(r)) { + if (pathname.match(r)) { document.location = path; return true; } diff --git a/app/assets/javascripts/discourse/lib/utilities.js.es6 b/app/assets/javascripts/discourse/lib/utilities.js.es6 index fcf67375273..5eeb3a358c4 100644 --- a/app/assets/javascripts/discourse/lib/utilities.js.es6 +++ b/app/assets/javascripts/discourse/lib/utilities.js.es6 @@ -158,7 +158,7 @@ export function setCaretPosition(ctrl, pos) { } } -export function validateUploadedFiles(files, bypassNewUserRestriction) { +export function validateUploadedFiles(files, opts) { if (!files || files.length === 0) { return false; } if (files.length > 1) { @@ -166,29 +166,48 @@ export function validateUploadedFiles(files, bypassNewUserRestriction) { return false; } - var upload = files[0]; + const upload = files[0]; // CHROME ONLY: if the image was pasted, sets its name to a default one if (typeof Blob !== "undefined" && typeof File !== "undefined") { if (upload instanceof Blob && !(upload instanceof File) && upload.type === "image/png") { upload.name = "blob.png"; } } - var type = uploadTypeFromFileName(upload.name); + opts = opts || {}; + opts["type"] = uploadTypeFromFileName(upload.name); - return validateUploadedFile(upload, type, bypassNewUserRestriction); + return validateUploadedFile(upload, opts); } -export function validateUploadedFile(file, type, bypassNewUserRestriction) { +export function validateUploadedFile(file, opts) { + opts = opts || {}; + + const name = file && file.name; + + if (!name) { return false; } + // check that the uploaded file is authorized - if (!authorizesAllExtensions() && !isAuthorizedUpload(file)) { - bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: authorizedExtensions() })); - return false; + if (opts["imagesOnly"]) { + if (!isAnImage(name) && !isAuthorizedImage(name)) { + bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: authorizedImagesExtensions() })); + return false; + } + } else if (opts["csvOnly"]) { + if (!(/\.csv$/i).test(name)) { + bootbox.alert(I18n.t('user.invited.bulk_invite.error')); + return false; + } + } else { + if (!authorizesAllExtensions() && !isAuthorizedFile(name)) { + bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: authorizedExtensions() })); + return false; + } } - if (!bypassNewUserRestriction) { + if (!opts["bypassNewUserRestriction"]) { // ensures that new users can upload a file - if (!Discourse.User.current().isAllowedToUploadAFile(type)) { - bootbox.alert(I18n.t('post.errors.' + type + '_upload_not_allowed_for_new_user')); + if (!Discourse.User.current().isAllowedToUploadAFile(opts["type"])) { + bootbox.alert(I18n.t(`post.errors.${opts["type"]}_upload_not_allowed_for_new_user`)); return false; } } @@ -197,13 +216,7 @@ export function validateUploadedFile(file, type, bypassNewUserRestriction) { return true; } -export function uploadTypeFromFileName(fileName) { - return isAnImage(fileName) ? 'image' : 'attachment'; -} - -export function authorizesAllExtensions() { - return Discourse.SiteSettings.authorized_extensions.indexOf("*") >= 0; -} +const IMAGES_EXTENSIONS_REGEX = /(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)/i; function extensions() { return Discourse.SiteSettings.authorized_extensions @@ -213,16 +226,52 @@ function extensions() { .filter(ext => ext.indexOf("*") === -1); } +function imagesExtensions() { + return extensions().filter(ext => IMAGES_EXTENSIONS_REGEX.test(ext)); +} + function extensionsRegex() { return new RegExp("\\.(" + extensions().join("|") + ")$", "i"); } -export function isAuthorizedUpload(file) { - return file && file.name && extensionsRegex().test(file.name); +function imagesExtensionsRegex() { + return new RegExp("\\.(" + imagesExtensions().join("|") + ")$", "i"); +} + +function isAuthorizedFile(fileName) { + return extensionsRegex().test(fileName); +} + +function isAuthorizedImage(fileName){ + return imagesExtensionsRegex().test(fileName); } export function authorizedExtensions() { - return extensions().join(", "); + return authorizesAllExtensions() ? "*" : extensions().join(", "); +} + +export function authorizedImagesExtensions() { + return authorizesAllExtensions() ? "png, jpg, jpeg, gif, bmp, tiff, svg, webp, ico" : imagesExtensions().join(", "); +} + +export function authorizesAllExtensions() { + return Discourse.SiteSettings.authorized_extensions.indexOf("*") >= 0; +} + +export function isAnImage(path) { + return (/\.(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)$/i).test(path); +} + +function uploadTypeFromFileName(fileName) { + return isAnImage(fileName) ? 'image' : 'attachment'; +} + +export function allowsImages() { + return authorizesAllExtensions() || IMAGES_EXTENSIONS_REGEX.test(authorizedExtensions()); +} + +export function allowsAttachments() { + return authorizesAllExtensions() || extensions().length > imagesExtensions().length; } export function uploadLocation(url) { @@ -243,27 +292,12 @@ export function getUploadMarkdown(upload) { if (isAnImage(upload.original_filename)) { return ''; } else if (!Discourse.SiteSettings.prevent_anons_from_downloading_files && (/\.(mov|mp4|webm|ogv|mp3|ogg|wav|m4a)$/i).test(upload.original_filename)) { - // is Audio/Video return uploadLocation(upload.url); } else { return '' + upload.original_filename + ' (' + I18n.toHumanSize(upload.filesize) + ')\n'; } } -export function isAnImage(path) { - return (/\.(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)$/i).test(path); -} - -export function allowsImages() { - return authorizesAllExtensions() || - (/(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)/i).test(authorizedExtensions()); -} - -export function allowsAttachments() { - return authorizesAllExtensions() || - !/^((png|jpe?g|gif|bmp|tiff?|svg|webp|ico)(,\s)?)+$/i.test(authorizedExtensions()); -} - export function displayErrorForUpload(data) { // deal with meaningful errors first if (data.jqXHR) { @@ -300,5 +334,35 @@ export function defaultHomepage() { return Discourse.SiteSettings.top_menu.split("|")[0].split(",")[0]; } +export function determinePostReplaceSelection({ selection, needle, replacement }) { + const diff = (replacement.end - replacement.start) - (needle.end - needle.start); + + if (selection.end <= needle.start) { + // Selection ends (and starts) before needle. + return { start: selection.start, end: selection.end }; + } else if (selection.start <= needle.start) { + // Selection starts before needle... + if (selection.end < needle.end) { + // ... and ends inside needle. + return { start: selection.start, end: needle.start }; + } else { + // ... and spans needle completely. + return { start: selection.start, end: selection.end + diff }; + } + } else if (selection.start < needle.end) { + // Selection starts inside needle... + if (selection.end <= needle.end) { + // ... and ends inside needle. + return { start: replacement.end, end: replacement.end }; + } else { + // ... and spans end of needle. + return { start: replacement.end, end: selection.end + diff }; + } + } else { + // Selection starts (and ends) behind needle. + return { start: selection.start + diff, end: selection.end + diff }; + } +} + // This prevents a mini racer crash export default {}; diff --git a/app/assets/javascripts/discourse/mapping-router.js.es6 b/app/assets/javascripts/discourse/mapping-router.js.es6 index 31d7c2c2eaf..e88b7f746d3 100644 --- a/app/assets/javascripts/discourse/mapping-router.js.es6 +++ b/app/assets/javascripts/discourse/mapping-router.js.es6 @@ -1,8 +1,21 @@ +import { defaultHomepage } from 'discourse/lib/utilities'; const rootURL = Discourse.BaseUri; const BareRouter = Ember.Router.extend({ rootURL, - location: Ember.testing ? 'none': 'discourse-location' + location: Ember.testing ? 'none': 'discourse-location', + + handleURL(url) { + const params = url.split('?'); + + if (params[0] === "/") { + url = defaultHomepage(); + if (params[1] && params[1].length) { + url = `${url}?${params[1]}`; + } + } + return this._super(url); + } }); // Ember's router can't be extended. We need to allow plugins to add routes to routes that were defined @@ -67,7 +80,8 @@ class RouteNode { if (paths.length > 1) { paths.filter(p => p !== this.opts.path).forEach(path => { const newOpts = jQuery.extend({}, this.opts, { path }); - router.route(this.name, newOpts, builder); + console.log(`warning: we can't have duplicate route names anymore`, newOpts); + // router.route(this.name, newOpts, builder); }); } } diff --git a/app/assets/javascripts/discourse/mixins/delegate-actions.js.es6 b/app/assets/javascripts/discourse/mixins/delegate-actions.js.es6 deleted file mode 100644 index ce3e46a56f5..00000000000 --- a/app/assets/javascripts/discourse/mixins/delegate-actions.js.es6 +++ /dev/null @@ -1,6 +0,0 @@ -export default Ember.Mixin.create({ - init() { - this._super(); - (this.get('delegated') || []).forEach(m => this.set(m, m)); - }, -}); diff --git a/app/assets/javascripts/discourse/mixins/delegated-actions.js.es6 b/app/assets/javascripts/discourse/mixins/delegated-actions.js.es6 deleted file mode 100644 index 2aae916a9df..00000000000 --- a/app/assets/javascripts/discourse/mixins/delegated-actions.js.es6 +++ /dev/null @@ -1,12 +0,0 @@ -export default Ember.Mixin.create({ - delegateAll(actionNames) { - actionNames = actionNames || []; - - this.actions = this.actions || {}; - - actionNames.forEach(m => { - this.actions[m] = function() { this.sendAction(m); }; - this.set(m, m); - }); - } -}); diff --git a/app/assets/javascripts/discourse/mixins/upload.js.es6 b/app/assets/javascripts/discourse/mixins/upload.js.es6 index 648d18dfd98..ec76aa1e660 100644 --- a/app/assets/javascripts/discourse/mixins/upload.js.es6 +++ b/app/assets/javascripts/discourse/mixins/upload.js.es6 @@ -8,6 +8,10 @@ export default Em.Mixin.create({ Em.warn("You should implement `uploadDone`"); }, + validateUploadedFilesOptions() { + return {}; + }, + _initialize: function() { const $upload = this.$(), csrf = Discourse.Session.currentProp("csrfToken"), @@ -40,7 +44,8 @@ export default Em.Mixin.create({ }); $upload.on("fileuploadsubmit", (e, data) => { - const isValid = validateUploadedFiles(data.files, true); + const opts = _.merge({ bypassNewUserRestriction: true }, this.validateUploadedFilesOptions()); + const isValid = validateUploadedFiles(data.files, opts); let form = { type: this.get("type") }; if (this.get("data")) { form = $.extend(form, this.get("data")); } data.formData = form; diff --git a/app/assets/javascripts/discourse/models/category.js.es6 b/app/assets/javascripts/discourse/models/category.js.es6 index a8657ad16ab..b31f715b810 100644 --- a/app/assets/javascripts/discourse/models/category.js.es6 +++ b/app/assets/javascripts/discourse/models/category.js.es6 @@ -97,10 +97,12 @@ const Category = RestModel.extend({ custom_fields: this.get('custom_fields'), topic_template: this.get('topic_template'), suppress_from_homepage: this.get('suppress_from_homepage'), + all_topics_wiki: this.get('all_topics_wiki'), allowed_tags: this.get('allowed_tags'), allowed_tag_groups: this.get('allowed_tag_groups'), sort_order: this.get('sort_order'), - sort_ascending: this.get('sort_ascending') + sort_ascending: this.get('sort_ascending'), + topic_featured_link_allowed: this.get('topic_featured_link_allowed') }, type: id ? 'PUT' : 'POST' }); @@ -169,18 +171,6 @@ const Category = RestModel.extend({ @computed("id") isUncategorizedCategory(id) { return id === Discourse.Site.currentProp("uncategorized_category_id"); - }, - - @computed('custom_fields.topic_featured_link_allowed') - topicFeaturedLinkAllowed: { - get(allowed) { - return allowed === "true"; - }, - set(value) { - value = value ? "true" : "false"; - this.set("custom_fields.topic_featured_link_allowed", value); - return value; - } } }); diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6 index 79ed585bbd4..bb833c7c1c7 100644 --- a/app/assets/javascripts/discourse/models/composer.js.es6 +++ b/app/assets/javascripts/discourse/models/composer.js.es6 @@ -143,6 +143,8 @@ const Composer = RestModel.extend({ if (!this.siteSettings.topic_featured_link_enabled || !canEditTitle || creatingPrivateMessage) { return false; } const categoryIds = this.site.get('topic_featured_link_allowed_category_ids'); + if (!categoryId && categoryIds && + (categoryIds.indexOf(this.site.get('uncategorized_category_id')) !== -1 || !this.siteSettings.allow_uncategorized_topics)) { return true; } return categoryIds === undefined || !categoryIds.length || categoryIds.indexOf(categoryId) !== -1; }, @@ -552,8 +554,7 @@ const Composer = RestModel.extend({ post.get('post_number') === 1 && this.get('topic.details.can_edit')) { const topicProps = this.getProperties(Object.keys(_edit_topic_serializer)); - - promise = Topic.update(this.get('topic'), topicProps); + promise = Topic.update(this.get('topic'), topicProps); } else { promise = Ember.RSVP.resolve(); } diff --git a/app/assets/javascripts/discourse/models/group.js.es6 b/app/assets/javascripts/discourse/models/group.js.es6 index c4cd97ddf00..99c95caf61a 100644 --- a/app/assets/javascripts/discourse/models/group.js.es6 +++ b/app/assets/javascripts/discourse/models/group.js.es6 @@ -1,8 +1,10 @@ import { ajax } from 'discourse/lib/ajax'; import { default as computed, observes } from "ember-addons/ember-computed-decorators"; import GroupHistory from 'discourse/models/group-history'; +import RestModel from 'discourse/models/rest'; +import { popupAjaxError } from 'discourse/lib/ajax-error'; -const Group = Discourse.Model.extend({ +const Group = RestModel.extend({ limit: 50, offset: 0, user_count: 0, @@ -109,7 +111,7 @@ const Group = Discourse.Model.extend({ @observes("visible", "canEveryoneMention") _updateAllowMembershipRequests() { if (!this.get('visible') || !this.get('canEveryoneMention')) { - this.set('allow_membership_requests', false); + this.set ('allow_membership_requests', false); } }, @@ -134,7 +136,8 @@ const Group = Discourse.Model.extend({ flair_color: this.get('flairHexColor'), bio_raw: this.get('bio_raw'), public: this.get('public'), - allow_membership_requests: this.get('allow_membership_requests') + allow_membership_requests: this.get('allow_membership_requests'), + full_name: this.get('full_name') }; }, @@ -206,6 +209,10 @@ Group.reopenClass({ return ajax("/groups/" + name + ".json").then(result => Group.create(result.basic_group)); }, + loadOwners(name) { + return ajax('/groups/' + name + '/owners.json').catch(popupAjaxError); + }, + loadMembers(name, offset, limit, params) { return ajax('/groups/' + name + '/members.json', { data: _.extend({ diff --git a/app/assets/javascripts/discourse/models/nav-item.js.es6 b/app/assets/javascripts/discourse/models/nav-item.js.es6 index 58845c2d51f..d28b6728345 100644 --- a/app/assets/javascripts/discourse/models/nav-item.js.es6 +++ b/app/assets/javascripts/discourse/models/nav-item.js.es6 @@ -86,9 +86,9 @@ NavItem.reopenClass({ testName = name.split("/")[0], anonymous = !Discourse.User.current(); - if (anonymous && !Discourse.Site.currentProp('anonymous_top_menu_items').contains(testName)) return null; + if (anonymous && !Discourse.Site.currentProp('anonymous_top_menu_items').includes(testName)) return null; if (!Discourse.Category.list() && testName === "categories") return null; - if (!Discourse.Site.currentProp('top_menu_items').contains(testName)) return null; + if (!Discourse.Site.currentProp('top_menu_items').includes(testName)) return null; var args = { name: name, hasIcon: name === "unread" }, extra = null, self = this; if (opts.category) { args.category = opts.category; } diff --git a/app/assets/javascripts/discourse/models/post-stream.js.es6 b/app/assets/javascripts/discourse/models/post-stream.js.es6 index a711303f228..32cfa6427f7 100644 --- a/app/assets/javascripts/discourse/models/post-stream.js.es6 +++ b/app/assets/javascripts/discourse/models/post-stream.js.es6 @@ -168,7 +168,7 @@ export default RestModel.extend({ this.set('summary', false); let jump = false; - if (userFilters.contains(username)) { + if (userFilters.includes(username)) { userFilters.removeObject(username); } else { userFilters.addObject(username); @@ -256,7 +256,7 @@ export default RestModel.extend({ return this.findPostsByIds(gap).then(posts => { posts.forEach(p => { const stored = this.storePost(p); - if (!currentPosts.contains(stored)) { + if (!currentPosts.includes(stored)) { currentPosts.insertAt(postIdx++, stored); } }); @@ -410,7 +410,7 @@ export default RestModel.extend({ if (stored) { const posts = this.get('posts'); - if (!posts.contains(stored)) { + if (!posts.includes(stored)) { if (!this.get('loadingBelow')) { this.get('postsWithPlaceholders').appendPost(() => posts.pushObject(stored)); } else { diff --git a/app/assets/javascripts/discourse/models/post.js.es6 b/app/assets/javascripts/discourse/models/post.js.es6 index b15683ca4a4..127b81f8612 100644 --- a/app/assets/javascripts/discourse/models/post.js.es6 +++ b/app/assets/javascripts/discourse/models/post.js.es6 @@ -70,7 +70,6 @@ const Post = RestModel.extend({ return ajax(`/posts/${this.get('id')}/${field}`, { type: 'PUT', data }).then(() => { this.set(field, value); - this.incrementProperty("version"); }).catch(popupAjaxError); }, diff --git a/app/assets/javascripts/discourse/models/tag-group.js.es6 b/app/assets/javascripts/discourse/models/tag-group.js.es6 index f27adad26b4..cfbd83e1640 100644 --- a/app/assets/javascripts/discourse/models/tag-group.js.es6 +++ b/app/assets/javascripts/discourse/models/tag-group.js.es6 @@ -9,9 +9,10 @@ const TagGroup = RestModel.extend({ }, save() { - var url = "/tag_groups", - self = this; - if (this.get('id')) { + let url = "/tag_groups"; + const self = this, + isNew = this.get('id') === 'new'; + if (!isNew) { url = "/tag_groups/" + this.get('id'); } @@ -25,9 +26,11 @@ const TagGroup = RestModel.extend({ parent_tag_name: this.get('parent_tag_name') ? this.get('parent_tag_name') : undefined, one_per_topic: this.get('one_per_topic') }, - type: this.get('id') ? 'PUT' : 'POST' + type: isNew ? 'POST' : 'PUT' }).then(function(result) { - if(result.id) { self.set('id', result.id); } + if(result.tag_group && result.tag_group.id) { + self.set('id', result.tag_group.id); + } self.set('savingStatus', I18n.t('saved')); self.set('saving', false); }); diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index 3e84d0c5501..d4e24f5af83 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -254,7 +254,7 @@ const User = RestModel.extend({ // TODO: We can remove this when migrated fully to rest model. this.set('isSaving', true); - return ajax(`/users/${this.get('username_lower')}`, { + return ajax(`/users/${this.get('username_lower')}.json`, { data: data, type: 'PUT' }).then(result => { diff --git a/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 b/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 index 5e3de23fee3..51849ef4025 100644 --- a/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 +++ b/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 @@ -17,7 +17,7 @@ function inject() { } function injectAll(app, name) { - inject(app, name, 'controller', 'component', 'route', 'view', 'model', 'adapter'); + inject(app, name, 'controller', 'component', 'route', 'model', 'adapter'); } export default { diff --git a/app/assets/javascripts/discourse/raw-views/topic-status.js.es6 b/app/assets/javascripts/discourse/raw-views/topic-status.js.es6 index 17e370bc6ee..e5d5befde9b 100644 --- a/app/assets/javascripts/discourse/raw-views/topic-status.js.es6 +++ b/app/assets/javascripts/discourse/raw-views/topic-status.js.es6 @@ -1,54 +1,58 @@ +import computed from 'ember-addons/ember-computed-decorators'; + export default Ember.Object.extend({ - renderDiv: function(){ + + @computed + renderDiv() { return this.get('statuses').length > 0 && !this.noDiv; - }.property(), - statuses: function(){ - var topic = this.get("topic"); - var results = []; - var self = this; + }, + + @computed + statuses() { + const topic = this.get("topic"); + const results = []; // TODO, custom statuses? via override? - - if(topic.get('is_warning')){ + if (topic.get('is_warning')) { results.push({icon: 'envelope', key: 'warning'}); } - if(topic.get('bookmarked')){ - var url = topic.get('url'); - var postNumbers = topic.get('bookmarked_post_numbers'); - var extraClasses = ""; - if(postNumbers && postNumbers[0] > 1) { + if (topic.get('bookmarked')) { + const postNumbers = topic.get('bookmarked_post_numbers'); + let url = topic.get('url'); + let extraClasses = ""; + if (postNumbers && postNumbers[0] > 1) { url += '/' + postNumbers[0]; } else { extraClasses = "op-bookmark"; } - results.push({extraClasses: extraClasses, icon: 'bookmark', key: 'bookmarked', href: url}); + results.push({ extraClasses, icon: 'bookmark', key: 'bookmarked', href: url }); } if (topic.get('closed') && topic.get('archived')) { results.push({icon: 'lock', key: 'locked_and_archived'}); - } else if(topic.get('closed')){ + } else if (topic.get('closed')) { results.push({icon: 'lock', key: 'locked'}); - } else if(topic.get('archived')){ + } else if (topic.get('archived')) { results.push({icon: 'lock', key: 'archived'}); } - if(topic.get('pinned')){ + if (topic.get('pinned')) { results.push({icon: 'thumb-tack', key: 'pinned'}); } - if(topic.get('unpinned')){ + if (topic.get('unpinned')) { results.push({icon: 'thumb-tack unpinned', key: 'unpinned'}); } - if(topic.get('invisible')){ + if (topic.get('invisible')) { results.push({icon: 'eye-slash', key: 'invisible'}); } - _.each(results, function(result){ - result.title = I18n.t("topic_statuses." + result.key + ".help"); - if(!self.disableActions && (result.key === "pinned" ||result.key === "unpinned")){ + results.forEach(result => { + result.title = I18n.t(`topic_statuses.${result.key}.help`); + if (!self.disableActions && (result.key === "pinned" ||result.key === "unpinned")) { result.openTag = 'a href'; result.closeTag = 'a'; } else { @@ -58,6 +62,5 @@ export default Ember.Object.extend({ }); return results; - }.property() + } }); - 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 37733386f1f..7dc4502cf75 100644 --- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 +++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 @@ -1,5 +1,3 @@ -import { defaultHomepage } from 'discourse/lib/utilities'; - export default function() { // Error page this.route('exception', { path: '/exception' }); @@ -45,18 +43,22 @@ export default function() { this.route('categoryNone', { path: '/c/:slug/none' }); this.route('category', { path: '/c/:parentSlug/:slug' }); this.route('categoryWithID', { path: '/c/:parentSlug/:slug/:id' }); - - // homepage - this.route(defaultHomepage(), { path: '/' }); }); + this.route('groups', { resetNamespace: true }); + this.route('group', { path: '/groups/:name', resetNamespace: true }, function() { this.route('members'); - this.route('posts'); - this.route('topics'); - this.route('mentions'); - this.route('messages'); + + this.route('activity', function() { + this.route('posts'); + this.route('topics'); + this.route('mentions'); + this.route('messages'); + }); + this.route('logs'); + this.route('edit'); }); // User routes diff --git a/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 b/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 index ad7118fcc0e..9f4c76ee7d5 100644 --- a/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 +++ b/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 @@ -114,7 +114,8 @@ const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, { const model = this.store.createRecord('category', { color: "AB9364", text_color: "FFFFFF", group_permissions: [{group_name: everyoneName, permission_type: 1}], available_groups: groups.map(g => g.name), - allow_badges: true + allow_badges: true, + topic_featured_link_allowed: true }); showModal("edit-category", { model }); diff --git a/app/assets/javascripts/discourse/routes/discovery.js.es6 b/app/assets/javascripts/discourse/routes/discovery.js.es6 index 400d1df1eea..a77806d1a4d 100644 --- a/app/assets/javascripts/discourse/routes/discovery.js.es6 +++ b/app/assets/javascripts/discourse/routes/discovery.js.es6 @@ -11,7 +11,7 @@ export default Discourse.Route.extend(OpenComposer, { }, beforeModel(transition) { - if (transition.intent.url === "/" && + if ((transition.intent.url === "/" || transition.intent.url === "/categories") && transition.targetName.indexOf("discovery.top") === -1 && Discourse.User.currentProp("should_be_redirected_to_top")) { Discourse.User.currentProp("should_be_redirected_to_top", false); diff --git a/app/assets/javascripts/discourse/routes/forgot-password.js.es6 b/app/assets/javascripts/discourse/routes/forgot-password.js.es6 index df8ab36145b..648bf44ca30 100644 --- a/app/assets/javascripts/discourse/routes/forgot-password.js.es6 +++ b/app/assets/javascripts/discourse/routes/forgot-password.js.es6 @@ -1,10 +1,12 @@ +import { defaultHomepage } from 'discourse/lib/utilities'; import buildStaticRoute from 'discourse/routes/build-static-route'; const ForgotPasswordRoute = buildStaticRoute('password-reset'); ForgotPasswordRoute.reopen({ beforeModel() { - this.replaceWith(this.controllerFor('application').get('loginRequired') ? 'login' : 'discovery').then(e => { + const loginRequired = this.controllerFor('application').get('loginRequired'); + this.replaceWith(loginRequired ? 'login' : `discovery.${defaultHomepage()}`).then(e => { Ember.run.next(() => e.send('showForgotPassword')); }); }, diff --git a/app/assets/javascripts/discourse/routes/group-activity-mentions.js.es6 b/app/assets/javascripts/discourse/routes/group-activity-mentions.js.es6 new file mode 100644 index 00000000000..48f4fc7d9d5 --- /dev/null +++ b/app/assets/javascripts/discourse/routes/group-activity-mentions.js.es6 @@ -0,0 +1,3 @@ +import { buildGroupPage } from 'discourse/routes/group-activity-posts'; + +export default buildGroupPage('mentions'); diff --git a/app/assets/javascripts/discourse/routes/group-activity-messages.js.es6 b/app/assets/javascripts/discourse/routes/group-activity-messages.js.es6 new file mode 100644 index 00000000000..660a5c7cd5f --- /dev/null +++ b/app/assets/javascripts/discourse/routes/group-activity-messages.js.es6 @@ -0,0 +1,3 @@ +import { buildGroupPage } from 'discourse/routes/group-activity-posts'; + +export default buildGroupPage('messages'); diff --git a/app/assets/javascripts/discourse/routes/group-posts.js.es6 b/app/assets/javascripts/discourse/routes/group-activity-posts.js.es6 similarity index 79% rename from app/assets/javascripts/discourse/routes/group-posts.js.es6 rename to app/assets/javascripts/discourse/routes/group-activity-posts.js.es6 index 25ee29e4dd0..03cd7ec1147 100644 --- a/app/assets/javascripts/discourse/routes/group-posts.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-activity-posts.js.es6 @@ -11,12 +11,12 @@ export function buildGroupPage(type) { }, setupController(controller, model) { - this.controllerFor('group-posts').setProperties({ model, type }); + this.controllerFor('group-activity-posts').setProperties({ model, type }); this.controllerFor("group").set("showing", type); }, renderTemplate() { - this.render('group-posts'); + this.render('group-activity-posts'); }, actions: { diff --git a/app/assets/javascripts/discourse/routes/group-activity-topics.js.es6 b/app/assets/javascripts/discourse/routes/group-activity-topics.js.es6 new file mode 100644 index 00000000000..16164a51bb3 --- /dev/null +++ b/app/assets/javascripts/discourse/routes/group-activity-topics.js.es6 @@ -0,0 +1,3 @@ +import { buildGroupPage } from 'discourse/routes/group-activity-posts'; + +export default buildGroupPage('topics'); diff --git a/app/assets/javascripts/discourse/routes/group-activity.js.es6 b/app/assets/javascripts/discourse/routes/group-activity.js.es6 new file mode 100644 index 00000000000..84011db59f4 --- /dev/null +++ b/app/assets/javascripts/discourse/routes/group-activity.js.es6 @@ -0,0 +1,5 @@ +export default Ember.Route.extend({ + beforeModel: function() { + this.transitionTo("group.activity.posts"); + } +}); diff --git a/app/assets/javascripts/discourse/routes/group-edit.js.es6 b/app/assets/javascripts/discourse/routes/group-edit.js.es6 new file mode 100644 index 00000000000..8608e6ecf3b --- /dev/null +++ b/app/assets/javascripts/discourse/routes/group-edit.js.es6 @@ -0,0 +1,15 @@ +export default Ember.Route.extend({ + titleToken() { + return I18n.t('groups.edit.title'); + }, + + model() { + return this.modelFor('group'); + }, + + setupController(controller, model) { + this.controllerFor('group-edit').setProperties({ model }); + this.controllerFor("group").set("showing", 'edit'); + model.findMembers(); + } +}); diff --git a/app/assets/javascripts/discourse/routes/group-mentions.js.es6 b/app/assets/javascripts/discourse/routes/group-mentions.js.es6 deleted file mode 100644 index 2a12734dc18..00000000000 --- a/app/assets/javascripts/discourse/routes/group-mentions.js.es6 +++ /dev/null @@ -1,3 +0,0 @@ -import { buildGroupPage } from 'discourse/routes/group-posts'; - -export default buildGroupPage('mentions'); diff --git a/app/assets/javascripts/discourse/routes/group-messages.js.es6 b/app/assets/javascripts/discourse/routes/group-messages.js.es6 deleted file mode 100644 index c800d6f7774..00000000000 --- a/app/assets/javascripts/discourse/routes/group-messages.js.es6 +++ /dev/null @@ -1,3 +0,0 @@ -import { buildGroupPage } from 'discourse/routes/group-posts'; - -export default buildGroupPage('messages'); diff --git a/app/assets/javascripts/discourse/routes/group-topics.js.es6 b/app/assets/javascripts/discourse/routes/group-topics.js.es6 deleted file mode 100644 index be4e87077e9..00000000000 --- a/app/assets/javascripts/discourse/routes/group-topics.js.es6 +++ /dev/null @@ -1,3 +0,0 @@ -import { buildGroupPage } from 'discourse/routes/group-posts'; - -export default buildGroupPage('topics'); diff --git a/app/assets/javascripts/discourse/routes/group.js.es6 b/app/assets/javascripts/discourse/routes/group.js.es6 index 51731bccb68..3df20f794bf 100644 --- a/app/assets/javascripts/discourse/routes/group.js.es6 +++ b/app/assets/javascripts/discourse/routes/group.js.es6 @@ -1,5 +1,4 @@ import Group from 'discourse/models/group'; -import showModal from 'discourse/lib/show-modal'; export default Discourse.Route.extend({ @@ -17,12 +16,5 @@ export default Discourse.Route.extend({ setupController(controller, model) { controller.setProperties({ model, counts: this.get('counts') }); - }, - - actions: { - showGroupEditor() { - showModal('edit-group'); - this.controllerFor('edit-group').set('model', this.modelFor('group')); - } } }); diff --git a/app/assets/javascripts/discourse/routes/groups.js.es6 b/app/assets/javascripts/discourse/routes/groups.js.es6 new file mode 100644 index 00000000000..582ebe0f5c6 --- /dev/null +++ b/app/assets/javascripts/discourse/routes/groups.js.es6 @@ -0,0 +1,13 @@ +export default Discourse.Route.extend({ + titleToken() { + return I18n.t('groups.index.title'); + }, + + model(params) { + return this.store.findAll('group', params); + }, + + setupController(controller, model) { + controller.set('groups', model); + } +}); diff --git a/app/assets/javascripts/discourse/routes/topic.js.es6 b/app/assets/javascripts/discourse/routes/topic.js.es6 index 794c432a7b6..105d0e6ba0e 100644 --- a/app/assets/javascripts/discourse/routes/topic.js.es6 +++ b/app/assets/javascripts/discourse/routes/topic.js.es6 @@ -72,8 +72,12 @@ const TopicRoute = Discourse.Route.extend({ showHistory(model) { showModal('history', { model }); - this.controllerFor('history').refresh(model.get("id"), "latest"); - this.controllerFor('history').set('post', model); + const historyController = this.controllerFor('history'); + + historyController.refresh(model.get("id"), "latest"); + historyController.set('post', model); + historyController.set('topicController', this.controllerFor('topic')); + this.controllerFor('modal').set('modalClass', 'history-modal'); }, @@ -117,7 +121,6 @@ const TopicRoute = Discourse.Route.extend({ willTransition() { this._super(); - this.controllerFor("topic").send('deselectText'); Em.run.cancel(scheduledReplace); isTransitioning = true; return true; @@ -207,6 +210,7 @@ const TopicRoute = Discourse.Route.extend({ // close the multi select when switching topics controller.set('multiSelect', false); + controller.get('quoteState').clear(); this.controllerFor('composer').set('topic', model); this.topicTrackingState.trackIncoming('all'); diff --git a/app/assets/javascripts/discourse/templates/additional-composer-buttons.hbs b/app/assets/javascripts/discourse/templates/additional-composer-buttons.hbs deleted file mode 100644 index 43ccd1b392d..00000000000 --- a/app/assets/javascripts/discourse/templates/additional-composer-buttons.hbs +++ /dev/null @@ -1 +0,0 @@ -{{!-- THIS IS AN EMPTY TEMPLATE THAT NEEDS TO BE OVERWRITTEN --}} diff --git a/app/assets/javascripts/discourse/templates/application.hbs b/app/assets/javascripts/discourse/templates/application.hbs index 8a074e2eb37..6250c28d1fd 100644 --- a/app/assets/javascripts/discourse/templates/application.hbs +++ b/app/assets/javascripts/discourse/templates/application.hbs @@ -1,17 +1,17 @@ -{{plugin-outlet "above-site-header"}} +{{plugin-outlet name="above-site-header"}} {{site-header canSignUp=canSignUp - showCreateAccount="showCreateAccount" - showLogin="showLogin" - showKeyboard="showKeyboardShortcutsHelp" - toggleMobileView="toggleMobileView" - toggleAnonymous="toggleAnonymous" - logout="logout"}} -{{plugin-outlet "below-site-header"}} + showCreateAccount=(action "appRouteAction" "showCreateAccount") + showLogin=(action "appRouteAction" "showLogin") + showKeyboard=(action "appRouteAction" "showKeyboardShortcutsHelp") + toggleMobileView=(action "appRouteAction" "toggleMobileView") + toggleAnonymous=(action "appRouteAction" "toggleAnonymous") + logout=(action "appRouteAction" "logout")}} +{{plugin-outlet name="below-site-header"}}
    {{#if showTop}} - {{custom-html "top"}} + {{custom-html name="top"}} {{/if}} {{global-notice}} {{create-topics-notice}} @@ -20,11 +20,11 @@ {{outlet "user-card"}}
    -{{plugin-outlet "above-footer"}} +{{plugin-outlet name="above-footer" args=(hash showFooter=showFooter)}} {{#if showFooter}} - {{custom-html "footer"}} + {{custom-html name="footer"}} {{/if}} -{{plugin-outlet "below-footer"}} +{{plugin-outlet name="below-footer" args=(hash showFooter=showFooter)}} {{outlet "modal"}} {{topic-entrance}} diff --git a/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs b/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs index f737c969760..bbf8ef4caba 100644 --- a/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs +++ b/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs @@ -8,6 +8,6 @@ {{tag-drop firstCategory=firstCategory secondCategory=secondCategory tagId=tagId}} {{/if}} -{{plugin-outlet "bread-crumbs-right" tagName="li"}} +{{plugin-outlet name="bread-crumbs-right" connectorTagName="li"}}
    diff --git a/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs b/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs index 790e61e9390..bf439c9e43c 100644 --- a/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs +++ b/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs @@ -19,11 +19,18 @@ +
    + +
    + {{#if siteSettings.topic_featured_link_enabled}}
    @@ -56,7 +63,7 @@
    - {{plugin-outlet "category-email-in"}} + {{plugin-outlet name="category-email-in" args=(hash category=category)}} {{/if}} {{#if showPositionInput}} @@ -82,4 +89,4 @@ {{/unless}} -{{plugin-outlet "category-custom-settings"}} +{{plugin-outlet name="category-custom-settings" args=(hash category=category)}} diff --git a/app/assets/javascripts/admin/templates/components/group-member.hbs b/app/assets/javascripts/discourse/templates/components/group-member.hbs similarity index 100% rename from app/assets/javascripts/admin/templates/components/group-member.hbs rename to app/assets/javascripts/discourse/templates/components/group-member.hbs diff --git a/app/assets/javascripts/discourse/templates/components/group-members-input.hbs b/app/assets/javascripts/discourse/templates/components/group-members-input.hbs new file mode 100644 index 00000000000..c720c630f53 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/group-members-input.hbs @@ -0,0 +1,23 @@ + +
    + + {{currentPage}}/{{totalPages}} + +
    +
    + {{#each model.members as |member|}} + {{group-member member=member automatic=model.automatic removeAction="removeMember"}} + {{/each}} +
    + +{{#unless model.automatic}} +
    + {{user-selector usernames=model.usernames}} + + {{d-button action="addMembers" + class="add" + icon="plus" + disabled=disableAddButton + label="groups.edit.add_members"}} +
    +{{/unless}} diff --git a/app/assets/javascripts/discourse/templates/components/group-membership-button.hbs b/app/assets/javascripts/discourse/templates/components/group-membership-button.hbs new file mode 100644 index 00000000000..1fc14e88970 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/group-membership-button.hbs @@ -0,0 +1,32 @@ +{{#if canJoinGroup}} + {{#if userIsGroupUser}} + {{d-button action="leaveGroup" + class="btn-danger group-index-leave" + icon="minus" + label="groups.leave" + disabled=updatingMembership}} + {{else}} + {{d-button action=joinGroupAction + class="group-index-join" + icon="plus" + label="groups.join" + disabled=updatingMembership}} + {{/if}} +{{else if canRequestMembership}} + {{#if userIsGroupUser}} + {{#if showMembershipStatus}} + {{d-button + class="btn-primary" + icon="user" + label="groups.is_group_user" + disabled=true}} + {{/if}} + {{else}} + {{d-button action=requestMembershipAction + class="group-index-request" + icon="envelope" + label="groups.request"}} + {{/if}} +{{else}} + {{yield}} +{{/if}} diff --git a/app/assets/javascripts/discourse/templates/components/latest-topic-list-item.hbs b/app/assets/javascripts/discourse/templates/components/latest-topic-list-item.hbs index e42241f0bb3..3d4aeab6a06 100644 --- a/app/assets/javascripts/discourse/templates/components/latest-topic-list-item.hbs +++ b/app/assets/javascripts/discourse/templates/components/latest-topic-list-item.hbs @@ -10,7 +10,7 @@
    - {{topic-status topic=topic}} + {{raw "topic-status" topic=topic}} {{topic-link topic}} {{#if topic.featured_link}} {{topic-featured-link topic}} diff --git a/app/assets/javascripts/discourse/templates/components/navigation-bar.hbs b/app/assets/javascripts/discourse/templates/components/navigation-bar.hbs index c7d381e5679..3a2496cc969 100644 --- a/app/assets/javascripts/discourse/templates/components/navigation-bar.hbs +++ b/app/assets/javascripts/discourse/templates/components/navigation-bar.hbs @@ -1,5 +1,5 @@ {{#each navItems as |navItem|}} {{navigation-item content=navItem filterMode=filterMode}} {{/each}} -{{custom-html "extraNavItem"}} -{{plugin-outlet "extra-nav-item" tagName="li"}} +{{custom-html name="extraNavItem"}} +{{plugin-outlet name="extra-nav-item" connectorTagName="li"}} diff --git a/app/assets/javascripts/discourse/templates/components/plugin-outlet.hbs b/app/assets/javascripts/discourse/templates/components/plugin-outlet.hbs new file mode 100644 index 00000000000..73126a2572f --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/plugin-outlet.hbs @@ -0,0 +1,3 @@ +{{#each connectors as |c|}} + {{plugin-connector connector=c args=args class=c.classNames tagName=connectorTagName}} +{{/each}} diff --git a/app/assets/javascripts/discourse/templates/components/stream-item.hbs b/app/assets/javascripts/discourse/templates/components/stream-item.hbs index 0018f8a2d84..fed530753ef 100644 --- a/app/assets/javascripts/discourse/templates/components/stream-item.hbs +++ b/app/assets/javascripts/discourse/templates/components/stream-item.hbs @@ -6,7 +6,7 @@ {{{item.title}}}
    {{category-link item.category}}
    - {{plugin-outlet "user-stream-item-header"}} + {{plugin-outlet name="user-stream-item-header" args=(hash item=item)}} {{#if actionDescription}} diff --git a/app/assets/javascripts/discourse/templates/components/topic-category.hbs b/app/assets/javascripts/discourse/templates/components/topic-category.hbs index cf717a09922..edf11686ba9 100644 --- a/app/assets/javascripts/discourse/templates/components/topic-category.hbs +++ b/app/assets/javascripts/discourse/templates/components/topic-category.hbs @@ -14,4 +14,4 @@ {{topic-featured-link topic}} {{/if}} -{{plugin-outlet "topic-category"}} +{{plugin-outlet name="topic-category" args=(hash topic=topic category=topic.category)}} diff --git a/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs b/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs index 83ed1bfe244..b2d37f5c700 100644 --- a/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs +++ b/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs @@ -1,16 +1,31 @@ {{#if showAdminButton}} - {{topic-admin-menu-button topic=topic delegated=topicDelegated openUpwards="true"}} + {{topic-admin-menu-button + topic=topic + openUpwards="true" + toggleMultiSelect=toggleMultiSelect + deleteTopic=deleteTopic + recoverTopic=recoverTopic + toggleClosed=toggleClosed + toggleArchived=toggleArchived + toggleVisibility=toggleVisibility + showAutoClose=showAutoClose + showFeatureTopic=showFeatureTopic + showChangeTimestamp=showChangeTimestamp + convertToPublicTopic=convertToPublicTopic + convertToPrivateMessage=convertToPrivateMessage}} {{/if}} {{#unless topic.isPrivateMessage}} {{#if site.mobileView}} - {{topic-footer-mobile-dropdown topic=topic}} + {{topic-footer-mobile-dropdown topic=topic + showInvite=showInvite + showFlagTopic=showFlagTopic}} {{else}} {{d-button class=bookmarkClass title=bookmarkTitle label=bookmarkLabel icon="bookmark" - action="toggleBookmark"}} + action=toggleBookmark}} {{/if}} - {{render "additional-composer-buttons" model}} {{/if}} {{/if}} - {{plugin-outlet "composer-fields"}} + {{plugin-outlet name="composer-fields" args=(hash model=model)}} {{composer-editor topic=topic @@ -104,7 +103,7 @@ {{#if currentUser}}
    - {{plugin-outlet "composer-fields-below"}} + {{plugin-outlet name="composer-fields-below" args=(hash model=model)}} {{#if canEditTags}} {{tag-chooser tags=model.tags tabIndex="4" categoryId=model.categoryId}} {{/if}} diff --git a/app/assets/javascripts/discourse/templates/discovery.hbs b/app/assets/javascripts/discourse/templates/discovery.hbs index 069be994bad..8c7a0d6d3f6 100644 --- a/app/assets/javascripts/discourse/templates/discovery.hbs +++ b/app/assets/javascripts/discourse/templates/discovery.hbs @@ -21,11 +21,12 @@
    - {{plugin-outlet "discovery-list-container-top"}} + {{plugin-outlet name="discovery-list-container-top" + args=(hash category=category)}} {{outlet "list-container"}}
    -{{plugin-outlet "discovery-below"}} +{{plugin-outlet name="discovery-below"}} diff --git a/app/assets/javascripts/discourse/templates/full-page-search.hbs b/app/assets/javascripts/discourse/templates/full-page-search.hbs index edaf9172db9..bfeab09cfe2 100644 --- a/app/assets/javascripts/discourse/templates/full-page-search.hbs +++ b/app/assets/javascripts/discourse/templates/full-page-search.hbs @@ -94,7 +94,7 @@ {{#each result.topic.tags as |tag|}} {{discourse-tag tag}} {{/each}} - {{plugin-outlet "full-page-search-category"}} + {{plugin-outlet name="full-page-search-category" args=(hash result=result)}} diff --git a/app/assets/javascripts/discourse/templates/group-posts.hbs b/app/assets/javascripts/discourse/templates/group-activity-posts.hbs similarity index 100% rename from app/assets/javascripts/discourse/templates/group-posts.hbs rename to app/assets/javascripts/discourse/templates/group-activity-posts.hbs diff --git a/app/assets/javascripts/discourse/templates/group-edit.hbs b/app/assets/javascripts/discourse/templates/group-edit.hbs new file mode 100644 index 00000000000..03122d2abaa --- /dev/null +++ b/app/assets/javascripts/discourse/templates/group-edit.hbs @@ -0,0 +1,46 @@ +
    +
    +
    + + {{input type='text' name='full_name' value=model.full_name class='group-edit-full-name'}} +
    + +
    + + {{d-editor value=model.bio_raw class="group-edit-bio"}} +
    + +
    + {{group-members-input model=model}} +
    + +
    + {{group-flair-inputs model=model}} +
    + +
    + +
    + +
    + +
    + + {{d-button action="save" class="btn-primary" disabled=saving label="save"}} + {{savingText}} + +
    diff --git a/app/assets/javascripts/discourse/templates/group-index.hbs b/app/assets/javascripts/discourse/templates/group-index.hbs index cd01f61fa4d..86a35b11122 100644 --- a/app/assets/javascripts/discourse/templates/group-index.hbs +++ b/app/assets/javascripts/discourse/templates/group-index.hbs @@ -1,37 +1,14 @@ -{{#if model}} - {{#if isOwner}} - - {{user-selector usernames=usernames placeholderKey="groups.selector_placeholder" id="user-search-selector" name="usernames"}} - {{d-button action="addMembers" class="add" icon="plus" label="groups.add"}} - - {{else if canJoinGroup}} - {{#if model.is_group_user}} - {{d-button action="leaveGroup" - class="btn-danger group-index-leave" - icon="minus" - label="groups.leave" - disabled=updatingMembership}} - {{else}} - {{d-button action="joinGroup" - class="group-index-join" - icon="plus" - label="groups.join" - disabled=updatingMembership}} - {{/if}} - {{else if canRequestMembership}} - {{d-button action="requestMembership" - class="group-index-request" - icon="envelope" - label="groups.request"}} - {{/if}} +{{group-membership-button model=model + createNewMessageViaParams='createNewMessageViaParams' + showLogin='showLogin'}} +{{#if hasMembers}} {{#load-more selector=".group-members tr" action="loadMore"}}
      {{i18n 'admin.dashboard.installed_version'}}
    {{group-index-toggle order=order desc=desc field='username_lower' i18nKey='username'}} {{group-index-toggle order=order desc=desc field='last_posted_at' i18nKey='last_post'}} {{group-index-toggle order=order desc=desc field='last_seen_at' i18nKey='last_seen'}} - @@ -48,13 +25,6 @@ - {{/each}} @@ -63,5 +33,7 @@ {{conditional-loading-spinner condition=loading}} {{else}} -
    {{i18n "groups.empty.users"}}
    +
    + +
    {{i18n "groups.empty.members"}}
    {{/if}} diff --git a/app/assets/javascripts/discourse/templates/group.hbs b/app/assets/javascripts/discourse/templates/group.hbs index f7188592d2b..571c1813d6e 100644 --- a/app/assets/javascripts/discourse/templates/group.hbs +++ b/app/assets/javascripts/discourse/templates/group.hbs @@ -1,6 +1,6 @@
    -
    +
    {{#if model.flair_url}} {{avatar-flair @@ -12,20 +12,12 @@ {{/if}} -

    - {{groupName}} -

    + {{groupName}} - {{#if model.title}} -

    @{{model.name}}

    - {{/if}} +
    + {{#if model.full_name}}{{model.name}}{{/if}} +
    - - {{#if canEditGroup}} - - {{d-button action="showGroupEditor" label="groups.edit.title" class="group-edit-btn" icon="pencil"}} - - {{/if}}
    {{#if model.bio_cooked}} @@ -37,9 +29,9 @@ {{/if}}
    - {{#mobile-nav class='group-nav' desktopClass="pull-left nav nav-stacked" currentPath=currentPath}} + {{#mobile-nav class='group-nav' desktopClass="nav nav-pills" currentPath=application.currentPath}} {{#each getTabs as |tab|}} -
  • +
  • {{#link-to tab.location model title=tab.message}} {{#if tab.icon}}{{fa-icon tab.icon}}{{/if}} {{tab.message}} @@ -49,9 +41,7 @@ {{/each}} {{/mobile-nav}} -
    -
    - {{outlet}} -
    +
    + {{outlet}}
    diff --git a/app/assets/javascripts/discourse/templates/group/activity.hbs b/app/assets/javascripts/discourse/templates/group/activity.hbs new file mode 100644 index 00000000000..d03a14e84f1 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/group/activity.hbs @@ -0,0 +1,27 @@ +
    + {{#mobile-nav class='group-activity-nav' desktopClass="pull-left nav nav-stacked" currentPath=application.currentPath}} +
  • + {{#link-to 'group.activity.posts'}}{{i18n 'groups.posts'}}{{/link-to}} +
  • + +
  • + {{#link-to 'group.activity.topics'}}{{i18n 'groups.topics'}}{{/link-to}} +
  • + +
  • + {{#link-to 'group.activity.mentions'}}{{i18n 'groups.mentions'}}{{/link-to}} +
  • + + {{#if showGroupMessages}} +
  • + {{#link-to 'group.activity.messages'}}{{i18n 'groups.messages'}}{{/link-to}} +
  • + {{/if}} + {{/mobile-nav}} + +
    +
    + {{outlet}} +
    +
    +
    diff --git a/app/assets/javascripts/discourse/templates/groups.hbs b/app/assets/javascripts/discourse/templates/groups.hbs new file mode 100644 index 00000000000..2699777f5a6 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/groups.hbs @@ -0,0 +1,69 @@ +{{#d-section pageClass="groups"}} +

    {{i18n "groups.index.title"}}

    + {{#if groups}} + {{#load-more selector=".groups-table .groups-table-row" action="loadMore"}} +
    +
    {{bound-date m.last_seen_at}} - {{#if isOwner}} - {{#unless m.owner}} - - {{/unless}} - {{/if}} -
    + + + + + + + + {{#each groups as |group|}} + + + + + + + + {{/each}} + +
    {{i18n "groups.user_count"}}{{i18n "groups.membership"}}
    + {{#link-to "group.members" group.name}} + {{#if group.flair_url}} + + {{avatar-flair + flairURL=group.flair_url + flairBgColor=group.flair_bg_color + flairColor=group.flair_color + groupName=group.name}} + + {{/if}} + + + {{group.name}} + + {{#if group.full_name}} + {{group.full_name}} + {{/if}} + + {{#if group.title}} +
    + {{group.title}} +
    + {{/if}} +
    + {{/link-to}} +
    {{group.user_count}} + {{#group-membership-button model=group + createNewMessageViaParams='createNewMessageViaParams' + showMembershipStatus=true + groupUserIds=groups.extras.group_user_ids + showLogin='showLogin'}} + + {{d-button icon="ban" + label=(if group.automatic 'groups.automatic_group' 'groups.closed_group') + disabled=true}} + {{/group-membership-button}} +
    +
    + {{/load-more}} + + {{conditional-loading-spinner condition=groups.loadingMore}} + {{else}} +

    {{i18n "groups.index.empty"}}

    + {{/if}} +{{/d-section}} diff --git a/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs b/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs index da825c4774b..05b387b719a 100644 --- a/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs +++ b/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs @@ -5,15 +5,19 @@ {{/if}} - {{raw "topic-status" topic=topic}} - {{topic-link topic}} - {{#if topic.featured_link}} - {{topic-featured-link topic}} - {{/if}} - {{plugin-outlet "topic-list-after-title"}} - {{#if showTopicPostBadges}} - {{raw "topic-post-badges" unread=topic.unread newPosts=topic.displayNewPosts unseen=topic.unseen url=topic.lastUnreadUrl}} - {{/if}} + + {{raw-plugin-outlet name="topic-list-before-status"}} + {{raw "topic-status" topic=topic}} + {{topic-link topic}} + {{#if topic.featured_link}} + {{topic-featured-link topic}} + {{/if}} + {{raw-plugin-outlet name="topic-list-after-title"}} + {{#if showTopicPostBadges}} + {{raw "topic-post-badges" unread=topic.unread newPosts=topic.displayNewPosts unseen=topic.unseen url=topic.lastUnreadUrl}} + {{/if}} + + {{#if topic.tags}}
    {{#each topic.visibleListTags as |tag|}} @@ -21,7 +25,7 @@ {{/each}}
    {{/if}} - {{plugin-outlet "topic-list-tags"}} + {{raw-plugin-outlet name="topic-list-tags"}} {{#if expandPinned}} {{raw "list/topic-excerpt" topic=topic}} {{/if}} diff --git a/app/assets/javascripts/discourse/templates/mobile/components/mobile-nav.hbs b/app/assets/javascripts/discourse/templates/mobile/components/mobile-nav.hbs index 6b46d500ee7..cdab47c07bb 100644 --- a/app/assets/javascripts/discourse/templates/mobile/components/mobile-nav.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/components/mobile-nav.hbs @@ -1,4 +1,6 @@ -
  • {{{selectedHtml}}}
  • +{{#if selectedHtml}} +
  • {{{selectedHtml}}}
  • +{{/if}}
      {{yield}}
    diff --git a/app/assets/javascripts/discourse/templates/mobile/list/topic-list-item.raw.hbs b/app/assets/javascripts/discourse/templates/mobile/list/topic-list-item.raw.hbs index e630889d492..159d836b48b 100644 --- a/app/assets/javascripts/discourse/templates/mobile/list/topic-list-item.raw.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/list/topic-list-item.raw.hbs @@ -10,6 +10,9 @@ {{/unless}} - {{#if context.topic.tags}} + {{#if topic.tags}}
    - {{#each context.topic.visibleListTags as |tag|}} + {{#each topic.visibleListTags as |tag|}} {{discourse-tag tag}} {{/each}}
    {{/if}} - {{plugin-outlet "topic-list-tags"}} + {{raw-plugin-outlet name="topic-list-tags"}}
    diff --git a/app/assets/javascripts/discourse/templates/mobile/modal/login.hbs b/app/assets/javascripts/discourse/templates/mobile/modal/login.hbs index aacaa22bc42..d156ca66dde 100644 --- a/app/assets/javascripts/discourse/templates/mobile/modal/login.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/modal/login.hbs @@ -1,54 +1,59 @@ -{{#d-modal-body title="login.title" class="login-modal"}} - {{login-buttons action="externalLogin"}} - {{#if canLoginLocal}} -
    -
    - - - - - - - - - - - - - -
    - - - {{text-field value=loginName type="email" placeholderKey="login.email_placeholder" id="login-account-name" autocorrect="off" autocapitalize="off"}} -
    - - - {{text-field value=loginPassword type="password" id="login-account-password" maxlength="200"}}   -
    - {{i18n 'forgot_password.action'}} -
    -
    -
    - {{/if}} - {{authMessage}} -
    {{alert}}
    -{{/d-modal-body}} +{{#login-modal screenX=lastX screenY=lastY loginName=loginName loginPassword=loginPassword action="login"}} + {{#d-modal-body title="login.title" class="login-modal"}} + {{login-buttons action="externalLogin"}} + {{#if canLoginLocal}} +
    +
    + + + + + + + + + + + + + +
    + + + {{text-field value=loginName type="email" placeholderKey="login.email_placeholder" id="login-account-name" autocorrect="off" autocapitalize="off"}} +
    + + + {{text-field value=loginPassword type="password" id="login-account-password" maxlength="200"}}   +
    + {{i18n 'forgot_password.action'}} +
    +
    -
    + {{authMessage}} +
    {{alert}}
    + {{/d-modal-body}} + + +{{/login-modal}} diff --git a/app/assets/javascripts/discourse/templates/modal/create-account.hbs b/app/assets/javascripts/discourse/templates/modal/create-account.hbs index 7921b2a2452..bdaa3d82394 100644 --- a/app/assets/javascripts/discourse/templates/modal/create-account.hbs +++ b/app/assets/javascripts/discourse/templates/modal/create-account.hbs @@ -52,7 +52,11 @@ {{/if}} - {{plugin-outlet "create-account-before-password"}} + {{plugin-outlet name="create-account-before-password" + args=(hash accountName=accountName + accountUsername=accountUsername + accountPassword=accountPassword + userFields=userFields)}} {{#if passwordRequired}} diff --git a/app/assets/javascripts/discourse/templates/modal/edit-group.hbs b/app/assets/javascripts/discourse/templates/modal/edit-group.hbs deleted file mode 100644 index 863f83dd3c3..00000000000 --- a/app/assets/javascripts/discourse/templates/modal/edit-group.hbs +++ /dev/null @@ -1,34 +0,0 @@ -{{#d-modal-body title="groups.edit.title" class="edit-group groups"}} -
    - - {{input type='text' name='title' value=model.title class='edit-group-title'}} - - - {{d-editor value=model.bio_raw class="edit-group-bio"}} - - {{group-flair-inputs model=model}} - - - - -
    -{{/d-modal-body}} - - diff --git a/app/assets/javascripts/discourse/templates/modal/forgot-password.hbs b/app/assets/javascripts/discourse/templates/modal/forgot-password.hbs index 9371c61ddbd..8a8db45cce2 100644 --- a/app/assets/javascripts/discourse/templates/modal/forgot-password.hbs +++ b/app/assets/javascripts/discourse/templates/modal/forgot-password.hbs @@ -1,9 +1,9 @@
    - - + {{#d-modal-body}} + + {{text-field value=accountEmailOrUsername placeholderKey="login.email_placeholder" id="username-or-email" autocorrect="off" autocapitalize="off"}} + {{/d-modal-body}} +
    diff --git a/app/assets/javascripts/discourse/templates/modal/history.hbs b/app/assets/javascripts/discourse/templates/modal/history.hbs index ce860fefcbf..62e7f9b9841 100644 --- a/app/assets/javascripts/discourse/templates/modal/history.hbs +++ b/app/assets/javascripts/discourse/templates/modal/history.hbs @@ -11,11 +11,25 @@ {{d-button action="loadNextVersion" icon="forward" title="post.revisions.controls.next" disabled=loadNextDisabled}} {{d-button action="loadLastVersion" icon="fast-forward" title="post.revisions.controls.last" disabled=loadLastDisabled}}
    +
    - {{d-button action="displayInline" label="post.revisions.displays.inline.button" title="post.revisions.displays.inline.title" class=inlineClass}} + {{d-button action="displayInline" + icon="square-o" + label="post.revisions.displays.inline.button" + title="post.revisions.displays.inline.title" + class=inlineClass}} {{#unless site.mobileView}} - {{d-button action="displaySideBySide" label="post.revisions.displays.side_by_side.button" title="post.revisions.displays.side_by_side.title" class=sideBySideClass}} - {{d-button action="displaySideBySideMarkdown" label="post.revisions.displays.side_by_side_markdown.button" title="post.revisions.displays.side_by_side_markdown.title" class=sideBySideMarkdownClass}} + {{d-button action="displaySideBySide" + icon="columns" + label="post.revisions.displays.side_by_side.button" + title="post.revisions.displays.side_by_side.title" + class=sideBySideClass}} + + {{d-button action="displaySideBySideMarkdown" + icon="columns" + label="post.revisions.displays.side_by_side_markdown.button" + title="post.revisions.displays.side_by_side_markdown.title" + class=sideBySideMarkdownClass}} {{/unless}}
    @@ -34,7 +48,7 @@ → {{bound-avatar-template model.user_changes.current.avatar_template "small"}} {{model.user_changes.current.username}} {{/if}} {{#if model.wiki_changes}} - — {{disabled-icon icon="pencil-square-o" secondary=wikiDisabled}} + — {{disabled-icon icon="pencil-square-o" disabled=wikiDisabled}} {{/if}} {{#if model.post_type_changes}} — {{disabled-icon icon="shield" disabled=postTypeDisabled}} @@ -59,7 +73,7 @@ {{/if}} {{#if model.wiki_changes}}
    - {{disabled-icon icon="pencil-square-o" secondary=wikiDisabled}} + {{disabled-icon icon="pencil-square-o" disabled=wikiDisabled}}
    {{/if}} {{#if model.post_type_changes}} @@ -94,7 +108,7 @@
    {{/if}} - {{plugin-outlet "post-revisions"}} + {{plugin-outlet name="post-revisions" args=(hash model=model)}} {{#links-redirect class="row"}} {{{bodyDiff}}} @@ -103,11 +117,19 @@ {{#if displayRevert}} {{d-button action="revertToVersion" icon="undo" label="post.revisions.controls.revert" class="btn-danger" disabled=loading}} {{/if}} + {{#if displayHide}} {{d-button action="hideVersion" icon="eye-slash" label="post.revisions.controls.hide" class="btn-danger" disabled=loading}} {{/if}} + {{#if displayShow}} {{d-button action="showVersion" icon="eye" label="post.revisions.controls.show" disabled=loading}} {{/if}} + + {{#if displayEdit}} + {{d-button action="editWiki" + icon="pencil" + label="post.revisions.controls.edit_wiki"}} + {{/if}}
    {{/d-modal-body}} diff --git a/app/assets/javascripts/discourse/templates/modal/jump-to-post.hbs b/app/assets/javascripts/discourse/templates/modal/jump-to-post.hbs new file mode 100644 index 00000000000..7c5b9b171a1 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/modal/jump-to-post.hbs @@ -0,0 +1,11 @@ +{{#d-modal-body title="topic.progress.jump_prompt_long"}} + {{text-field value=postNumber insert-newline="jump"}} + + {{i18n "topic.progress.jump_prompt_of" count=topic.postStream.filteredPostsCount}} + +{{/d-modal-body}} + + diff --git a/app/assets/javascripts/discourse/templates/navigation/category.hbs b/app/assets/javascripts/discourse/templates/navigation/category.hbs index e7f01c1cd1b..2e9579cbf28 100644 --- a/app/assets/javascripts/discourse/templates/navigation/category.hbs +++ b/app/assets/javascripts/discourse/templates/navigation/category.hbs @@ -1,8 +1,8 @@ {{add-category-class category=category}}
    - {{#if category.logo_url}} - {{cdn-img src=category.logo_url class="category-logo"}} + {{#if category.uploaded_logo.url}} + {{cdn-img src=category.uploaded_logo.url class="category-logo"}} {{#if category.description}}

    {{{category.description}}}

    {{/if}} @@ -33,4 +33,6 @@ {{#if canEditCategory}} {{d-button class="btn-default edit-category" action="editCategory" actionParam=category icon="wrench" label="category.edit_long"}} {{/if}} + + {{plugin-outlet name="category-navigation" args=(hash category=category)}}
    diff --git a/app/assets/javascripts/discourse/templates/preferences-email.hbs b/app/assets/javascripts/discourse/templates/preferences-email.hbs index 0aecb67abd3..6c1beb2ad80 100644 --- a/app/assets/javascripts/discourse/templates/preferences-email.hbs +++ b/app/assets/javascripts/discourse/templates/preferences-email.hbs @@ -25,7 +25,8 @@
    - {{text-field value=newEmail id="change_email" classNames="input-xxlarge" autofocus="autofocus"}} + {{text-field value=newEmail id="change-email" classNames="input-xxlarge" autofocus="autofocus"}} + {{input-tip validation=emailValidation}}
    {{#if taken}} diff --git a/app/assets/javascripts/discourse/templates/preferences.hbs b/app/assets/javascripts/discourse/templates/preferences.hbs index 2afbb4d9869..3f39e111fd6 100644 --- a/app/assets/javascripts/discourse/templates/preferences.hbs +++ b/app/assets/javascripts/discourse/templates/preferences.hbs @@ -248,7 +248,7 @@ {{preference-checkbox labelKey="user.enable_quoting" checked=model.user_option.enable_quoting}} {{preference-checkbox labelKey="user.dynamic_favicon" checked=model.user_option.dynamic_favicon}} {{preference-checkbox labelKey="user.disable_jump_reply" checked=model.user_option.disable_jump_reply}} - {{plugin-outlet "user-custom-preferences"}} + {{plugin-outlet name="user-custom-preferences" args=(hash model=model)}}
    @@ -350,7 +350,7 @@
    {{/if}} - {{plugin-outlet "user-custom-controls"}} + {{plugin-outlet name="user-custom-controls" args=(hash model=model)}}
    diff --git a/app/assets/javascripts/discourse/templates/static.hbs b/app/assets/javascripts/discourse/templates/static.hbs index 529b5ba149e..c535f16fb35 100644 --- a/app/assets/javascripts/discourse/templates/static.hbs +++ b/app/assets/javascripts/discourse/templates/static.hbs @@ -1,7 +1,7 @@ {{#d-section bodyClass=bodyClass class="container"}} {{#watch-read action="markFaqRead" path=model.path}}
    - {{plugin-outlet "above-static"}} + {{plugin-outlet name="above-static"}} {{{model.html}}} {{#if showSignupButton}} diff --git a/app/assets/javascripts/discourse/templates/tags/show.hbs b/app/assets/javascripts/discourse/templates/tags/show.hbs index 9cf29e587af..4b33995216c 100644 --- a/app/assets/javascripts/discourse/templates/tags/show.hbs +++ b/app/assets/javascripts/discourse/templates/tags/show.hbs @@ -42,7 +42,7 @@
    -{{plugin-outlet "discovery-list-container-top"}} +{{plugin-outlet name="discovery-list-container-top"}}
    {{conditional-loading-spinner condition=loading}} diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs index 65c0f3f6a81..bd02891d6bc 100644 --- a/app/assets/javascripts/discourse/templates/topic.hbs +++ b/app/assets/javascripts/discourse/templates/topic.hbs @@ -6,7 +6,7 @@
    {{/if}} - {{plugin-outlet "topic-above-post-stream"}} + {{plugin-outlet name="topic-above-post-stream" args=(hash model=model)}} {{#if model.postStream.loaded}} {{#if model.postStream.firstPostPresent}} @@ -30,8 +30,9 @@ {{tag-chooser tags=buffered.tags categoryId=buffered.category_id}} {{/if}} - {{plugin-outlet "edit-topic"}} + {{plugin-outlet name="edit-topic" args=(hash model=model buffered=buffered)}} +
    {{d-button action="finishedEditingTopic" class="btn-primary btn-small submit-edit" icon="check"}} {{d-button action="cancelEditingTopic" class="btn-small cancel-edit" icon="times"}} {{else}} @@ -59,7 +60,7 @@ {{/unless}} {{/if}}
    - {{plugin-outlet "topic-title"}} + {{plugin-outlet name="topic-title" args=(hash model=model)}}
    {{/if}} @@ -69,25 +70,55 @@ {{partial "selected-posts"}}
    - {{#topic-navigation jumpToIndex="jumpToIndex" as |info|}} - + {{#topic-navigation topic=model jumpToIndex=(action "jumpToIndex") as |info|}} {{#if info.renderAdminMenuButton}} - {{topic-admin-menu-button topic=model fixed="true" delegated=topicDelegated}} + {{topic-admin-menu-button + topic=model + fixed="true" + toggleMultiSelect=(action "toggleMultiSelect") + deleteTopic=(action "deleteTopic") + recoverTopic=(action "recoverTopic") + toggleClosed=(action "toggleClosed") + toggleArchived=(action "toggleArchived") + toggleVisibility=(action "toggleVisibility") + showAutoClose=(action "topicRouteAction" "showAutoClose") + showFeatureTopic=(action "topicRouteAction" "showFeatureTopic") + showChangeTimestamp=(action "topicRouteAction" "showChangeTimestamp") + convertToPublicTopic=(action "convertToPublicTopic") + convertToPrivateMessage=(action "convertToPrivateMessage")}} {{/if}} {{#if info.renderTimeline}} - {{topic-timeline topic=model - prevEvent=info.prevEvent - fullscreen=info.topicProgressExpanded - enteredIndex=enteredIndex - loading=model.postStream.loading - delegated=topicDelegated}} - + {{topic-timeline + topic=model + prevEvent=info.prevEvent + fullscreen=info.topicProgressExpanded + enteredIndex=enteredIndex + loading=model.postStream.loading + jumpToPost=(action "jumpToPost") + jumpTop=(action "jumpTop") + jumpBottom=(action "jumpBottom") + jumpToPostPrompt=(action "jumpToPostPrompt") + jumpToIndex=(action "jumpToIndex") + replyToPost=(action "replyToPost") + toggleMultiSelect=(action "toggleMultiSelect") + deleteTopic=(action "deleteTopic") + recoverTopic=(action "recoverTopic") + toggleClosed=(action "toggleClosed") + toggleArchived=(action "toggleArchived") + toggleVisibility=(action "toggleVisibility") + showAutoClose=(action "topicRouteAction" "showAutoClose") + showFeatureTopic=(action "topicRouteAction" "showFeatureTopic") + showChangeTimestamp=(action "topicRouteAction" "showChangeTimestamp") + convertToPublicTopic=(action "convertToPublicTopic") + convertToPrivateMessage=(action "convertToPrivateMessage")}} {{else}} - {{topic-progress prevEvent=info.prevEvent topic=model delegated=topicDelegated expanded=info.topicProgressExpanded}} + {{topic-progress + prevEvent=info.prevEvent + topic=model + expanded=info.topicProgressExpanded + jumpToPost=(action "jumpToPost")}} {{/if}} - - {{/topic-navigation}}
    @@ -96,7 +127,7 @@
    {{conditional-loading-spinner condition=model.postStream.loadingAbove}} - {{plugin-outlet "topic-above-posts"}} + {{plugin-outlet name="topic-above-posts" args=(hash model=model)}} {{#unless model.postStream.loadingFilter}} {{scrolling-post-stream @@ -106,35 +137,34 @@ selectedPostsCount=selectedPostsCount selectedQuery=selectedQuery gaps=model.postStream.gaps - showFlags="showFlags" - editPost="editPost" - showHistory="showHistory" - showLogin="showLogin" - showRawEmail="showRawEmail" - deletePost="deletePost" - recoverPost="recoverPost" - expandHidden="expandHidden" - newTopicAction="replyAsNewTopic" - expandFirstPost="expandFirstPost" - toggleBookmark="toggleBookmark" - togglePostType="togglePostType" - rebakePost="rebakePost" - changePostOwner="changePostOwner" - unhidePost="unhidePost" - replyToPost="replyToPost" - toggleWiki="toggleWiki" - toggleSummary="toggleSummary" - removeAllowedUser="removeAllowedUser" - removeAllowedGroup="removeAllowedGroup" - showInvite="showInvite" - topVisibleChanged="topVisibleChanged" - currentPostChanged="currentPostChanged" - currentPostScrolled="currentPostScrolled" - bottomVisibleChanged="bottomVisibleChanged" - selectPost="toggledSelectedPost" - selectReplies="toggledSelectedPostReplies" - fillGapBefore="fillGapBefore" - fillGapAfter="fillGapAfter"}} + showFlags=(action "showPostFlags") + editPost=(action "editPost") + showHistory=(action "topicRouteAction" "showHistory") + showLogin=(action "topicRouteAction" "showLogin") + showRawEmail=(action "topicRouteAction" "showRawEmail") + deletePost=(action "deletePost") + recoverPost=(action "recoverPost") + expandHidden=(action "expandHidden") + newTopicAction=(action "replyAsNewTopic") + toggleBookmark=(action "toggleBookmark") + togglePostType=(action "togglePostType") + rebakePost=(action "rebakePost") + changePostOwner=(action "changePostOwner") + unhidePost=(action "unhidePost") + replyToPost=(action "replyToPost") + toggleWiki=(action "toggleWiki") + toggleSummary=(action "toggleSummary") + removeAllowedUser=(action "removeAllowedUser") + removeAllowedGroup=(action "removeAllowedGroup") + showInvite=(action "topicRouteAction" "showInvite") + topVisibleChanged=(action "topVisibleChanged") + currentPostChanged=(action "currentPostChanged") + currentPostScrolled=(action "currentPostScrolled") + bottomVisibleChanged=(action "bottomVisibleChanged") + selectPost=(action "toggledSelectedPost") + selectReplies=(action "toggledSelectedPostReplies") + fillGapBefore=(action "fillGapBefore") + fillGapAfter=(action "fillGapAfter")}} {{/unless}} {{conditional-loading-spinner condition=model.postStream.loadingBelow}} @@ -150,7 +180,25 @@ {{signup-cta}} {{else}} {{#if currentUser}} - {{topic-footer-buttons topic=model topicDelegated=topicDelegated}} + {{topic-footer-buttons + topic=model + toggleMultiSelect=(action "toggleMultiSelect") + deleteTopic=(action "deleteTopic") + recoverTopic=(action "recoverTopic") + toggleClosed=(action "toggleClosed") + toggleArchived=(action "toggleArchived") + toggleVisibility=(action "toggleVisibility") + showAutoClose=(action "topicRouteAction" "showAutoClose") + showFeatureTopic=(action "topicRouteAction" "showFeatureTopic") + showChangeTimestamp=(action "topicRouteAction" "showChangeTimestamp") + convertToPublicTopic=(action "convertToPublicTopic") + convertToPrivateMessage=(action "convertToPrivateMessage") + toggleBookmark=(action "toggleBookmark") + showFlagTopic=(action "topicRouteAction" "showFlagTopic") + showInvite=(action "topicRouteAction" "showInvite") + toggleArchiveMessage=(action "toggleArchiveMessage") + replyToPost=(action "replyToPost") + }} {{else}} {{d-button icon="reply" class="btn-primary" action="showLogin" label="topic.reply.title"}} {{/if}} @@ -175,7 +223,7 @@
    {{/if}} - {{plugin-outlet "topic-above-suggested"}} + {{plugin-outlet name="topic-above-suggested" args=(hash model=model)}} {{#if model.details.suggested_topics.length}}
    @@ -225,8 +273,6 @@ {{share-popup topic=model replyAsNewTopic="replyAsNewTopic"}} {{#if currentUser.enable_quoting}} - {{quote-button quoteState=quoteState - selectText="selectText" - deselectText="deselectText"}} + {{quote-button quoteState=quoteState selectText=(action "selectText")}} {{/if}} {{/discourse-topic}} diff --git a/app/assets/javascripts/discourse/templates/user-selector-autocomplete.raw.hbs b/app/assets/javascripts/discourse/templates/user-selector-autocomplete.raw.hbs index 28d76c43ccb..02a8b005dd5 100644 --- a/app/assets/javascripts/discourse/templates/user-selector-autocomplete.raw.hbs +++ b/app/assets/javascripts/discourse/templates/user-selector-autocomplete.raw.hbs @@ -2,7 +2,7 @@
    @@ -153,7 +156,7 @@ {{d-button action="adminDelete" icon="exclamation-triangle" label="user.admin_delete" class="btn-danger"}} {{/if}} - {{plugin-outlet "user-profile-secondary"}} + {{plugin-outlet name="user-profile-secondary" args=(hash model=model)}} {{/unless}} diff --git a/app/assets/javascripts/discourse/templates/user/activity.hbs b/app/assets/javascripts/discourse/templates/user/activity.hbs index f1818f2ec9a..b0fa84ba144 100644 --- a/app/assets/javascripts/discourse/templates/user/activity.hbs +++ b/app/assets/javascripts/discourse/templates/user/activity.hbs @@ -23,7 +23,9 @@ {{/link-to}} {{/if}} - {{plugin-outlet "user-activity-bottom" tagName='li'}} + {{plugin-outlet name="user-activity-bottom" + connectorTagName='li' + args=(hash model=model)}} {{/mobile-nav}} {{#if viewingSelf}} diff --git a/app/assets/javascripts/discourse/templates/user/summary.hbs b/app/assets/javascripts/discourse/templates/user/summary.hbs index e36928a986a..5dfd55a16a2 100644 --- a/app/assets/javascripts/discourse/templates/user/summary.hbs +++ b/app/assets/javascripts/discourse/templates/user/summary.hbs @@ -37,7 +37,9 @@
  • {{user-stat value=model.likes_received label="user.summary.likes_received"}}
  • - {{plugin-outlet "user-summary-stat" tagName="li"}} + {{plugin-outlet name="user-summary-stat" + connectorTagName="li" + args=(hash model=model)}} @@ -104,7 +106,7 @@ {{shorten-url link.url}} diff --git a/app/assets/javascripts/discourse/views/modal-body.js.es6 b/app/assets/javascripts/discourse/views/modal-body.js.es6 deleted file mode 100644 index e7e1f865baa..00000000000 --- a/app/assets/javascripts/discourse/views/modal-body.js.es6 +++ /dev/null @@ -1,40 +0,0 @@ -import deprecated from 'discourse-common/lib/deprecated'; - -export default Ember.View.extend({ - focusInput: true, - - didInsertElement() { - this._super(); - - deprecated('ModalBodyView is deprecated. Use the `d-modal-body` component instead'); - - $('#modal-alert').hide(); - $('#discourse-modal').modal('show'); - Ember.run.scheduleOnce('afterRender', this, this._afterFirstRender); - - this.appEvents.on('modal-body:flash', msg => this._flash(msg)); - }, - - willDestroyElement() { - this._super(); - this.appEvents.off('modal-body:flash'); - }, - - _afterFirstRender() { - if (!this.site.mobileView && this.get('focusInput')) { - this.$('input:first').focus(); - } - - const title = this.get('title'); - if (title) { - this.set('controller.modal.title', title); - } - }, - - _flash(msg) { - $('#modal-alert').hide() - .removeClass('alert-error', 'alert-success') - .addClass(`alert alert-${msg.messageClass || 'success'}`).html(msg.text || '') - .fadeIn(); - } -}); diff --git a/app/assets/javascripts/discourse/widgets/avatar-flair.js.es6 b/app/assets/javascripts/discourse/widgets/avatar-flair.js.es6 index 265d6a69b55..1c489367c2f 100644 --- a/app/assets/javascripts/discourse/widgets/avatar-flair.js.es6 +++ b/app/assets/javascripts/discourse/widgets/avatar-flair.js.es6 @@ -13,7 +13,13 @@ createWidget('avatar-flair', { }, buildClasses(attrs) { - return 'avatar-flair-' + attrs.primary_group_name + (attrs.primary_group_flair_bg_color ? ' rounded' : ''); + let defaultClass = `avatar-flair-${attrs.primary_group_name} ${(attrs.primary_group_flair_bg_color ? 'rounded' : '')}`; + + if (!this.isIcon(attrs)) { + defaultClass += ' avatar-flair-image'; + } + + return defaultClass; }, buildAttributes(attrs) { @@ -32,7 +38,10 @@ createWidget('avatar-flair', { html(attrs) { if (this.isIcon(attrs)) { - return [h('i', { className: 'fa ' + attrs.primary_group_flair_url })]; + return [h('i', { + className: 'fa ' + attrs.primary_group_flair_url, + attributes: { style: attrs.primary_group_flair_color ? 'color: #' + Handlebars.Utils.escapeExpression(attrs.primary_group_flair_color) + '; ' : '' } + })]; } else { return []; } diff --git a/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6 b/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6 index d670a89c6fa..7bd5d30dd75 100644 --- a/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6 +++ b/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6 @@ -103,6 +103,10 @@ export default createWidget('hamburger-menu', { links.push({ route: 'users', className: 'user-directory-link', label: 'directory.title' }); } + if (this.siteSettings.enable_group_directory) { + links.push({ route: 'groups', className: 'groups-link', label: 'groups.index.title' }); + } + if (this.siteSettings.tagging_enabled) { links.push({ route: 'tags', label: 'tagging.tags' }); } diff --git a/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 b/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 index a3d5ad585d7..20045a93718 100644 --- a/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 +++ b/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 @@ -53,9 +53,12 @@ export default createWidget('header-topic-info', { } } if (this.siteSettings.topic_featured_link_enabled) { - extra.push(topicFeaturedLinkNode(attrs.topic)); + const featured = topicFeaturedLinkNode(attrs.topic); + if (featured) { + extra.push(featured); + } } - if (extra) { + if (extra.length) { title.push(h('div.topic-header-extra', extra)); } } diff --git a/app/assets/javascripts/discourse/widgets/header.js.es6 b/app/assets/javascripts/discourse/widgets/header.js.es6 index 03fe6a6901e..8dbb00349ab 100644 --- a/app/assets/javascripts/discourse/widgets/header.js.es6 +++ b/app/assets/javascripts/discourse/widgets/header.js.es6 @@ -104,6 +104,8 @@ createWidget('header-icons', { }, html(attrs) { + if (this.siteSettings.login_required && !this.currentUser) { return []; } + const hamburger = this.attach('header-dropdown', { title: 'hamburger_menu', icon: 'bars', @@ -112,12 +114,9 @@ createWidget('header-icons', { action: 'toggleHamburger', contents() { if (!attrs.flagCount) { return; } - return this.attach('link', { - href: Discourse.getURL('/admin/flags/active'), - title: 'notifications.total_flagged', - rawLabel: attrs.flagCount, - className: 'badge-notification flagged-posts' - }); + return h('div.badge-notification.flagged-posts', { attributes: { + title: I18n.t('notifications.total_flagged') + } }, attrs.flagCount); } }); @@ -223,8 +222,8 @@ export default createWidget('header', { this.state.searchVisible = false; }, - linkClickedEvent() { - this.closeAll(); + linkClickedEvent(attrs) { + if (!(attrs && attrs.searchContextEnabled)) this.closeAll(); this.updateHighlight(); }, diff --git a/app/assets/javascripts/discourse/widgets/home-logo.js.es6 b/app/assets/javascripts/discourse/widgets/home-logo.js.es6 index a609944b59d..ad4c59b26a0 100644 --- a/app/assets/javascripts/discourse/widgets/home-logo.js.es6 +++ b/app/assets/javascripts/discourse/widgets/home-logo.js.es6 @@ -8,7 +8,7 @@ export default createWidget('home-logo', { tagName: 'div.title', settings: { - href: '/' + href: Discourse.getURL("/") }, href() { diff --git a/app/assets/javascripts/discourse/widgets/hooks.js.es6 b/app/assets/javascripts/discourse/widgets/hooks.js.es6 index d863d46e81a..45d8f8bf4bf 100644 --- a/app/assets/javascripts/discourse/widgets/hooks.js.es6 +++ b/app/assets/javascripts/discourse/widgets/hooks.js.es6 @@ -56,12 +56,12 @@ let _dragging; const DRAG_NAME = "mousemove.discourse-widget-drag"; const DRAG_NAME_TOUCH = "touchmove.discourse-widget-drag"; -function cancelDrag() { +function cancelDrag(e) { $('body').removeClass('widget-dragging'); $(document).off(DRAG_NAME).off(DRAG_NAME_TOUCH); if (_dragging) { - if (_dragging.dragEnd) { _dragging.dragEnd(); } + if (_dragging.dragEnd) { _dragging.dragEnd(e); } _dragging = null; } } @@ -70,7 +70,7 @@ WidgetClickHook.setupDocumentCallback = function() { if (_watchingDocument) { return; } $(document).on('mousedown.discource-widget-drag, touchstart.discourse-widget-drag', e => { - cancelDrag(); + cancelDrag(e); const widget = findWidget(e.target, DRAG_ATTRIBUTE_NAME); if (widget) { e.preventDefault(); @@ -87,7 +87,7 @@ WidgetClickHook.setupDocumentCallback = function() { } }); - $(document).on('mouseup.discourse-widget-drag, touchend.discourse-widget-drag', () => cancelDrag()); + $(document).on('mouseup.discourse-widget-drag, touchend.discourse-widget-drag', e => cancelDrag(e)); $(document).on('click.discourse-widget', e => { nodeCallback(e.target, CLICK_ATTRIBUTE_NAME, w => w.click(e)); diff --git a/app/assets/javascripts/discourse/widgets/link.js.es6 b/app/assets/javascripts/discourse/widgets/link.js.es6 index 9ba519fff4d..429403268de 100644 --- a/app/assets/javascripts/discourse/widgets/link.js.es6 +++ b/app/assets/javascripts/discourse/widgets/link.js.es6 @@ -79,7 +79,7 @@ export default createWidget('link', { e.preventDefault(); return this.sendWidgetAction(this.attrs.action, this.attrs.actionParam); } else { - this.sendWidgetEvent('linkClicked'); + this.sendWidgetEvent('linkClicked', this.attrs); } return DiscourseURL.routeToTag($(e.target).closest('a')[0]); diff --git a/app/assets/javascripts/discourse/widgets/post-edits-indicator.js.es6 b/app/assets/javascripts/discourse/widgets/post-edits-indicator.js.es6 index 9eac352d6ba..531e4396850 100644 --- a/app/assets/javascripts/discourse/widgets/post-edits-indicator.js.es6 +++ b/app/assets/javascripts/discourse/widgets/post-edits-indicator.js.es6 @@ -22,18 +22,41 @@ export default createWidget('post-edits-indicator', { }, html(attrs) { - const contents = [attrs.version - 1, ' ', iconNode('pencil')]; + let icon = 'pencil'; const updatedAt = new Date(attrs.updated_at); + let className = this.historyHeat(updatedAt); + const date = longDate(updatedAt); + let title; + + if (attrs.wiki) { + icon = 'pencil-square-o'; + className = `${className} wiki`; + + if (attrs.version > 1) { + title = `${I18n.t('post.last_edited_on')} ${date}`; + } else { + title = I18n.t('post.wiki.about'); + } + } else { + title = `${I18n.t('post.last_edited_on')} ${date}`; + } + + const contents = [ + attrs.version > 1 ? attrs.version - 1 : '', + ' ', + iconNode(icon) + ]; - const title = `${I18n.t('post.last_edited_on')} ${longDate(updatedAt)}`; return h('a', { - className: this.historyHeat(updatedAt), + className, attributes: { title } }, contents); }, click() { - if (this.attrs.canViewEditHistory) { + if (this.attrs.wiki && this.attrs.version === 1) { + this.sendWidgetAction('editPost'); + } else if (this.attrs.canViewEditHistory) { this.sendWidgetAction('showHistory'); } } diff --git a/app/assets/javascripts/discourse/widgets/post.js.es6 b/app/assets/javascripts/discourse/widgets/post.js.es6 index 7e9fd93496c..5309768e58b 100644 --- a/app/assets/javascripts/discourse/widgets/post.js.es6 +++ b/app/assets/javascripts/discourse/widgets/post.js.es6 @@ -110,20 +110,6 @@ createWidget('post-avatar', { } }); - -createWidget('wiki-edit-button', { - tagName: 'div.post-info.wiki', - title: 'post.wiki.about', - - html() { - return iconNode('pencil-square-o'); - }, - - click() { - this.sendWidgetAction('editPost'); - } -}); - createWidget('post-email-indicator', { tagName: 'div.post-info.via-email', @@ -181,14 +167,10 @@ createWidget('post-meta-data', { result.push(this.attach('post-email-indicator', attrs)); } - if (attrs.version > 1) { + if (attrs.version > 1 || attrs.wiki) { result.push(this.attach('post-edits-indicator', attrs)); } - if (attrs.wiki) { - result.push(this.attach('wiki-edit-button', attrs)); - } - if (attrs.multiSelect) { result.push(this.attach('select-post', attrs)); } diff --git a/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6 b/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6 index 2eddf7f87f3..56ac661370b 100644 --- a/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6 +++ b/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6 @@ -25,7 +25,8 @@ function createSearchResult(type, linkField, fn) { return h('li', this.attach('link', { href: r.get(linkField), contents: () => fn.call(this, r, attrs.term), - className: 'search-link' + className: 'search-link', + searchContextEnabled: this.attrs.searchContextEnabled })); }); } @@ -98,7 +99,11 @@ createWidget('search-menu-results', { } return [ - h('ul', this.attach(rt.componentName, { results: rt.results, term: attrs.term })), + h('ul', this.attach(rt.componentName, { + searchContextEnabled: this.attrs.searchContextEnabled, + results: rt.results, + term: attrs.term + })), h('div.no-results', more) ]; }); diff --git a/app/assets/javascripts/discourse/widgets/search-menu.js.es6 b/app/assets/javascripts/discourse/widgets/search-menu.js.es6 index f8d626f4568..c50a314e451 100644 --- a/app/assets/javascripts/discourse/widgets/search-menu.js.es6 +++ b/app/assets/javascripts/discourse/widgets/search-menu.js.es6 @@ -125,7 +125,8 @@ export default createWidget('search-menu', { results.push(this.attach('search-menu-results', { term: searchData.term, noResults: searchData.noResults, results: searchData.results, - invalidTerm: searchData.invalidTerm })); + invalidTerm: searchData.invalidTerm, + searchContextEnabled: searchData.contextEnabled })); } } @@ -191,6 +192,8 @@ export default createWidget('search-menu', { if (url) { this.sendWidgetEvent('linkClicked'); DiscourseURL.routeTo(url); + } else if (searchData.contextEnabled) { + this.triggerSearch(); } } }); diff --git a/app/assets/javascripts/discourse/widgets/topic-map.js.es6 b/app/assets/javascripts/discourse/widgets/topic-map.js.es6 index 675e8b9d3a3..7d4c89c0b39 100644 --- a/app/assets/javascripts/discourse/widgets/topic-map.js.es6 +++ b/app/assets/javascripts/discourse/widgets/topic-map.js.es6 @@ -11,7 +11,7 @@ function renderParticipants(userFilters, participants) { userFilters = userFilters || []; return participants.map(p => { - return this.attach('topic-participant', p, { state: { toggled: userFilters.contains(p.username) } }); + return this.attach('topic-participant', p, { state: { toggled: userFilters.includes(p.username) } }); }); } @@ -27,6 +27,10 @@ createWidget('topic-map-show-links', { }); createWidget('topic-participant', { + buildClasses(attrs) { + if (attrs.primary_group_name) { return `group-${attrs.primary_group_name}`; } + }, + html(attrs, state) { const linkContents = [avatarImg('medium', { username: attrs.username, template: attrs.avatar_template })]; @@ -34,6 +38,10 @@ createWidget('topic-participant', { linkContents.push(h('span.post-count', attrs.post_count.toString())); } + if (attrs.primary_group_flair_url || attrs.primary_group_flair_bg_color) { + linkContents.push(this.attach('avatar-flair', attrs)); + } + return h('a.poster.trigger-user-card', { className: state.toggled ? 'toggled' : null, attributes: { title: attrs.username, 'data-user-card': attrs.username } @@ -116,7 +124,14 @@ createWidget('topic-map-link', { }, html(attrs) { - return attrs.title ? replaceEmoji(attrs.title) : attrs.url; + let content = attrs.title || attrs.url; + const truncateLength = 85; + + if (content.length > truncateLength) { + content = `${content.substr(0, truncateLength).trim()}...`; + } + + return attrs.title ? replaceEmoji(content) : content; } }); diff --git a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 index da4bc1be528..ca925d343db 100644 --- a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 +++ b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 @@ -7,33 +7,39 @@ import RawHtml from 'discourse/widgets/raw-html'; const SCROLLAREA_HEIGHT = 300; const SCROLLER_HEIGHT = 50; const SCROLLAREA_REMAINING = SCROLLAREA_HEIGHT - SCROLLER_HEIGHT; +const LAST_READ_HEIGHT = 20; function clamp(p, min=0.0, max=1.0) { return Math.max(Math.min(p, max), min); } +function attachBackButton(widget) { + return widget.attach('button', { + className: 'btn btn-primary btn-small back-button', + label: 'topic.timeline.back', + title: 'topic.timeline.back_description', + action: 'goBack' + }); +} + createWidget('timeline-last-read', { tagName: 'div.timeline-last-read', buildAttributes(attrs) { - return { style: `height: 40px; top: ${attrs.top}px` }; + const bottom = SCROLLAREA_HEIGHT - (LAST_READ_HEIGHT / 2); + const top = attrs.top > bottom ? bottom : attrs.top; + return { style: `height: ${LAST_READ_HEIGHT}px; top: ${top}px` }; }, - html() { - return [ - iconNode('circle', { class: 'progress' }), - this.attach('button', { - className: 'btn btn-primary btn-small', - label: 'topic.timeline.back', - title: 'topic.timeline.back_description', - action: 'goBack' - }) - ]; + html(attrs) { + const result = [ iconNode('minus', { class: 'progress' }) ]; + if (attrs.showButton) { + result.push(attachBackButton(this)); + } + + return result; }, - goBack() { - this.sendWidgetAction('jumpToPost', this.attrs.lastRead); - } }); function timelineDate(date) { @@ -43,12 +49,17 @@ function timelineDate(date) { createWidget('timeline-scroller', { tagName: 'div.timeline-scroller', + buildKey: () => `timeline-scroller`, + + defaultState() { + return { dragging: false }; + }, buildAttributes() { return { style: `height: ${SCROLLER_HEIGHT}px` }; }, - html(attrs) { + html(attrs, state) { const { current, total, date } = attrs; const contents = [ @@ -59,6 +70,9 @@ createWidget('timeline-scroller', { contents.push(h('div.timeline-ago', timelineDate(date))); } + if (attrs.showDockedButton && !state.dragging) { + contents.push(attachBackButton(this)); + } let result = [ h('div.timeline-handle'), h('div.timeline-scroller-content', contents) ]; if (attrs.fullScreen) { @@ -69,11 +83,17 @@ createWidget('timeline-scroller', { }, drag(e) { + this.state.dragging = true; this.sendWidgetAction('updatePercentage', e.pageY); }, - dragEnd() { - this.sendWidgetAction('commit'); + dragEnd(e) { + this.state.dragging = false; + if ($(e.target).is('button')) { + this.sendWidgetAction('goBack'); + } else { + this.sendWidgetAction('commit'); + } } }); @@ -151,17 +171,41 @@ createWidget('timeline-scrollarea', { const before = SCROLLAREA_REMAINING * percentage; const after = (SCROLLAREA_HEIGHT - before) - SCROLLER_HEIGHT; + let showButton = false; + const hasBackPosition = + position.lastRead > 3 && + Math.abs(position.lastRead - position.current) > 3 && + Math.abs(position.lastRead - position.total) > 1 && + (position.lastRead && position.lastRead !== position.total); + + if (hasBackPosition) { + const lastReadTop = Math.round(position.lastReadPercentage * SCROLLAREA_HEIGHT); + showButton = ((before + SCROLLER_HEIGHT - 5) < lastReadTop) || + (before > (lastReadTop + 25)); + + + // Don't show if at the bottom of the timeline + if (lastReadTop > (SCROLLAREA_HEIGHT - (LAST_READ_HEIGHT / 2))) { + showButton = false; + } + } + const result = [ this.attach('timeline-padding', { height: before }), - this.attach('timeline-scroller', _.merge(position, {fullScreen: attrs.fullScreen})), + this.attach('timeline-scroller', _.merge(position, { + showDockedButton: !attrs.mobileView && hasBackPosition && !showButton, + fullScreen: attrs.fullScreen + })), this.attach('timeline-padding', { height: after }) ]; - if (position.lastRead && position.lastRead !== position.total) { + if (hasBackPosition) { const lastReadTop = Math.round(position.lastReadPercentage * SCROLLAREA_HEIGHT); - if ((lastReadTop > (before + SCROLLER_HEIGHT)) && (lastReadTop < (SCROLLAREA_HEIGHT - SCROLLER_HEIGHT))) { - result.push(this.attach('timeline-last-read', { top: lastReadTop, lastRead: position.lastRead })); - } + result.push(this.attach('timeline-last-read', { + top: lastReadTop, + lastRead: position.lastRead, + showButton + })); } return result; @@ -190,6 +234,10 @@ createWidget('timeline-scrollarea', { _percentFor(topic, postIndex) { const total = topic.get('postStream.filteredPostsCount'); return clamp(parseFloat(postIndex - 1.0) / total); + }, + + goBack() { + this.sendWidgetAction('jumpToIndex', this.position().lastRead); } }); diff --git a/app/assets/javascripts/discourse/widgets/widget.js.es6 b/app/assets/javascripts/discourse/widgets/widget.js.es6 index 8cf85e2555f..0b3e169a46f 100644 --- a/app/assets/javascripts/discourse/widgets/widget.js.es6 +++ b/app/assets/javascripts/discourse/widgets/widget.js.es6 @@ -256,31 +256,24 @@ export default class Widget { } _sendComponentAction(name, param) { - const view = this._findAncestorWithProperty('_emberView'); - let promise; - if (view) { - // Peek into ember internals to allow us to return promises from actions - const ev = view._emberView; - const target = ev.get('targetObject'); - const actionName = ev.get(name); - if (!actionName) { - Ember.warn(`${name} not found`); + const view = this._findView(); + if (view) { + const method = view.get(name); + if (!method) { + console.warn(`${name} not found`); return; } - if (target) { - // TODO: Use ember closure actions - const actions = target.actions || target.actionHooks || {}; - const method = actions[actionName]; - if (method) { - promise = method.call(target, param); - if (!promise || !promise.then) { - promise = Ember.RSVP.resolve(promise); - } - } else { - return ev.sendAction(name, param); + if (typeof method === "string") { + view.sendAction(method, param); + promise = Ember.RSVP.resolve(); + } else { + const target = view.get('targetObject'); + promise = method.call(target, param); + if (!promise || !promise.then) { + promise = Ember.RSVP.resolve(promise); } } } @@ -305,12 +298,12 @@ export default class Widget { return result; } - sendWidgetEvent(name) { + sendWidgetEvent(name, attrs) { const methodName = `${name}Event`; return this.rerenderResult(() => { const widget = this._findAncestorWithProperty(methodName); if (widget) { - return widget[methodName](); + return widget[methodName](attrs); } }); } diff --git a/app/assets/javascripts/env.js b/app/assets/javascripts/env.js index 12deda108c5..f561c7fad78 100644 --- a/app/assets/javascripts/env.js +++ b/app/assets/javascripts/env.js @@ -1,4 +1,3 @@ window.ENV = { }; window.EmberENV = window.EmberENV || {}; window.EmberENV.FORCE_JQUERY = true; -window.EmberENV._ENABLE_LEGACY_VIEW_SUPPORT = true; diff --git a/app/assets/javascripts/locales/ar.js.erb b/app/assets/javascripts/locales/ar.js.erb index b607af2c59e..9755d378a0a 100644 --- a/app/assets/javascripts/locales/ar.js.erb +++ b/app/assets/javascripts/locales/ar.js.erb @@ -7,6 +7,6 @@ I18n.pluralizationRules['ar'] = function (n) { if (n == 1) return "one"; if (n == 2) return "two"; if (n%100 >= 3 && n%100 <= 10) return "few"; - if (n%100 >= 11) return "many"; + if (n%100 >= 11 && n%100 <= 99) return "many"; return "other"; }; diff --git a/app/assets/javascripts/locales/uk.js.erb b/app/assets/javascripts/locales/uk.js.erb index 3978d25c15b..c6aeb8a7ec5 100644 --- a/app/assets/javascripts/locales/uk.js.erb +++ b/app/assets/javascripts/locales/uk.js.erb @@ -6,5 +6,5 @@ I18n.pluralizationRules['uk'] = function (n) { if (n == 0) return ["zero", "none", "other"]; if (n % 10 == 1 && n % 100 != 11) return "one"; if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)) return "few"; - return "many"; + return "other"; // TODO: should be "many" but is not defined in translations }; diff --git a/app/assets/javascripts/pretty-text/emoji.js.es6 b/app/assets/javascripts/pretty-text/emoji.js.es6 index 67f047dc01d..3df9040a240 100644 --- a/app/assets/javascripts/pretty-text/emoji.js.es6 +++ b/app/assets/javascripts/pretty-text/emoji.js.es6 @@ -38,7 +38,7 @@ export function performEmojiUnescape(string, opts) { const classes = isCustomEmoji(emojiVal, opts) ? "emoji emoji-custom" : "emoji"; return url && (isEmoticon || hasEndingColon) ? - `${emojiVal}` : m; + `${emojiVal}` : m; }); } diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown/quote.js.es6 b/app/assets/javascripts/pretty-text/engines/discourse-markdown/quote.js.es6 index 4172a2a46f2..96b798a3269 100644 --- a/app/assets/javascripts/pretty-text/engines/discourse-markdown/quote.js.es6 +++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown/quote.js.es6 @@ -1,9 +1,18 @@ import { register } from 'pretty-text/engines/discourse-markdown/bbcode'; +import { registerOption } from 'pretty-text/pretty-text'; +import { performEmojiUnescape } from 'pretty-text/emoji'; + +registerOption((siteSettings, opts) => { + opts.enableEmoji = siteSettings.enable_emoji; + opts.emojiSet = siteSettings.emoji_set; +}); + export function setup(helper) { register(helper, 'quote', {noWrap: true, singlePara: true}, (contents, bbParams, options) => { const params = {'class': 'quote'}; let username = null; + const opts = helper.getOptions(); if (bbParams) { const paramsSplit = bbParams.split(/\,\s*/); @@ -52,7 +61,16 @@ export function setup(helper) { if (postNumber > 0) { href += "/" + postNumber; } // get rid of username said stuff header.pop(); - header.push(['a', {'href': href}, topicInfo.title]); + + let title = topicInfo.title; + + if (opts.enableEmoji) { + title = performEmojiUnescape(topicInfo.title, { + getURL: opts.getURL, emojiSet: opts.emojiSet + }); + } + + header.push(['a', {'href': href}, title]); } } diff --git a/app/assets/javascripts/pretty-text/oneboxer.js.es6 b/app/assets/javascripts/pretty-text/oneboxer.js.es6 index 90be7612c0e..b56cff9d5a8 100644 --- a/app/assets/javascripts/pretty-text/oneboxer.js.es6 +++ b/app/assets/javascripts/pretty-text/oneboxer.js.es6 @@ -1,9 +1,46 @@ +let timeout; +const loadingQueue = []; const localCache = {}; const failedCache = {}; -// Perform a lookup of a onebox based an anchor element. +function loadNext(ajax) { + if (loadingQueue.length === 0) { + timeout = null; + return; + } + + let timeoutMs = 150; + let removeLoading = true; + const { url, refresh, $elem, userId } = loadingQueue.shift(); + + // Retrieve the onebox + return ajax("/onebox", { + dataType: 'html', + data: { url, refresh, user_id: userId }, + cache: true + }).then(html => { + localCache[url] = html; + $elem.replaceWith(html); + }, result => { + if (result && result.jqXHR && result.jqXHR.status === 429) { + timeoutMs = 2000; + removeLoading = false; + loadingQueue.unshift({ url, refresh, $elem, userId }); + } else { + failedCache[url] = true; + } + }).finally(() => { + timeout = Ember.run.later(() => loadNext(ajax), timeoutMs); + if (removeLoading) { + $elem.removeClass('loading-onebox'); + $elem.data('onebox-loaded'); + } + }); +} + +// Perform a lookup of a onebox based an anchor $element. // It will insert a loading indicator and remove it when the loading is complete or fails. -export function load(e, refresh, ajax) { +export function load(e, refresh, ajax, userId, synchronous) { const $elem = $(e); // If the onebox has loaded or is loading, return @@ -26,20 +63,15 @@ export function load(e, refresh, ajax) { // Add the loading CSS class $elem.addClass('loading-onebox'); - // Retrieve the onebox - return ajax("/onebox", { - dataType: 'html', - data: { url, refresh }, - cache: true - }).then(html => { - localCache[url] = html; - $elem.replaceWith(html); - }, () => { - failedCache[url] = true; - }).finally(() => { - $elem.removeClass('loading-onebox'); - $elem.data('onebox-loaded'); - }); + // Add to the loading queue + loadingQueue.push({ url, refresh, $elem, userId }); + + // Load next url in queue + if (synchronous) { + return loadNext(ajax); + } else { + timeout = timeout || Ember.run.later(() => loadNext(ajax), 150); + } } export function lookupCache(url) { diff --git a/app/assets/stylesheets/common/base/combobox.scss b/app/assets/stylesheets/common/base/combobox.scss index f0def437254..cd9f44b52ca 100644 --- a/app/assets/stylesheets/common/base/combobox.scss +++ b/app/assets/stylesheets/common/base/combobox.scss @@ -37,6 +37,8 @@ .select2-container { border-radius: 3px; border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + min-width: 200px; + &.select2-dropdown-open { border: 0; margin-bottom: 2px; diff --git a/app/assets/stylesheets/common/base/compose.scss b/app/assets/stylesheets/common/base/compose.scss index 4e53da0fc26..b47d4c385aa 100644 --- a/app/assets/stylesheets/common/base/compose.scss +++ b/app/assets/stylesheets/common/base/compose.scss @@ -8,26 +8,27 @@ list-style: none; padding: 0; margin: 0; + li { .fa-users { color: lighten($primary, 40%); padding: 0 2px; } + border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); - a[href] { + + a { padding: 5px; display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + span.username { color: darken($primary, 40%); - display: inline-block; } span.name { font-size: 11px; - display: inline-block; - width: 90px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; vertical-align: middle; } &.selected { diff --git a/app/assets/stylesheets/common/base/discourse.scss b/app/assets/stylesheets/common/base/discourse.scss index 5bde52ae8ec..58cd75db007 100644 --- a/app/assets/stylesheets/common/base/discourse.scss +++ b/app/assets/stylesheets/common/base/discourse.scss @@ -80,15 +80,6 @@ body { .coldmap-low { color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)) !important; } - .heatmap-high { - color: #fe7a15 !important; - } - .heatmap-med { - color: #cf7721 !important; - } - .heatmap-low { - color: #9b764f !important; - } #loading-message { position: absolute; @@ -339,3 +330,12 @@ body { span.relative-date { white-space:nowrap; } + +@keyframes background-fade-highlight { + 0% { + background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + } + 100% { + background-color: transparent; + } +} diff --git a/app/assets/stylesheets/common/base/group.scss b/app/assets/stylesheets/common/base/group.scss index 146c5039ad2..5287a777c3b 100644 --- a/app/assets/stylesheets/common/base/group.scss +++ b/app/assets/stylesheets/common/base/group.scss @@ -1,18 +1,42 @@ -.group-header { - font-size: 2.142em; - font-weight: normal; -} - -.group-name { - font-weight: normal; - margin-top: 5px; - color: dark-light-diff($primary, $secondary, 50%, -50%); -} - .group-details-container { background: rgba(230, 230, 230, 0.3); padding: 20px; - margin-bottom: 30px; + margin-bottom: 15px; +} + +.group-info { + width: 100%; + + .group-info-name { + font-size: 1.4em; + font-weight: bold; + color: $primary; + } + + .group-info-full-name { + font-size: 1.2em; + color: dark-light-choose(scale-color($primary, $lightness: 30%), scale-color($secondary, $lightness: 70%)); + } + + span { + display: inline-block; + vertical-align: middle; + } + + $size: 50px; + + .avatar-flair-image { + width: $size; + } + + .avatar-flair { + background-size: $size; + height: $size; + + i { + font-size: $size !important; + } + } } .group-logs-filter { @@ -23,10 +47,6 @@ } } -.group-index-request, .group-index-join, .group-index-leave { - float: right; -} - table.group-logs { width: 100%; @@ -56,30 +76,35 @@ table.group-members { width: 100%; table-layout: fixed; - th, tr { + tr { border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); } th:first-child { width: 60%; + text-align: left; } - th:last-child { + th.group-members-actions { width: 5%; } th { - text-align: left; - padding: 5px 0px; + border-bottom: 3px solid dark-light-diff($primary, $secondary, 90%, -60%); + text-align: center; + padding: 5px 0px 5px 5px; + color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); + font-weight: normal; + } + th.sortable { i { margin-left: 5px; } &:hover { - color: $tertiary; cursor: pointer; - text-decoration: underline; + background-color: dark-light-diff($primary, $secondary, 90%, -75%); } } @@ -88,7 +113,12 @@ table.group-members { display: block; } + td:first-child { + text-align: left; + } + td { + text-align: center; color: dark-light-diff($primary, $secondary, 50%, -50%); padding: 0.8em 0; } @@ -99,37 +129,9 @@ table.group-members { color: $primary; } -.group-details { - width: 100%; -} - -.group-details { - span { - display: inline-block; - vertical-align: middle; - } - - .avatar-flair { - $size: 50px; - - background-size: $size; - height: $size; - width: $size; - - i { - font-size: $size !important; - } - } -} - -.group-edit { - float: right; -} - .form-horizontal { .group-flair-inputs { display: inline-block; - margin: 15px 0px; input[type="text"] { width: 80% !important; @@ -156,13 +158,11 @@ table.group-members { } } -.groups.edit-group .form-horizontal { - textarea { - width: 99%; - } - - label { - font-weight: bold; +.group-edit { + .form-horizontal { + label { + font-weight: bold; + } } } diff --git a/app/assets/stylesheets/common/base/groups.scss b/app/assets/stylesheets/common/base/groups.scss new file mode 100644 index 00000000000..f40697b01c2 --- /dev/null +++ b/app/assets/stylesheets/common/base/groups.scss @@ -0,0 +1,65 @@ +.groups-page { + h1 { + margin: 20px 0px; + } +} + +.groups-table { + width: 100%; + + th { + border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + padding: 5px 0px; + text-align: left; + } + + tr { + border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + + td { + color: dark-light-diff($primary, $secondary, 50%, -50%); + padding: 0.8em 0; + } + + td.groups-user-count { + font-size: 1.2em; + } + } + + .groups-info { + .groups-info-name { + font-weight: bold; + color: $primary; + color: dark-light-choose(scale-color($primary, $lightness: 30%), scale-color($secondary, $lightness: 70%)); + } + + .groups-info-full-name { + color: dark-light-choose(scale-color($primary, $lightness: 30%), scale-color($secondary, $lightness: 70%)); + } + + .groups-info-title { + font-size: 0.9em; + color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); + } + + span { + display: inline-block; + vertical-align: middle; + } + + $size: 40px; + + .avatar-flair { + background-size: $size; + height: $size; + + i { + font-size: $size !important; + } + } + + .avatar-flair-image { + width: $size; + } + } +} diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index 958de096433..09b81cea1b5 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -11,6 +11,15 @@ } +.input-hint-text { + margin-left: 0.5em; + color: dark-light-diff($secondary, $primary, 30%, -35%); +} + +.modal-header { + border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); +} + .modal-backdrop { position: fixed; top: 0; diff --git a/app/assets/stylesheets/common/base/onebox.scss b/app/assets/stylesheets/common/base/onebox.scss index 5b61f3cc38e..9ad0c248a8d 100644 --- a/app/assets/stylesheets/common/base/onebox.scss +++ b/app/assets/stylesheets/common/base/onebox.scss @@ -95,8 +95,9 @@ aside.onebox { font-size: 1em; header { + margin-bottom: 8px; a[href] { - color: $primary; + color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); text-decoration: none; } } @@ -118,7 +119,7 @@ aside.onebox { h3, h4 { font-size: 1.17em; - margin: 10px 0; + margin: 0 0 10px 0; } a[href] { @@ -131,7 +132,7 @@ aside.onebox { } img { - max-height: 80%; + max-height: 170px; max-width: 20%; height: auto; float: left; diff --git a/app/assets/stylesheets/common/base/tagging.scss b/app/assets/stylesheets/common/base/tagging.scss index 2a32c29d3b0..aa13934ae54 100644 --- a/app/assets/stylesheets/common/base/tagging.scss +++ b/app/assets/stylesheets/common/base/tagging.scss @@ -32,6 +32,23 @@ animation: fadein .7s; } +.bullet + .topic-header-extra { + display: block; + line-height: 15px; + font-size: 12px; + .list-tags { font-size: 12px; } +} + +.bar + .topic-header-extra { + line-height: 1.25; +} + +.box + .topic-header-extra { + display: inline-block; + margin: 0 0 0 5px; + padding-top: 5px; +} + .add-tags .select2 { margin: 0; } diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss index 5cb0d0d54e8..4c82cb4f8e4 100644 --- a/app/assets/stylesheets/common/base/topic-post.scss +++ b/app/assets/stylesheets/common/base/topic-post.scss @@ -141,6 +141,7 @@ aside.quote { color: dark-light-choose($secondary, $primary); padding: 10px; z-index: 401; + opacity: 0.8; &:before { font-family: "FontAwesome"; @@ -157,15 +158,17 @@ aside.quote { position: relative; } -.topic-avatar .avatar-flair, .avatar-flair-preview .avatar-flair, .user-card-avatar .avatar-flair { - display: flex; - align-items: center; - justify-content: center; - background-repeat: no-repeat; - background-position: center; - position: absolute; - bottom: 0; - right: -6px; +.topic-avatar, .avatar-flair-preview, .user-card-avatar, .topic-map .poster { + .avatar-flair { + display: flex; + align-items: center; + justify-content: center; + background-repeat: no-repeat; + background-position: center; + position: absolute; + bottom: 0; + right: -6px; + } } .topic-avatar .avatar-flair, .avatar-flair-preview .avatar-flair { background-size: 20px 20px; @@ -196,6 +199,24 @@ aside.quote { font-size: 24px; } } +.topic-map .poster .avatar-flair { + right: 0; + background-size: 12px 12px; + width: 16px; + height: 16px; + bottom: -3px; + &.rounded { + background-size: 12px 12px; + border-radius: 8px; + width: 16px; + height: 16px; + bottom: -2px; + right: 0; + } + .fa { + font-size: 14px; + } +} .topic-avatar .poster-avatar-extra { display: none; } @@ -208,7 +229,7 @@ aside.quote { overflow: hidden; } &.highlighted { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + animation: background-fade-highlight 2.5s ease-out; } } @@ -219,16 +240,17 @@ aside.quote { } .post-info { - &.wiki, &.via-email, &.whisper { + &.via-email, &.whisper { margin-right: 5px; i.fa { font-size: 1em; } } - &.wiki { - cursor: pointer; - color: #408040; + + .wiki { + color: green !important; } + &.via-email { color: dark-light-choose(scale-color($primary, $lightness: 70%), scale-color($secondary, $lightness: 30%)); } diff --git a/app/assets/stylesheets/common/base/topic.scss b/app/assets/stylesheets/common/base/topic.scss index def557e03e7..196aa05e2e7 100644 --- a/app/assets/stylesheets/common/base/topic.scss +++ b/app/assets/stylesheets/common/base/topic.scss @@ -1,3 +1,26 @@ +@keyframes button-jump-up { + 0% { bottom: 0;} + 50% { bottom: 45px;} + 65% { bottom: 40px;} + 77% { bottom: 43px;} + 100% { bottom: 40px;} +} + +.progress-back-container { + position: fixed; + bottom: 40px; + z-index: 950; + margin-right: 0px; + animation-duration: 0.5s; + animation-name: button-jump-up; + width: 145px; + text-align: center; + + .btn { + margin: 0; + } +} + #topic-title { .title-wrapper { float: left; @@ -8,6 +31,7 @@ .badge-wrapper { float: left; + margin-right: 12px; } a.topic-featured-link { @@ -15,6 +39,10 @@ } } + h1 { + margin: 0 0 4px 0; + } + a.badge-category { margin-top: 5px; } diff --git a/app/assets/stylesheets/common/components/group-members-input.scss b/app/assets/stylesheets/common/components/group-members-input.scss new file mode 100644 index 00000000000..fde660de04a --- /dev/null +++ b/app/assets/stylesheets/common/components/group-members-input.scss @@ -0,0 +1,9 @@ +.group-members-input { + .group-members-input-selector { + margin-top: 10px; + + .add { + margin-top: 7px; + } + } +} diff --git a/app/assets/stylesheets/common/foundation/base.scss b/app/assets/stylesheets/common/foundation/base.scss index b4267e703fe..2a3c5588d02 100644 --- a/app/assets/stylesheets/common/foundation/base.scss +++ b/app/assets/stylesheets/common/foundation/base.scss @@ -85,6 +85,7 @@ fieldset { pre code { overflow: auto; + tab-size: 4; } // TODO figure out a clean place to put stuff like this diff --git a/app/assets/stylesheets/common/topic-timeline.scss b/app/assets/stylesheets/common/topic-timeline.scss index 4ce8a903bf1..8ba1911d70b 100644 --- a/app/assets/stylesheets/common/topic-timeline.scss +++ b/app/assets/stylesheets/common/topic-timeline.scss @@ -49,8 +49,12 @@ left: 0; right: 0; border-top: 1px solid dark-light-choose(scale-color($primary, $lightness: 90%), scale-color($secondary, $lightness: 90%)); + box-shadow: 0px -2px 4px -1px rgba(0,0,0,.25); padding-top: 20px; z-index: 100000; + .back-button { + display: none; + } .topic-timeline { width: 100%; table-layout: fixed; @@ -106,8 +110,7 @@ right: 0px; margin-left: 0; i.progress { - margin-right: -3px; - margin-left: 1em; + display: none } } .timeline-footer-controls { @@ -254,6 +257,10 @@ cursor: ns-resize; display: flex; align-items: center; + + .back-button { + margin-top: 1em; + } } .timeline-replies { @@ -262,19 +269,19 @@ .timeline-last-read { position: absolute; - margin-left: -0.19em; - - .btn-small { - padding: 2px 5px; - } + margin-left: -0.35em; i.progress { - font-size: 0.5em; - color: dark-light-choose(scale-color($tertiary, $lightness: 80%), scale-color($tertiary, $lightness: 20%)); + font-size: 0.8em; + color: $tertiary; margin-right: 1em; } } + .back-button { + padding: 2px 5px; + } + .now-date { @include unselectable; display: inline-block; diff --git a/app/assets/stylesheets/desktop/compose.scss b/app/assets/stylesheets/desktop/compose.scss index 620a31a0220..0f9bfb589b7 100644 --- a/app/assets/stylesheets/desktop/compose.scss +++ b/app/assets/stylesheets/desktop/compose.scss @@ -373,6 +373,20 @@ .reply-to { margin-bottom: 10px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + color: $tertiary; + + @media (min-width: 1101px) { + max-width: 80%; + } + @media (max-width: 1100px) { + max-width: 500px; + } + @media (max-width: 600px) { + max-width: 300px; + } i { color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); diff --git a/app/assets/stylesheets/desktop/group.scss b/app/assets/stylesheets/desktop/group.scss index e368da25fd8..5c913eef7f3 100644 --- a/app/assets/stylesheets/desktop/group.scss +++ b/app/assets/stylesheets/desktop/group.scss @@ -1,12 +1,59 @@ -.group-outlet { - width: 75%; -} - .group-nav { - width: 20%; - margin-right: 30px; + li { + float: left; + + a, i { + color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 40%)); + } + + .active { + a, i { + color: $secondary; + } + } + } + + margin-bottom: 30px; } -.group-details { +.group-info { margin-bottom: 20px; } + +.group-activity-nav { + width: 15%; + background-color: transparent; + + li { + border: none; + + a { + padding: 8px 13px; + } + + a.active { + background-color: transparent; + font-weight: bold; + color: $primary; + } + + a.active:after { + display: none; + } + } +} + +.group-activity-outlet { + width: 85%; +} + +.group-edit { + border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + padding: 10px; + + .form-horizontal { + button { + float: none; + } + } +} diff --git a/app/assets/stylesheets/desktop/history.scss b/app/assets/stylesheets/desktop/history.scss index 5becce0f32d..bc228aa02c9 100644 --- a/app/assets/stylesheets/desktop/history.scss +++ b/app/assets/stylesheets/desktop/history.scss @@ -1,10 +1,7 @@ // styles that apply to the popup that appears when you show the edit history of a post .modal.history-modal { - .btn { - // remove transitions on the buttons in the history modal - transition: none; - } + .modal-inner-container { min-width: 960px; min-height: 500px; @@ -21,6 +18,14 @@ } #display-modes { text-align: right; + .btn { + background-color:inherit; + color: dark-light-diff($primary, $secondary, 50%, -50%); + } + .btn-primary { + color: $primary; + font-weight: bold; + } } #revision-details { padding: 5px; diff --git a/app/assets/stylesheets/desktop/modal.scss b/app/assets/stylesheets/desktop/modal.scss index cf4902e5af7..e35b93fa117 100644 --- a/app/assets/stylesheets/desktop/modal.scss +++ b/app/assets/stylesheets/desktop/modal.scss @@ -47,7 +47,6 @@ } .modal-header { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); h3 { font-size: 1.429em; padding: 10px 15px 7px; diff --git a/app/assets/stylesheets/desktop/topic-list.scss b/app/assets/stylesheets/desktop/topic-list.scss index 0df2a15fe3b..49724880c79 100644 --- a/app/assets/stylesheets/desktop/topic-list.scss +++ b/app/assets/stylesheets/desktop/topic-list.scss @@ -56,7 +56,7 @@ > tbody > tr { &.highlighted { - background-color: dark-light-diff($tertiary, $secondary, 85%, -65%); + animation: background-fade-highlight 2.5s ease-out; } } button.bulk-select { diff --git a/app/assets/stylesheets/desktop/topic-post.scss b/app/assets/stylesheets/desktop/topic-post.scss index 2c0c57e4fd1..219d31569f3 100644 --- a/app/assets/stylesheets/desktop/topic-post.scss +++ b/app/assets/stylesheets/desktop/topic-post.scss @@ -155,10 +155,6 @@ nav.post-controls { box-shadow: none; } - &.wikied { - color: green; - } - &.bookmark {padding: 8px 11px; } .read-icon { @@ -333,7 +329,7 @@ a.star { } .post-count { position: absolute; - right: 3px; + right: 0; border-radius: 100px; padding: 4px 5px 2px 5px; text-align: center; @@ -530,21 +526,6 @@ video { } } -.bullet + .topic-header-extra { - display: block; - line-height: 12px; -} - -.bar + .topic-header-extra { - line-height: 1.25; -} - -.box + .topic-header-extra { - display: inline-block; - margin: 0 0 0 5px; - padding-top: 5px; -} - /* default docked header CSS for all topics, including those without categories */ .extra-info { h1 { diff --git a/app/assets/stylesheets/desktop/topic.scss b/app/assets/stylesheets/desktop/topic.scss index 571649f60a7..85e51b389df 100644 --- a/app/assets/stylesheets/desktop/topic.scss +++ b/app/assets/stylesheets/desktop/topic.scss @@ -38,7 +38,6 @@ } h1 { font-size: 1.8em; - margin: 0; line-height: 1.2em; overflow: hidden; a {color: $primary;} diff --git a/app/assets/stylesheets/desktop/user.scss b/app/assets/stylesheets/desktop/user.scss index 5ec7d0ecd80..7b4527c9f5c 100644 --- a/app/assets/stylesheets/desktop/user.scss +++ b/app/assets/stylesheets/desktop/user.scss @@ -142,7 +142,6 @@ .user-content { padding: 10px 8px; background-color: $secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); margin-bottom: 10px; box-sizing: border-box; diff --git a/app/assets/stylesheets/embed.css.scss b/app/assets/stylesheets/embed.css.scss index ae15f2cc66e..afb4a40c403 100644 --- a/app/assets/stylesheets/embed.css.scss +++ b/app/assets/stylesheets/embed.css.scss @@ -116,17 +116,33 @@ img.emoji { color: #999; } +.clearfix { + clear: both; +} + + header.discourse { padding-left: 10px; + padding-right: 10px; padding-bottom: 8px; font-size: 1.286em; border-bottom: 3px solid #ddd; - .button { - float:right; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + + h3 { + margin: 0 auto 0 0; + font-size: 1.0em; } } +.embed-error { + padding: 0 10px; +} + footer { font-size: 1.286em; margin-top: 0.5em; diff --git a/app/assets/stylesheets/mobile/group.scss b/app/assets/stylesheets/mobile/group.scss index c254518732c..cfbb849340b 100644 --- a/app/assets/stylesheets/mobile/group.scss +++ b/app/assets/stylesheets/mobile/group.scss @@ -10,7 +10,7 @@ margin: 5px 0px 0px 0px; } -.group-nav, .group-outlet { +.group-nav { width: 100%; } @@ -20,16 +20,32 @@ .group-nav.mobile-nav { margin-bottom: 15px; +} - > li { - a { - color: white; +.group-activity { + position: relative; +} - .fa { color: white; } - } +.group-activity-nav.mobile-nav { + position: absolute; + right: 0px; + top: -50px; +} + +.group-activity-outlet { + float: none; +} + +.form-horizontal { + .control-group { + margin-bottom: 10px; } - background-color: $quaternary; + .group-flair-inputs { + .group-flair-right { + margin: 0px + } + } } table.group-logs { @@ -43,7 +59,7 @@ table.group-members { tr { .user-info { - width: 130px; + width: auto; } td { diff --git a/app/assets/stylesheets/mobile/topic-list.scss b/app/assets/stylesheets/mobile/topic-list.scss index 660446f6f55..17644a5f27c 100644 --- a/app/assets/stylesheets/mobile/topic-list.scss +++ b/app/assets/stylesheets/mobile/topic-list.scss @@ -69,7 +69,7 @@ > tbody > tr { &.highlighted { - background-color: dark-light-choose(scale-color($tertiary, $lightness: 85%), scale-color($tertiary, $lightness: -55%)); + animation: background-fade-highlight 2.5s ease-out; } } diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss index 92c004d0640..475d35b0c96 100644 --- a/app/assets/stylesheets/mobile/topic-post.scss +++ b/app/assets/stylesheets/mobile/topic-post.scss @@ -76,7 +76,7 @@ button { margin:10px 0 10px 0; } &.has-like {color: $love;} - &.wikied { color: green; } + .read-icon { &:before { font-family: "FontAwesome"; @@ -221,7 +221,7 @@ a.star { } .post-count { position: absolute; - right: 3px; + right: 0; border-radius: 100px; padding: 4px 5px 2px 5px; text-align: center; diff --git a/app/assets/stylesheets/mobile/topic.scss b/app/assets/stylesheets/mobile/topic.scss index 4e51a5a8f46..00210c6be54 100644 --- a/app/assets/stylesheets/mobile/topic.scss +++ b/app/assets/stylesheets/mobile/topic.scss @@ -19,7 +19,6 @@ h1 { font-size: 1.5em; line-height: 1.25em; - margin: 0; a { color: $primary; vertical-align: middle; @@ -192,6 +191,6 @@ sup sup, sub sup, sup sub, sub sub { top: 0; } // make mobile timeline top and bottom dates easier to select .topic-timeline { - .start-date { font-size: 120%; padding: 5px; } - .now-date { font-size: 120%; padding: 5px; } -} \ No newline at end of file + .start-date { font-size: 110%; padding: 5px; } + .now-date { font-size: 110%; padding: 5px; } +} diff --git a/app/controllers/admin/backups_controller.rb b/app/controllers/admin/backups_controller.rb index 3c7855668c9..b0449ec6069 100644 --- a/app/controllers/admin/backups_controller.rb +++ b/app/controllers/admin/backups_controller.rb @@ -32,7 +32,7 @@ class Admin::BackupsController < Admin::AdminController rescue BackupRestore::OperationRunningError render json: failed_json.merge(message: I18n.t("backup.operation_already_running")) else - StaffActionLogger.new(current_user).log_backup_operation + StaffActionLogger.new(current_user).log_backup_create render json: success_json end @@ -46,9 +46,9 @@ class Admin::BackupsController < Admin::AdminController # download def show - filename = params.fetch(:id) - if backup = Backup[filename] - headers['Content-Length'] = File.size(backup.path) + if backup = Backup[params.fetch(:id)] + StaffActionLogger.new(current_user).log_backup_download(backup) + headers['Content-Length'] = File.size(backup.path).to_s send_file backup.path else render nothing: true, status: 404 @@ -56,8 +56,8 @@ class Admin::BackupsController < Admin::AdminController end def destroy - backup = Backup[params.fetch(:id)] - if backup + if backup = Backup[params.fetch(:id)] + StaffActionLogger.new(current_user).log_backup_destroy(backup) backup.remove render nothing: true else @@ -95,7 +95,16 @@ class Admin::BackupsController < Admin::AdminController def readonly enable = params.fetch(:enable).to_s == "true" - enable ? Discourse.enable_readonly_mode(user_enabled: true) : Discourse.disable_readonly_mode(user_enabled: true) + readonly_mode_key = Discourse::USER_READONLY_MODE_KEY + + if enable + Discourse.enable_readonly_mode(readonly_mode_key) + else + Discourse.disable_readonly_mode(readonly_mode_key) + end + + StaffActionLogger.new(current_user).log_change_readonly_mode(enable) + render nothing: true end diff --git a/app/controllers/admin/email_templates_controller.rb b/app/controllers/admin/email_templates_controller.rb index a5587c6863e..d3d1e963289 100644 --- a/app/controllers/admin/email_templates_controller.rb +++ b/app/controllers/admin/email_templates_controller.rb @@ -9,12 +9,11 @@ class Admin::EmailTemplatesController < Admin::AdminController "system_messages.bulk_invite_succeeded", "system_messages.csv_export_failed", "system_messages.csv_export_succeeded", "system_messages.download_remote_images_disabled", "system_messages.email_error_notification", "system_messages.email_reject_auto_generated", - "system_messages.email_reject_destination", "system_messages.email_reject_empty", + "system_messages.email_reject_empty", "system_messages.email_reject_invalid_access", "system_messages.email_reject_no_account", - "system_messages.email_reject_parsing", "system_messages.email_reject_post_error", - "system_messages.email_reject_post_error_specified", "system_messages.email_reject_user_not_found", + "system_messages.email_reject_parsing", "system_messages.email_reject_user_not_found", "system_messages.email_reject_reply_key", "system_messages.email_reject_topic_closed", - "system_messages.email_reject_topic_not_found", "system_messages.email_reject_trust_level", + "system_messages.email_reject_topic_not_found", "system_messages.email_reject_screened_email", "system_messages.pending_users_reminder", "system_messages.post_hidden", "system_messages.restore_failed", "system_messages.restore_succeeded", diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index ed96b325100..d2a93629fc6 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -69,6 +69,11 @@ class Admin::GroupsController < Admin::AdminController group.flair_color = group_params[:flair_color].presence group.public = group_params[:public] if group_params[:public] group.bio_raw = group_params[:bio_raw] if group_params[:bio_raw] + group.full_name = group_params[:full_name] if group_params[:full_name] + + if group_params[:allow_membership_requests] + group.allow_membership_requests = group_params[:allow_membership_requests] + end if group.save Group.reset_counters(group.id, :group_users) @@ -145,7 +150,7 @@ class Admin::GroupsController < Admin::AdminController :name, :alias_level, :visible, :automatic_membership_email_domains, :automatic_membership_retroactive, :title, :primary_group, :grant_trust_level, :incoming_email, :flair_url, :flair_bg_color, - :flair_color, :bio_raw, :public, :allow_membership_requests + :flair_color, :bio_raw, :public, :allow_membership_requests, :full_name ) end end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index c8702c28c50..2359bc31e2a 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -46,6 +46,7 @@ class Admin::UsersController < Admin::AdminController def delete_all_posts @user = User.find_by(id: params[:user_id]) @user.delete_all_posts!(guardian) + # staff action logs will have an entry for each post render nothing: true end @@ -137,7 +138,7 @@ class Admin::UsersController < Admin::AdminController group = Group.find(params[:group_id].to_i) return render_json_error group unless group && !group.automatic group.remove(@user) - GroupActionLogger.new(current_user, group).log_remove_user_from_group(user) + GroupActionLogger.new(current_user, group).log_remove_user_from_group(@user) render nothing: true end @@ -182,6 +183,8 @@ class Admin::UsersController < Admin::AdminController @user.trust_level_locked = new_lock == "true" @user.save + StaffActionLogger.new(current_user).log_lock_trust_level(@user) + unless @user.trust_level_locked p = Promotion.new(@user) 2.times{ p.review } @@ -210,12 +213,14 @@ class Admin::UsersController < Admin::AdminController def activate guardian.ensure_can_activate!(@user) @user.activate + StaffActionLogger.new(current_user).log_user_activate(@user, I18n.t('user.activated_by_staff')) render json: success_json end def deactivate guardian.ensure_can_deactivate!(@user) @user.deactivate + StaffActionLogger.new(current_user).log_user_deactivate(@user, I18n.t('user.deactivated_by_staff')) refresh_browser @user render nothing: true end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f02c9c97595..cec61bf9d6f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -9,6 +9,7 @@ require_dependency 'json_error' require_dependency 'letter_avatar' require_dependency 'distributed_cache' require_dependency 'global_path' +require_dependency 'secure_session' class ApplicationController < ActionController::Base include CurrentUser @@ -25,7 +26,7 @@ class ApplicationController < ActionController::Base # and then raising a CSRF exception def handle_unverified_request # NOTE: API key is secret, having it invalidates the need for a CSRF token - unless is_api? + unless is_api? || is_user_api? super clear_current_user render text: "['BAD CSRF']", status: 403 @@ -381,6 +382,11 @@ class ApplicationController < ActionController::Base end end + + def secure_session + SecureSession.new(session["secure_session_id"] ||= SecureRandom.hex) + end + private def locale_from_header @@ -501,7 +507,7 @@ class ApplicationController < ActionController::Base def check_xhr # bypass xhr check on PUT / POST / DELETE provided api key is there, otherwise calling api is annoying - return if !request.get? && is_api? + return if !request.get? && (is_api? || is_user_api?) raise RenderEmpty.new unless ((request.format && request.format.json?) || request.xhr?) end @@ -558,6 +564,7 @@ class ApplicationController < ActionController::Base render_to_string status: status, layout: layout, formats: [:html], template: '/exceptions/not_found' end + protected def render_post_json(post, add_raw=true) diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 5887ec71971..742ac3973b1 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -230,6 +230,7 @@ class CategoriesController < ApplicationController :email_in, :email_in_allow_strangers, :suppress_from_homepage, + :all_topics_wiki, :parent_category_id, :auto_close_hours, :auto_close_based_on_last_post, @@ -240,6 +241,7 @@ class CategoriesController < ApplicationController :topic_template, :sort_order, :sort_ascending, + :topic_featured_link_allowed, :custom_fields => [params[:custom_fields].try(:keys)], :permissions => [*p.try(:keys)], :allowed_tags => [], diff --git a/app/controllers/embed_controller.rb b/app/controllers/embed_controller.rb index 3286eaead1b..9407f847f20 100644 --- a/app/controllers/embed_controller.rb +++ b/app/controllers/embed_controller.rb @@ -6,6 +6,16 @@ class EmbedController < ApplicationController layout 'embed' + rescue_from Discourse::InvalidAccess do + response.headers['X-Frame-Options'] = "ALLOWALL" + if current_user.try(:admin?) + @setup_url = "#{Discourse.base_url}/admin/customize/embedding" + @show_reason = true + @hosts = EmbeddableHost.all + end + render 'embed_error' + end + def comments embed_url = params[:embed_url] embed_username = params[:discourse_username] diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 87137ed5937..e5c99c2433a 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -10,10 +10,42 @@ class GroupsController < ApplicationController skip_before_filter :preload_json, :check_xhr, only: [:posts_feed, :mentions_feed] + def index + unless SiteSetting.enable_group_directory? + raise Discourse::InvalidAccess.new(:enable_group_directory) + end + + page_size = 30 + page = params[:page]&.to_i || 0 + + groups = Group.order(name: :asc).where(visible: true) + + if !guardian.is_admin? + groups = groups.where(automatic: false) + end + + count = groups.count + groups = groups.offset(page * page_size).limit(page_size) + + group_user_ids = GroupUser.where(group: groups, user: current_user).pluck(:group_id) + + render_json_dump( + groups: serialize_data(groups, BasicGroupSerializer), + extras: { + group_user_ids: group_user_ids + }, + total_rows_groups: count, + load_more_groups: groups_path(page: page + 1) + ) + end + def show render_serialized(find_group(:id), GroupShowSerializer, root: 'basic_group') end + def edit + end + def update group = Group.find(params[:id]) guardian.ensure_can_edit!(group) @@ -79,10 +111,10 @@ class GroupsController < ApplicationController limit = (params[:limit] || 20).to_i offset = params[:offset].to_i dir = (params[:desc] && !params[:desc].blank?) ? 'DESC' : 'ASC' - order = {} + order = "" if params[:order] && %w{last_posted_at last_seen_at}.include?(params[:order]) - order.merge!(params[:order] => dir) + order = "#{params[:order]} #{dir} NULLS LAST" end total = group.users.count @@ -109,6 +141,16 @@ class GroupsController < ApplicationController } end + def owners + group = find_group(:group_id) + + owners = group.users.where('group_users.owner') + .order("users.last_seen_at DESC") + .limit(5) + + render_serialized(owners, GroupUserSerializer) + end + def add_members group = Group.find(params[:id]) group.public ? ensure_logged_in : guardian.ensure_can_edit!(group) @@ -129,7 +171,9 @@ class GroupsController < ApplicationController raise Discourse::NotFound if users.blank? if group.public - raise Discourse::InvalidAccess unless current_user == users.first + if !guardian.can_log_group_changes?(group) && current_user != users.first + raise Discourse::InvalidAccess + end unless current_user.staff? RateLimiter.new(current_user, "public_group_membership", 3, 1.minute).performed! @@ -180,7 +224,9 @@ class GroupsController < ApplicationController raise Discourse::NotFound unless user if group.public - raise Discourse::InvalidAccess unless current_user == user + if !guardian.can_log_group_changes?(group) && current_user != user + raise Discourse::InvalidAccess + end unless current_user.staff? RateLimiter.new(current_user, "public_group_membership", 3, 1.minute).performed! @@ -236,7 +282,7 @@ class GroupsController < ApplicationController :flair_bg_color, :flair_color, :bio_raw, - :title, + :full_name, :public, :allow_membership_requests ) diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index ae62b9b8732..7c539b46ebd 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -7,10 +7,15 @@ class InvitesController < ApplicationController skip_before_filter :redirect_to_login_if_required before_filter :ensure_logged_in, only: [:destroy, :create, :create_invite_link, :resend_invite, :resend_all_invites, :upload_csv] - before_filter :ensure_new_registrations_allowed, only: [:show, :redeem_disposable_invite] - before_filter :ensure_not_logged_in, only: [:show, :redeem_disposable_invite] + before_filter :ensure_new_registrations_allowed, only: [:show, :perform_accept_invitation, :redeem_disposable_invite] + before_filter :ensure_not_logged_in, only: [:show, :perform_accept_invitation, :redeem_disposable_invite] def show + expires_now + render layout: 'no_ember' + end + + def perform_accept_invitation invite = Invite.find_by(invite_key: params[:id]) if invite.present? @@ -27,9 +32,12 @@ class InvitesController < ApplicationController return end end - end - redirect_to path("/") + redirect_to path("/") + else + flash.now[:error] = I18n.t('invite.not_found') + render layout: 'no_ember' + end end def create @@ -156,9 +164,9 @@ class InvitesController < ApplicationController Scheduler::Defer.later("Upload CSV") do begin - data = if extension == ".csv" + data = if extension.downcase == ".csv" path = Invite.create_csv(file, name) - Jobs.enqueue(:bulk_invite, filename: "#{name}.csv", current_user_id: current_user.id) + Jobs.enqueue(:bulk_invite, filename: "#{name}#{extension}", current_user_id: current_user.id) {url: path} else failed_json.merge(errors: [I18n.t("bulk_invite.file_should_be_csv")]) diff --git a/app/controllers/metadata_controller.rb b/app/controllers/metadata_controller.rb index ab317885a19..9a8fc915ce3 100644 --- a/app/controllers/metadata_controller.rb +++ b/app/controllers/metadata_controller.rb @@ -13,11 +13,11 @@ class MetadataController < ApplicationController private def default_manifest - { + manifest = { name: SiteSetting.title, short_name: SiteSetting.title, display: 'standalone', - orientation: 'portrait', + orientation: 'any', start_url: "#{Discourse.base_uri}/", background_color: "##{ColorScheme.hex_for_name('secondary')}", theme_color: "##{ColorScheme.hex_for_name('header_background')}", @@ -29,5 +29,19 @@ class MetadataController < ApplicationController } ] } + + if SiteSetting.native_app_install_banner + manifest = manifest.merge({ + prefer_related_applications: true, + related_applications: [ + { + platform: "play", + id: "com.discourse" + } + ] + }) + end + + manifest end end diff --git a/app/controllers/onebox_controller.rb b/app/controllers/onebox_controller.rb index 474feb5fd73..9b09a0f3b87 100644 --- a/app/controllers/onebox_controller.rb +++ b/app/controllers/onebox_controller.rb @@ -1,16 +1,32 @@ require_dependency 'oneboxer' class OneboxController < ApplicationController + before_filter :ensure_logged_in def show - result = Oneboxer.preview(params[:url], invalidate_oneboxes: params[:refresh] == 'true') - result.strip! if result.present? + params.require(:user_id) - # If there is no result, return a 404 - if result.blank? + preview = Oneboxer.cached_preview(params[:url]) + preview.strip! if preview.present? + + return render(text: preview) if preview.present? + + # only 1 outgoing preview per user + return render(nothing: true, status: 429) if Oneboxer.is_previewing?(params[:user_id]) + + Oneboxer.preview_onebox!(params[:user_id]) + + preview = Oneboxer.preview(params[:url], invalidate_oneboxes: params[:refresh] == 'true') + preview.strip! if preview.present? + + Scheduler::Defer.later("Onebox previewed") { + Oneboxer.onebox_previewed!(params[:user_id]) + } + + if preview.blank? render nothing: true, status: 404 else - render text: result + render text: preview end end diff --git a/app/controllers/post_actions_controller.rb b/app/controllers/post_actions_controller.rb index 1c478504c36..3cef663c565 100644 --- a/app/controllers/post_actions_controller.rb +++ b/app/controllers/post_actions_controller.rb @@ -6,9 +6,16 @@ class PostActionsController < ApplicationController before_filter :fetch_post_action_type_id_from_params def create + raise Discourse::NotFound if @post.blank? + taken = PostAction.counts_for([@post], current_user)[@post.id] - guardian.ensure_post_can_act!(@post, PostActionType.types[@post_action_type_id], taken_actions: taken) - guardian.ensure_post_can_act!(@post, PostActionType.types[@post_action_type_id], is_warning: params[:is_warning]) + + guardian.ensure_post_can_act!( + @post, + PostActionType.types[@post_action_type_id], + is_warning: params[:is_warning], + taken_actions: taken + ) args = {} args[:message] = params[:message] if params[:message].present? @@ -77,7 +84,6 @@ class PostActionsController < ApplicationController finder = finder.with_deleted if guardian.is_staff? @post = finder.first - guardian.ensure_can_see!(@post) end def fetch_post_action_type_id_from_params diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 7f68a648eff..52618c5cafd 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -467,7 +467,7 @@ class PostsController < ApplicationController json_obj = json_obj[:post] end - if !success && GlobalSetting.try(:verbose_api_logging) && is_api? + if !success && GlobalSetting.try(:verbose_api_logging) && (is_api? || is_user_api?) Rails.logger.error "Error creating post via API:\n\n#{json_obj.inspect}" end diff --git a/app/controllers/safe_mode_controller.rb b/app/controllers/safe_mode_controller.rb index d414f141b7a..e52161cff20 100644 --- a/app/controllers/safe_mode_controller.rb +++ b/app/controllers/safe_mode_controller.rb @@ -14,7 +14,7 @@ class SafeModeController < ApplicationController if safe_mode.length > 0 redirect_to path("/?safe_mode=#{safe_mode.join("%2C")}") else - redirect_to :index + redirect_to safe_mode_path end end end diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index a73541a3fb9..7ac3749f46b 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -118,7 +118,7 @@ class SessionController < ApplicationController if return_path !~ /^\/[^\/]/ begin uri = URI(return_path) - return_path = path("/") unless uri.host == Discourse.current_hostname + return_path = path("/") unless SiteSetting.sso_allows_all_return_paths || uri.host == Discourse.current_hostname rescue return_path = path("/") end @@ -218,6 +218,9 @@ class SessionController < ApplicationController RateLimiter.new(nil, "forgot-password-hr-#{request.remote_ip}", 6, 1.hour).performed! RateLimiter.new(nil, "forgot-password-min-#{request.remote_ip}", 3, 1.minute).performed! + RateLimiter.new(nil, "forgot-password-login-hour-#{params[:login].to_s[0..100]}", 12, 1.hour).performed! + RateLimiter.new(nil, "forgot-password-login-min-#{params[:login].to_s[0..100]}", 3, 1.minute).performed! + user = User.find_by_username_or_email(params[:login]) user_presence = user.present? && user.id != Discourse::SYSTEM_USER_ID && !user.staged if user_presence diff --git a/app/controllers/static_controller.rb b/app/controllers/static_controller.rb index 1641c019565..6fa864c2683 100644 --- a/app/controllers/static_controller.rb +++ b/app/controllers/static_controller.rb @@ -135,23 +135,25 @@ class StaticController < ApplicationController opts = { disposition: nil } opts[:type] = "application/javascript" if path =~ /\.js.br$/ - response.headers["Expires"] = 1.year.from_now.httpdate - response.headers["Cache-Control"] = 'max-age=31557600, public' - response.headers["Content-Encoding"] = 'br' begin response.headers["Last-Modified"] = File.ctime(path).httpdate response.headers["Content-Length"] = File.size(path).to_s rescue Errno::ENOENT - raise Discourse::NotFound + response.headers["Expires"] = 5.seconds.from_now.httpdate + response.headers["Cache-Control"] = 'max-age=5, public' + expires_in 5.seconds, public: true, must_revalidate: false + + render text: "missing brotli asset", status: 404 + return end + response.headers["Expires"] = 1.year.from_now.httpdate + response.headers["Cache-Control"] = 'max-age=31557600, public' + response.headers["Content-Encoding"] = 'br' + expires_in 1.year, public: true, must_revalidate: false - if File.exists?(path) - send_file(path, opts) - else - raise Discourse::NotFound - end + send_file(path, opts) end diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index f72c1ede90b..92973a9dbf5 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -66,7 +66,8 @@ class TagsController < ::ApplicationController @description_meta = I18n.t("rss_by_tag", tag: tag_params.join(' & ')) @title = @description_meta - canonical_url "#{Discourse.base_url_no_prefix}#{public_send(url_method(params.slice(:category, :parent_category)))}" + path_name = url_method(params.slice(:category, :parent_category)) + canonical_url "#{Discourse.base_url_no_prefix}#{public_send(path_name, *(params.slice(:parent_category, :category, :tag_id).values))}" if @list.topics.size == 0 && params[:tag_id] != 'none' && !Tag.where(name: @tag_id).exists? permalink_redirect_or_not_found diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb index ef0cd8ba69d..f5bddc8981a 100644 --- a/app/controllers/topics_controller.rb +++ b/app/controllers/topics_controller.rb @@ -382,6 +382,8 @@ class TopicsController < ApplicationController topic = Topic.find(params[:topic_id].to_i) first_post = topic.ordered_posts.first + guardian.ensure_can_see!(first_post) + PostAction.act(current_user, first_post, PostActionType.types[:bookmark]) render nothing: true diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 0f6ccba284a..57f19f151fd 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -4,6 +4,9 @@ class UploadsController < ApplicationController def create type = params.require(:type) + + raise Discourse::InvalidAccess.new unless type =~ /^[a-z\-\_]{1,100}$/ + file = params[:file] || params[:files].try(:first) url = params[:url] client_id = params[:client_id] @@ -73,6 +76,7 @@ class UploadsController < ApplicationController # convert pasted images to HQ jpegs if filename == "blob.png" && SiteSetting.convert_pasted_images_to_hq_jpg jpeg_path = "#{File.dirname(tempfile.path)}/blob.jpg" + OptimizedImage.ensure_safe_paths!(tempfile.path, jpeg_path) `convert #{tempfile.path} -quality #{SiteSetting.convert_pasted_images_quality} #{jpeg_path}` # only change the format of the image when JPG is at least 5% smaller if File.size(jpeg_path) < File.size(tempfile.path) * 0.95 diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d67c12455e1..a61541aa1ab 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -389,19 +389,21 @@ class UsersController < ApplicationController def password_reset expires_now - if EmailToken.valid_token_format?(params[:token]) + token = params[:token] + + if EmailToken.valid_token_format?(token) if request.put? - @user = EmailToken.confirm(params[:token]) + @user = EmailToken.confirm(token) else - email_token = EmailToken.confirmable(params[:token]) + email_token = EmailToken.confirmable(token) @user = email_token.try(:user) end if @user - session["password-#{params[:token]}"] = @user.id + secure_session["password-#{token}"] = @user.id else - user_id = session["password-#{params[:token]}"] - @user = User.find(user_id) if user_id + user_id = secure_session["password-#{token}"].to_i + @user = User.find(user_id) if user_id > 0 end else @invalid_token = true @@ -420,7 +422,7 @@ class UsersController < ApplicationController @user.auth_token = nil if @user.save Invite.invalidate_for_email(@user.email) # invite link can't be used to log in anymore - session["password-#{params[:token]}"] = nil + secure_session["password-#{token}"] = nil logon_after_password_reset return redirect_to(wizard_path) if Wizard.user_requires_completion?(@user) @@ -566,7 +568,7 @@ class UsersController < ApplicationController if params[:include_groups] == "true" to_render[:groups] = Group.search_group(term).map do |m| - {name: m.name, usernames: []} + { name: m.name, full_name: m.full_name } end end @@ -574,7 +576,7 @@ class UsersController < ApplicationController to_render[:groups] = Group.mentionable(current_user) .where("name ILIKE :term_like", term_like: "#{term}%") .map do |m| - {name: m.name, usernames: []} + { name: m.name, full_name: m.full_name } end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e13539e6471..6e32e866bac 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -137,7 +137,7 @@ module ApplicationHelper end def rtl? - ["ar", "fa_IR", "he"].include? I18n.locale.to_s + ["ar", "ur", "fa_IR", "he"].include? I18n.locale.to_s end def user_locale @@ -241,19 +241,35 @@ module ApplicationHelper MobileDetection.mobile_device?(request.user_agent) end + NO_CUSTOM = "no_custom".freeze + NO_PLUGINS = "no_plugins".freeze + ONLY_OFFICIAL = "only_official".freeze + SAFE_MODE = "safe_mode".freeze + def customization_disabled? - safe_mode = params["safe_mode"] - session[:disable_customization] || (safe_mode && safe_mode.include?("no_custom")) + safe_mode = params[SAFE_MODE] + session[:disable_customization] || (safe_mode && safe_mode.include?(NO_CUSTOM)) end def allow_plugins? - safe_mode = params["safe_mode"] - !(safe_mode && safe_mode.include?("no_plugins")) + safe_mode = params[SAFE_MODE] + !(safe_mode && safe_mode.include?(NO_PLUGINS)) end def allow_third_party_plugins? - safe_mode = params["safe_mode"] - !(safe_mode && (safe_mode.include?("no_plugins") || safe_mode.include?("only_official"))) + safe_mode = params[SAFE_MODE] + !(safe_mode && (safe_mode.include?(NO_PLUGINS) || safe_mode.include?(ONLY_OFFICIAL))) + end + + def normalized_safe_mode + mode_string = params["safe_mode"] + safe_mode = nil + (safe_mode ||= []) << NO_CUSTOM if mode_string.include?(NO_CUSTOM) + (safe_mode ||= []) << NO_PLUGINS if mode_string.include?(NO_PLUGINS) + (safe_mode ||= []) << ONLY_OFFICIAL if mode_string.include?(ONLY_OFFICIAL) + if safe_mode + safe_mode.join(",").html_safe + end end def loading_admin? diff --git a/app/helpers/user_notifications_helper.rb b/app/helpers/user_notifications_helper.rb index 10231369f1e..044b4eb3128 100644 --- a/app/helpers/user_notifications_helper.rb +++ b/app/helpers/user_notifications_helper.rb @@ -36,9 +36,9 @@ module UserNotificationsHelper doc = Nokogiri::HTML(html) result = "" - doc.css('p').each do |p| - if p.text.present? - result << p.to_s + doc.css('body > p, aside.onebox').each do |node| + if node.text.present? + result << node.to_s return result if result.size >= 100 end end @@ -48,9 +48,9 @@ module UserNotificationsHelper doc.css('div').first end - def email_excerpt(html, posts_count=nil) + def email_excerpt(html_arg, posts_count=nil) # only include 1st paragraph when more than 1 posts - html = first_paragraph_from(html).to_s if posts_count.nil? || posts_count > 1 + html = (posts_count.nil? || posts_count > 1) ? (first_paragraph_from(html_arg)||html_arg).to_s : html_arg PrettyText.format_for_email(html).html_safe end diff --git a/app/jobs/onceoff/migrate_featured_links.rb b/app/jobs/onceoff/migrate_featured_links.rb new file mode 100644 index 00000000000..6d08826dfc1 --- /dev/null +++ b/app/jobs/onceoff/migrate_featured_links.rb @@ -0,0 +1,28 @@ +module Jobs + + class MigrateFeaturedLinks < Jobs::Onceoff + + def execute_onceoff(args) + TopicCustomField.where(name: "featured_link").find_each do |tcf| + if tcf.value.present? + Topic.where(id: tcf.topic_id).update_all(featured_link: tcf.value) + end + end + + # Plugin behaviour: only categories explicitly allowed to have featured links can have them. + # All others implicitly DO NOT allow them. + # If no categories were explicitly allowed to have them, then all implicitly DID allow them. + + allowed = CategoryCustomField.where(name: "topic_featured_link_allowed").where(value: "true").pluck(:category_id) + + if !allowed.empty? + # all others are not allowed + Category.where.not(id: allowed).update_all(topic_featured_link_allowed: false) + else + not_allowed = CategoryCustomField.where(name: "topic_featured_link_allowed").where.not(value: "true").pluck(:category_id) + Category.where(id: not_allowed).update_all(topic_featured_link_allowed: false) + end + end + end + +end diff --git a/app/jobs/regular/automatic_group_membership.rb b/app/jobs/regular/automatic_group_membership.rb index a6220db4277..dbe679889b0 100644 --- a/app/jobs/regular/automatic_group_membership.rb +++ b/app/jobs/regular/automatic_group_membership.rb @@ -15,6 +15,8 @@ module Jobs User.where("email ~* '@(#{domains})$'") .where("users.id NOT IN (SELECT user_id FROM group_users WHERE group_users.group_id = ?)", group_id) + .activated + .where(staged: false) .find_each do |user| group.add(user) diff --git a/app/jobs/regular/pull_hotlinked_images.rb b/app/jobs/regular/pull_hotlinked_images.rb index fd8191f4a18..14bd57948e9 100644 --- a/app/jobs/regular/pull_hotlinked_images.rb +++ b/app/jobs/regular/pull_hotlinked_images.rb @@ -26,7 +26,7 @@ module Jobs downloaded_urls = {} extract_images_from(post.cooked).each do |image| - src = image['src'] + src = original_src = image['src'] src = "http:" + src if src.start_with?("//") if is_valid_image_url(src) @@ -53,7 +53,7 @@ module Jobs # have we successfully downloaded that file? if downloaded_urls[src].present? url = downloaded_urls[src] - escaped_src = Regexp.escape(src) + escaped_src = Regexp.escape(original_src) # there are 6 ways to insert an image in a post # HTML tag - raw.gsub!(/src=["']#{escaped_src}["']/i, "src='#{url}'") diff --git a/app/jobs/regular/user_email.rb b/app/jobs/regular/user_email.rb index 3f6193501df..3214055563b 100644 --- a/app/jobs/regular/user_email.rb +++ b/app/jobs/regular/user_email.rb @@ -74,7 +74,7 @@ module Jobs set_skip_context(type, user.id, to_address || user.email, post.try(:id)) return skip_message(I18n.t("email_log.anonymous_user")) if user.anonymous? - return skip_message(I18n.t("email_log.suspended_not_pm")) if user.suspended? && type != :user_private_message + return skip_message(I18n.t("email_log.suspended_not_pm")) if user.suspended? && type.to_s != "user_private_message" return if user.staged && type == :digest diff --git a/app/mailers/user_notifications.rb b/app/mailers/user_notifications.rb index 184b4e088cc..aeef876c491 100644 --- a/app/mailers/user_notifications.rb +++ b/app/mailers/user_notifications.rb @@ -3,6 +3,7 @@ require_dependency 'email/message_builder' require_dependency 'age_words' class UserNotifications < ActionMailer::Base + include UserNotificationsHelper helper :application default charset: 'UTF-8' @@ -97,64 +98,72 @@ class UserNotifications < ActionMailer::Base build_summary_for(user) min_date = opts[:since] || user.last_emailed_at || user.last_seen_at || 1.month.ago - @last_seen_at = short_date(user.last_seen_at || user.created_at) - - @preheader_text = I18n.t('user_notifications.digest.preheader', last_seen_at: @last_seen_at) - - # Try to find 3 interesting stats for the top of the digest - @counts = [{label_key: 'user_notifications.digest.new_topics', - value: Topic.new_since_last_seen(user, min_date).count, - href: "#{Discourse.base_url}/new"}] - - value = user.unread_notifications - @counts << {label_key: 'user_notifications.digest.unread_notifications', value: value, href: "#{Discourse.base_url}/my/notifications"} if value > 0 - - value = user.unread_private_messages - @counts << {label_key: 'user_notifications.digest.unread_messages', value: value, href: "#{Discourse.base_url}/my/messages"} if value > 0 - - if @counts.size < 3 - value = user.unread_notifications_of_type(Notification.types[:liked]) - @counts << {label_key: 'user_notifications.digest.liked_received', value: value, href: "#{Discourse.base_url}/my/notifications"} if value > 0 + # Fetch some topics and posts to show + digest_opts = {limit: SiteSetting.digest_topics + SiteSetting.digest_other_topics, top_order: true} + topics_for_digest = Topic.for_digest(user, min_date, digest_opts).to_a + if topics_for_digest.empty? && !user.user_option.try(:include_tl0_in_digests) + # Find some topics from new users that are at least 24 hours old + topics_for_digest = Topic.for_digest(user, min_date, digest_opts.merge(include_tl0: true)).where('topics.created_at < ?', 24.hours.ago).to_a end - if @counts.size < 3 - @counts << { - label_key: 'user_notifications.digest.new_posts', - value: Post.for_mailing_list(user, min_date).where("posts.post_number > ?", 1).count, - href: "#{Discourse.base_url}/new" - } - end - - if @counts.size < 3 - value = User.real.where(active: true, staged: false).not_suspended.where("created_at > ?", min_date).count - @counts << { - label_key: 'user_notifications.digest.new_users', - value: value, - href: "#{Discourse.base_url}/about" - } if value > 0 - end - - # Now fetch some topics and posts to show - topics_for_digest = Topic.for_digest(user, min_date, limit: SiteSetting.digest_topics + SiteSetting.digest_other_topics, top_order: true).to_a - @popular_topics = topics_for_digest[0,SiteSetting.digest_topics] - @other_new_for_you = topics_for_digest.size > SiteSetting.digest_topics ? topics_for_digest[SiteSetting.digest_topics..-1] : [] - - @popular_posts = if SiteSetting.digest_posts > 0 - Post.order("posts.score DESC") - .for_mailing_list(user, min_date) - .where('posts.post_type = ?', Post.types[:regular]) - .where('posts.deleted_at IS NULL AND posts.hidden = false AND posts.user_deleted = false') - .where("posts.post_number > ? AND posts.score > ?", 1, ScoreCalculator.default_score_weights[:like_score] * 5.0) - .limit(SiteSetting.digest_posts) - else - [] - end - - topic_lookup = TopicUser.lookup_for(user, @other_new_for_you) - @other_new_for_you.each { |t| t.user_data = topic_lookup[t.id] } if @popular_topics.present? + @other_new_for_you = topics_for_digest.size > SiteSetting.digest_topics ? topics_for_digest[SiteSetting.digest_topics..-1] : [] + + @popular_posts = if SiteSetting.digest_posts > 0 + Post.order("posts.score DESC") + .for_mailing_list(user, min_date) + .where('posts.post_type = ?', Post.types[:regular]) + .where('posts.deleted_at IS NULL AND posts.hidden = false AND posts.user_deleted = false') + .where("posts.post_number > ? AND posts.score > ?", 1, ScoreCalculator.default_score_weights[:like_score] * 5.0) + .limit(SiteSetting.digest_posts) + else + [] + end + + @excerpts = {} + + @popular_topics.map do |t| + @excerpts[t.first_post.id] = email_excerpt(t.first_post.cooked) if t.first_post.present? + end + + # Try to find 3 interesting stats for the top of the digest + + new_topics_count = Topic.new_since_last_seen(user, min_date).count + if new_topics_count == 0 + # We used topics from new users instead, so count should match + new_topics_count = topics_for_digest.size + end + @counts = [{label_key: 'user_notifications.digest.new_topics', + value: new_topics_count, + href: "#{Discourse.base_url}/new"}] + + value = user.unread_notifications + @counts << {label_key: 'user_notifications.digest.unread_notifications', value: value, href: "#{Discourse.base_url}/my/notifications"} if value > 0 + + value = user.unread_private_messages + @counts << {label_key: 'user_notifications.digest.unread_messages', value: value, href: "#{Discourse.base_url}/my/messages"} if value > 0 + + if @counts.size < 3 + value = user.unread_notifications_of_type(Notification.types[:liked]) + @counts << {label_key: 'user_notifications.digest.liked_received', value: value, href: "#{Discourse.base_url}/my/notifications"} if value > 0 + end + + if @counts.size < 3 + value = Post.for_mailing_list(user, min_date).where("posts.post_number > ?", 1).count + @counts << { label_key: 'user_notifications.digest.new_posts', value: value, href: "#{Discourse.base_url}/new" } if value > 0 + end + + if @counts.size < 3 + value = User.real.where(active: true, staged: false).not_suspended.where("created_at > ?", min_date).count + @counts << { label_key: 'user_notifications.digest.new_users', value: value, href: "#{Discourse.base_url}/about" } if value > 0 + end + + @last_seen_at = short_date(user.last_seen_at || user.created_at) + + @preheader_text = I18n.t('user_notifications.digest.preheader', last_seen_at: @last_seen_at) + opts = { from_alias: I18n.t('user_notifications.digest.from', site_name: SiteSetting.title), subject: I18n.t('user_notifications.digest.subject_template', site_name: @site_name, date: short_date(Time.now)), diff --git a/app/models/anon_site_json_cache_observer.rb b/app/models/anon_site_json_cache_observer.rb deleted file mode 100644 index cacb0d1431e..00000000000 --- a/app/models/anon_site_json_cache_observer.rb +++ /dev/null @@ -1,12 +0,0 @@ -class AnonSiteJsonCacheObserver < ActiveRecord::Observer - observe :category, :post_action_type, :user_field, :group - - def after_destroy(object) - Site.clear_anon_cache! - end - - def after_save(object) - Site.clear_anon_cache! - end - -end diff --git a/app/models/backup.rb b/app/models/backup.rb index dfa5381219b..d23d459d008 100644 --- a/app/models/backup.rb +++ b/app/models/backup.rb @@ -61,7 +61,9 @@ class Backup end def self.base_directory - File.join(Rails.root, "public", "backups", RailsMultisite::ConnectionManagement.current_db) + base_directory = File.join(Rails.root, "public", "backups", RailsMultisite::ConnectionManagement.current_db) + FileUtils.mkdir_p(base_directory) unless Dir.exists?(base_directory) + base_directory end def self.chunk_path(identifier, filename, chunk_number) diff --git a/app/models/badge.rb b/app/models/badge.rb index 6851b210dce..13e7916f1b1 100644 --- a/app/models/badge.rb +++ b/app/models/badge.rb @@ -1,3 +1,5 @@ +require_dependency 'slug' + class Badge < ActiveRecord::Base # NOTE: These badge ids are not in order! They are grouped logically. # When picking an id, *search* for it. @@ -119,6 +121,10 @@ class Badge < ActiveRecord::Base } end + def awarded_for_trust_level? + id <= 4 + end + def reset_grant_count! self.grant_count = UserBadge.where(badge_id: id).count save! @@ -208,6 +214,7 @@ SQL def i18n_name self.name.downcase.tr(' ', '_') end + end # == Schema Information diff --git a/app/models/category.rb b/app/models/category.rb index 7681188e8e3..62b22a11954 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -6,6 +6,7 @@ class Category < ActiveRecord::Base include Positionable include HasCustomFields include CategoryHashtag + include AnonCacheInvalidator belongs_to :topic, dependent: :destroy belongs_to :topic_only_relative_url, @@ -41,20 +42,26 @@ class Category < ActiveRecord::Base validate :email_in_validator validate :ensure_slug + + after_create :create_category_definition + before_save :apply_permissions before_save :downcase_email before_save :downcase_name - after_create :create_category_definition - - after_save :publish_category - after_destroy :publish_category_deletion - - after_update :rename_category_definition, if: :name_changed? - - after_create :delete_category_permalink - after_update :create_category_permalink, if: :slug_changed? after_save :publish_discourse_stylesheet + after_save :publish_category + after_save :reset_topic_ids_cache + after_save :clear_url_cache + after_save :index_search + + after_destroy :reset_topic_ids_cache + after_destroy :publish_category_deletion + + after_create :delete_category_permalink + + after_update :rename_category_definition, if: :name_changed? + after_update :create_category_permalink, if: :slug_changed? has_one :category_search_data belongs_to :parent_category, class_name: 'Category' @@ -65,8 +72,6 @@ class Category < ActiveRecord::Base has_many :category_tag_groups, dependent: :destroy has_many :tag_groups, through: :category_tag_groups - after_save :reset_topic_ids_cache - after_destroy :reset_topic_ids_cache scope :latest, -> { order('topic_count DESC') } @@ -425,9 +430,7 @@ SQL @@url_cache = DistributedCache.new('category_url') - after_save do - # parent takes part in url calculation - # any change could invalidate multiples + def clear_url_cache @@url_cache.clear end @@ -491,6 +494,10 @@ SQL DiscourseStylesheets.cache.clear end + def index_search + SearchIndexer.index(self) + end + def self.find_by_slug(category_slug, parent_category_slug=nil) if parent_category_slug parent_category_id = self.where(slug: parent_category_slug, parent_category_id: nil).pluck(:id).first @@ -538,6 +545,7 @@ end # auto_close_based_on_last_post :boolean default(FALSE) # topic_template :text # suppress_from_homepage :boolean default(FALSE) +# all_topics_wiki :boolean default(FALSE) # contains_messages :boolean # sort_order :string # sort_ascending :boolean diff --git a/app/models/color_scheme.rb b/app/models/color_scheme.rb index c2af572183d..d9c9216c277 100644 --- a/app/models/color_scheme.rb +++ b/app/models/color_scheme.rb @@ -92,15 +92,21 @@ class ColorScheme < ActiveRecord::Base new_color_scheme end - def self.hex_for_name(name) - val = begin - hex_cache[name] ||= begin - # Can't use `where` here because base doesn't allow it - (enabled || base).colors.find {|c| c.name == name }.try(:hex) || :nil + def self.lookup_hex_for_name(name) + Discourse.plugin_themes.each do |pt| + if pt.color_scheme + found = pt.color_scheme[name.to_sym] + return found if found end end - val == :nil ? nil : val + # Can't use `where` here because base doesn't allow it + (enabled || base).colors.find {|c| c.name == name }.try(:hex) || :nil + end + + def self.hex_for_name(name) + hex_cache[name] ||= lookup_hex_for_name(name) + hex_cache[name] == :nil ? nil : hex_cache[name] end def colors=(arr) diff --git a/app/models/concerns/anon_cache_invalidator.rb b/app/models/concerns/anon_cache_invalidator.rb new file mode 100644 index 00000000000..ac37eb69450 --- /dev/null +++ b/app/models/concerns/anon_cache_invalidator.rb @@ -0,0 +1,13 @@ +module AnonCacheInvalidator + extend ActiveSupport::Concern + + included do + after_destroy do + Site.clear_anon_cache! + end + + after_save do + Site.clear_anon_cache! + end + end +end diff --git a/app/models/discourse_single_sign_on.rb b/app/models/discourse_single_sign_on.rb index a4c1fd151b2..daf64826fa2 100644 --- a/app/models/discourse_single_sign_on.rb +++ b/app/models/discourse_single_sign_on.rb @@ -146,7 +146,7 @@ class DiscourseSingleSignOn < SingleSignOn sso_record.last_payload = unsigned_payload sso_record.external_id = external_id else - Jobs.enqueue(:download_avatar_from_url, url: avatar_url, user_id: user.id) if avatar_url.present? + Jobs.enqueue(:download_avatar_from_url, url: avatar_url, user_id: user.id, override_gravatar: SiteSetting.sso_overrides_avatar) if avatar_url.present? user.create_single_sign_on_record( last_payload: unsigned_payload, external_id: external_id, @@ -180,7 +180,7 @@ class DiscourseSingleSignOn < SingleSignOn avatar_changed = sso_record.external_avatar_url != avatar_url if avatar_force_update || avatar_changed || avatar_missing - Jobs.enqueue(:download_avatar_from_url, url: avatar_url, user_id: user.id) + Jobs.enqueue(:download_avatar_from_url, url: avatar_url, user_id: user.id, override_gravatar: SiteSetting.sso_overrides_avatar) end end diff --git a/app/models/email_change_request.rb b/app/models/email_change_request.rb index 229b858d470..9778e84be3a 100644 --- a/app/models/email_change_request.rb +++ b/app/models/email_change_request.rb @@ -1,6 +1,12 @@ +require_dependency 'email_validator' + class EmailChangeRequest < ActiveRecord::Base belongs_to :old_email_token, class_name: 'EmailToken' belongs_to :new_email_token, class_name: 'EmailToken' + belongs_to :user + + validates :old_email, presence: true + validates :new_email, presence: true, format: { with: EmailValidator.email_regex } def self.states @states ||= Enum.new(authorizing_old: 1, authorizing_new: 2, complete: 3) diff --git a/app/models/email_token.rb b/app/models/email_token.rb index b20450be78f..820ea078f9b 100644 --- a/app/models/email_token.rb +++ b/app/models/email_token.rb @@ -23,10 +23,6 @@ class EmailToken < ActiveRecord::Base SiteSetting.email_token_valid_hours.hours.ago end - def self.confirm_valid_after - SiteSetting.email_token_grace_period_hours.hours.ago - end - def self.unconfirmed where(confirmed: false) end @@ -52,7 +48,7 @@ class EmailToken < ActiveRecord::Base user = email_token.user failure[:user] = user - row_count = EmailToken.where(id: email_token.id, expired: false).update_all 'confirmed = true' + row_count = EmailToken.where(confirmed: false, id: email_token.id, expired: false).update_all 'confirmed = true' if row_count == 1 { success: true, user: user, email_token: email_token } @@ -85,8 +81,8 @@ class EmailToken < ActiveRecord::Base def self.confirmable(token) EmailToken.where(token: token) - .where(expired: false) - .where("(NOT confirmed AND created_at >= ?) OR (confirmed AND created_at >= ?)", EmailToken.valid_after, EmailToken.confirm_valid_after) + .where(expired: false, confirmed: false) + .where("created_at >= ?", EmailToken.valid_after) .includes(:user) .first end diff --git a/app/models/emoji.rb b/app/models/emoji.rb index 6eb570fce4b..c58cff9dd32 100644 --- a/app/models/emoji.rb +++ b/app/models/emoji.rb @@ -66,6 +66,7 @@ class Emoji def self.create_for(file, name) extension = File.extname(file.original_filename) path = "#{Emoji.base_directory}/#{name}#{extension}" + full_path = "#{Rails.root}/#{path}" # store the emoji FileUtils.mkdir_p(Pathname.new(path).dirname) @@ -73,7 +74,7 @@ class Emoji # clear the cache Emoji.clear_cache # launch resize job - Jobs.enqueue(:resize_emoji, path: path) + Jobs.enqueue(:resize_emoji, path: full_path) # return created emoji Emoji[name] end diff --git a/app/models/global_setting.rb b/app/models/global_setting.rb index dd1c04820ef..a7600d48206 100644 --- a/app/models/global_setting.rb +++ b/app/models/global_setting.rb @@ -145,14 +145,14 @@ class GlobalSetting attr_accessor :provider end - - if Rails.env == "test" - @provider = BlankProvider.new - else - @provider = - FileProvider.from(File.expand_path('../../../config/discourse.conf', __FILE__)) || - EnvProvider.new + def self.configure! + if Rails.env == "test" + @provider = BlankProvider.new + else + @provider = + FileProvider.from(File.expand_path('../../../config/discourse.conf', __FILE__)) || + EnvProvider.new + end end - load_defaults end diff --git a/app/models/group.rb b/app/models/group.rb index 1adbaa4a292..b97c34356c5 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -1,5 +1,6 @@ class Group < ActiveRecord::Base include HasCustomFields + include AnonCacheInvalidator has_many :category_groups, dependent: :destroy has_many :group_users, dependent: :destroy @@ -514,6 +515,7 @@ end # bio_cooked :text # public :boolean default(FALSE), not null # allow_membership_requests :boolean default(FALSE), not null +# full_name :string # # Indexes # diff --git a/app/models/notification.rb b/app/models/notification.rb index 9d0814c8615..cdac6ed46e3 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -15,6 +15,8 @@ class Notification < ActiveRecord::Base after_save :refresh_notification_count after_destroy :refresh_notification_count + after_commit :send_email + def self.ensure_consistency! Notification.exec_sql(" DELETE FROM Notifications n WHERE notification_type = :id AND @@ -196,6 +198,11 @@ class Notification < ActiveRecord::Base user.publish_notifications_state end + def send_email + transaction_includes_action = self.send(:transaction_include_any_action?, [:create]) + NotificationEmailer.process_notification(self) if transaction_includes_action + end + end # == Schema Information diff --git a/app/models/optimized_image.rb b/app/models/optimized_image.rb index 19953098e97..8af90fded90 100644 --- a/app/models/optimized_image.rb +++ b/app/models/optimized_image.rb @@ -97,7 +97,24 @@ class OptimizedImage < ActiveRecord::Base !(url =~ /^(https?:)?\/\//) end + def self.safe_path?(path) + # this matches instructions which call #to_s + path = path.to_s + return false if path != File.expand_path(path) + return false if path !~ /\A[\w\-\.\/]+\z/m + true + end + + def self.ensure_safe_paths!(*paths) + paths.each do |path| + raise Discourse::InvalidAccess unless safe_path?(path) + end + end + + def self.resize_instructions(from, to, dimensions, opts={}) + ensure_safe_paths!(from, to) + # NOTE: ORDER is important! %W{ convert @@ -115,6 +132,8 @@ class OptimizedImage < ActiveRecord::Base end def self.resize_instructions_animated(from, to, dimensions, opts={}) + ensure_safe_paths!(from, to) + %W{ gifsicle --colors=256 @@ -126,6 +145,8 @@ class OptimizedImage < ActiveRecord::Base end def self.crop_instructions(from, to, dimensions, opts={}) + ensure_safe_paths!(from, to) + %W{ convert #{from}[0] @@ -141,6 +162,8 @@ class OptimizedImage < ActiveRecord::Base end def self.crop_instructions_animated(from, to, dimensions, opts={}) + ensure_safe_paths!(from, to) + %W{ gifsicle --crop 0,0+#{dimensions} @@ -152,6 +175,8 @@ class OptimizedImage < ActiveRecord::Base end def self.downsize_instructions(from, to, dimensions, opts={}) + ensure_safe_paths!(from, to) + %W{ convert #{from}[0] diff --git a/app/models/post.rb b/app/models/post.rb index e262f259ba7..4670b6c0758 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -51,6 +51,9 @@ class Post < ActiveRecord::Base validates_with ::Validators::PostValidator + after_save :index_search + after_save :create_user_action + # We can pass several creating options to a post via attributes attr_accessor :image_sizes, :quoted_post_numbers, :no_bump, :invalidate_oneboxes, :cooking_options, :skip_unique_check @@ -66,10 +69,13 @@ class Post < ActiveRecord::Base scope :visible, -> { joins(:topic).where('topics.visible = true').where(hidden: false) } scope :secured, lambda { |guardian| where('posts.post_type in (?)', Topic.visible_post_types(guardian && guardian.user))} scope :for_mailing_list, ->(user, since) { - created_since(since) - .joins(:topic) - .where(topic: Topic.for_digest(user, 100.years.ago)) # we want all topics with new content, regardless when they were created - .order('posts.created_at ASC') + q = created_since(since) + .joins(:topic) + .where(topic: Topic.for_digest(user, 100.years.ago)) # we want all topics with new content, regardless when they were created + + q = q.where.not(post_type: Post.types[:whisper]) unless user.staff? + + q.order('posts.created_at ASC') } scope :mailing_list_new_topics, ->(user, since) { for_mailing_list(user, since).where('topics.created_at > ?', since) } scope :mailing_list_updates, ->(user, since) { for_mailing_list(user, since).where('topics.created_at <= ?', since) } @@ -126,7 +132,8 @@ class Post < ActiveRecord::Base updated_at: Time.now, user_id: user_id, last_editor_id: last_editor_id, - type: type + type: type, + version: version }.merge(options) if Topic.visible_post_types.include?(post_type) @@ -447,7 +454,7 @@ class Post < ActiveRecord::Base new_cooked = cook(raw, topic_id: topic_id, invalidate_oneboxes: opts.fetch(:invalidate_oneboxes, false)) old_cooked = cooked - update_columns(cooked: new_cooked, baked_at: Time.new, baked_version: BAKED_VERSION) + self.update!(cooked: new_cooked, baked_at: Time.new, baked_version: BAKED_VERSION) # Extracts urls from the body TopicLink.extract_from(self) @@ -636,6 +643,14 @@ class Post < ActiveRecord::Base PostTiming.where(topic_id: topic_id, post_number: post_number, user_id: user.id).exists? end + def index_search + SearchIndexer.index(self) + end + + def create_user_action + UserActionCreator.log_post(self) + end + private def parse_quote_into_arguments(quote) diff --git a/app/models/post_action.rb b/app/models/post_action.rb index 5bc031ccae5..e90767a087c 100644 --- a/app/models/post_action.rb +++ b/app/models/post_action.rb @@ -22,6 +22,9 @@ class PostAction < ActiveRecord::Base after_save :update_counters after_save :enforce_rules + after_save :create_user_action + after_save :update_notifications + after_create :create_notifications after_commit :notify_subscribers def disposed_by_id @@ -280,7 +283,7 @@ SQL post_action.recover! action_attrs.each { |attr, val| post_action.send("#{attr}=", val) } post_action.save - PostAlertObserver.after_create_post_action(post_action) + PostActionNotifier.post_action_created(post_action) else post_action = create(where_attrs.merge(action_attrs)) if post_action && post_action.errors.count == 0 @@ -453,6 +456,22 @@ SQL SpamRulesEnforcer.enforce!(post.user) end + def create_user_action + if is_bookmark? || is_like? + UserActionCreator.log_post_action(self) + end + end + + def update_notifications + if self.deleted_at.present? + PostActionNotifier.post_action_deleted(self) + end + end + + def create_notifications + PostActionNotifier.post_action_created(self) + end + def notify_subscribers if (is_like? || is_flag?) && post post.publish_change_to_clients! :acted diff --git a/app/models/post_action_type.rb b/app/models/post_action_type.rb index 48935123b03..6af07c53af6 100644 --- a/app/models/post_action_type.rb +++ b/app/models/post_action_type.rb @@ -5,6 +5,8 @@ class PostActionType < ActiveRecord::Base after_save :expire_cache after_destroy :expire_cache + include AnonCacheInvalidator + def expire_cache ApplicationSerializer.expire_cache_fragment!("post_action_types") ApplicationSerializer.expire_cache_fragment!("post_action_flag_types") diff --git a/app/models/post_revision.rb b/app/models/post_revision.rb index a11a1f35ed7..0a7016966dd 100644 --- a/app/models/post_revision.rb +++ b/app/models/post_revision.rb @@ -6,6 +6,8 @@ class PostRevision < ActiveRecord::Base serialize :modifications, Hash + after_create :create_notification + def self.ensure_consistency! # 1 - fix the numbers PostRevision.exec_sql <<-SQL @@ -34,6 +36,10 @@ class PostRevision < ActiveRecord::Base update_column(:hidden, false) end + def create_notification + PostActionNotifier.after_create_post_revision(self) + end + end # == Schema Information diff --git a/app/models/site_customization.rb b/app/models/site_customization.rb index 703ba8eeab6..4b2e0ab988e 100644 --- a/app/models/site_customization.rb +++ b/app/models/site_customization.rb @@ -5,7 +5,7 @@ require_dependency 'distributed_cache' class SiteCustomization < ActiveRecord::Base ENABLED_KEY = '7e202ef2-56d7-47d5-98d8-a9c8d15e57dd' - COMPILER_VERSION = 2 + COMPILER_VERSION = 4 @cache = DistributedCache.new('site_customization') @@ -45,20 +45,27 @@ PLUGIN_API_JS doc = Nokogiri::HTML.fragment(html) doc.css('script[type="text/x-handlebars"]').each do |node| name = node["name"] || node["data-template-name"] || "broken" - precompiled = - if name =~ /\.raw$/ - "require('discourse-common/lib/raw-handlebars').template(#{Barber::Precompiler.compile(node.inner_html)})" - else - "Ember.HTMLBars.template(#{Barber::Ember::Precompiler.compile(node.inner_html)})" - end - - node.replace < - (function() { - Ember.TEMPLATES[#{name.inspect}] = #{precompiled}; - })(); - + is_raw = name =~ /\.raw$/ + if is_raw + template = "require('discourse-common/lib/raw-handlebars').template(#{Barber::Precompiler.compile(node.inner_html)})" + node.replace < + (function() { + Discourse.RAW_TEMPLATES[#{name.sub(/\.raw$/, '').inspect}] = #{template}; + })(); + COMPILED + else + template = "Ember.HTMLBars.template(#{Barber::Ember::Precompiler.compile(node.inner_html)})" + node.replace < + (function() { + Ember.TEMPLATES[#{name.inspect}] = #{template}; + })(); + +COMPILED + end + end doc.css('script[type="text/discourse-plugin"]').each do |node| diff --git a/app/models/topic.rb b/app/models/topic.rb index 577c9315a01..1e8078051fd 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -7,7 +7,6 @@ require_dependency 'text_cleaner' require_dependency 'archetype' require_dependency 'html_prettify' require_dependency 'discourse_tagging' -require_dependency 'discourse_featured_link' class Topic < ActiveRecord::Base include ActionView::Helpers::SanitizeHelper @@ -55,6 +54,7 @@ class Topic < ActiveRecord::Base validates :title, :if => Proc.new { |t| t.new_record? || t.title_changed? }, :presence => true, :topic_title_length => true, + :censored_words => true, :quality_title => { :unless => :private_message? }, :unique_among => { :unless => Proc.new { |t| (SiteSetting.allow_duplicate_topic_titles? || t.private_message?) }, :message => :has_already_been_used, @@ -76,11 +76,12 @@ class Topic < ActiveRecord::Base validates :featured_link, allow_nil: true, format: URI::regexp(%w(http https)) validate if: :featured_link do - errors.add(:featured_link, :invalid_category) unless Guardian.new.can_edit_featured_link?(category_id) + errors.add(:featured_link, :invalid_category) unless !featured_link_changed? || Guardian.new.can_edit_featured_link?(category_id) end before_validation do self.title = TextCleaner.clean_title(TextSentinel.title_sentinel(title).text) if errors[:title].empty? + self.featured_link.strip! if self.featured_link end belongs_to :category @@ -198,6 +199,9 @@ class Topic < ActiveRecord::Base TagUser.auto_track(topic_id: id) self.tags_changed = false end + + SearchIndexer.index(self) + UserActionCreator.log_topic(self) end def initialize_default_values @@ -338,7 +342,7 @@ class Topic < ActiveRecord::Base .listable_topics .includes(:category) - unless user.user_option.try(:include_tl0_in_digests) + unless opts[:include_tl0] || user.user_option.try(:include_tl0_in_digests) topics = topics.where("COALESCE(users.trust_level, 0) > 0") end @@ -383,14 +387,6 @@ class Topic < ActiveRecord::Base featured_topic_ids ? topics.where("topics.id NOT IN (?)", featured_topic_ids) : topics end - def featured_link - custom_fields[DiscourseFeaturedLink::CUSTOM_FIELD_NAME] - end - - def featured_link=(link) - custom_fields[DiscourseFeaturedLink::CUSTOM_FIELD_NAME] = link.strip - end - def meta_data=(data) custom_fields.replace(data) end diff --git a/app/models/topic_list.rb b/app/models/topic_list.rb index f758a358afb..e0b3fd8353b 100644 --- a/app/models/topic_list.rb +++ b/app/models/topic_list.rb @@ -1,5 +1,4 @@ require_dependency 'avatar_lookup' -require_dependency 'discourse_featured_link' class TopicList include ActiveModel::Serialization @@ -28,7 +27,6 @@ class TopicList end preloaded_custom_fields << DiscourseTagging::TAGS_FIELD_NAME if SiteSetting.tagging_enabled - preloaded_custom_fields << DiscourseFeaturedLink::CUSTOM_FIELD_NAME if SiteSetting.topic_featured_link_enabled end def tags diff --git a/app/models/topic_user.rb b/app/models/topic_user.rb index f4369f56988..49c43e7b4e0 100644 --- a/app/models/topic_user.rb +++ b/app/models/topic_user.rb @@ -132,8 +132,6 @@ SQL if rows == 0 create_missing_record(user_id, topic_id, attrs) - else - observe_after_save_callbacks_for topic_id, user_id end end @@ -203,8 +201,6 @@ SQL if rows == 0 change(user_id, topic_id, last_visited_at: now, first_visited_at: now) - else - observe_after_save_callbacks_for(topic_id, user_id) end end @@ -323,11 +319,6 @@ SQL end end - def observe_after_save_callbacks_for(topic_id, user_id) - TopicUser.where(topic_id: topic_id, user_id: user_id).each do |topic_user| - UserActionObserver.instance.after_save topic_user - end - end end def self.update_post_action_cache(opts={}) diff --git a/app/models/upload.rb b/app/models/upload.rb index cf95ec5aa28..d6119abc13c 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -95,6 +95,8 @@ class Upload < ActiveRecord::Base # - image_type ("avatar", "profile_background", "card_background") # - is_attachment_for_group_message (boolean) def self.create_for(user_id, file, filename, filesize, options = {}) + upload = Upload.new + DistributedMutex.synchronize("upload_#{user_id}_#{filename}") do # do some work on images if FileHelper.is_image?(filename) && is_actual_image?(file) @@ -105,13 +107,19 @@ class Upload < ActiveRecord::Base File.write(file.path, doc.to_s) file.rewind else + # ensure image isn't huge + w, h = FastImage.size(file) || [0, 0] + if w * h >= SiteSetting.max_image_megapixels * 1_000_000 + upload.errors.add(:base, I18n.t("upload.images.larger_than_x_megapixels", max_image_megapixels: SiteSetting.max_image_megapixels)) + return upload + end + # fix orientation first fix_image_orientation(file.path) if should_optimize?(file.path) end # retrieve image info - image_info = FastImage.new(file) - w, h = *(image_info.try(:size) || [0, 0]) + w, h = FastImage.size(file) || [0, 0] # default size width, height = ImageSizer.resize(w, h) @@ -214,8 +222,7 @@ class Upload < ActiveRecord::Base # don't optimize GIFs or SVGs return false if path =~ /\.(gif|svg)$/i return true if path !~ /\.png$/i - image_info = FastImage.new(path) rescue nil - w, h = *(image_info.try(:size) || [0, 0]) + w, h = FastImage.size(path) || [0, 0] # don't optimize large PNGs w > 0 && h > 0 && w * h < LARGE_PNG_SIZE end diff --git a/app/models/user.rb b/app/models/user.rb index e363f5dd55a..0efcb78c84a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,5 +1,6 @@ require_dependency 'email' require_dependency 'email_token' +require_dependency 'email_validator' require_dependency 'trust_level' require_dependency 'pbkdf2' require_dependency 'discourse' @@ -39,6 +40,7 @@ class User < ActiveRecord::Base has_many :warnings has_many :user_archived_messages, dependent: :destroy has_many :email_change_requests, dependent: :destroy + has_many :directory_items, dependent: :delete_all has_one :user_option, dependent: :destroy @@ -76,9 +78,10 @@ class User < ActiveRecord::Base validates_presence_of :username validate :username_validator, if: :username_changed? validates :email, presence: true, uniqueness: true + validates :email, format: { with: EmailValidator.email_regex }, if: :email_changed? validates :email, email: true, if: :should_validate_email? validate :password_validator - validates :name, user_full_name: true, if: :name_changed? + validates :name, user_full_name: true, if: :name_changed?, length: { maximum: 255 } validates :ip_address, allowed_ip_address: {on: :create, message: :signup_not_allowed} after_initialize :add_trust_level @@ -88,17 +91,18 @@ class User < ActiveRecord::Base after_create :create_user_option after_create :create_user_profile after_create :ensure_in_trust_level_group - after_create :automatic_group_membership after_create :set_default_categories_preferences after_create :trigger_user_created_event before_save :update_username_lower before_save :ensure_password_is_hashed + after_save :automatic_group_membership after_save :clear_global_notice_if_needed after_save :refresh_avatar after_save :badge_grant after_save :expire_old_email_tokens + after_save :index_search before_destroy do # These tables don't have primary keys, so destroying them with activerecord is tricky: @@ -913,6 +917,10 @@ class User < ActiveRecord::Base end end + def index_search + SearchIndexer.index(self) + end + def clear_global_notice_if_needed if admin && SiteSetting.has_login_hint SiteSetting.has_login_hint = false @@ -928,10 +936,13 @@ class User < ActiveRecord::Base Group.where(automatic: false) .where("LENGTH(COALESCE(automatic_membership_email_domains, '')) > 0") .each do |group| + domains = group.automatic_membership_email_domains.gsub('.', '\.') - if self.email =~ Regexp.new("@(#{domains})$", true) && !group.users.include?(self) - group.add(self) - GroupActionLogger.new(Discourse.system_user, group).log_add_user_to_group(self) + user = User.find(self.id) + + if user.reload.email =~ Regexp.new("@(#{domains})$", true) && !group.users.include?(user) + group.add(user) + GroupActionLogger.new(Discourse.system_user, group).log_add_user_to_group(user) end end end diff --git a/app/models/user_action.rb b/app/models/user_action.rb index 042d4a53976..5051302b81d 100644 --- a/app/models/user_action.rb +++ b/app/models/user_action.rb @@ -277,7 +277,9 @@ SQL MessageBus.publish("/user/#{hash[:user_id]}", {user_action_id: action.id, remove: true}) end - update_like_count(hash[:user_id], hash[:action_type], -1) + if !Topic.where(id: hash[:target_topic_id], archetype: Archetype.private_message).exists? + update_like_count(hash[:user_id], hash[:action_type], -1) + end end def self.synchronize_target_topic_ids(post_ids = nil) @@ -352,8 +354,24 @@ SQL builder.where('a.action_type <> :pending', pending: UserAction::PENDING) end - if !guardian.can_see_private_messages?(user_id) || ignore_private_messages - builder.where("t.archetype != :archetype", archetype: Archetype::private_message) + if !guardian.can_see_private_messages?(user_id) || ignore_private_messages || !guardian.user + builder.where("t.archetype <> :private_message", private_message: Archetype::private_message) + else + unless guardian.is_admin? + sql = <<~SQL + t.archetype <> :private_message OR + EXISTS ( + SELECT 1 FROM topic_allowed_users tu WHERE tu.topic_id = t.id AND tu.user_id = :current_user_id + ) OR + EXISTS ( + SELECT 1 FROM topic_allowed_groups tg WHERE tg.topic_id = t.id AND tg.group_id IN ( + SELECT group_id FROM group_users gu WHERE gu.user_id = :current_user_id + ) + ) + SQL + + builder.where(sql, private_message: Archetype::private_message, current_user_id: guardian.user.id) + end end unless guardian.is_admin? diff --git a/app/models/user_field.rb b/app/models/user_field.rb index 751b65755a1..6505982b9cc 100644 --- a/app/models/user_field.rb +++ b/app/models/user_field.rb @@ -1,4 +1,7 @@ class UserField < ActiveRecord::Base + + include AnonCacheInvalidator + validates_presence_of :name, :description, :field_type has_many :user_field_options, dependent: :destroy accepts_nested_attributes_for :user_field_options diff --git a/app/models/user_history.rb b/app/models/user_history.rb index 635014b1d08..50b616391c3 100644 --- a/app/models/user_history.rb +++ b/app/models/user_history.rb @@ -51,12 +51,17 @@ class UserHistory < ActiveRecord::Base revoke_admin: 33, grant_moderation: 34, revoke_moderation: 35, - backup_operation: 36, + backup_create: 36, rate_limited_like: 37, # not used anymore revoke_email: 38, deactivate_user: 39, - wizard_step: 40 - ) + wizard_step: 40, + lock_trust_level: 41, + unlock_trust_level: 42, + activate_user: 43, + change_readonly_mode: 44, + backup_download: 45, + backup_destroy: 46) end # Staff actions is a subset of all actions, used to audit actions taken by staff users. @@ -89,9 +94,15 @@ class UserHistory < ActiveRecord::Base :revoke_admin, :grant_moderation, :revoke_moderation, - :backup_operation, + :backup_create, :revoke_email, - :deactivate_user] + :deactivate_user, + :lock_trust_level, + :unlock_trust_level, + :activate_user, + :change_readonly_mode, + :backup_download, + :backup_destroy] end def self.staff_action_ids diff --git a/app/models/user_profile.rb b/app/models/user_profile.rb index c05caea3b20..be6484552c5 100644 --- a/app/models/user_profile.rb +++ b/app/models/user_profile.rb @@ -12,6 +12,8 @@ class UserProfile < ActiveRecord::Base validates :profile_background, upload_url: true, if: :profile_background_changed? validates :card_background, upload_url: true, if: :card_background_changed? + validate :website_domain_validator, if: Proc.new { |c| c.new_record? || c.website_changed? } + belongs_to :card_image_badge, class_name: 'Badge' has_many :user_profile_views, dependent: :destroy @@ -102,6 +104,14 @@ class UserProfile < ActiveRecord::Base end end + def website_domain_validator + allowed_domains = SiteSetting.user_website_domains_whitelist + return if (allowed_domains.blank? || self.website.blank?) + + domain = URI.parse(self.website).host + self.errors.add :base, (I18n.t('user.website.domain_not_allowed', domains: allowed_domains.split('|').join(", "))) unless allowed_domains.split('|').include?(domain) + end + end # == Schema Information diff --git a/app/models/user_search.rb b/app/models/user_search.rb index 56a40af3429..2b1c05f0ded 100644 --- a/app/models/user_search.rb +++ b/app/models/user_search.rb @@ -1,4 +1,6 @@ # Searches for a user by username or full text or name (if enabled in SiteSettings) +require_dependency 'search' + class UserSearch def initialize(term, opts={}) diff --git a/app/models/username_validator.rb b/app/models/username_validator.rb index 0dbae4bae6e..eeb4df859de 100644 --- a/app/models/username_validator.rb +++ b/app/models/username_validator.rb @@ -1,3 +1,5 @@ +require_dependency 'user' + class UsernameValidator # Public: Perform the validation of a field in a given object # it adds the errors (if any) to the object that we're giving as parameter diff --git a/app/models/web_hook.rb b/app/models/web_hook.rb index 9884bbf52eb..4eed81e6bef 100644 --- a/app/models/web_hook.rb +++ b/app/models/web_hook.rb @@ -71,7 +71,7 @@ class WebHook < ActiveRecord::Base WebHook.enqueue_topic_hooks(:topic_edited, post.topic) if post.is_first_post? && topic_changed end - %i(user_created user_approved).each do |event| + %i(user_created user_approved user_updated).each do |event| DiscourseEvent.on(event) do |user| WebHook.enqueue_hooks(:user, user_id: user.id, event_name: event.to_s) end diff --git a/app/serializers/admin_email_template_serializer.rb b/app/serializers/admin_email_template_serializer.rb index 05779d3e237..0a670091ed9 100644 --- a/app/serializers/admin_email_template_serializer.rb +++ b/app/serializers/admin_email_template_serializer.rb @@ -6,7 +6,11 @@ class AdminEmailTemplateSerializer < ApplicationSerializer end def title - object.gsub(/.*\./, '').titleize + if I18n.exists?("#{object}.title") + I18n.t("#{object}.title") + else + object.gsub(/.*\./, '').titleize + end end def subject diff --git a/app/serializers/basic_group_serializer.rb b/app/serializers/basic_group_serializer.rb index 264013cbdaf..b37184e7232 100644 --- a/app/serializers/basic_group_serializer.rb +++ b/app/serializers/basic_group_serializer.rb @@ -18,7 +18,8 @@ class BasicGroupSerializer < ApplicationSerializer :bio_raw, :bio_cooked, :public, - :allow_membership_requests + :allow_membership_requests, + :full_name def include_incoming_email? staff? diff --git a/app/serializers/category_serializer.rb b/app/serializers/category_serializer.rb index 5e487a570ed..beb7ae1d07b 100644 --- a/app/serializers/category_serializer.rb +++ b/app/serializers/category_serializer.rb @@ -9,13 +9,15 @@ class CategorySerializer < BasicCategorySerializer :email_in, :email_in_allow_strangers, :suppress_from_homepage, + :all_topics_wiki, :can_delete, :cannot_delete_reason, :is_special, :allow_badges, :custom_fields, :allowed_tags, - :allowed_tag_groups + :allowed_tag_groups, + :topic_featured_link_allowed def group_permissions @group_permissions ||= begin diff --git a/app/serializers/post_revision_serializer.rb b/app/serializers/post_revision_serializer.rb index 8ff8b1826e3..6fe950739d2 100644 --- a/app/serializers/post_revision_serializer.rb +++ b/app/serializers/post_revision_serializer.rb @@ -23,7 +23,8 @@ class PostRevisionSerializer < ApplicationSerializer :body_changes, :title_changes, :user_changes, - :tags_changes + :tags_changes, + :wiki # Creates a field called field_name_changes with previous and @@ -95,6 +96,10 @@ class PostRevisionSerializer < ApplicationSerializer user.avatar_template end + def wiki + object.post.wiki + end + def edit_reason # only show 'edit_reason' when revisions are consecutive current["edit_reason"] if scope.can_view_hidden_post_revisions? || diff --git a/app/serializers/topic_post_count_serializer.rb b/app/serializers/topic_post_count_serializer.rb index c780d120312..70cac7fa574 100644 --- a/app/serializers/topic_post_count_serializer.rb +++ b/app/serializers/topic_post_count_serializer.rb @@ -1,6 +1,7 @@ class TopicPostCountSerializer < BasicUserSerializer - attributes :post_count + attributes :post_count, :primary_group_name, + :primary_group_flair_url, :primary_group_flair_color, :primary_group_flair_bg_color def id object[:user].id @@ -14,4 +15,21 @@ class TopicPostCountSerializer < BasicUserSerializer object[:post_count] end + def primary_group_name + return nil unless object[:user].primary_group_id + object[:user]&.primary_group&.name + end + + def primary_group_flair_url + object[:user]&.primary_group&.flair_url + end + + def primary_group_flair_bg_color + object[:user]&.primary_group&.flair_bg_color + end + + def primary_group_flair_color + object[:user]&.primary_group&.flair_color + end + end diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index ece099e4f1f..426e24ee8e0 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -274,7 +274,7 @@ class BadgeGranter /*where*/ RETURNING id, user_id, granted_at ) - select w.*, username, locale FROM w + select w.*, username, locale, (u.admin OR u.moderator) AS staff FROM w JOIN users u on u.id = w.user_id " @@ -315,6 +315,8 @@ class BadgeGranter # Make this variable in this scope notification = nil + next if (row.staff && badge.awarded_for_trust_level?) + I18n.with_locale(notification_locale) do notification = Notification.create!( user_id: row.user_id, diff --git a/app/services/group_action_logger.rb b/app/services/group_action_logger.rb index 1518c0d0138..9f1f429a8f2 100644 --- a/app/services/group_action_logger.rb +++ b/app/services/group_action_logger.rb @@ -1,4 +1,5 @@ class GroupActionLogger + def initialize(acting_user, group) @acting_user = acting_user @group = group @@ -57,22 +58,21 @@ class GroupActionLogger private - def excluded_attributes - [ - :bio_cooked, - :updated_at, - :created_at, - :user_count - ] - end - - def default_params - { group: @group, acting_user: @acting_user } - end - - def can_edit? - unless Guardian.new(@acting_user).can_log_group_changes?(@group) - raise Discourse::InvalidParameter + def excluded_attributes + [ + :bio_cooked, + :updated_at, + :created_at, + :user_count + ] end - end + + def default_params + { group: @group, acting_user: @acting_user } + end + + def can_edit? + raise Discourse::InvalidParameters.new unless Guardian.new(@acting_user).can_log_group_changes?(@group) + end + end diff --git a/app/models/user_email_observer.rb b/app/services/notification_emailer.rb similarity index 90% rename from app/models/user_email_observer.rb rename to app/services/notification_emailer.rb index bb410294da7..534d4037a13 100644 --- a/app/models/user_email_observer.rb +++ b/app/services/notification_emailer.rb @@ -1,5 +1,4 @@ -class UserEmailObserver < ActiveRecord::Observer - observe :notification +class NotificationEmailer class EmailUser attr_reader :notification @@ -105,12 +104,17 @@ class UserEmailObserver < ActiveRecord::Observer end - def after_commit(notification) - transaction_includes_action = notification.send(:transaction_include_any_action?, [:create]) - self.class.process_notification(notification) if transaction_includes_action + def self.disable + @disabled = true + end + + def self.enable + @disabled = false end def self.process_notification(notification) + return if @disabled + email_user = EmailUser.new(notification) email_method = Notification.types[notification.notification_type] diff --git a/app/models/post_alert_observer.rb b/app/services/post_action_notifier.rb similarity index 73% rename from app/models/post_alert_observer.rb rename to app/services/post_action_notifier.rb index f1913ab7767..345e6aa735a 100644 --- a/app/models/post_alert_observer.rb +++ b/app/services/post_action_notifier.rb @@ -1,27 +1,18 @@ -class PostAlertObserver < ActiveRecord::Observer - observe :post_action, :post_revision +class PostActionNotifier + + def self.disable + @disabled = true + end + + def self.enable + @disabled = false + end def self.alerter @alerter ||= PostAlerter.new end - def alerter - self.class.alerter - end - - # Dispatch to an after_save_#{class_name} method - def after_save(model) - method_name = callback_for('after_save', model) - send(method_name, model) if respond_to?(method_name) - end - - # Dispatch to an after_create_#{class_name} method - def after_create(model) - method_name = callback_for('after_create', model) - send(method_name, model) if respond_to?(method_name) - end - - def refresh_like_notification(post, read) + def self.refresh_like_notification(post, read) return unless post && post.user_id usernames = post.post_actions.where(post_action_type_id: PostActionType.types[:like]) @@ -49,7 +40,10 @@ class PostAlertObserver < ActiveRecord::Observer end end - def after_save_post_action(post_action) + def self.post_action_deleted(post_action) + + return if @disabled + # We only care about deleting post actions for now return if post_action.deleted_at.blank? @@ -74,7 +68,10 @@ class PostAlertObserver < ActiveRecord::Observer end end - def self.after_create_post_action(post_action) + def self.post_action_created(post_action) + + return if @disabled + # We only notify on likes for now return unless post_action.is_like? @@ -91,11 +88,10 @@ class PostAlertObserver < ActiveRecord::Observer ) end - def after_create_post_action(post_action) - self.class.after_create_post_action(post_action) - end + def self.after_create_post_revision(post_revision) + + return if @disabled - def after_create_post_revision(post_revision) post = post_revision.post return unless post @@ -113,10 +109,4 @@ class PostAlertObserver < ActiveRecord::Observer ) end - protected - - def callback_for(action, model) - "#{action}_#{model.class.name.underscore.gsub(/.+\//, '')}" - end - end diff --git a/app/services/post_alerter.rb b/app/services/post_alerter.rb index 00e27ab3727..4f2d9026a72 100644 --- a/app/services/post_alerter.rb +++ b/app/services/post_alerter.rb @@ -343,7 +343,7 @@ class PostAlerter end end - UserActionObserver.log_notification(original_post, user, type, opts[:acting_user_id]) + UserActionCreator.log_notification(original_post, user, type, opts[:acting_user_id]) topic_title = post.topic.title # when sending a private message email, keep the original title diff --git a/app/models/search_observer.rb b/app/services/search_indexer.rb similarity index 83% rename from app/models/search_observer.rb rename to app/services/search_indexer.rb index e45e5b2d9b4..08478265679 100644 --- a/app/models/search_observer.rb +++ b/app/services/search_indexer.rb @@ -1,7 +1,14 @@ require_dependency 'search' -class SearchObserver < ActiveRecord::Observer - observe :topic, :post, :user, :category +class SearchIndexer + + def self.disable + @disabled = true + end + + def self.enable + @disabled = false + end def self.scrub_html_for_search(html) HtmlScrubber.scrub(html) @@ -72,17 +79,19 @@ class SearchObserver < ActiveRecord::Observer end def self.index(obj) + return if @disabled + if obj.class == Post && obj.cooked_changed? if obj.topic category_name = obj.topic.category.name if obj.topic.category - SearchObserver.update_posts_index(obj.id, obj.cooked, obj.topic.title, category_name) - SearchObserver.update_topics_index(obj.topic_id, obj.topic.title, obj.cooked) if obj.is_first_post? + SearchIndexer.update_posts_index(obj.id, obj.cooked, obj.topic.title, category_name) + SearchIndexer.update_topics_index(obj.topic_id, obj.topic.title, obj.cooked) if obj.is_first_post? else - Rails.logger.warn("Orphan post skipped in search_observer, topic_id: #{obj.topic_id} post_id: #{obj.id} raw: #{obj.raw}") + Rails.logger.warn("Orphan post skipped in search_indexer, topic_id: #{obj.topic_id} post_id: #{obj.id} raw: #{obj.raw}") end end if obj.class == User && (obj.username_changed? || obj.name_changed?) - SearchObserver.update_users_index(obj.id, obj.username_lower || '', obj.name ? obj.name.downcase : '') + SearchIndexer.update_users_index(obj.id, obj.username_lower || '', obj.name ? obj.name.downcase : '') end if obj.class == Topic && obj.title_changed? @@ -90,21 +99,17 @@ class SearchObserver < ActiveRecord::Observer post = obj.posts.find_by(post_number: 1) if post category_name = obj.category.name if obj.category - SearchObserver.update_posts_index(post.id, post.cooked, obj.title, category_name) - SearchObserver.update_topics_index(obj.id, obj.title, post.cooked) + SearchIndexer.update_posts_index(post.id, post.cooked, obj.title, category_name) + SearchIndexer.update_topics_index(obj.id, obj.title, post.cooked) end end end if obj.class == Category && obj.name_changed? - SearchObserver.update_categories_index(obj.id, obj.name) + SearchIndexer.update_categories_index(obj.id, obj.name) end end - def after_save(object) - SearchObserver.index(object) - end - class HtmlScrubber < Nokogiri::XML::SAX::Document attr_reader :scrubbed diff --git a/app/services/staff_action_logger.rb b/app/services/staff_action_logger.rb index 57c213b4e2f..2bd24889fe7 100644 --- a/app/services/staff_action_logger.rb +++ b/app/services/staff_action_logger.rb @@ -14,7 +14,6 @@ class StaffActionLogger raise Discourse::InvalidParameters.new(:deleted_user) unless deleted_user && deleted_user.is_a?(User) UserHistory.create( params(opts).merge({ action: UserHistory.actions[:delete_user], - email: deleted_user.email, ip_address: deleted_user.ip_address.to_s, details: [:id, :username, :name, :created_at, :trust_level, :last_seen_at, :last_emailed_at].map { |x| "#{x}: #{deleted_user.send(x)}" }.join("\n") })) @@ -96,6 +95,14 @@ class StaffActionLogger })) end + def log_lock_trust_level(user, opts={}) + raise Discourse::InvalidParameters.new(:user) unless user && user.is_a?(User) + UserHistory.create!( params(opts).merge({ + action: UserHistory.actions[user.trust_level_locked ? :lock_trust_level : :unlock_trust_level], + target_user_id: user.id + })) + end + def log_site_setting_change(setting_name, previous_value, new_value, opts={}) raise Discourse::InvalidParameters.new(:setting_name) unless setting_name.present? && SiteSetting.respond_to?(setting_name) UserHistory.create( params(opts).merge({ @@ -329,13 +336,31 @@ class StaffActionLogger })) end - def log_backup_operation(opts={}) + def log_backup_create(opts={}) UserHistory.create(params(opts).merge({ - action: UserHistory.actions[:backup_operation], + action: UserHistory.actions[:backup_create], ip_address: @admin.ip_address.to_s })) end + def log_backup_download(backup, opts={}) + raise Discourse::InvalidParameters.new(:backup) unless backup + UserHistory.create(params(opts).merge({ + action: UserHistory.actions[:backup_download], + ip_address: @admin.ip_address.to_s, + details: backup.filename + })) + end + + def log_backup_destroy(backup, opts={}) + raise Discourse::InvalidParameters.new(:backup) unless backup + UserHistory.create(params(opts).merge({ + action: UserHistory.actions[:backup_destroy], + ip_address: @admin.ip_address.to_s, + details: backup.filename + })) + end + def log_revoke_email(user, reason, opts={}) UserHistory.create(params(opts).merge({ action: UserHistory.actions[:revoke_email], @@ -353,15 +378,31 @@ class StaffActionLogger })) end + def log_user_activate(user, reason, opts={}) + raise Discourse::InvalidParameters.new(:user) unless user + UserHistory.create(params(opts).merge({ + action: UserHistory.actions[:activate_user], + target_user_id: user.id, + details: reason + })) + end + def log_wizard_step(step, opts={}) raise Discourse::InvalidParameters.new(:step) unless step UserHistory.create(params(opts).merge({ action: UserHistory.actions[:wizard_step], - acting_user_id: @admin.id, context: step.id })) end + def log_change_readonly_mode(state) + UserHistory.create(params.merge({ + action: UserHistory.actions[:change_readonly_mode], + previous_value: !state, + new_value: state + })) + end + private def params(opts=nil) diff --git a/app/models/user_action_observer.rb b/app/services/user_action_creator.rb similarity index 88% rename from app/models/user_action_observer.rb rename to app/services/user_action_creator.rb index 932e8254ed4..bbf21f9fb9d 100644 --- a/app/models/user_action_observer.rb +++ b/app/services/user_action_creator.rb @@ -1,18 +1,15 @@ -class UserActionObserver < ActiveRecord::Observer - observe :post_action, :topic, :post, :notification, :topic_user +class UserActionCreator + def self.disable + @disabled = true + end - def after_save(model) - case - when (model.is_a?(PostAction) && (model.is_bookmark? || model.is_like?)) - log_post_action(model) - when (model.is_a?(Topic)) - log_topic(model) - when (model.is_a?(Post)) - UserActionObserver.log_post(model) - end + def self.enable + @disabled = false end def self.log_notification(post, user, notification_type, acting_user_id=nil) + return if @disabled + action = case notification_type when Notification.types[:quoted] @@ -44,6 +41,8 @@ class UserActionObserver < ActiveRecord::Observer end def self.log_post(model) + return if @disabled + # first post gets nada return if model.is_first_post? return if model.topic.blank? @@ -78,7 +77,8 @@ class UserActionObserver < ActiveRecord::Observer end end - def log_topic(model) + def self.log_topic(model) + return if @disabled # no action to log here, this can happen if a user is deleted # then topic has no user_id @@ -113,7 +113,9 @@ class UserActionObserver < ActiveRecord::Observer end end - def log_post_action(model) + def self.log_post_action(model) + return if @disabled + action = UserAction::BOOKMARK if model.is_bookmark? action = UserAction::LIKE if model.is_like? diff --git a/app/services/user_blocker.rb b/app/services/user_blocker.rb index 5ee5bc01892..01b5896e887 100644 --- a/app/services/user_blocker.rb +++ b/app/services/user_blocker.rb @@ -17,8 +17,11 @@ class UserBlocker unless @user.blocked? @user.blocked = true if @user.save - SystemMessage.create(@user, @opts[:message] || :blocked_by_staff) - StaffActionLogger.new(@by_user).log_block_user(@user) if @by_user + message_type = @opts[:message] || :blocked_by_staff + post = SystemMessage.create(@user, message_type) + if post && @by_user + StaffActionLogger.new(@by_user).log_block_user(@user, {context: "#{message_type}: '#{post.topic&.title rescue ''}'"}) + end end else false @@ -28,8 +31,8 @@ class UserBlocker def hide_posts return unless @user.trust_level == TrustLevel[0] - Post.where(user_id: @user.id).update_all(["hidden = true, hidden_reason_id = COALESCE(hidden_reason_id, ?)", Post.hidden_reasons[:new_user_spam_threshold_reached]]) - topic_ids = Post.where(user_id: @user.id, post_number: 1).pluck(:topic_id) + Post.where(user_id: @user.id).where("created_at > ?", 24.hours.ago).update_all(["hidden = true, hidden_reason_id = COALESCE(hidden_reason_id, ?)", Post.hidden_reasons[:new_user_spam_threshold_reached]]) + topic_ids = Post.where(user_id: @user.id, post_number: 1).where("created_at > ?", 24.hours.ago).pluck(:topic_id) Topic.where(id: topic_ids).update_all(visible: false) unless topic_ids.empty? end diff --git a/app/services/user_destroyer.rb b/app/services/user_destroyer.rb index edf842f9f6c..4b56229a346 100644 --- a/app/services/user_destroyer.rb +++ b/app/services/user_destroyer.rb @@ -31,15 +31,17 @@ class UserDestroyer # block all external urls if opts[:block_urls] post.topic_links.each do |link| - unless link.internal or Oneboxer.oneboxer_exists_for_url?(link.url) - ScreenedUrl.watch(link.url, link.domain, ip_address: user.ip_address).try(:record_match!) + unless link.internal || + (Oneboxer.engine(link.url) != Onebox::Engine::WhitelistedGenericOnebox) + + ScreenedUrl.watch(link.url, link.domain, ip_address: user.ip_address)&.record_match! end end end PostDestroyer.new(@actor.staff? ? @actor : Discourse.system_user, post).destroy - if post.topic and post.is_first_post? + if post.topic && post.is_first_post? Topic.unscoped.where(id: post.topic.id).update_all(user_id: nil) end end diff --git a/app/services/user_updater.rb b/app/services/user_updater.rb index 524d97db1fb..762a0cd0b91 100644 --- a/app/services/user_updater.rb +++ b/app/services/user_updater.rb @@ -98,7 +98,9 @@ class UserUpdater update_muted_users(attributes[:muted_usernames]) end - (!save_options || user.user_option.save) && user_profile.save && user.save + saved = (!save_options || user.user_option.save) && user_profile.save && user.save + DiscourseEvent.trigger(:user_updated, user) if saved + saved end end diff --git a/app/views/common/_discourse_javascript.html.erb b/app/views/common/_discourse_javascript.html.erb index c214d5e1fda..9e2da0a9005 100644 --- a/app/views/common/_discourse_javascript.html.erb +++ b/app/views/common/_discourse_javascript.html.erb @@ -53,7 +53,7 @@ Discourse.set('assetVersion','<%= Discourse.assets_digest %>'); Discourse.Session.currentProp("disableCustomCSS", <%= loading_admin? %>); <%- if params["safe_mode"] %> - Discourse.Session.currentProp("safe_mode", <%= params["safe_mode"].inspect.html_safe %>); + Discourse.Session.currentProp("safe_mode", <%= normalized_safe_mode.inspect.html_safe %>); <%- end %> Discourse.HighlightJSPath = <%= HighlightJs.path.inspect.html_safe %>; <%- if SiteSetting.enable_s3_uploads %> diff --git a/app/views/embed/embed_error.html.erb b/app/views/embed/embed_error.html.erb new file mode 100644 index 00000000000..65f4c3c43df --- /dev/null +++ b/app/views/embed/embed_error.html.erb @@ -0,0 +1,25 @@ +
    +

    <%= t 'embed.error' %>

    + <%= link_to(image_tag(SiteSetting.logo_url, class: 'logo'), Discourse.base_url) %> +
    +
    +<%- if @show_reason %> +
    + <%- if @hosts.present? %> +

    <%= t 'embed.referer' %><%= request.referer %>

    +

    <%= t 'embed.mismatch' %>

    + +
      + <%- @hosts.each do |eh| %> +
    • + <%= eh.host %><%- if eh.path_whitelist.present? %><%= eh.path_whitelist %><% end %> +
    • + <%- end %> +
    + <%- else %> +

    <%= t 'embed.no_hosts' %>

    + <%- end %> + +

    <%= link_to(t('embed.configure'), @setup_url, target: '_blank') %>

    +
    +<%- end %> diff --git a/app/views/embed/loading.html.erb b/app/views/embed/loading.html.erb index e4c6ccd5d98..2a5621de827 100644 --- a/app/views/embed/loading.html.erb +++ b/app/views/embed/loading.html.erb @@ -1,12 +1,12 @@ -
    - <%= t 'embed.loading' %> +
    +

    <%= t 'embed.loading' %>

    <%= link_to(image_tag(SiteSetting.logo_url, class: 'logo'), Discourse.base_url) %> +
    - \ No newline at end of file + diff --git a/app/views/invites/perform_accept_invitation.html.erb b/app/views/invites/perform_accept_invitation.html.erb new file mode 100644 index 00000000000..cc4b0acc1e7 --- /dev/null +++ b/app/views/invites/perform_accept_invitation.html.erb @@ -0,0 +1,7 @@ +
    + <%if flash[:error]%> +
    + <%=flash[:error]%> +
    + <%end%> +
    diff --git a/app/views/invites/show.html.erb b/app/views/invites/show.html.erb index cc4b0acc1e7..1fdd39e3ee3 100644 --- a/app/views/invites/show.html.erb +++ b/app/views/invites/show.html.erb @@ -3,5 +3,11 @@
    <%=flash[:error]%>
    + <%else%> +

    <%= t 'activation.welcome_to', site_name: SiteSetting.title %>

    +
    + <%= button_to(perform_accept_invite_path, method: :put, class: 'btn btn-primary') do %> + <%= t 'invite.accept_invite' %> + <% end %> <%end%> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 178fd7cbd83..41b321f22d3 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -47,6 +47,10 @@ <%= render_google_universal_analytics_code %> + <%- if SiteSetting.native_app_install_banner? %> + + <%- end %> + <%= yield :head %> diff --git a/app/views/list/list.rss.erb b/app/views/list/list.rss.erb index 78193a8f0d7..d0f6c14957c 100644 --- a/app/views/list/list.rss.erb +++ b/app/views/list/list.rss.erb @@ -6,7 +6,7 @@ <%= @title %> <%= @link %> <%= @description %> - <% if lang %><%= lang%><% end %> + <% if lang %><%= lang.sub('_', '-')%><% end %> <% if @topic_list.topics && @topic_list.topics.length > 0 %> <%= @topic_list.topics.first.created_at.rfc2822 %> diff --git a/app/views/topics/show.rss.erb b/app/views/topics/show.rss.erb index aa7d08c4a85..a7efff93641 100644 --- a/app/views/topics/show.rss.erb +++ b/app/views/topics/show.rss.erb @@ -7,7 +7,7 @@ <%= @topic_view.title %> <%= topic_url %> <%= @topic_view.posts.first.raw %> - <%= "#{lang}" if lang %> + <% if lang %><%= lang.sub('_', '-')%><% end %> <%= @topic_view.topic.bumped_at.rfc2822 %> <%= @topic_view.topic.category.name %> diff --git a/app/views/user_notifications/digest.html.erb b/app/views/user_notifications/digest.html.erb index 4211e8a6615..66e5930732b 100644 --- a/app/views/user_notifications/digest.html.erb +++ b/app/views/user_notifications/digest.html.erb @@ -47,7 +47,7 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
    -
    +
    @@ -58,13 +58,13 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo @@ -121,10 +121,10 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
    - +
    <%- @counts.each do |count| -%> - <%- end -%> <%- @counts.each do |count| -%> - <%- end -%>

    -
    <%=t 'user_notifications.digest.since_last_visit' %>
    +
    <%=t 'user_notifications.digest.since_last_visit' %>
    @@ -72,22 +72,22 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
    - <%= count[:value] -%> + + <%= count[:value] -%>
    - <%=t count[:label_key] -%> + + <%=t count[:label_key] -%>
    -
    <%=t 'user_notifications.digest.popular_topics' %>
    +
    <%=t 'user_notifications.digest.popular_topics' %>
    -
    +

    - - <%= t.title -%> + + <%= t.title.truncate(60, separator: /\s/) -%>

    <%- if SiteSetting.show_topic_featured_link_in_digest && t.featured_link %> @@ -138,18 +138,18 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo - - - <%- if show_image_with_url(t.image_url) -%> + <%- if show_image_with_url(t.image_url) && t.featured_link.nil? && !(@excerpts[t.first_post&.id]||"").include?(t.image_url) -%> @@ -162,8 +162,8 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
    + + <% if t.user %> -
    <%= t.user.username -%>
    <% if SiteSetting.enable_names? && t.user.name.present? && t.user.name.downcase != t.user.username.downcase %> -

    <%= t.user.name -%>

    +
    <%= t.user.name -%>
    <% end %> +

    <%= t.user.username -%>

    <% end %>
    - @@ -189,7 +189,7 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo <% end %> @@ -215,8 +215,8 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
    - <%= email_excerpt(t.first_post.cooked) %> + + <%= @excerpts[t.first_post.id] %>
    - + <%=t 'user_notifications.digest.join_the_discussion' %>
    - -
    + +
    @@ -231,15 +231,9 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo <% if @popular_posts.present? %> -
    - - - -
    -

    - <%=t 'user_notifications.digest.popular_posts' %> -

    -
    +
    + <%=t 'user_notifications.digest.popular_posts' %> +
    @@ -252,7 +246,7 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
    - @@ -272,23 +266,23 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
    + <%= email_excerpt(post.cooked) %>
    - @@ -331,13 +325,8 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo -
    + <% if post.user %> -
    <%= post.user.username -%>
    <% if SiteSetting.enable_names? && post.user.name && post.user.name.downcase != post.user.username.downcase %> -

    <%= post.user.name -%>

    +
    <%= post.user.name -%>
    <% end %> +

    <%= post.user.username -%>

    <% end %>

    <%=t 'user_notifications.digest.from_topic_label' %> - <%= post.topic.title -%> + <%= post.topic.title.truncate(60, separator: /\s/) -%>

    - + <%=t 'user_notifications.digest.join_the_discussion' %>
    -

    - <%= t.user_data ? (t.highest_post_number - (t.user_data.last_read_post_number || 0)) : t.highest_post_number %> -

    -
    - - <%= t.title -%> + + <%= t.title.truncate(60, separator: /\s/) -%> <%- if SiteSetting.show_topic_featured_link_in_digest && t.featured_link %> <%= raw topic_featured_link_domain(t.featured_link) %> diff --git a/app/views/user_notifications/mailing_list.html.erb b/app/views/user_notifications/mailing_list.html.erb index 749ee60867e..582f7c66b3d 100644 --- a/app/views/user_notifications/mailing_list.html.erb +++ b/app/views/user_notifications/mailing_list.html.erb @@ -56,7 +56,16 @@

    - '><%= post.user.name || post.user.username %> + + <%- if show_username_on_post(post) %> + <%= post.user.username %> + <% end %> + + <%- if show_name_on_post(post) %> + - <%= post.user.name %> + <% end %> + + - <%= I18n.l(post.created_at, format: :long) %>

    diff --git a/app/views/users/password_reset.html.erb b/app/views/users/password_reset.html.erb index 24364acffc5..61a61feb645 100644 --- a/app/views/users/password_reset.html.erb +++ b/app/views/users/password_reset.html.erb @@ -49,6 +49,7 @@
    <%- content_for(:no_ember_head) do %> + <%= script "ember_jquery" %> <%= render_google_universal_analytics_code %> <%- end %> diff --git a/bin/docker/mailcatcher b/bin/docker/mailcatcher index e25dc7c3642..f1f258d70ff 100755 --- a/bin/docker/mailcatcher +++ b/bin/docker/mailcatcher @@ -1,4 +1,4 @@ #!/bin/bash -CMD="mailcatcher --http-ip 0.0.0.0 -f || (apt-get install -y libsqlite3-dev && gem install mailcatcher && mailcatcher --http-ip 0.0.0.0 -f)" +CMD="mailcatcher --http-ip 0.0.0.0 -f" docker exec -it discourse_dev /bin/bash -c "$CMD" diff --git a/bin/docker/rails b/bin/docker/rails index 74b3e211034..1c35b782123 100755 --- a/bin/docker/rails +++ b/bin/docker/rails @@ -5,5 +5,6 @@ if [[ $# = 1 ]] && [[ "$1" =~ "s" ]]; then PARAMS="$PARAMS -b 0.0.0.0" fi -CMD="cd /src && RACK_HANDLER=puma RAILS_ENV=${RAILS_ENV:=development} rails $PARAMS" + +CMD="cd /src && RUBY_GLOBAL_METHOD_CACHE_SIZE=131072 LD_PRELOAD=/usr/lib/libjemalloc.so RACK_HANDLER=puma RAILS_ENV=${RAILS_ENV:=development} rails $PARAMS" docker exec -it -u discourse:discourse discourse_dev /bin/bash -c "$CMD" diff --git a/bin/docker/rake b/bin/docker/rake index 92abb3546b5..d70b45d7659 100755 --- a/bin/docker/rake +++ b/bin/docker/rake @@ -1,5 +1,5 @@ #!/bin/bash PARAMS="$@" -CMD="cd /src && RAILS_ENV=${RAILS_ENV:=development} rake $PARAMS" +CMD="cd /src && RUBY_GLOBAL_METHOD_CACHE_SIZE=131072 LD_PRELOAD=/usr/lib/libjemalloc.so RAILS_ENV=${RAILS_ENV:=development} rake $PARAMS" docker exec -it -u discourse:discourse discourse_dev /bin/bash -c "$CMD" diff --git a/config/application.rb b/config/application.rb index 5ac23191642..49b35de4743 100644 --- a/config/application.rb +++ b/config/application.rb @@ -6,8 +6,15 @@ require_relative '../lib/discourse_event' require_relative '../lib/discourse_plugin' require_relative '../lib/discourse_plugin_registry' +require_relative '../lib/plugin_gem' + # Global config require_relative '../app/models/global_setting' +GlobalSetting.configure! +unless Rails.env.test? && ENV['LOAD_PLUGINS'] != "1" + require_relative '../lib/custom_setting_providers' +end +GlobalSetting.load_defaults require 'pry-rails' if Rails.env.development? @@ -15,8 +22,10 @@ if defined?(Bundler) Bundler.require(*Rails.groups(assets: %w(development test profile))) end + module Discourse class Application < Rails::Application + def config.database_configuration if Rails.env.production? GlobalSetting.database_config @@ -80,14 +89,6 @@ module Discourse config.assets.precompile << "locales/#{file.match(/([a-z_A-Z]+\.js)\.erb$/)[1]}" end - # Activate observers that should always be running. - config.active_record.observers = [ - :user_email_observer, - :user_action_observer, - :post_alert_observer, - :search_observer - ] - # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. config.time_zone = 'UTC' @@ -142,7 +143,7 @@ module Discourse # Our templates shouldn't start with 'discourse/templates' config.handlebars.templates_root = 'discourse/templates' - config.handlebars.raw_template_namespace = "Ember.TEMPLATES" + config.handlebars.raw_template_namespace = "Discourse.RAW_TEMPLATES" require 'discourse_redis' require 'logster/redis_store' @@ -169,6 +170,22 @@ module Discourse end config.after_initialize do + # require common dependencies that are often required by plugins + # in the past observers would load them as side-effects + # correct behavior is for plugins to require stuff they need, + # however it would be a risky and breaking change not to require here + require_dependency 'category' + require_dependency 'post' + require_dependency 'topic' + require_dependency 'user' + require_dependency 'post_action' + require_dependency 'post_revision' + require_dependency 'notification' + require_dependency 'topic_user' + require_dependency 'group' + require_dependency 'user_field' + require_dependency 'post_action_type' + # So open id logs somewhere sane OpenID::Util.logger = Rails.logger if plugins = Discourse.plugins diff --git a/config/locales/client.ar.yml b/config/locales/client.ar.yml index 25fe51aa684..be52c0a93f2 100644 --- a/config/locales/client.ar.yml +++ b/config/locales/client.ar.yml @@ -425,18 +425,59 @@ ar: few: "%{count} أعضاء" many: "%{count} عضوًا" other: "%{count} عضو" + group_histories: + actions: + change_group_setting: "تغيير إعدادات المجموعة" + add_user_to_group: "إضافة مستخدم" + remove_user_from_group: "حذف العضو" + make_user_group_owner: "تعيين كمالك" + remove_user_as_group_owner: "سحب صلاحية المالك" groups: + logs: + title: "السجلات" + when: "حين" + action: "إجراء" + acting_user: "العضو المسؤول" + target_user: "العضو المستهدف" + subject: "الموضوع" + details: "التفاصيل" + from: "من" + to: "إلى" + edit: + title: 'تعديل المجموعة' + full_name: 'الإسم الكامل' + add_members: "إضافة أعضاء" + delete_member_confirm: "إزالة '%{username}' من المجموعة '%{group}'؟" + request_membership_pm: + title: "طلب العضوية" + body: "أود تسجيل العضوية في المجموعة @%{groupName}" + name_placeholder: "اسم المجموعة، بدون مسافات. يتبع قواعد اسم المستخدم" + public: "السماح للأعضاء للإنضمام / ترك المجموعة (يطبق على المجموعات الظاهرة)" empty: - posts: "لا مشاركات من أعضاء هذه المجموعة." + posts: "لا مواضيع لأعضاء هذه المجموعة." members: "لا أعضاء في هذه المجموعة." - mentions: "لم يُشر أحد إلى هذه المجموعة." - messages: "لا رسائل لهذه المجموعة." - topics: "لا مواضيع لأعضاء هذه المجموعة." + mentions: "لا توجد إشارات في هذه المجموعة." + messages: "لا توجد رسائل في هذه المجموعة." + topics: "لا توجد مواضيع لأعضاء هذه المجموعة." + logs: "لا توجد سجلات في هذ المجموعة." add: "أضف" + join: "إنضمام للمجموعة" + leave: "ترك المجموعة" + request: "طلب الإنضمام للمجموعة" + automatic_group: مجموعة تلقائية + closed_group: مجموعة مغلقة + is_group_user: "أنت عضو في هذه المجموعة." + allow_membership_requests: "السماح للأعضاء لإرسال طلبات الإنضمام إلى أصحاب المجموعات (يجب أن يسمح للجميع بذكر هذه المجموعة)" + membership: "العضوية" + name: "الاسم" + user_count: "عدد اﻷعضاء" + bio: "عن المجموعة" selector_placeholder: "أضف أعضاء" owner: "المالك" visible: "المجموعة مرئية لكل المستخدمين" - index: "المجموعات" + index: + title: "المجموعات" + empty: "لا توجد مجموعات ظاهرة" title: zero: "مجموعات" one: "مجموعات" @@ -444,6 +485,7 @@ ar: few: "مجموعات" many: "مجموعات" other: "مجموعات" + activity: "نشاط" members: "الأعضاء" topics: "المواضيع" posts: "المشاركات" @@ -475,6 +517,15 @@ ar: muted: title: "مكتوم" description: "لن نرسل لك أي إشعار لأي من المواضيع الجديدة في هذه المجموعة." + flair_url: "الصورة الرمزية المميزة" + flair_url_placeholder: "(إختياري) رابط الصورة أو صنف Font Awesome" + flair_bg_color: "خلفية الصورة الرمزية المميزة" + flair_bg_color_placeholder: "(إختياري) اللون برقم الهكس" + flair_color: "لون الصورة الرمزية" + flair_color_placeholder: "(إختياري) اللون برقم الهكس" + flair_preview_icon: "معاينة الأيقونة" + flair_preview_image: "معاينة الصورة" + flair_note: "ملاحظة: الصورة المميزة تظهر فقط لمجموعة العضو الرئيسية." user_action_groups: '1': "الإعجابات المعطاة" '2': "الإعجابات المستلمة" @@ -544,6 +595,11 @@ ar: profile: "الصفحة الشخصية" mute: "كتم" edit: "تعديل التفضيلات" + download_archive: + button_text: "تحميل مواضيعي" + confirm: "هل أنت متأكد من رغبتك في تحميل جميع مشاركاتك ؟" + success: "بدأ التحميل, سيتم إعلامك برسالة عند اكتمال العملية." + rate_limit_error: "المشاركات يمكن تحميلها لمرة واحدة في اليوم , الرجاء المحاولة غدا." new_private_message: "رسالة جديدة" private_message: "رسالة" private_messages: "الرسائل" @@ -567,6 +623,7 @@ ar: each_browser_note: "ملاحظة: عليك تغيير هذا الإعداد في كل متصفح تستخدمه." dismiss_notifications: "تجاهل الكل" dismiss_notifications_tooltip: "جعل جميع اشعارات غيرمقروء الى مقروء" + first_notification: "إشعارك الأول! قم بإختياره للبدء." disable_jump_reply: "لا تنتقل إلى مشاركتي بعد ما أردّ" dynamic_favicon: "إعرض عدد المواضيع الجديدة والمحدثة في أيقونة المتصفح" external_links_in_new_tab: "فتح الروابط الخارجية في ألسنة جديدة" @@ -810,12 +867,11 @@ ar: account_age_days: "عمر الحساب بالأيام" create: "أرسل دعوة" generate_link: "انسخ رابط الدعوة" + link_generated: "تم إنشاء رابط الدعوة بنجاح!" + valid_for: "رابط الدعوة صحيح فقط للبريد الإلكتروني %{email}" bulk_invite: - none: "لم تقم بدعوة اي احد حتى الان. تستطيع ارسال دعوة , أو ارسال عدة دعوات عن طريقuploading a bulk invite file." text: "الدعوة من ملف" - uploading: "يرفع..." success: "رُفع الملف بنجاح. سيصلك إشعارا عبر رسالة عند اكتمال العملية." - error: "حدثت مشكلة في رفع '{{filename}}': {{message}}" password: title: "كلمة المرور" too_short: "كلمة المرور قصيرة جدا." @@ -920,6 +976,8 @@ ar: too_few_topics_notice: "دعونا الحصول على هذه المناقشة التي! وهناك حاليا %{currentTopics} / %{requiredTopics} المواضيع. الزوار الجديدة بحاجة إلى بعض الأحاديث قراءة والرد عليها." too_few_posts_notice: "دعونا الحصول على هذه المناقشة التي بدأت! يوجد حاليا %{currentPosts} / %{requiredPosts} مشاركات. الزوار الجديدة بحاجة إلى بعض الأحاديث قراءة والرد عليها." learn_more: "تعلم المزيد..." + all_time: 'المجموع' + all_time_desc: 'عدد المواضيع المنشأة' year: 'عام' year_desc: 'المواضيع المكتوبة خلال 365 يوم الماضية' month: 'شهر' @@ -1034,6 +1092,9 @@ ar: twitter: "تويتر" emoji_one: "إموجي واحد" win10: "وندوز10" + category_page_style: + categories_only: "الفئات فقط" + categories_with_featured_topics: "فئات ذات مواضيع متميزة" shortcut_modifier_key: shift: 'Shift' ctrl: 'Ctrl' @@ -1217,6 +1278,8 @@ ar: label: في المجموعة with_badge: label: مع الشعارات + with_tags: + label: مع أوسمة filters: label: استرجع فقط المواضيع/المشاركات التي... likes: أعجبني @@ -1248,6 +1311,7 @@ ar: topics: new_messages_marker: "آخر مشاهدة" bulk: + clear_all: "مسح الكل" unlist_topics: "ازالة المواضيع من القائمة" reset_read: "تصفير القراءات" delete: "المواضيع المحذوفة" @@ -1396,7 +1460,6 @@ ar: go_bottom: "أسفل" go: "اذهب" jump_bottom: "انتقل لآخر مشاركة" - jump_prompt: "اقفز الى المشاركة" jump_prompt_long: "إلى أي مشاركة تريد الانتقال؟" jump_bottom_with_number: "انتقل إلى المشاركة %{post_number}" total: مجموع المشاركات @@ -1676,7 +1739,6 @@ ar: file_too_large: "آسفون، الملف هذا كبير جدا (أقصى حجم هو {{max_size_kb}}ك.بايت). ما رأيك برفع الملف على خدمة سحابيّة، ومن ثمّ تشارك الوصلة؟" too_many_uploads: "آسفون، يمكنك فقط رفع ملفّ واحد كلّ مرة." too_many_dragged_and_dropped_files: "آسفون، يمكنك فقط رفع 10 ملفّات كلّ مرة." - upload_not_authorized: "المعذرة، الملف الذي تحاول رفعه غير مسموح به، الامتدادات المسموح بها هي {{authorized_extensions}}." image_upload_not_allowed_for_new_user: "آسفون، لا يمكن للمستخدمين الجدد رفع الصور." attachment_upload_not_allowed_for_new_user: "آسفون، لا يمكن للمستخدمين الجدد رفع المرفقات." attachment_download_requires_login: "آسفون، عليك الولوج لتنزيل المرفقات." @@ -2065,7 +2127,6 @@ ar: many: "المشاهدات" other: "المشاهدات" replies: "الردود" - views_long: "هذا الموضوع قد تمت مشاهدته {{number}} مرات" activity: "النشاط" likes: "اعجابات" likes_lowercase: @@ -2394,8 +2455,6 @@ ar: backups: "النسخ الاحتياطية" traffic_short: "المرور" traffic: "طلبات تطبيقات الويب" - page_views: "طلبات API " - page_views_short: "طلبات API " show_traffic_report: "عرض تقرير مرور مفصل" reports: today: "اليوم" @@ -2505,15 +2564,12 @@ ar: refresh: "تحديث" new: "جديد" selector_placeholder: "أدخل اسم المستخدم" - name_placeholder: "اسم المجموعة، بدون مسافات. يتبع قواعد اسم المستخدم" about: "هنا عدّل على عضوية المجموعة والاسماء" group_members: "أعضاء المجموعة" delete: "حذف" delete_confirm: "أأحذف هذه المجموعة؟" delete_failed: "تعذّر حذف المجموعة. إن كانت مجموعة آليّة، فلا يمكن تدميرها." - delete_member_confirm: "أأزيل '%{username}' من المجموعة '%{group}'؟" delete_owner_confirm: "هل تريد إزالة صلاحيات الإدارة من '%{username} ؟" - name: "الاسم" add: "اضافة" add_members: "اضافة عضو" custom: "مخصص" diff --git a/config/locales/client.bs_BA.yml b/config/locales/client.bs_BA.yml index 218da0806fa..c99081e1dca 100644 --- a/config/locales/client.bs_BA.yml +++ b/config/locales/client.bs_BA.yml @@ -586,11 +586,8 @@ bs_BA: create: "Pošalji Pozivnicu" generate_link: "Kopiraj link za invite" bulk_invite: - none: "Još niste nikoga pozvali ovdje. Moete slati pojedinačne pozivnice ili pozvati više ljudi odjednom učitavanjem datoteke za grupno pozivanje." text: "Bulk Invite from File" - uploading: "Uploading..." success: "File uploaded successfully, you will be notified shortly with progress." - error: "There was an error uploading '{{filename}}': {{message}}" password: title: "Šifra" too_short: "Vaša šifra je prekratka." @@ -1074,7 +1071,6 @@ bs_BA: edit: "Sorry, there was an error editing your post. Please try again." upload: "Sorry, there was an error uploading that file. Please try again." too_many_uploads: "Sorry, you can only upload one file at a time." - upload_not_authorized: "Sorry, the file you are trying to upload is not authorized (authorized extension: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Sorry, new users can not upload images." attachment_upload_not_allowed_for_new_user: "Sorry, new users can not upload attachments." attachment_download_requires_login: "Sorry, you need to be logged in to download attachments." @@ -1250,7 +1246,6 @@ bs_BA: original_post: "Originalni Odgovor" views: "Pregleda" replies: "Odgovora" - views_long: "ova tema je pregledana {{number}} puta" activity: "Aktivnost" likes: "Lajkovi" likes_long: "postoji {{number}} lajkova u ovoj temi" @@ -1343,7 +1338,6 @@ bs_BA: space_free: "{{size}} slobodno" uploads: "Učitavanja" backups: "backupovi" - page_views_short: "API pozivi" show_traffic_report: "Pokaži detaljan izvještaj prometa" reports: today: "Today" @@ -1412,7 +1406,6 @@ bs_BA: refresh: "Refresh" new: "New" selector_placeholder: "add users" - name_placeholder: "Group name, no spaces, same as username rule" about: "Edit your group membership and names here" group_members: "Group members" delete: "Delete" diff --git a/config/locales/client.cs.yml b/config/locales/client.cs.yml index c86a8b5e1db..0631c278f3b 100644 --- a/config/locales/client.cs.yml +++ b/config/locales/client.cs.yml @@ -347,17 +347,10 @@ cs: few: "%{count} uživatelé" other: "%{count} uživatelů" groups: - empty: - posts: "V této skupině není od žádného člena ani jeden příspěvek." - members: "V této skupině není žádny uživatel." - mentions: "Tato skupina nebyla ještě @zmíněna." - messages: "Pro tuto skupinu není žádná zpráva." - topics: "V této skupině není od žádného člena ani jedno téma." add: "Přidat" selector_placeholder: "Přidat členy" owner: "Vlastník" visible: "Skupina je viditelná pro všechny uživatele" - index: "Skupiny" title: one: "skupina" few: "skupiny" @@ -715,11 +708,8 @@ cs: create: "Poslat pozvánku" generate_link: "Zkopírovat odkaz na pozvánku" bulk_invite: - none: "Zatím jste nikoho nepozval. Můžete poslat individuální pozvánku nebo pozvat skupinu lidí naráz pomocí nahrání souboru." text: "Hromadné pozvání s pomocí souboru" - uploading: "Nahrávám..." success: "Nahrání souboru proběhlo úspěšně. O dokončení celého procesu budete informování pomocí zprávy." - error: "Nastala chyba při nahrávání '{{filename}}': {{message}}" password: title: "Heslo" too_short: "Vaše heslo je příliš krátké." @@ -1312,7 +1302,6 @@ cs: go_bottom: "dolů" go: "go" jump_bottom: "na poslední příspěvek" - jump_prompt: "přejít na příspěvek" jump_prompt_long: "Na který příspěvek chcete přejít?" jump_bottom_with_number: "Skočit na příspěvěk %{post_number}" total: celkem příspěvků @@ -1555,7 +1544,6 @@ cs: file_too_large: "Soubor, který se snažíte nahrát, je bohužel příliš velký (maximální velikost je {{max_size_kb}}kb). Co třeba jej nahrát na cloudovou službu a nasdílet sem odkaz?" too_many_uploads: "Bohužel, najednou smíte nahrát jen jeden soubor." too_many_dragged_and_dropped_files: "Bohužel, najednou smíte nahrát jen 10 souborů." - upload_not_authorized: "Bohužel, soubor, který se snažíte nahrát, není povolený (povolené přípony: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Bohužel, noví uživatelé nemohou nahrávat obrázky." attachment_upload_not_allowed_for_new_user: "Bohužel, noví uživatelé nemohou nahrávat přílohy." attachment_download_requires_login: "Omlouváme se, ale pro stáhnutí přílohy musíte být přihlášen." @@ -1903,7 +1891,6 @@ cs: few: "zobrazení" other: "zobrazení" replies: "Odpovědi" - views_long: "toto téma bylo zobrazeno {{number}}krát" activity: "Aktivita" likes: "Líbí se" likes_lowercase: @@ -2207,8 +2194,6 @@ cs: backups: "zálohy" traffic_short: "Provoz" traffic: "Webové požadavky na aplikaci" - page_views: "API požadavky" - page_views_short: "API požadavky" show_traffic_report: "Zobrazit detailní zprávu o provozu" reports: today: "Dnes" @@ -2303,15 +2288,12 @@ cs: refresh: "Obnovit" new: "Nová" selector_placeholder: "zadejte uživatelské jméno" - name_placeholder: "Název skupiny, bez mezer, stejná pravidla jako pro uživatelská jména" about: "Zde můžete upravit názvy skupin a členství" group_members: "Členové skupiny" delete: "Smazat" delete_confirm: "Smazat toto skupiny?" delete_failed: "Unable to delete group. If this is an automatic group, it cannot be destroyed." - delete_member_confirm: "Odstranit '%{username}' ze '%{group}' skupiny?" delete_owner_confirm: "Odstranit vlastnickou výsadu od '%{username}'?" - name: "Jméno" add: "Přidat" add_members: "Přidat členy" custom: "Přizpůsobené" @@ -2328,11 +2310,6 @@ cs: add_owners: Přidat vlastníky incoming_email: "Vlastní příchozí emailová adresa" incoming_email_placeholder: "zadej emailovou adresu" - flair_url: "Avatar Flair Image" - flair_url_placeholder: "(Volitelné) URL obrázku nebo třídy Font Awesome " - flair_bg_color: "Avatar Flair Barva pozadí" - flair_color: "Avatar Flair Color" - flair_preview: "Náhled" api: generate_master: "Vygenerovat Master API Key" none: "Nejsou tu žádné aktivní API klíče." diff --git a/config/locales/client.da.yml b/config/locales/client.da.yml index 845f5f829b2..6ea55ddc40a 100644 --- a/config/locales/client.da.yml +++ b/config/locales/client.da.yml @@ -321,17 +321,10 @@ da: one: "1 bruger" other: "%{count} brugere" groups: - empty: - posts: "Der er ingen indlæg af medlemmer af denne gruppe." - members: "Der er ingen medlemmer i denne gruppe." - mentions: "Denne gruppe er ikke nævnt." - messages: "Der er ingen besked til denne gruppe." - topics: "Der er intet emne af medlemmer af denne gruppe." add: "Tilføj" selector_placeholder: "Tilføj medlemmer" owner: "ejer" visible: "Gruppen er synlige for alle brugere" - index: "Grupper" title: one: "gruppe" other: "grupper" @@ -683,11 +676,8 @@ da: create: "Send en invitation" generate_link: "Kopier invitations-link" bulk_invite: - none: "Du har ikke inviteret nogen her endnu. Du kan sende individuelle invitationer eller invitere en masse mennesker på én gang ved at uploade en samlet liste over invitationer." text: "Masse invitering fra en fil" - uploading: "Uploader..." success: "Fil uploaded successfuldt, du vil blive meddelt via en beskede når processen er fuldendt." - error: "Der var en fejl ved upload af filen '{{filename}}': {{message}}" password: title: "Adgangskode" too_short: "Din adgangskode er for kort." @@ -1203,7 +1193,6 @@ da: go_bottom: "bund" go: "start" jump_bottom: "Hop til sidste indlæg" - jump_prompt: "hop til indlæg" jump_prompt_long: "Hvilket indlæg vil du gerne springe til?" jump_bottom_with_number: "hop til indlæg %{post_number}" total: antal indlæg @@ -1431,7 +1420,6 @@ da: file_too_large: "Beklager, filen du prøver at uploade er for stor (den maksimale størrelse er {{max_size_kb}}kb). Du kan evt. uploade filen til en fildelings service og dele linket her." too_many_uploads: "Beklager, men du kan kun uploade én fil ad gangen." too_many_dragged_and_dropped_files: "Beklager, du kan maksimalt uploade 10 filer ad gangen" - upload_not_authorized: "Beklager, filen, som du forsøger at uploade, er ikke godkendt (godkendte filendelser: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Beklager, nye brugere kan ikke uploade billeder." attachment_upload_not_allowed_for_new_user: "Beklager, nye brugere kan ikke uploade vedhæftede filer." attachment_download_requires_login: "Beklager, du skal være logget på for at downloade vedhæftede filer." @@ -1727,7 +1715,6 @@ da: one: "visning" other: "visninger" replies: "Svar" - views_long: "dette emne er blevet vist {{number}} gange" activity: "Aktivitet" likes: "Likes" likes_lowercase: @@ -1977,8 +1964,6 @@ da: backups: "backups" traffic_short: "Trafik" traffic: "Applikation web forespørgsler" - page_views: "API Forespørgsler" - page_views_short: "API Forespørgsler" show_traffic_report: "Vist detaljeret trafik rapport" reports: today: "I dag" @@ -2067,15 +2052,12 @@ da: refresh: "Genindlæs" new: "Nye" selector_placeholder: "indtast brugernavn" - name_placeholder: "Gruppenavn, ingen mellemrum, på samme måde som brugernavne" about: "Redigér gruppemedlemsskaber og gruppenavne her" group_members: "Gruppe medlemmer" delete: "Slet" delete_confirm: "Slet denne gruppe?" delete_failed: "Kan ikke slette gruppen. Hvis dette er en automatisk gruppe, kan den ikke ødelægges." - delete_member_confirm: "Fjern '%{username}' fra gruppen '%{group}'?" delete_owner_confirm: "Fjern ejer-privilegier for '%{username}'?" - name: "Navn" add: "Tilføj" add_members: "Tilføj medlemmer" custom: "Brugerdefineret" @@ -2092,8 +2074,6 @@ da: add_owners: Tilføj ejere incoming_email: "Brugerdefineret indkommende email" incoming_email_placeholder: "indtast email" - flair_bg_color_placeholder: "(Valgfrit) Hex farveværdi" - flair_preview: "Vis" api: generate_master: "Generér API-nøgle" none: "Der er ingen aktive API-nøgler i øjeblikket." diff --git a/config/locales/client.de.yml b/config/locales/client.de.yml index d59f5af7c82..51f6da0df7e 100644 --- a/config/locales/client.de.yml +++ b/config/locales/client.de.yml @@ -138,8 +138,8 @@ de: topic_admin_menu: "Thema administrieren" wizard_required: "Es ist an der Zeit, Dein Forum einzurichten! Einrichtungs-Assistenten starten!" emails_are_disabled: "Die ausgehende E-Mail-Kommunikation wurde von einem Administrator global deaktiviert. Es werden keinerlei Benachrichtigungen per E-Mail verschickt." - bootstrap_mode_enabled: "Damit du mit deiner Site einfacher loslegen kannst, befindest du dich im Bootstrapping-Modus. Alle neuen Benutzer erhalten die Vertrauensstufe 1 und bekommen eine tägliche Zusammenfassung per E-Mail. Der Modus wird automatisch deaktiviert, sobald sich mindestens %{min_users} Benutzer angemeldet haben." - bootstrap_mode_disabled: "Der Bootstrapping-Modus wird innerhalb der nächsten 24 Stunden deaktiviert." + bootstrap_mode_enabled: "Damit du mit deiner Seite einfacher loslegen kannst, befindest du dich im Starthilfe-Modus. Alle neuen Benutzer erhalten die Vertrauensstufe 1 und bekommen eine tägliche E-Mail-Zusammenfassung. Der Modus wird automatisch deaktiviert, sobald sich mindestens %{min_users} Benutzer angemeldet haben." + bootstrap_mode_disabled: "Der Starthilfe-Modus wird innerhalb der nächsten 24 Stunden deaktiviert." s3: regions: us_east_1: "USA Ost (Nord-Virginia)" @@ -209,8 +209,8 @@ de: our_moderators: "Unsere Moderatoren" stat: all_time: "Gesamt" - last_7_days: "Letzten 7 Tage" - last_30_days: "Letzten 30 Tage" + last_7_days: "Letzte 7 Tage" + last_30_days: "Letzte 30 Tage" like_count: "Likes" topic_count: "Themen" post_count: "Beiträge" @@ -321,21 +321,63 @@ de: total_rows: one: "1 Benutzer" other: "%{count} Benutzer" + group_histories: + actions: + change_group_setting: "Gruppeneinstellung ändern" + add_user_to_group: "Benutzer hinzufügen" + remove_user_from_group: "Benutzer entfernen" + make_user_group_owner: "Zum Eigentümer machen" + remove_user_as_group_owner: "Eigentümerrechte entziehen" groups: + logs: + title: "Protokolle" + when: "Wann" + action: "Aktion" + acting_user: "Benutzer der Aktion" + target_user: "Betroffener Benutzer" + subject: "Gegenstand" + details: "Details" + from: "Von" + to: "An" + edit: + title: 'Gruppe bearbeiten' + full_name: 'Vollständiger Name' + add_members: "Mitglieder hinzufügen" + delete_member_confirm: "'%{username}' aus der Gruppe '%{group}' entfernen?" + request_membership_pm: + title: "Mitgliedschaftsanfrage" + body: "Ich möchte mich um eine Mitgliedschaft in @%{groupName} bewerben." + name_placeholder: "Gruppenname, keine Leerzeichen, gleiche Regel wie beim Benutzernamen" + public: "Benutzern erlauben, die Gruppenzugehörigkeit frei zu wechseln (Erfordert, dass die Gruppe sichtbar ist)" empty: - posts: "Es gibt keinen Beitrag von Mitgliedern dieser Gruppe." - members: "Diese Gruppe hat keine Mitglieder." - mentions: "Diese Gruppe wurde nicht erwähnt." + posts: "Es gibt keine Beiträge von Mitgliedern dieser Gruppe." + members: "Es gibt keine Mitglieder in dieser Gruppe." + mentions: "Es gibt keine Erwähnungen in dieser Gruppe." messages: "Es gibt keine Nachrichten für diese Gruppe." - topics: "Es gibt kein Thema von Mitgliedern dieser Gruppe." + topics: "Es gibt keine Themen von Mitgliedern dieser Gruppe." + logs: "Es gibt keine Protokolleinträge für diese Gruppe." add: "Hinzufügen" + join: "Gruppe beitreten" + leave: "Gruppe verlassen" + request: "Gruppenbeitritt beantragen" + automatic_group: Automatische Gruppe + closed_group: Geschlossene Gruppe + is_group_user: "Du bist ein Mitglied in dieser Gruppe." + allow_membership_requests: "Erlaube Benutzern, eine Mitgliedschaftsanfrage an Gruppenbesitzer zu schicken (Erfordert, dass jeder die Gruppe erwähnen kann)" + membership: "Mitgliedschaft" + name: "Name" + user_count: "Anzahl der Mitglieder" + bio: "Über die Gruppe" selector_placeholder: "Mitglieder hinzufügen" owner: "Eigentümer" visible: "Gruppe ist für alle Benutzer sichtbar" - index: "Gruppen" + index: + title: "Gruppen" + empty: "Es gibt keine sichtbaren Gruppen." title: one: "Gruppe" other: "Gruppen" + activity: "Aktivität" members: "Mitglieder" topics: "Themen" posts: "Beiträge" @@ -367,6 +409,15 @@ de: muted: title: "Stummgeschaltet" description: "Du erhältst keine Benachrichtigungen über neue Themen in dieser Gruppe." + flair_url: "Avatar-Hintergrund" + flair_url_placeholder: "(Optional) Bild-URL oder Font Awesome-Klasse" + flair_bg_color: "Avatar-Hintergrundfarbe" + flair_bg_color_placeholder: "(Optional) Hex-Farbwert" + flair_color: "Avatar-Hintergrundfarbe" + flair_color_placeholder: "(Optoinal) Hex-Farbwert" + flair_preview_icon: "Vorschau-Icon" + flair_preview_image: "Vorschaubild" + flair_note: "Hinweise: Ein Avatar-Hintergrund wird nur für die Hauptgruppe eines Benutzers angezeigt." user_action_groups: '1': "Abgegebene Likes" '2': "Erhaltene Likes" @@ -695,11 +746,10 @@ de: link_generated: "Der Einladungslink wurde erfolgreich generiert!" valid_for: "Der Einladungslink ist nur für die Adresse %{email} gültig" bulk_invite: - none: "Du hast noch niemanden hierher eingeladen. Du kannst individuelle Einladungen verschicken oder eine Masseneinladung an eine Gruppe von Leuten verschicken indem du eine Datei für Masseneinladung hochlädst." + none: "Du hast hier noch niemanden eingeladen. Du kannst einzelne Einladungen versenden, oder eine Reihe von Leuten auf einmal einladen, indem du eine CSV-Datei hochlädst." text: "Masseneinladung aus Datei" - uploading: "Wird hochgeladen…" success: "Die Datei wurde erfolgreich hochgeladen. Du erhältst eine Nachricht, sobald der Vorgang abgeschlossen ist." - error: "Beim Hochladen der Datei '{{filename}}' ist ein Fehler aufgetreten: {{message}}" + error: "Entschuldige, die Datei sollte im CSV-Format sein." password: title: "Passwort" too_short: "Dein Passwort ist zu kurz." @@ -744,10 +794,10 @@ de: more_badges: "weitere Abzeichen" top_links: "Die besten Links" no_links: "Noch keine Links." - most_liked_by: "Häufigste „Gefällt mir“-Angaben von" - most_liked_users: "Häufigste „Gefällt mir“-Angaben für" + most_liked_by: "Häufigste Likes von" + most_liked_users: "Häufigste Likes für" most_replied_to_users: "Häufigste Antworten an" - no_likes: "Noch keine „Gefällt mir“-Angaben." + no_likes: "Noch keine Likes." associated_accounts: "Anmeldeinformationen" ip_address: title: "Letzte IP-Adresse" @@ -879,7 +929,7 @@ de: or: "Oder" authenticating: "Authentifiziere…" awaiting_confirmation: "Dein Konto ist noch nicht aktiviert. Verwende den 'Passwort vergessen'-Link, um eine weitere E-Mail mit Anweisungen zur Aktivierung zu erhalten." - awaiting_approval: "Dein Konto wurde noch nicht von einem Mitarbeiter genehmigt. Du bekommst eine E-Mail, sobald das geschehen ist." + awaiting_approval: "Dein Konto wurde noch nicht von einem Team-Mitglied genehmigt. Du bekommst eine E-Mail, sobald das geschehen ist." requires_invite: "Entschuldige, der Zugriff auf dieses Forum ist nur mit einer Einladung möglich." not_activated: "Du kannst dich noch nicht anmelden. Wir haben dir schon eine E-Mail zur Aktivierung an {{sentTo}} geschickt. Bitte folge den Anweisungen in dieser E-Mail, um dein Benutzerkonto zu aktivieren." not_allowed_from_ip_address: "Von dieser IP-Adresse darfst du dich nicht anmelden." @@ -964,8 +1014,10 @@ de: title: "Oder drücke Strg+Eingabetaste" users_placeholder: "Benutzer hinzufügen" title_placeholder: "Um was geht es in dieser Diskussion? Schreib einen kurzen Satz." + title_or_link_placeholder: "Gib einen Titel ein oder füge einen Link ein" edit_reason_placeholder: "Warum bearbeitest du?" show_edit_reason: "(Bearbeitungsgrund hinzufügen)" + topic_featured_link_placeholder: "Gib einen Link, der mit dem Titel angezeigt wird." reply_placeholder: "Schreib hier. Verwende Markdown, BBCode oder HTML zur Formatierung. Füge Bilder ein oder ziehe sie herein." view_new_post: "Sieh deinen neuen Beitrag an." saving: "Wird gespeichert" @@ -1008,7 +1060,7 @@ de: yourself_confirm: title: "Hast du vergessen Empfänger hinzuzufügen?" body: "Im Augenblick wird diese Nachricht nur an dich selbst gesendet!" - admin_options_title: "Optionale Mitarbeiter-Einstellungen für dieses Thema" + admin_options_title: "Optionale Team-Einstellungen für dieses Thema" auto_close: label: "Zeitpunkt der automatischen Schließung:" error: "Bitte gib einen gültigen Wert ein." @@ -1126,8 +1178,8 @@ de: private: sind in meinen Nachrichten bookmarks: Ich habe ein Lesezeichen gesetzt first: sind die allerersten Beiträge - pinned: sind angepinnt - unpinned: sind nicht angepinnt + pinned: sind angeheftet + unpinned: sind nicht angeheftet wiki: sind Wiki statuses: label: Wo Themen @@ -1279,7 +1331,8 @@ de: go_bottom: "Ende" go: "Los" jump_bottom: "springe zum letzten Beitrag" - jump_prompt: "Springe zu Beitrag" + jump_prompt: "springe zu..." + jump_prompt_of: "von %{count} Beiträgen" jump_prompt_long: "Zu welchem Beitrag möchtest du springen?" jump_bottom_with_number: "springe zu Beitrag %{post_number}" total: Beiträge insgesamt @@ -1372,7 +1425,7 @@ de: unpin: "Dieses Thema vom Anfang der {{categoryLink}} Kategorie loslösen." unpin_until: "Dieses Thema vom Anfang der {{categoryLink}} Kategorie loslösen oder bis %{until} warten." pin_note: "Benutzer können das Thema für sich selbst loslösen." - pin_validation: "Ein Datum wird benötigt um diesen Beitrag zu fixieren." + pin_validation: "Ein Datum wird benötigt um diesen Beitrag anzuheften." not_pinned: "Es sind in {{categoryLink}} keine Themen angeheftet." already_pinned: one: "Momentan in {{categoryLink}} angeheftete Themen: 1" @@ -1511,7 +1564,7 @@ de: file_too_large: "Entschuldige, diese Datei ist zu groß (maximal erlaubt sind {{max_size_kb}} KB). Wie wär’s, wenn du deine große Datei bei einem Filehosting-Dienst hochlädst und dann den Link teilst?" too_many_uploads: "Entschuldige, du darfst immer nur eine Datei hochladen." too_many_dragged_and_dropped_files: "Entschuldige, du kannst nur 10 Dateien auf einmal hochladen." - upload_not_authorized: "Entschuldige, die Datei, die du hochladen wolltest, ist nicht erlaubt (erlaubte Endungen: {{authorized_extensions}})." + upload_not_authorized: "Entschuldigung, die Datei die du hochladen möchtest ist nicht erlaubt (erlaubte Dateiendungen sind: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Entschuldige, neue Benutzer dürfen keine Bilder hochladen." attachment_upload_not_allowed_for_new_user: "Entschuldige, neue Benutzer dürfen keine Dateien hochladen." attachment_download_requires_login: "Entschuldige, du musst angemeldet sein, um Dateien herunterladen zu können." @@ -1548,8 +1601,8 @@ de: admin: "Administrative Aktionen" wiki: "Wiki erstellen" unwiki: "Wiki entfernen" - convert_to_moderator: "Mitarbeiter-Einfärbung hinzufügen" - revert_to_regular: "Mitarbeiter-Einfärbung entfernen" + convert_to_moderator: "Team-Einfärbung hinzufügen" + revert_to_regular: "Team-Einfärbung entfernen" rebake: "HTML erneuern" unhide: "Einblenden" change_owner: "Eigentümer ändern" @@ -1677,6 +1730,7 @@ de: tags_allowed_tag_groups: "Schlagwortgruppen, die nur in dieser Kategorie verwendet werden können:" tags_placeholder: "(Optional) Liste erlaubter Schlagwörter" tag_groups_placeholder: "(Optional) Liste erlaubter Schlagwort-Gruppen" + topic_featured_link_allowed: "Erlaube hervorgehobene Links in dieser Kategorie" delete: 'Kategorie löschen' create: 'Neue Kategorie' create_long: 'Eine neue Kategorie erstellen' @@ -1711,6 +1765,7 @@ de: email_in_disabled: "Das Erstellen von neuen Themen per E-Mail ist in den Website-Einstellungen deaktiviert. Um das Erstellen von neuen Themen per E-Mail zu erlauben," email_in_disabled_click: 'aktiviere die Einstellung „email in“.' suppress_from_homepage: "Löse diese Kategorie von der Startseite." + all_topics_wiki: "Mache neue Themen standardmäßig zu Wikis." sort_order: "Standardsortierung:" allow_badges_label: "Erlaube das Verleihen von Abzeichen in dieser Kategorie." edit_permissions: "Berechtigungen bearbeiten" @@ -1763,7 +1818,7 @@ de: submit_tooltip: "Private Meldung abschicken" take_action_tooltip: "Den Meldungsschwellenwert sofort erreichen, anstatt auf weitere Meldungen aus der Community zu warten." cant: "Entschuldige, du kannst diesen Beitrag derzeit nicht melden." - notify_staff: 'Mitarbeiter nichtöffentlich benachrichtigen' + notify_staff: 'Team nicht-öffentlich benachrichtigen' formatted_name: off_topic: "Es ist am Thema vorbei" inappropriate: "Es ist unangemessen" @@ -1829,7 +1884,9 @@ de: one: "Aufruf" other: "Aufrufe" replies: "Antworten" - views_long: "dieses Thema wurde {{number}} mal betrachtet" + views_long: + one: "dieses Thema wurde 1-mal betrachtet" + other: "dieses Thema wurde {{number}}-mal betrachtet" activity: "Aktivität" likes: "Likes" likes_lowercase: @@ -1964,7 +2021,7 @@ de: actions: title: 'Aktionen' bookmark_topic: 'f Lesezeichen hinzufügen/entfernen' - pin_unpin_topic: 'shift+p Thema hervorheben/nicht mehr hervorheben' + pin_unpin_topic: 'shift+p Thema anheften/loslösen' share_topic: 'shift+s Thema teilen' share_post: 's Beitrag teilen' reply_as_new_topic: 't Mit verknüpftem Thema antworten' @@ -2134,14 +2191,14 @@ de: backups: "Backups" traffic_short: "Traffic" traffic: "Web Requests der Applikation" - page_views: "API Requests" - page_views_short: "API Requests" + page_views: "Seitenaufrufe" + page_views_short: "Seitenaufrufe" show_traffic_report: "Zeige detaillierten Traffic-Bericht" reports: today: "Heute" yesterday: "Gestern" - last_7_days: "Letzten 7 Tage" - last_30_days: "Letzten 30 Tage" + last_7_days: "Letzte 7 Tage" + last_30_days: "Letzte 30 Tage" all_time: "Gesamt" 7_days_ago: "vor 7 Tagen" 30_days_ago: "vor 30 Tagen" @@ -2225,15 +2282,12 @@ de: refresh: "Aktualisieren" new: "Neu" selector_placeholder: "Benutzername eingeben" - name_placeholder: "Gruppenname, keine Leerzeichen, gleiche Regel wie beim Benutzernamen" about: "Hier kannst du Gruppenzugehörigkeiten und Gruppennamen bearbeiten." group_members: "Gruppenmitglieder" delete: "Löschen" delete_confirm: "Diese Gruppe löschen?" delete_failed: "Gruppe konnte nicht gelöscht werden. Wenn dies eine automatische Gruppe ist, kann sie nicht gelöscht werden." - delete_member_confirm: "'%{username}' aus der Gruppe '%{group}' entfernen?" delete_owner_confirm: "Eigentümerrechte für '%{username}' entfernen?" - name: "Name" add: "Hinzufügen" add_members: "Mitglieder hinzufügen" custom: "Benutzerdefiniert" @@ -2250,14 +2304,6 @@ de: add_owners: Eigentümer hinzufügen incoming_email: "Benutzerdefinierte Adresse für eingehende E-Mails" incoming_email_placeholder: "E-Mail-Adresse eingeben" - flair_url: "Avatar Flair Bild" - flair_url_placeholder: "(optionale) Bild-URL oder Font Awesome class" - flair_bg_color: "Profilbild Dekor-Knopf Hintergrundfarbe" - flair_bg_color_placeholder: "(Optional) Hex Farbwert" - flair_color: "Avatar Flair Farbe" - flair_color_placeholder: "(optionaler) Hex Farbenwert" - flair_preview: "Vorschau" - flair_note: "Beachte: Das Flair wird nur für die Primärgruppe eines Nutzers angezeigt" api: generate_master: "Master API Key erzeugen" none: "Es gibt momentan keine aktiven API-Keys" @@ -2312,7 +2358,7 @@ de: details: "Wenn auf einen Beitrag geantwortet wird oder der Beitrag geändert, gelöscht oder wiederhergestellt wird." user_event: name: "Benutzer Ereignis" - details: "Wenn ein Benutzer erstellt oder angenommen wird." + details: "Wenn ein Benutzer erstellt, genehmigt oder aktualisiert wird." delivery_status: title: "Versandstatus" inactive: "Inaktiv" @@ -2586,10 +2632,10 @@ de: block: "blockieren" do_nothing: "nichts tun" staff_actions: - title: "Mitarbeiter-Aktionen" + title: "Team-Aktionen" instructions: "Klicke auf die Benutzernamen und Aktionen, um die Liste zu filtern. Klicke auf das Profilbild, um die Benutzerseiten zu sehen." clear_filters: "Alles anzeigen" - staff_user: "Mitarbeiter" + staff_user: "Team-Mitglied" target_user: "Betroffener Benutzer" subject: "Objekt" when: "Wann" @@ -2633,6 +2679,11 @@ de: deleted_tag: "Schlagwort gelöscht" renamed_tag: "Schlagwort umbenannt" revoke_email: "E-Mail widerrufen" + lock_trust_level: "Vertrauensstufe sperren" + unlock_trust_level: "Vertrauensstufe entsperren" + activate_user: "Benutzer aktivieren" + deactivate_user: "Benutzer deaktivieren" + change_readonly_mode: "Nur-Lesen-Modus ändern" screened_emails: title: "Gefilterte E-Mails" description: "Wenn jemand ein Konto erstellt, werden die folgenden E-Mail-Adressen überprüft und es wird die Anmeldung blockiert oder eine andere Aktion ausgeführt." @@ -2682,7 +2733,7 @@ de: new: "Neu" active: "Aktiv" pending: "Genehmigung" - staff: 'Mitarbeiter' + staff: 'Team' suspended: 'Gesperrt' blocked: 'Blockiert' suspect: 'Verdächtig' @@ -2702,7 +2753,7 @@ de: member: 'Benutzer mit Vertrauensstufe 2 (Mitglied)' regular: 'Benutzer mit Vertrauensstufe 3 (Stammgast)' leader: 'Benutzer mit Vertrauensstufe 4 (Anführer)' - staff: "Mitarbeiter" + staff: "Team" admins: 'Administratoren' moderators: 'Moderatoren' blocked: 'Blockierte Benutzer' @@ -2933,6 +2984,7 @@ de: user_preferences: "Benutzereinstellungen" tags: "Schlagwörter" search: "Suche" + groups: "Gruppen" badges: title: Abzeichen new_badge: Neues Abzeichen @@ -3003,7 +3055,7 @@ de: with_time: %{username} um %{time} emoji: title: "Emoji" - help: "Neues Emoji hinzufügen, dass für alle verfügbar sein wird. (Tipp: per Drag & Drop kannst du gleichzeitig mehrere Dateien hinzufügen)" + help: "Neues Emoji hinzufügen, das für alle verfügbar sein wird. (Tipp: per Drag & Drop kannst du gleichzeitig mehrere Dateien hinzufügen)" add: "Neues Emoji hinzufügen" name: "Name" image: "Bild" @@ -3059,11 +3111,11 @@ de: uploading: "Hochladen..." quit: "Vielleicht später" staff_count: - one: "Deine Community hat 1 Mitarbeiter" - other: "Deine Community hat %{count} Mitarbeiter" + one: "Deine Community hat 1 Team-Mitglied." + other: "Deine Community hat %{count} Team-Mitglieder." invites: add_user: "Hinzufügen" - none_added: "Du hast bisher keine Mitarbeiter eingeladen. Willst du fortfahren?" + none_added: "Du hast bisher kein Team eingeladen. Möchtest du wirklich fortfahren?" roles: admin: "Administration" moderator: "Moderator" diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 62cd9883e82..2107e2511ff 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -248,7 +248,7 @@ en: like_count: "Likes" topic_count: "Topics" post_count: "Posts" - user_count: "New Users" + user_count: "Users" active_user_count: "Active Users" contact: "Contact Us" contact_info: "In the event of a critical issue or urgent matter affecting this site, please contact us at %{contact_info}." @@ -396,33 +396,43 @@ en: to: "To" edit: title: 'Edit Group' - group_title: 'Title' + full_name: 'Full Name' + add_members: "Add Members" + delete_member_confirm: "Remove '%{username}' from the '%{group}' group?" request_membership_pm: title: "Membership Request" - body: "I would like to request membership in @%{groupName}." + body: "I would like to apply for membership in @%{groupName}." name_placeholder: "Group name, no spaces, same as username rule" public: "Allow users to join/leave the group freely (Requires group to be visible)" empty: - posts: "There is no post by members of this group." - members: "There is no member in this group." - mentions: "There is no mention of this group." - messages: "There is no message for this group." - topics: "There is no topic by members of this group." - logs: "There is no logs for this group." + posts: "There are no posts by members of this group." + members: "There are no members in this group." + mentions: "There are no mentions of this group." + messages: "There are no messages for this group." + topics: "There are no topics by members of this group." + logs: "There are no logs for this group." add: "Add" join: "Join Group" leave: "Leave Group" request: "Request to Join Group" + automatic_group: Automatic Group + closed_group: Closed Group + is_group_user: "You are a member of this group" allow_membership_requests: "Allow users to send membership requests to group owners (Requires everyone to be able to mention the group)" + membership: "Membership" name: "Name" + user_count: "Number of Members" bio: "About Group" selector_placeholder: "Add members" owner: "owner" visible: "Group is visible to all users" - index: "Groups" + index: + title: "Groups" + empty: "There are no visible groups." title: one: "group" other: "groups" + activity: "Activity" members: "Members" topics: "Topics" posts: "Posts" @@ -686,7 +696,7 @@ en: email: title: "Email" - instructions: "Never shown to the public" + instructions: "never shown to the public" ok: "We will email you to confirm" invalid: "Please enter a valid email address" authenticated: "Your email has been authenticated by {{provider}}" @@ -697,13 +707,13 @@ en: name: title: "Name" - instructions: "Your full name (optional)" + instructions: "your full name (optional)" instructions_required: "Your full name" too_short: "Your name is too short" ok: "Your name looks good" username: title: "Username" - instructions: "Unique, no spaces, short" + instructions: "unique, no spaces, short" short_instructions: "People can mention you as @{{username}}" available: "Your username is available" global_match: "Email matches the registered username" @@ -823,6 +833,7 @@ en: none: "You haven't invited anyone here yet. You can send individual invites, or invite a bunch of people at once by uploading a CSV file." text: "Bulk Invite from File" success: "File uploaded successfully, you will be notified via message when the process is complete." + error: "Sorry, file should be of csv format." password: title: "Password" @@ -831,7 +842,7 @@ en: same_as_username: "Your password is the same as your username." same_as_email: "Your password is the same as your email." ok: "Your password looks good." - instructions: "At least %{count} characters." + instructions: "at least %{count} characters" summary: title: "Summary" @@ -1467,7 +1478,8 @@ en: go_bottom: "bottom" go: "go" jump_bottom: "jump to last post" - jump_prompt: "jump to post" + jump_prompt: "jump to..." + jump_prompt_of: "of %{count} posts" jump_prompt_long: "What post would you like to jump to?" jump_bottom_with_number: "jump to post %{post_number}" total: total posts @@ -1692,6 +1704,7 @@ en: edit: "Editing {{link}} {{replyAvatar}} {{username}}" edit_reason: "Reason: " post_number: "post {{number}}" + wiki_last_edited_on: "wiki last edited on" last_edited_on: "post last edited on" reply_as_new_topic: "Reply as linked Topic" continue_discussion: "Continuing the discussion from {{postLink}}:" @@ -1730,7 +1743,7 @@ en: file_too_large: "Sorry, that file is too big (maximum size is {{max_size_kb}}kb). Why not upload your large file to a cloud sharing service, then share the link?" too_many_uploads: "Sorry, you can only upload one file at a time." too_many_dragged_and_dropped_files: "Sorry, you can only upload 10 files at a time." - upload_not_authorized: "Sorry, the file you are trying to upload is not authorized (authorized extension: {{authorized_extensions}})." + upload_not_authorized: "Sorry, the file you are trying to upload is not authorized (authorized extensions: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Sorry, new users can not upload images." attachment_upload_not_allowed_for_new_user: "Sorry, new users can not upload attachments." attachment_download_requires_login: "Sorry, you need to be logged in to download attachments." @@ -1879,17 +1892,18 @@ en: hide: "Hide revision" show: "Show revision" revert: "Revert to this revision" + edit_wiki: "Edit wiki" comparing_previous_to_current_out_of_total: "{{previous}} {{current}} / {{total}}" displays: inline: title: "Show the rendered output with additions and removals inline" - button: ' HTML' + button: 'HTML' side_by_side: title: "Show the rendered output diffs side-by-side" - button: ' HTML' + button: 'HTML' side_by_side_markdown: title: "Show the raw source diffs side-by-side" - button: ' Raw' + button: 'Raw' category: can: 'can… ' @@ -1907,7 +1921,7 @@ en: tags_allowed_tag_groups: "Tag groups that can only be used in this category:" tags_placeholder: "(Optional) list of allowed tags" tag_groups_placeholder: "(Optional) list of allowed tag groups" - topic_featured_link_allowed: "Restricts editing the topic featured link in this category. Require site setting topic_featured_link_enabled is checked." + topic_featured_link_allowed: "Allow featured links in this category" delete: 'Delete Category' create: 'New Category' create_long: 'Create a new category' @@ -1942,6 +1956,7 @@ en: email_in_disabled: "Posting new topics via email is disabled in the Site Settings. To enable posting new topics via email, " email_in_disabled_click: 'enable the "email in" setting.' suppress_from_homepage: "Suppress this category from the homepage." + all_topics_wiki: "Make new topics wikis by default." sort_order: "Default Sort:" allow_badges_label: "Allow badges to be awarded in this category" edit_permissions: "Edit Permissions" @@ -2073,7 +2088,9 @@ en: one: "view" other: "views" replies: "Replies" - views_long: "this topic has been viewed {{number}} times" + views_long: + one: "this topic has been viewed 1 time" + other: "this topic has been viewed {{number}} times" activity: "Activity" likes: "Likes" likes_lowercase: @@ -2399,8 +2416,8 @@ en: backups: "backups" traffic_short: "Traffic" traffic: "Application web requests" - page_views: "API Requests" - page_views_short: "API Requests" + page_views: "Pageviews" + page_views_short: "Pageviews" show_traffic_report: "Show Detailed Traffic Report" reports: @@ -2503,7 +2520,6 @@ en: delete: "Delete" delete_confirm: "Delete this group?" delete_failed: "Unable to delete group. If this is an automatic group, it cannot be destroyed." - delete_member_confirm: "Remove '%{username}' from the '%{group}' group?" delete_owner_confirm: "Remove owner privilege for '%{username}'?" add: "Add" add_members: "Add members" @@ -2554,7 +2570,7 @@ en: warn_local_payload_url: "It seems you are trying to set up the webhook to a local url. Event delivered to a local address may cause side-effect or unexpected behaviours. Continue?" secret_invalid: "Secret must not have any blank characters." secret_too_short: "Secret should be at least 12 characters." - secret_placeholder: "A optional string, used for generating signature" + secret_placeholder: "An optional string, used for generating signature" event_type_missing: "You need to set up at least one event type." content_type: "Content Type" secret: "Secret" @@ -2577,7 +2593,7 @@ en: details: "When there is a new reply, edit, deleted or recovered." user_event: name: "User Event" - details: "When a user is created or approved." + details: "When a user is created, approved or updated." delivery_status: title: "Delivery Status" inactive: "Inactive" @@ -2901,10 +2917,17 @@ en: revoke_admin: "revoke admin" grant_moderation: "grant moderation" revoke_moderation: "revoke moderation" - backup_operation: "backup operation" + backup_create: "create backup" deleted_tag: "deleted tag" renamed_tag: "renamed tag" revoke_email: "revoke email" + lock_trust_level: "lock trust level" + unlock_trust_level: "unlock trust level" + activate_user: "activate user" + deactivate_user: "deactivate user" + change_readonly_mode: "change readonly mode" + backup_download: "download backup" + backup_destroy: "destroy backup" screened_emails: title: "Screened Emails" description: "When someone tries to create a new account, the following email addresses will be checked and the registration will be blocked, or some other action performed." @@ -3214,6 +3237,7 @@ en: user_preferences: "User Preferences" tags: "Tags" search: "Search" + groups: "Groups" badges: title: Badges diff --git a/config/locales/client.es.yml b/config/locales/client.es.yml index dc0795abae0..f8596ce4d87 100644 --- a/config/locales/client.es.yml +++ b/config/locales/client.es.yml @@ -99,7 +99,7 @@ es: x_years: one: "%{count} año después" other: "%{count} años después" - previous_month: 'Anterior mes' + previous_month: 'Mes anterior' next_month: 'Próximo mes' share: topic: 'comparte un enlace a este tema' @@ -142,9 +142,9 @@ es: bootstrap_mode_disabled: "El modo de arranque se desactivará en las próximas 24 horas." s3: regions: - us_east_1: "US East (N. Virginia)" - us_west_1: "US West (N. California)" - us_west_2: "US West (Oregon)" + us_east_1: "EEUU Este (Virginia del Norte)" + us_west_1: "EEUU Oeste (Californa norte)" + us_west_2: "EEUU Oeste (Oregon)" us_gov_west_1: "AWS GovCloud (US)" eu_west_1: "UE (Irlanda)" eu_central_1: "UE (Frankfurt)" @@ -211,10 +211,10 @@ es: all_time: "Todo el tiempo" last_7_days: "Últimos 7 días" last_30_days: "Últimos 30 días" - like_count: "Me Gusta" + like_count: "Me gusta" topic_count: "Temas" post_count: "Posts" - user_count: "Nuevos usuarios" + user_count: "Usuarios nuevos" active_user_count: "Usuarios activos" contact: "Contáctanos" contact_info: "En caso de un error crítico o un asunto urgente referente a este sitio, por favor, contáctanos en %{contact_info}." @@ -222,8 +222,8 @@ es: title: "Marcador" clear_bookmarks: "Quitar Marcadores" help: - bookmark: "Clic para guardar en marcadores el primer post de este tema" - unbookmark: "Clic para quitar todos los marcadores de este tema" + bookmark: "Haz clic para guardar en marcadores el primer post de este tema" + unbookmark: "Haz clic para quitar todos los marcadores de este tema" bookmarks: not_logged_in: "Lo sentimos, debes iniciar sesión para guardar posts en marcadores." created: "has guardado este post en marcadores" @@ -270,7 +270,7 @@ es: approve: 'Aprobar' reject: 'Rechazar' delete_user: 'Eliminar usuario' - title: "Necesita Aprobación" + title: "Necesita aprobación" none: "No hay posts para revisar" edit: "Editar" cancel: "Cancelar" @@ -278,10 +278,10 @@ es: has_pending_posts: one: "Este tema tiene 1 post esperando aprobación" other: "Este tema tiene {{count}} posts esperando aprobación" - confirm: "Guardar Cambios" + confirm: "Guardar cambios" delete_prompt: "¿Seguro que quieres eliminar a %{username}? Se eliminarán todos sus posts y se bloqueará su email y dirección IP." approval: - title: "El Post Necesita Aprobación" + title: "El post necesita aprobación" description: "Hemos recibido tu nuevo post pero necesita ser aprobado por un moderador antes de aparecer. Por favor, ten paciencia." pending_posts: one: "Tienes 1 post pendiente." @@ -302,13 +302,13 @@ es: sent_by_user: "Enviado por {{user}}" sent_by_you: "Enviado por ti" directory: - filter_name: "filtrar por usuario" + filter_name: "filtrar por nombre de usuario" title: "Usuarios" likes_given: "Dados" likes_received: "Recibidos" topics_entered: "Vistos" topics_entered_long: "Temas vistos" - time_read: "Tiempo de Lectura" + time_read: "Tiempo de lectura" topic_count: "Temas" topic_count_long: "Temas creados" post_count: "Respuestas" @@ -321,21 +321,63 @@ es: total_rows: one: "1 usuario" other: "%{count} usuarios" + group_histories: + actions: + change_group_setting: "Cambiar ajustes de grupo" + add_user_to_group: "Añadir usuario" + remove_user_from_group: "Quitar usuario" + make_user_group_owner: "Convertir en dueño" + remove_user_as_group_owner: "Quitar de dueño" groups: + logs: + title: "Registros" + when: "Cuándo" + action: "Acción" + acting_user: "Usuario que actuó" + target_user: "Usuario objetivo" + subject: "Sujeto" + details: "Detalles" + from: "De" + to: "A" + edit: + title: 'Editar grupo' + full_name: 'Nombre completo' + add_members: "Añadir miembros" + delete_member_confirm: "¿Quitar a '%{username}' del grupo '%{group}'?" + request_membership_pm: + title: "Solicitud de miembro" + body: "Me gustaría pertenecer al grupo @%{groupName}." + name_placeholder: "Nombre del grupo, sin espacios, igual que los nombres de usuarios" + public: "Permitir a los usuarios unirse o salir del grupo cuando quieran (es necesario que el grupo sea visible)" empty: - posts: "No hay mensajes publicados por los miembros de este grupo." - members: "Este grupo no tiene miembros." + posts: "No existe ningún post de miembros de este grupo" + members: "No hay miembros en este grupo." mentions: "No hay menciones de este grupo." - messages: "No hay mensajes para este grupo." + messages: "No hay menciones a este grupo." topics: "No hay temas de miembros de este grupo." + logs: "No hay registros para este grupo." add: "Añadir" + join: "Unirse al grupo" + leave: "Salir del grupo" + request: "Solicitar unirse al grupo" + automatic_group: Grupo automático + closed_group: Grupo cerrado + is_group_user: "Eres miembro de este grupo" + allow_membership_requests: "Permitir a los usuarios solicitudes para ser miembro a los dueños del grupo (es necesario que todo el mundo pueda mencionar al grupo)" + membership: "Membresía" + name: "Nombre" + user_count: "Número de miembros" + bio: "Acerca del grupo" selector_placeholder: "Añadir miembros" owner: "propietario" visible: "El grupo es visible para todos los usuarios" - index: "Grupos" + index: + title: "Grupos" + empty: "No hay grupos visibles." title: one: "grupo" other: "grupos" + activity: "Actividad" members: "Miembros" topics: "Temas" posts: "Posts" @@ -354,7 +396,7 @@ es: notifications: watching: title: "Vigilando" - description: "e te notificará de cada nuevo post en este mensaje y se mostrará un contador de nuevos posts." + description: "Se te notificará de cada nuevo post en este mensaje y se mostrará un contador de nuevos posts." watching_first_post: title: "Vigilar Primer Post" description: "Sólo se te notificará del primer post en cada nuevo tema en este grupo." @@ -367,6 +409,15 @@ es: muted: title: "Silenciado" description: "Nunca se te notificará de nada sobre temas en este grupo." + flair_url: "Adorno de imagen de usuario" + flair_url_placeholder: "(Opcional) Dirección URL de una imagen o clase de Font Awesome" + flair_bg_color: "Color de fondo del adorno de la imagen de usuario" + flair_bg_color_placeholder: "(Opcional) Valor del color en hexadecimal" + flair_color: "Color del adorno de la imagen de usuario" + flair_color_placeholder: "(Opcional) Valor del color en hexadecimal" + flair_preview_icon: "Previsualización del icono" + flair_preview_image: "Previsualización de la imagen" + flair_note: "Nota: el adorno solo se mostrará para el grupo primario del usuario." user_action_groups: '1': "'Me gusta' Dados" '2': "'Me gusta' Recibidos" @@ -695,11 +746,10 @@ es: link_generated: "¡Enlace de invitación generado satisfactoriamente!" valid_for: "El enlace de invitación sólo es válido para esta dirección: %{email}" bulk_invite: - none: "No has invitado a nadie todavía. Puedes enviar invitaciones individuales o invitar a un grupo de personas a la vez subiendo un archivo para invitaciones en masa." + none: "Aún no has invitado a nadie aquí. Puedes enviar invitaciones individuales, o invitar varias personas a la vez subiendo un archivo CSV." text: "Archivo de Invitación en Masa" - uploading: "Subiendo..." success: "Archivo subido correctamente, se te notificará con un mensaje cuando se complete el proceso." - error: "Hubo un error al subir '{{filename}}': {{message}}" + error: "Lo sentimos, el archivo debería tener formato csv." password: title: "Contraseña" too_short: "Tu contraseña es demasiada corta." @@ -793,9 +843,9 @@ es: enabled: "Este sitio está en modo solo-lectura. Puedes continuar navegando pero algunas acciones como responder o dar \"me gusta\" no están disponibles por ahora." login_disabled: "Iniciar sesión está desactivado mientras el foro esté en modo solo lectura." logout_disabled: "Cerrar sesión está desactivado mientras el sitio se encuentre en modo de sólo lectura." - too_few_topics_and_posts_notice: "¡Vamos a dar por comenzada la comunidad! Hay %{currentTopics} / %{requiredTopics} temas y %{currentPosts} / %{requiredPosts} mensajes. Los nuevos visitantes necesitan algo que leer y a lo que responder." + too_few_topics_and_posts_notice: "¡Vamos a dar por comenzada la comunidad! Hay %{currentTopics} / %{requiredTopics} temas y %{currentPosts} / %{requiredPosts} posts. Los nuevos visitantes necesitan algo que leer y a lo que responder." too_few_topics_notice: "¡Vamos a dar por comenzada la comunidad! Hay %{currentTopics} / %{requiredTopics} temas. Los nuevos visitantes necesitan algo que leer y a lo que responder." - too_few_posts_notice: "¡Vamos a dar por empezada la comunidad! Hay %{currentPosts} / %{requiredPosts} mensajes. Los nuevos visitantes necesitan algo que leer y a lo que responder." + too_few_posts_notice: "¡Vamos a dar por empezada la comunidad! Hay %{currentPosts} / %{requiredPosts} posts. Los nuevos visitantes necesitan algo que leer y a lo que responder." logs_error_rate_notice: reached: "%{relativeAge}%{rate} alcanzó el límite establecido en las opciones del sitio del %{siteSettingRate}." exceeded: "%{relativeAge}%{rate} excedió el límite establecido en las opciones del sitio del %{siteSettingRate}." @@ -826,7 +876,7 @@ es: hide_forever: "no, gracias" hidden_for_session: "Vale, te preguntaremos mañana. Recuerda que también puedes usar el botón 'Iniciar sesión' para crear una cuenta en cualquier momento." intro: "¡Hola! :heart_eyes: Parece que estás interesado en las cosas que nuestros usuarios publican, pero no tienes una cuenta registrada." - value_prop: "Cuando te registras, recordamos lo que has leído, para que puedas volver justo donde estabas leyendo. También recibes notificaciones, por aquí y por email, cuando se publican nuevos mensajes. ¡También puedes darle a Me gusta a los mensajes! :heartbeat:" + value_prop: "Cuando te registras, recordamos lo que has leído, para que puedas volver justo donde estabas leyendo. También recibes notificaciones, por aquí y por email, cuando se publican nuevos posts. ¡También puedes darle a Me gusta a los mensajes! :heartbeat:" summary: enabled_description: "Estás viendo un resumen de este tema: los posts más interesantes determinados por la comunidad." description: "Hay {{replyCount}} respuestas." @@ -964,8 +1014,10 @@ es: title: "O pulsa Ctrl+Intro" users_placeholder: "Añadir usuario" title_placeholder: "En una frase breve, ¿de qué trata este tema?" + title_or_link_placeholder: "Escribe un título o pega un enlace aquí" edit_reason_placeholder: "¿Por qué lo estás editando?" show_edit_reason: "(añadir motivo de edición)" + topic_featured_link_placeholder: "Introduce el enlace mostrado con el título." reply_placeholder: "Escribe aquí. Usa Markdown, BBCode o HTML para darle formato. Arrastra o pega imágenes." view_new_post: "Ver tu nuevo post." saving: "Guardando" @@ -1279,7 +1331,8 @@ es: go_bottom: "abajo" go: "ir" jump_bottom: "salta al último post" - jump_prompt: "saltar al post" + jump_prompt: "saltar a..." + jump_prompt_of: "de %{count} posts" jump_prompt_long: "¿Hacia qué post quieres saltar?" jump_bottom_with_number: "saltar al post %{post_number}" total: posts totales @@ -1511,7 +1564,7 @@ es: file_too_large: "Lo sentimos, ese archivo es demasiado grande (el tamaño máximo es {{max_size_kb}}kb). ¿Quizá podrías subir el archivo a un servicio de almacenamiento en la nube y compartir aquí el enlace?" too_many_uploads: "Lo siento solo puedes subir un archivo cada vez." too_many_dragged_and_dropped_files: "Lo sentimos, sólo puedes subir 10 archivos a la vez." - upload_not_authorized: "Lo sentimos, el archivo que intenta cargar no está autorizado (authorized extension: {{authorized_extensions}})." + upload_not_authorized: "Lo sentimos, el archivo que estás intentando subir no está permitido (extensiones autorizadas: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Lo siento, usuarios nuevos no pueden subir imágenes." attachment_upload_not_allowed_for_new_user: "Lo siento, usuarios nuevos no pueden subir archivos adjuntos." attachment_download_requires_login: "Lo sentimos, necesitas haber iniciado sesión para descargar archivos adjuntos." @@ -1677,6 +1730,7 @@ es: tags_allowed_tag_groups: "Grupos de etiquetas que sólo pueden pueden utilizarse en esta categoría:" tags_placeholder: "(Opcional) lista de etiquetas permitidas" tag_groups_placeholder: "(Opcional) lista de grupos de etiquetas permitidos" + topic_featured_link_allowed: "Permitir enlaces destacados en esta categoría" delete: 'Eliminar categoría' create: 'Crear categoría' create_long: 'Crear una nueva categoría' @@ -1711,6 +1765,7 @@ es: email_in_disabled: "La posibilidad de publicar nuevos temas por email está deshabilitada en los ajustes del sitio. Para habilitar la publicación de nuevos temas por email," email_in_disabled_click: 'activa la opción "email in".' suppress_from_homepage: "Ocultar categoría de la página de inicio." + all_topics_wiki: "Hacer todos los temas wiki por defecto" sort_order: "Orden por defecto:" allow_badges_label: "Permitir conceder distintivos en esta categoría" edit_permissions: "Editar permisos" @@ -1833,7 +1888,9 @@ es: one: "visita" other: "visitas" replies: "Respuestas" - views_long: "este tema se ha visto {{number}} veces" + views_long: + one: "este tema se ha visto 1 vez" + other: "este tema se ha visto {{number}} veces" activity: "Actividad" likes: "Likes" likes_lowercase: @@ -1989,7 +2046,7 @@ es: earned_n_times: one: "Ganó este distintivo 1 vez" other: "Ganó este distintivo %{count} veces" - granted_on: "Concedido el %{date}" + granted_on: "Concedido hace: %{date}" others_count: "Otras personas con este distintivo (%{count})" title: Distintivos allow_title: "título disponible" @@ -2138,8 +2195,8 @@ es: backups: "backups" traffic_short: "Tráfico" traffic: "Peticiones web de la app" - page_views: "Peticiones de API" - page_views_short: "Peticiones de API" + page_views: "Páginas vistas" + page_views_short: "Páginas vistas" show_traffic_report: "Mostrar informe detallado del tráfico" reports: today: "Hoy" @@ -2229,15 +2286,12 @@ es: refresh: "Actualizar" new: "Nuevo" selector_placeholder: "introduce nombre de usuario" - name_placeholder: "Nombre del grupo, sin espacios, al igual que la regla del nombre usuario" about: "Edita los aquí los nombres de los grupos y sus miembros" group_members: "Miembros del grupo" delete: "Borrar" delete_confirm: "Borrar este grupo?" delete_failed: "No se pudo borrar el grupo. Si este es un grupo automático, no se puede destruir." - delete_member_confirm: "¿Eliminar a '%{username}' del grupo '%{group}'?" delete_owner_confirm: "¿Quitar privilegios de propietario para '%{username}'?" - name: "Nombre" add: "Añadir" add_members: "Añadir miembros" custom: "Personalizado" @@ -2254,14 +2308,6 @@ es: add_owners: Añadir propietarios incoming_email: "Correos electrónicos entrantes personalizados" incoming_email_placeholder: "introducir dirección de email" - flair_url: "Imagen distintiva" - flair_url_placeholder: "(Opcional) URL de imagen o clase de Font Awesome" - flair_bg_color: "Color de fondo de imagen distintiva" - flair_bg_color_placeholder: "(Optional) Valor hexadecimal del color" - flair_color: "Color de la imagen distintiva" - flair_color_placeholder: "(Opcional) Color en valor hexadecimal" - flair_preview: "Vista previa" - flair_note: "Nota: sólo se mostrará la imagen distintiva del grupo principal del usuario." api: generate_master: "Generar clave maestra de API" none: "No hay ninguna clave de API activa en este momento." @@ -2293,7 +2339,7 @@ es: warn_local_payload_url: "Parece que estás estableciendo el webhook a una url local. El evento enviado a una dirección local podría causar algún efecto secundario o comportamientos inesperados. ¿Continuar?" secret_invalid: "Secret no debe tener espacios en blanco." secret_too_short: "Secret debería tener al menos 12 caracteres." - secret_placeholder: "Una cadena opcional, para generar firma" + secret_placeholder: "Una cadena opcional, utilizada para generar una firma" event_type_missing: "Necesitas establecer al menos un tipo de evento." content_type: "Tipo de contenido" secret: "Secret" @@ -2316,7 +2362,7 @@ es: details: "Cuando se publique, edite, elimine o recupere una respuesta." user_event: name: "Evento de usuario" - details: "Cuando se cree o apruebe un usuario." + details: "Cuando un usuario es creado, aprobado o actualizado." delivery_status: title: "Estado de entrega" inactive: "Inactivo" @@ -2637,6 +2683,11 @@ es: deleted_tag: "etiqueta eliminada" renamed_tag: "etiqueta renombrada" revoke_email: "revocar email" + lock_trust_level: "Bloqueó el nivel de confianza" + unlock_trust_level: "Desbloqueó el nivel de confianza" + activate_user: "activó a un usuario" + deactivate_user: "desactivó a un usuario" + change_readonly_mode: "cambio a modo de sólo lectura" screened_emails: title: "Correos bloqueados" description: "Cuando alguien trata de crear una cuenta nueva, los siguientes correos serán revisados y el registro será bloqueado, o alguna otra acción será realizada." @@ -2937,6 +2988,7 @@ es: user_preferences: "Preferencias de los Usuarios" tags: "Etiquetas" search: "Búsqueda" + groups: "Grupos" badges: title: Distintivos new_badge: Nuevo distintivo diff --git a/config/locales/client.et.yml b/config/locales/client.et.yml index fbe631c0ba9..ce8595abe59 100644 --- a/config/locales/client.et.yml +++ b/config/locales/client.et.yml @@ -136,6 +136,7 @@ et: enabled: 'lisatud %{when}' disabled: 'eemaldatud %{when}' topic_admin_menu: "teema admintegevused" + wizard_required: "On aeg oma foorum seadistada! Käivita algseadistamise viisard!" emails_are_disabled: "Kõik väljuvad meilid on administraatori poolt blokeeritud. Ühtegi teavitust meili teel ei saadeta." bootstrap_mode_enabled: "Oma uue saidi lansseerimise hõlbustamiseks oled käivitusrežiimil. Kõik uued kasutajad saavad usaldustaseme 1 ja nende igapäevased kokkuvõtvad teavitused meili teel on aktiveeritud. See lülitub automaatselt välja kui kasutajate koguarv ületab %{min_users} piiri." bootstrap_mode_disabled: "Käivitusrežiim lülitub välja järgmise 24 tunni jooksul." @@ -320,21 +321,63 @@ et: total_rows: one: "1 kasutaja" other: "%{count} kasutajat" + group_histories: + actions: + change_group_setting: "Muuda grupi sätteid" + add_user_to_group: "Lisa kasutaja" + remove_user_from_group: "Eemalda kasutaja" + make_user_group_owner: "Määra omanikuks" + remove_user_as_group_owner: "Eemalda omanik" groups: + logs: + title: "Logid" + when: "Millal" + action: "Tegevus" + acting_user: "Tegev kasutaja" + target_user: "Sihtkasutaja" + subject: "Teema" + details: "Detailid" + from: "Kellelt" + to: "Kellele" + edit: + title: 'Muuda gruppi' + full_name: 'Täisnimi' + add_members: "Lisa liikmed" + delete_member_confirm: "Eemalda '%{username}' grupist '%{group}'?" + request_membership_pm: + title: "Liikmelisuse taotlus" + body: "Soovin liituda grupiga @%{groupName}." + name_placeholder: "Grupi nimi, tühikuteta, vastab kasutajanime reeglitele" + public: "Luba kasutajatel vabalt grupiga liituda/sellest lahkuda (nõuab, et grupp oleks nähtav)" empty: posts: "Selle grupi liikmetelt ei ole postitusi." - members: "Selles grupis liikmeid pole." + members: "Sellel grupil liikmed puuduvad." mentions: "Seda gruppi pole mainitud." messages: "Sellele grupile teated puuduvad." - topics: "Selle grupi liikmetelt teemasid ei ole." + topics: "Selle grupi liikmetelt ei ole teemasid." + logs: "Sellele grupile logid puuduvad." add: "Lisa" + join: "Liitu grupiga" + leave: "Lahku grupist" + request: "Taotle liitumist grupiga" + automatic_group: Automaatne grupp + closed_group: Suletud grupp + is_group_user: "Oled selle grupi liige" + allow_membership_requests: "Luba kasutajatel saata grupi omanikele liikmelisuse taotlusi (eeldab, et igaüks saab gruppi mainida)" + membership: "Liikmelisus" + name: "Nimi" + user_count: "Liikmete arv" + bio: "Grupist" selector_placeholder: "Lisa liikmeid" owner: "omanik" visible: "Grupp on kõigile kasutajatele nähtav." - index: "Grupid" + index: + title: "Grupid" + empty: "Ühtegi nähtavat gruppi pole." title: one: "grupp" other: "grupid" + activity: "Tegevused" members: "Liikmed" topics: "Teemat" posts: "Postitused" @@ -366,6 +409,15 @@ et: muted: title: "Vaigistatud" description: "Sind ei teavitata ühestki uuest teemast selles grupis." + flair_url: "Avatari andekuse pilt" + flair_url_placeholder: "(Valikuline) Pildi URL või Font Awesome klass" + flair_bg_color: "Avatari andekuse taustavärv" + flair_bg_color_placeholder: "(Valikuline) Värvi väärtus heksakoodis" + flair_color: "Avatari andekuse värv" + flair_color_placeholder: "(Valikuline) Värvi väärtus heksakoodis" + flair_preview_icon: "Ikooni eelvaatlus" + flair_preview_image: "Pildi eelvaatlus" + flair_note: "Märkus: Andekus kuvatakse vaid kasutaja põhigrupi jaoks." user_action_groups: '1': "Meeldimisi antud" '2': "Meeldimisi saadud" @@ -427,6 +479,11 @@ et: profile: "Profiil" mute: "Vaigista" edit: "Muuda Eelistusi" + download_archive: + button_text: "Lae Minu Postitused alla" + confirm: "Oled kindel, et soovid enda postitused alla laadida?" + success: "Allalaadimine käivitatud. Protsessi lõppemisel saadetakse Sulle teade." + rate_limit_error: "Postitusi saab alla laadida üks kord ööpäevas. Palun proovi homme uuesti." new_private_message: "Uus sõnum" private_message: "Sõnum" private_messages: "Sõnumid" @@ -450,6 +507,7 @@ et: each_browser_note: "Märkus: see säte tuleb muuta igas kasutusel olevas brauseris." dismiss_notifications: "Lükka kõik tagasi" dismiss_notifications_tooltip: "Märgi kõik lugemata teavitused loetuks" + first_notification: "Sinu esimene teavitus! Vali see et alustada." disable_jump_reply: "Ära hüppa minu postitusse peale vastamist" dynamic_favicon: "Kuva uute / muudetud teemade arvu brauseri ikoonil" external_links_in_new_tab: "Ava kõik välisviited uuel sakil" @@ -472,6 +530,7 @@ et: Vaigistatud teemad ja foorumid ei kajastu nendes meilides. daily: "Saada igapäevased kokkuvõtted" individual: "Saada meil iga uue postituse kohta" + individual_no_echo: "Saada meil iga uue postituse kohta, v.a. enda omad" many_per_day: "Saada mulle meil iga uue postituse kohta (umbes {{dailyEmailEstimate}} meili päevas)" few_per_day: "Saada mulle meil iga uue postituse kohta (umbes 2 meili päevas)" tag_settings: "Sildid" @@ -595,6 +654,7 @@ et: title: "Kasutujaliidese keel" instructions: "Kasutajaliidese keel. See muutub, kui lehe uuesti laed." default: "(vaikimisi)" + any: "iga" password_confirmation: title: "Salasõna uuesti" last_posted: "Viimane postitus" @@ -652,6 +712,7 @@ et: after_4_minutes: "pärast 4 minutit" after_5_minutes: "pärast 5 minutit" after_10_minutes: "pärast 10 minutit" + notification_level_when_replying: "Kui ma postitan teemasse, vali teemaks" invited: search: "kirjuta kutsete otsimiseks..." title: "kutsed" @@ -682,12 +743,12 @@ et: account_age_days: "Konto vanus päevades" create: "Saada kutse" generate_link: "Kopeeri viide kutsele" + link_generated: "Kutse link edukalt genereeritud!" + valid_for: "Kutse link kehtib vaid meiliaadressile: %{email}" bulk_invite: - none: "Sa ei ole veel kedagi siia kutsunud. Võid saata kutseid individuaalselt, või korraga tervele grupile kui laed üles masskutsete faili." + none: "Sa ei ole kedagi veel siia kutsunud. Võid saata kutsed personaalselt või korraga tervele nimekirjale laadides üles CSV faili." text: "Masskutse Failist" - uploading: "Laen üles..." success: "Fail edukalt üles laetud. Sulle saabub teade, kui protsess on lõpule jõudnud." - error: "Faili '{{filename}}' üleslaadimisel tekkis viga: {{message}}" password: title: "Parool" too_short: "Parool on liiga lühike." @@ -839,6 +900,7 @@ et: trust_level: 'Usaldustase' search_hint: 'kasutajanimi, meil või IP-aadress' create_account: + disclaimer: "Registreerudes nõustud nii puutumatusnormide kui ka teenuse tingimustega." title: "Loo uus konto" failed: "Miski läks valesti - võimalik, et see meiliaadress on juba registreeritud. Proovi viidet unustatud parooli lehele" forgot_password: @@ -929,6 +991,9 @@ et: group_mentioned: one: "Mainides {{group}}, oled teavitamas 1 inimest – oled selles kindel?" other: "Mainides {{group}}, oled teavitamas {{count}} inimest – oled selles kindel?" + cannot_see_mention: + category: "Mainisid kasutajat {{username}} kuid teda ei teavitata, kuna tal puudub juurdepääs siia foorumisse. Lisa ta gruppi, kellel on siia foorumisse ligipääs." + private: "Mainisid kasutajat {{username}} kuid teda ei teavitata, kuna tal puudub juurdepääs käesoleva privaatsõnumi juurde. Kutsu ta seda privaatsõnumit vaatama." duplicate_link: "Näib, et sinu viide {{domain}} oli juba postitatud teemasse kasutaja @{{username}} poolt postituse vastuses {{ago}} – oled kindel, et soovid selle uuesti postitada?" error: title_missing: "Pealkiri on kohustuslik" @@ -948,8 +1013,10 @@ et: title: "Või vajuta Ctrl+Enter" users_placeholder: "Lisa kasutaja" title_placeholder: "Kuidas seda vestlust ühe lausega kirjeldada?" + title_or_link_placeholder: "Kirjuta pealkiri või kleebi link siia" edit_reason_placeholder: "miks sa seda muudad?" show_edit_reason: "(lisa muutmise põhjus)" + topic_featured_link_placeholder: "Järgi pealkirjas näidatud viidet." reply_placeholder: "Kirjuta siia. Kujundamiseks kasuta Markdown, BBCode, või HTML-i. Pildid võid siia lohistada või kleepida." view_new_post: "Vaata oma uut postitust." saving: "Salvestan" @@ -1097,6 +1164,8 @@ et: label: Foorumis in_group: label: Grupis + with_badge: + label: Märgisega with_tags: label: Sildiga filters: @@ -1108,6 +1177,8 @@ et: private: on minu sõnumite hulgas bookmarks: on minu järjehoidjaga first: on teema esimesed postitused + pinned: on esile tõstetud + unpinned: ei ole esile tõstetud wiki: on wiki statuses: label: Kus teemad @@ -1131,6 +1202,8 @@ et: topics: new_messages_marker: "viimane visiit" bulk: + select_all: "Vali kõik" + clear_all: "Puhasta kõik" unlist_topics: "Eemalda teemad loetelust" reset_read: "Nulli loetud" delete: "Kustuta teemad" @@ -1257,7 +1330,7 @@ et: go_bottom: "alla" go: "mine" jump_bottom: "hüppa viimase postituse juurde" - jump_prompt: "hüppa postituse juurde" + jump_prompt_of: "%{count} postitusest" jump_prompt_long: "Millise postituse juurde soovid hüpata?" jump_bottom_with_number: "hüppa postituse %{post_number} juurde" total: postitusi kokku @@ -1338,6 +1411,7 @@ et: help: 'jaga viidet sellele teemale' print: title: 'Trüki' + help: 'Ava selle teema prindikõlblik versioon' flag_topic: title: 'Tähista' help: 'tähista see teema privaatselt meelespidamiseks või saada selle kohta privaatsõnum' @@ -1450,6 +1524,7 @@ et: post: reply: " {{replyAvatar}} {{usernameLink}}" reply_topic: " {{link}}" + quote_reply: "Tsitaat" edit: "Redigeerin {{link}} {{replyAvatar}} {{username}}" edit_reason: "Põhjus:" post_number: "postitus {{number}}" @@ -1487,7 +1562,6 @@ et: file_too_large: "Vabandame. see fail on liiga suur (maksimum on {{max_size_kb}}kB). Miks mitte laadida see suur fail mõnda failijagamisteenusesse pilves ja jagada viidet selleni?" too_many_uploads: "Vabandame, faile saab üles laadida vaid ühekaupa." too_many_dragged_and_dropped_files: "Vabandame, faile saab üles laadida vaid kuni 10 korraga." - upload_not_authorized: "Vabandame, faili tüüp, mida püüad üles laadida, ei ole lubatud (lubatud laiendid: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Vabandame, uued kasutajad ei saa pilte üles laadida." attachment_upload_not_allowed_for_new_user: "Vabandame, uued kasutajad ei saa manuseid üles laadida." attachment_download_requires_login: "Vabandame, manuste allalaadimiseks pead olema sisse logitud." @@ -1653,6 +1727,7 @@ et: tags_allowed_tag_groups: "Siltide grupid, mida saab kasutada vaid selles foorumis:" tags_placeholder: "(Valikuline) loetelu lubatud silte" tag_groups_placeholder: "(Valikuline) loetelu lubatud siltide gruppe" + topic_featured_link_allowed: "Luba selles foorumis esiletõstetud linke " delete: 'Kustuta foorum' create: 'Uus foorum' create_long: 'Loo uus foorum' @@ -1687,6 +1762,8 @@ et: email_in_disabled: "Uute teemade avamine meili teel on saidi sätetes välja lülitatud. Avamiseks" email_in_disabled_click: 'aktiveeri säte "sissetulev meil".' suppress_from_homepage: "Eemalda see foorum avalehelt." + all_topics_wiki: "Tee uued teemad vaikimisi wikideks." + sort_order: "Vaikejärjestus" allow_badges_label: "Luba selles foorumis autasustamist märgistega" edit_permissions: "Muuda kasutusõigusi" add_permission: "Lisa kasutusõigus" @@ -1712,6 +1789,18 @@ et: muted: title: "Vaigistatud" description: "Sind ei teavitata ühestki uuest teemast nendes foorumites, samuti ei ilmu nad viimaste teemade alla." + sort_options: + default: "vaikimisi" + likes: "Meeldimisi" + op_likes: "Algse postituse meeldimisi" + views: "Vaatamisi" + posts: "Postitused" + activity: "Tegevused" + posters: "Postitajad" + category: "Foorum" + created: "Loodud" + sort_ascending: 'Ülenev' + sort_descending: 'Alanev' flagging: title: 'Täname, et aitad meie kogukonna viisakust säilitada!' action: 'Tähista postitus' @@ -1719,6 +1808,7 @@ et: notify_action: 'Sõnum' official_warning: 'Ametlik hoiatus' delete_spammer: "Kustuta spämmija" + delete_confirm_MF: "Oled kustutamas {POSTS, plural, one {1 postitust} other {# postitust}} ja {TOPICS, plural, one {1 teemat} other {# teemat}} sellelt kasutajalt, eemaldamas tema kontot, blokeerimas registreerumisi tema IP-aadressilt {ip_address}, ja lisamas tema meiliaddressi {email} püsiva blokeeringu loetellu. Oled kindel, et see kasutaja on tõesti spämmija?" yes_delete_spammer: "Jah, kustuta spämmija" ip_address_missing: "(asjassepuutumatu)" hidden_email_address: "(peidetud)" @@ -1733,6 +1823,9 @@ et: custom_placeholder_notify_user: "Ole täpne, konstruktiivne ja alati lahke." custom_placeholder_notify_moderators: "Anna meile teada, mis Sulle täpsemalt muret teeb ja võimalusel lisa asjassepuutuvaid viiteid ning näiteid." custom_message: + at_least: + one: "sisesta vähemalt 1 sümbol" + other: "sisesta vähemalt {{count}} sümbolit" more: one: "1 veel" other: "{{count}} veel..." @@ -1792,7 +1885,6 @@ et: one: "vaatamine" other: "vaatamisi" replies: "Vastuseid" - views_long: "seda teemat on vaadatud {{number}} korda" activity: "Aktiivsus" likes: "Meeldimisi" likes_lowercase: @@ -1945,6 +2037,7 @@ et: mark_regular: 'm, r Tavaline (vaikimisi) teema' mark_tracking: 'm, t Jälgi teemat' mark_watching: 'm, w Vaatle teemat' + print: 'ctrl+p Prindi teema' badges: earned_n_times: one: "Teenis selle märgise 1 kord" @@ -2062,6 +2155,8 @@ et: custom_message_placeholder: "Sisesta oma individuaalne sõnum" custom_message_template_forum: "Kuule, Sa peaksid selle foorumiga liituma!" custom_message_template_topic: "Kuule, arvan et see teema meeldiks Sulle!" + safe_mode: + enabled: "Kaitstud režiim on aktiivne, väljumiseks sulge see brauseri aken." admin_js: type_to_filter: "filtreerimiseks trüki..." admin: @@ -2096,8 +2191,6 @@ et: backups: "varundusi" traffic_short: "Liiklus" traffic: "Rakenduse veebipäringud" - page_views: "API päringuid" - page_views_short: "API päringuid" show_traffic_report: "Näita liikluse detailraportit" reports: today: "Täna" @@ -2187,15 +2280,12 @@ et: refresh: "Värskenda" new: "Uus" selector_placeholder: "sisesta kasutajanimi" - name_placeholder: "Grupi nimi, tühikuteta, vastab kasutajanime reeglitele" about: "Siin saad muuta oma grupi liikmelisust ja nimesid" group_members: "Grupi liikmed" delete: "Kustuta" delete_confirm: "Kustutame selle grupi?" delete_failed: "Ei suuda kustutada seda gruppi. Kui see on automaatne grupp, ei saa seda hävitada." - delete_member_confirm: "Eemalda '%{username}' grupist '%{group}'?" delete_owner_confirm: "Eemaldan kasutajalt '%{username}' omaniku õigused?" - name: "Nimi" add: "Lisa" add_members: "Lisa liikmeid" custom: "Individuaalne" @@ -2212,7 +2302,6 @@ et: add_owners: Lisa omanikke incoming_email: "Individuaalne sissetuleva meili aadress" incoming_email_placeholder: "sisesta meiliaadress" - flair_preview: "Eelvaade" api: generate_master: "Genereeri API peavõti" none: "Hetkel aktiivsed API võtmed puuduvad." @@ -2228,27 +2317,73 @@ et: 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." web_hooks: + title: "Veebihaagid" + none: "Hetkel veebihaagid puuduvad." + instruction: "Veebihaagid lubavad Discourse'l teavitada muid teenuseid sündmustest Sinu saidil. Kui veebihaak vallandub, saadetakse etteantud URL-dele POST päring." + detailed_instruction: "Valitud sündmuse toimumisel saadetakse etteantud URL-le POST päring." + new: "Uus veebihaak" create: "Loo" save: "Salvesta" destroy: "Kustuta" description: "Kirjeldus" + controls: "Juhtpult" go_back: "Tagasi nimekirja" + payload_url: "Kasuliku lasti URL" + payload_url_placeholder: "https://example.com/postreceive" + warn_local_payload_url: "Näib, et püüad seada veebihaaki lokaalsele URL-le. Lokaalsele aadressile saadetud sündmus võib esile kusuda kõrvalnähte või ootamatusi. Kas jätkame?" + secret_invalid: "Salavõti ei tohi sisaldada tühikuid." + secret_too_short: "Salavõti peab olema vähemalt 12 sümbolit pikk." + event_type_missing: "Pead seadistama vähemalt ühe sündmuse liigi." content_type: "Sisutüüp" + secret: "Salavõti" + event_chooser: "Millised sündmused peaksid selle veebihaagi käivitama?" wildcard_event: "Saada mulle kõik." + individual_event: "Vali üksikud sündmused." + verify_certificate: "Kontrolli kasuliku lasti URL-i TLS sertifikaati" + active: "Aktiivne" + active_notice: "Teavitame sündmuse üksikasjadest peale selle toimumist." + categories_filter_instructions: "Asjakohased veebihaagid vallanduvad vaid juhul, kui sündmus on seotud määratud foorumitega. Jäta tühjaks, kui soovid veebihaagid vallandada kõigi foorumite jaoks." + categories_filter: "Käivitatud foorumid" + groups_filter_instructions: "Asjakohased veebihaagid vallanduvad vaid juhul, kui sündmus on seotud määratud gruppidega. Jäta tühjaks, kui soovid veebihaagid vallandada kõigi gruppide jaoks." + groups_filter: "Käivitatud grupid" + delete_confirm: "Kustutame selle veebihaagi?" + topic_event: + name: "Teema sündmus" + details: "Kui teema luuakse, muudetakse või kustutatakse." + post_event: + name: "Postituse sündmus" + details: "Kui teemas on uus vastus, muudatus, kustutamine või taastamine." + user_event: + name: "Kasutaja sündmus" + details: "Kui kasutaja luuakse, kinnitatakse või muudetakse." delivery_status: + title: "Kättetoimetamise staatus" inactive: "Mitteaktiivne" failed: "Ebaõnnestunud" successful: "Edukas" events: + none: "Ühtegi seotud sündmust pole." + redeliver: "Saada uuesti" + incoming: + one: "On tekkinud uus sündmus." + other: "On tekkinud {{count}} uut sündmust." + completed_in: + one: "Lõpetatud 1 sekundiga." + other: "Lõpetatud {{count}} sekundiga." + request: "Päring" response: "Vastus" + redeliver_confirm: "Oled kindel, et soovid sama kasulikku lasti uuesti saata?" headers: "Päised" + payload: "Kasulik last" body: "Sisu" go_list: "Mine nimekirja" + go_details: "Muuda veebihaaki" go_events: "Mine sündmuste juurde" ping: "Ping" status: "Staatus" event_id: "ID" timestamp: "Loaded" + completion: "Soorituse aeg" actions: "Tegevused" plugins: title: "Plugin" @@ -2438,10 +2573,14 @@ et: delivery_method: "Kättetoimetamise viis" preview_digest_desc: "Passiivsetele kasutajatele meilitud saadetiste sisu eelvaatlus." refresh: "Värskenda" + send_digest_label: "Saada see tulemus:" + send_digest: "Saada" + sending_email: "Saadan meili..." format: "Formaat" html: "html" text: "tekst" last_seen_user: "Viimati nähtud kasutaja:" + no_result: "Referaadile ei leitud ühtegi tulemust." reply_key: "Vastuse võti" skipped_reason: "Ülehüppamise põhjus" incoming_emails: @@ -2727,6 +2866,9 @@ et: unlock_trust_level: "Eemalda usaldustaseme lukustus" tl3_requirements: title: "Usaldustaseme 3 nõuded" + table_title: + one: "viimase päeva jooksul:" + other: "viimase %{count} päeva jooksul:" value_heading: "Väärtus" requirement_heading: "Nõue" visits: "Külastusi" @@ -2834,6 +2976,7 @@ et: user_preferences: "Kasutaja seaded" tags: "Sildid" search: "Otsi" + groups: "Grupid" badges: title: Märgised new_badge: Uus märgis diff --git a/config/locales/client.fa_IR.yml b/config/locales/client.fa_IR.yml index 33fbec66f41..a7af2fce1c3 100644 --- a/config/locales/client.fa_IR.yml +++ b/config/locales/client.fa_IR.yml @@ -264,16 +264,12 @@ fa_IR: total_rows: other: "%{count} کاربران" groups: - empty: - posts: "در این گروه هیچ پستی توسط کاربران " - members: "هیچ عضوی در این گروه وجود ندارد." - mentions: "هیچ کجا به این گروه اشاره‌ای نشده است." - messages: "پیامی در این گروه وجود ندارد." - topics: "در این گروه هیچ موضوعی توسط کاربران ارسال نشده." add: "افزودن" selector_placeholder: "افزودن عضو" owner: "مالک" visible: "همهٔ کاربران گروه را می‌بینند" + index: + title: "گروه‌ها" title: other: "گروه‌ها" members: "اعضا" @@ -559,11 +555,8 @@ fa_IR: create: "فرستادن یک دعوتنامه" generate_link: "کپی لینک دعوت" bulk_invite: - none: "شما هنوز کسی را اینجا دعوت نکرده اید. می توانید بصورت تکی یا گروهی یکجا دعوتنامه را بفرستید از طریق بارگذار فراخوانه فله ای ." text: "دعوت گروهی از طریق فایل" - uploading: "بارگذاری..." success: "فایل با موفقیت بارگذاری شد٬ وقتی که پروسه تمام شد به شما را از طریق پیام اطلاع می دهیم. " - error: "در بارگذاری «{{filename}}» خطایی روی داد: {{message}}" password: title: "رمزعبور" too_short: "رمز عبورتان خیلی کوتاه است" @@ -572,6 +565,10 @@ fa_IR: same_as_email: "رمز عبورتان با ایمیل شما برابر است. " ok: "گذرواژهٔ خوبی است." instructions: "در آخرین %{count} کاراکتر" + summary: + top_badges: "مدال های برتر" + no_badges: "هنوز مدالی نیست." + more_badges: "مدال های بیشتر" associated_accounts: "ورود ها" ip_address: title: "آخرین نشانی IP" @@ -904,6 +901,8 @@ fa_IR: category: "هیچ موضوعاتی در {{category}} نیست." top: "موضوع برتر وجود ندارد." search: " هیچ نتیجه جستجویی وجود ندارد." + educate: + unread: '

    موضوعات جدید در اینجا قرار می گیرند.

    به طور پیش فرض، موضوعات جدید در نظر گرفته خواهند شد و نشان داده می شوند جدید شاخص اگر آنها در 2 روز گذشته ایجاد شده باشند

    شما می توانید این را برای خود تغییر دهید تنظیمات.

    ' bottom: latest: "موضوع تازهٔ دیگری نیست." hot: "موضوع داغ دیگری نیست." @@ -1172,7 +1171,6 @@ fa_IR: edit: "متأسفیم، در ویرایش نوشته شما خطایی روی داد. لطفاً دوباره تلاش کنید." upload: "متأسفیم، در بارگذاری آن پرونده خطایی روی داد. لطفاً دوباره تلاش کنید." too_many_uploads: "متأسفیم، هر بار تنها می‌توانید یک پرونده را بار بگذارید." - upload_not_authorized: "متأسفیم، پرونده‌ای که تلاش دارید آن را بار بگذارید، پروانه‌دار نیست (پسوندهای پروانه‌دار: {{authorized_extensions})" image_upload_not_allowed_for_new_user: "با عرض پوزش، کاربران جدید نمی توانند تصویر بار گذاری نماییند." attachment_upload_not_allowed_for_new_user: "با عرض پوزش، کاربران جدید نمی توانند فایل پیوست بار گذاری نماییند." attachment_download_requires_login: "با عرض پوزش، شما برای دانلود فایل پیوست باید وارد سایت شوید." @@ -1413,7 +1411,6 @@ fa_IR: views_lowercase: other: "بازدیدها" replies: "پاسخ‌ها" - views_long: "از این موضوع {{number}} بار بازدید شده" activity: "فعالیت" likes: "پسندها" likes_lowercase: @@ -1503,6 +1500,14 @@ fa_IR: full: "ساختن / پاسخ دادن / دیدن" create_post: "پاسخ دادن / دیدن" readonly: "دیدن" + badges: + earned_n_times: + other: "این مدال را %{count} بار به دست آورده" + others_count: "بقیه با این مدال (%{count})" + title: مدال ها + badge_count: + other: "%{count} مدال" + select_badge_for_title: انتخاب یک مدال برای استفاده در عنوان خود admin_js: type_to_filter: "بنویسید تا فیلتر کنید..." admin: @@ -1537,8 +1542,6 @@ fa_IR: backups: "پشتیبان ها" traffic_short: "ترافیک" traffic: "درخواست های نرم افزار وب" - page_views: "درخواست های API" - page_views_short: "درخواست های API" show_traffic_report: "نمایش دقیق گزارش ترافیک" reports: today: "امروز" @@ -1621,15 +1624,12 @@ fa_IR: refresh: "تازه کردن" new: "جدید" selector_placeholder: "نام کاربری را وارد نمایید ." - name_placeholder: "نام گروه، بدون فاصله، همان قاعده نام کاربری" about: "اعضای گروهت و نام ها را اینجا ویرایش کن" group_members: "اعضای گروه" delete: "حذف" delete_confirm: "حفظ کردن این گروه؟" delete_failed: "قادر به حذف گروه نیستیم. اگر این یک گروه خودکار است، نمی توان آن را از بین برد." - delete_member_confirm: "حذف کردن '%{username}' از '%{group}' گروه؟" delete_owner_confirm: "حذف حق مالکیت برای '%{username}'؟" - name: "نام" add: "اضافه کردن" add_members: "اضافه کردن عضو" custom: "دلخواه" diff --git a/config/locales/client.fi.yml b/config/locales/client.fi.yml index b3776d68d98..a37bce8f291 100644 --- a/config/locales/client.fi.yml +++ b/config/locales/client.fi.yml @@ -321,28 +321,68 @@ fi: total_rows: one: "1 käyttäjä" other: "%{count} käyttäjää" + group_histories: + actions: + change_group_setting: "Muuta ryhmän asetusta" + add_user_to_group: "Lisää käyttäjä" + remove_user_from_group: "Poista käyttäjä" + make_user_group_owner: "Myönnä isännyys" + remove_user_as_group_owner: "Peru isännyys" groups: + logs: + title: "Lokit" + when: "Milloin" + action: "Toiminta" + acting_user: "Toimiva käyttäjä" + target_user: "Kohdekäyttäjä" + subject: "Aihe" + details: "Yksityiskohdat" + edit: + title: 'Muuta ryhmää' + full_name: 'Täysimittainen nimi' + add_members: "Lisää jäseniä" + delete_member_confirm: "Poista '%{username}' ryhmästä '%{group}'?" + request_membership_pm: + title: "Jäsenhakemus" + body: "Haluaisin ryhmään @%{groupName}." + name_placeholder: "Ryhmän nimi. Ei välilyöntejä, samat säännöt kuin käyttäjänimillä" + public: "Salli jäsenten liittyä/poistua ryhmästä vapaasti (ryhmän tulee olla näkyvillä)" empty: - posts: "Ryhmän jäsenet eivät ole kirjoittaneet viestejä." - members: "Kukaan ei kuulu tähän ryhmään." + posts: "Ryhmän jäsenet eivät ole lähettäneet viestejä." + members: "Ryhmässä ei ole jäseniä." mentions: "Ryhmää ei ole mainittu." - messages: "Tällä ryhmällä ei ole yksityistä ketjua." - topics: "Ryhmän jäsenet eivät ole aloittaneet ketjuja." + messages: "Ryhmälle ei ole yksityisviestejä." + topics: "Ryhmän jäsenet eivät ole luoneet ketjuja." + logs: "Ryhmälle ei ole lokitietoja." add: "Lisää" + join: "Liity ryhmään" + leave: "Poistu ryhmästä" + request: "Hae ryhmään" + automatic_group: Automaattinen ryhmä + closed_group: Suljettu ryhmä + is_group_user: "Olet tämän ryhmän jäsen" + allow_membership_requests: "Salli käyttäjien lähettää jäsenhakemuksia ryhmien isännille (vaatii että kaikki voivat mainita ryhmän)" + membership: "Jäsenyys" + name: "Nimi" + user_count: "Jäsenmäärä" + bio: "Tietoa ryhmästä" selector_placeholder: "Lisää jäseniä" owner: "omistaja" visible: "Ryhmä näkyy kaikille käyttäjille" - index: "Ryhmät" + index: + title: "Ryhmät" + empty: "Näkyvillä olevia ryhmiä ei ole." title: one: "ryhmä" other: "ryhmät" + activity: "Toiminta" members: "Jäsenet" topics: "Ketjut" posts: "Viestit" - mentions: "Viittaukset" + mentions: "Maininnat" messages: "Viestit" alias_levels: - title: "Ketkä voivat lähettää viestejä tälle ryhmälle tai @viitata siihen?" + title: "Ketkä voivat lähettää viestejä tälle ryhmälle tai @mainita sen?" nobody: "Ei kukaan" only_admins: "Vain ylläpitäjät" mods_and_admins: "Vain ylläpitäjät ja valvojat" @@ -367,6 +407,15 @@ fi: muted: title: "Vaimennetut" description: "Et saa ilmoituksia uusista ketjuista tässä ryhmässä." + flair_url: "Avatarpinssin kuva" + flair_url_placeholder: "(Valinnainen) kuvan URL tai Font Awesome -luokka" + flair_bg_color: "Avatar-pinssin taustaväri" + flair_bg_color_placeholder: "(Valinnainen) värin Hex-arvo" + flair_color: "Avatarpinssin väri" + flair_color_placeholder: "(Valinnainen) värin Hex-arvo" + flair_preview_icon: "Ikonin esikatselu" + flair_preview_image: "Kuvan esikatselu" + flair_note: "Huom. Käyttäjän ensisijainen ryhmä määrää pinssin." user_action_groups: '1': "Annetut tykkäykset" '2': "Saadut tykkäykset" @@ -374,7 +423,7 @@ fi: '4': "Ketjut" '5': "Vastauksia" '6': "Vastaukset" - '7': "Viittaukset" + '7': "Maininnat" '9': "Lainaukset" '11': "Muokkaukset" '12': "Lähetetyt" @@ -432,7 +481,7 @@ fi: button_text: "Lataa viestini" confirm: "Haluatko varmasti ladata viestisi?" success: "Lataus aloitettu. Saat ilmoituksen yksityisviestinä, kun prosessi on valmis." - rate_limit_error: "Viestit voi ladata kerran vuorokaudessa. Ole hyvä ja yritä huomenna uudelleen." + rate_limit_error: "Viestit voi ladata kerran vuorokaudessa. Yritä huomenna uudelleen." new_private_message: "Uusi viesti" private_message: "Viesti" private_messages: "Viestit" @@ -575,7 +624,7 @@ fi: title: "Sähköposti" instructions: "Ei tule julkiseksi" ok: "Lähetämme sinulle sähköpostin varmistukseksi." - invalid: "Ole hyvä ja anna toimiva sähköpostiosoite" + invalid: "Sähköpostiosoite ei kelpaa." authenticated: "{{provider}} on todentanut sähköpostiosoitteesi" frequency_immediately: "Saat sähköpostia välittömästi, jollet ole jo lukenut asiaa, jota sähköpostiviesti koskee." frequency: @@ -638,7 +687,7 @@ fi: every_two_weeks: "joka toinen viikko" include_tl0_in_digests: "Sisällytä uusien käyttäjien viestit sähköpostikoosteisiin" email_in_reply_to: "Liitä sähköpostiin lyhennelmä viestistä, johon vastataan" - email_direct: "Lähetä minulle sähköposti, jos joku lainaa viestiäni, vastaa viestiini, viittaa @nimeeni tai kutsuu minut viestiketjuun" + email_direct: "Lähetä minulle sähköposti, jos joku lainaa viestiäni, vastaa viestiini, maintsee @nimeni tai kutsuu minut viestiketjuun" email_private_messages: "Lähetä minulle sähköposti, kun joku lähettää minulle viestin" email_always: "Lähetä sähköposti-ilmoitukset, vaikka olen aktiivinen palstalla." other_settings: "Muut" @@ -696,11 +745,10 @@ fi: link_generated: "Kutsulinkki luotiin onnistuneesti!" valid_for: "Kutsulinkki on käypä tälle sähköpostiosoitteelle: %{email}" bulk_invite: - none: "Et ole kutsunut vielä ketään. Voit lähettää yksittäisiä kutsuja tai kutsua useita ihmisiä kerralla lähettämällä massakutsun tiedostosta." + none: "Et ole kutsunut vielä ketään tänne. Voit lähettää yksittäisiä kutsuja tai kutsua joukon ihmisiä kerralla lataamalla CSV-tiedoston." text: "Lähetä massakutsu tiedostosta" - uploading: "Lähettää..." success: "Tiedoston lähettäminen onnistui. Saat viestin, kun prosessi on valmis." - error: "Tiedoston '{{filename}}' lähetyksen aikana tapahtui virhe: {{message}}" + error: "Pahoittelut, tiedoston tulee olla CSV-muodossa." password: title: "Salasana" too_short: "Salasanasi on liian lyhyt." @@ -873,7 +921,7 @@ fi: email_placeholder: "sähköposti tai käyttäjätunnus" caps_lock_warning: "Caps Lock on päällä" error: "Tuntematon virhe" - rate_limit: "Ole hyvä ja odota hetki ennen kuin yrität kirjautua uudelleen." + rate_limit: "Odota hetki ennen kuin yrität kirjautua uudelleen." blank_username_or_password: "Kirjoita sähköpostiosoite tai käyttäjänimi ja salasana." reset_password: 'Uusi salasana' logging_in: "Kirjaudutaan..." @@ -941,8 +989,8 @@ fi: similar_topics: "Tämä ketju vaikuttaa samalta kuin.." drafts_offline: "offline luonnokset" group_mentioned: - one: "Jos viittaat ryhmään {{group}}, 1 käyttäjä saa ilmoituksen – oletko varma?" - other: "Jos viittaat ryhmään {{group}}, {{count}} käyttäjää saa ilmoituksen – oletko varma?" + one: "Jos mainitset ryhmän {{group}}, 1 käyttäjä saa ilmoituksen – oletko varma?" + other: "Jos mainitset ryhmän {{group}}, {{count}} käyttäjää saa ilmoituksen – oletko varma?" cannot_see_mention: category: "Mainitsit käyttäjän {{username}} mutta hän ei saa ilmoitusta, koska hänellä ei ole pääsyä tälle alueelle. Hänet tulee lisätä ryhmään, jolla on pääsy alueelle." private: "Mainitsit käyttäjän {{username}} mutta hän ei saa ilmoitusta, koska hän ei näe tätä yksityiskeskustelua. Hänet tulee kutsua tähän yksityiskeskusteluun." @@ -965,8 +1013,10 @@ fi: title: "Tai paina Ctrl+Enter" users_placeholder: "Lisää käyttäjä" title_placeholder: "Kuvaile lyhyesti mistä tässä ketjussa on kyse?" + title_or_link_placeholder: "Kirjoita otsikko tai liitä linkki tähän" edit_reason_placeholder: "miksi muokkaat viestiä?" show_edit_reason: "(lisää syy muokkaukselle)" + topic_featured_link_placeholder: "Tähän linkki, joka näytetään otsikon yhteydessä." reply_placeholder: "Kirjoita tähän. Käytä Markdownia, BBCodea tai HTML:ää muotoiluun. Raahaa tai liitä kuvia." view_new_post: "Katsele uutta viestiäsi." saving: "Tallennetaan" @@ -1012,7 +1062,7 @@ fi: admin_options_title: "Tämän ketjun vain henkilökunnalle näytettävät asetukset" auto_close: label: "Sulje ketju automaattisesti tämän ajan jälkeen:" - error: "Ole hyvä ja syötä kelpaava arvo." + error: "Arvo ei kelpaa." based_on_last_post: "Älä sulje ennen kuin viimeisin viesti ketjussa on vähintään näin vanha." all: examples: 'Syötä aika tunteina (24), absoluuttisena aikana (17:30) tai aikaleimana (2013-11-22 14:00).' @@ -1048,7 +1098,7 @@ fi: one: "

    {{count}} viesti ryhmän {{group_name}} saapuneissa

    " other: "

    {{count}} viestiä ryhmän {{group_name}} saapuneissa

    " alt: - mentioned: "Viittaaja" + mentioned: "Mainitsija" quoted: "Lainaaja" replied: "Vastasi" posted: "Kirjoittaja" @@ -1280,7 +1330,8 @@ fi: go_bottom: "loppuun" go: "siirry" jump_bottom: "hyppää viimeisimpään viestiin" - jump_prompt: "hyppää viestiin" + jump_prompt: "hyppää..." + jump_prompt_of: "%{count} viestistä" jump_prompt_long: "Mihin viestiin haluat siirtyä?" jump_bottom_with_number: "hyppää viestiin %{post_number}" total: yhteensä viestejä @@ -1512,7 +1563,7 @@ fi: file_too_large: "Pahoittelut, tiedosto jonka latausta yritit on liian suuri (suurin tiedostokoko on {{max_size_kb}}kb). Mitäpä jos lataisit tiedoston johonkin pilvipalveluun ja jakaisit täällä siihen linkin?" too_many_uploads: "Pahoittelut, voit ladata vain yhden tiedoston kerrallaan." too_many_dragged_and_dropped_files: "Pahoittelut, voit ladata korkeintaan 10 tiedostoa kerrallaan." - upload_not_authorized: "Pahoittelut, tiedostomuoto ei ole sallittu (sallitut tiedostopäätteet: {{authorized_extensions}})." + upload_not_authorized: "Pahoittelut, tiedosto jota yrität ladata ei ole sallittu (sallitut laajennukset: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Pahoittelut, uudet käyttjät eivät saa ladata kuvia." attachment_upload_not_allowed_for_new_user: "Pahoittelut, uudet käyttäjät eivät saa ladata liitteitä." attachment_download_requires_login: "Pahoittelut, sinun täytyy kirjautua sisään voidaksesi ladata liitetiedostoja." @@ -1678,6 +1729,7 @@ fi: tags_allowed_tag_groups: "Tällä alueella sallitut tunnisteryhmät:" tags_placeholder: "(Valinnainen) lista sallituista tunnisteista" tag_groups_placeholder: "(Valinnainen) lista sallituista tunnisteryhmistä" + topic_featured_link_allowed: "Salli ketjulinkit tällä alueella" delete: 'Poista alue' create: 'Uusi alue' create_long: 'Luo uusi alue' @@ -1712,6 +1764,7 @@ fi: email_in_disabled: "Uusien ketjujen luominen sähköpostitse on otettu pois käytöstä sivuston asetuksissa. Salliaksesi uusien ketjujen luomisen sähköpostilla, " email_in_disabled_click: 'ota käyttöön "email in" asetus.' suppress_from_homepage: "Vaimenna alue kotisivulta." + all_topics_wiki: "Tee uusista ketjuista wiki-viestejä oletuksena." sort_order: "Oletusjärjestys:" allow_badges_label: "Salli ansiomerkkien myöntäminen tältä alueelta" edit_permissions: "Muokkaa oikeuksia" @@ -1834,7 +1887,9 @@ fi: one: "katselu" other: "katselut" replies: "Vastauksia" - views_long: "tätä ketjua on katseltu {{number}} kertaa" + views_long: + one: "ketjua on katseltu yhden kerran" + other: "ketjua on katseltu {{number}} kertaa" activity: "Toiminta" likes: "Tykkäykset" likes_lowercase: @@ -2139,8 +2194,8 @@ fi: backups: "varmuuskopiot" traffic_short: "Liikenne" traffic: "Sovelluksen web-pyynnöt" - page_views: "API pyynnöt" - page_views_short: "API pyynnöt" + page_views: "Sivunkatselut" + page_views_short: "Sivunkatselut" show_traffic_report: "Näytä yksityiskohtainen liikenneraportti" reports: today: "Tänään" @@ -2230,15 +2285,12 @@ fi: refresh: "Lataa uudelleen" new: "Uusi" selector_placeholder: "syötä käyttäjätunnus" - name_placeholder: "Ryhmän nimi, ei välilyöntejä, samat säännöt kuin käyttäjänimillä" about: "Muokkaa ryhmien jäsenyyksiä ja nimiä täällä" group_members: "Ryhmään kuuluvat" delete: "Poista" delete_confirm: "Poista tämä ryhmä?" delete_failed: "Ryhmän poistaminen ei onnistu. Jos tämä on automaattinen ryhmä, sitä ei voi poistaa." - delete_member_confirm: "Poista '%{username}' ryhmästä '%{group}'?" delete_owner_confirm: "Poista omistajan etuudet käyttäjältä '%{username}'?" - name: "Nimi" add: "Lisää" add_members: "Lisää jäseniä" custom: "Mukautetut" @@ -2255,14 +2307,6 @@ fi: add_owners: Lisää omistajia incoming_email: "Saapuvan sähköpostin osoite" incoming_email_placeholder: "aseta sähköpostiosoite" - flair_url: "Avatarpinssikuva" - flair_url_placeholder: "(Valinnainen) Kuvan URL tai Font Awesome luokka" - flair_bg_color: "Avatarpinssin taustaväri" - flair_bg_color_placeholder: "(Valinnainen) värin Hex-arvo" - flair_color: "Avatarpinssin väri" - flair_color_placeholder: "(Valinnainen) värin Hex-arvo" - flair_preview: "Esikatselu" - flair_note: "Huom: Pinssi määräytyy käyttäjän ensisijaisen ryhmän mukaan." api: generate_master: "Luo rajapinnan pääavain" none: "Aktiivisia API avaimia ei ole määritelty." @@ -2474,10 +2518,14 @@ fi: delivery_method: "Lähetystapa" preview_digest_desc: "Esikatsele inaktiivisille käyttäjille lähetettyjen tiivistelmäsähköpostien sisältöä." refresh: "Päivitä" + send_digest_label: "Lähetä tämä tulos:" + send_digest: "Lähetä" + sending_email: "Lähetetään sähköpostia..." format: "Muotoilu" html: "html" text: "teksti" last_seen_user: "Käyttäjän edellinen kirjautuminen:" + no_result: "Tuloksia ei löydetty tiivistelmää varten." reply_key: "Vastausavain" skipped_reason: "Syy väliinjättämiselle" incoming_emails: @@ -2573,6 +2621,8 @@ fi: deleted_tag: "poistettu tunniste" renamed_tag: "uudelleen nimetty tunniste" revoke_email: "peru sähköpostiosoite" + unlock_trust_level: "poista luottamustason lukitus" + activate_user: "aktivoi käyttäjä" screened_emails: title: "Seulottavat sähköpostiosoitteet" description: "Uuden käyttäjätunnuksen luonnin yhteydessä annettua sähköpostiosoitetta verrataan alla olevaan listaan ja tarvittaessa tunnuksen luonti joko estetään tai suoritetaan muita toimenpiteitä." @@ -2873,6 +2923,7 @@ fi: user_preferences: "Käyttäjäasetukset" tags: "Tunnisteet" search: "Haku" + groups: "Ryhmät" badges: title: Ansiomerkit new_badge: Uusi ansiomerkki diff --git a/config/locales/client.fr.yml b/config/locales/client.fr.yml index 15827143e01..313adca2530 100644 --- a/config/locales/client.fr.yml +++ b/config/locales/client.fr.yml @@ -321,21 +321,63 @@ fr: total_rows: one: "1 utilisateur" other: "%{count} utilisateurs" + group_histories: + actions: + change_group_setting: "Changer les paramètres du groupe" + add_user_to_group: "Ajouter l'utilisateur" + remove_user_from_group: "Supprimer l'utilisateur" + make_user_group_owner: "Rendre propriétaire" + remove_user_as_group_owner: "Retirer le propriétaire" groups: + logs: + title: "Journaux" + when: "Quand" + action: "Action" + acting_user: "Utilisateur agissant" + target_user: "Utilisateur cible" + subject: "Sujet" + details: "Détails" + from: "De" + to: "À" + edit: + title: 'Modifier le groupe' + full_name: 'Nom complet' + add_members: "Ajouter des membres" + delete_member_confirm: "Supprimer %{username} du groupe « %{group} » ?" + request_membership_pm: + title: "Demande d'adhésion" + body: "Je souhaiterais adhérer à @%{groupName}." + name_placeholder: "Nom du groupe, sans espaces, même règle que pour les pseudos" + public: "Autoriser les utilisateurs à rejoindre/quitter le groupe librement (nécessite que le groupe soit visible)" empty: - posts: "Il n'y a aucun message de la part des membres de ce groupe." - members: "Il n'y a aucun membre dans ce groupe." + posts: "Il n'y a aucun message de membres de ce groupe." + members: "Il n' y a aucun membre dans ce groupe." mentions: "Il n'y a aucune mention de ce groupe." messages: "Il n'y a aucun message pour ce groupe." - topics: "Il n'y a aucun sujet de la part des membres de ce groupe." + topics: "Il n'y a aucun sujet par des membres de ce groupe." + logs: "Il n'y a aucun journal pour ce groupe." add: "Ajouter" + join: "Rejoindre le groupe" + leave: "Quitter le groupe" + request: "Demander à rejoindre le groupe" + automatic_group: Groupe automatique + closed_group: Groupe fermé + is_group_user: "Vous êtes membre de ce groupe" + allow_membership_requests: "Autoriser les utilisateurs à envoyer des demandes d'adhésion aux propriétaires de groupe (nécessite que tout le monde puisse mentionner le groupe)" + membership: "Adhésion" + name: "Nom" + user_count: "Nombre de membres" + bio: "À propos du groupe" selector_placeholder: "Ajouter des membres" owner: "propriétaire" visible: "Ce groupe est visible par tous les utilisateurs" - index: "Groupes" + index: + title: "Groupes" + empty: "Il n'y a aucun groupe visible." title: one: "groupe" other: "groupes" + activity: "Activité" members: "Membres" topics: "Sujets" posts: "Messages" @@ -367,6 +409,15 @@ fr: muted: title: "Silencieux" description: "Nous ne serez jamais notifié de quoi que ce soit à propos des nouveaux sujets dans ce groupe." + flair_url: "Image de la vignette d'avatar" + flair_url_placeholder: "(Facultatif) URL de l'image ou classe Font Awesome" + flair_bg_color: "Couleur de l'arrière-plan de la vignette d'avatar" + flair_bg_color_placeholder: "(Facultatif) Couleur en héxadécimal" + flair_color: "Couleur de la vignette d'avatar" + flair_color_placeholder: "(Facultatif) Couleur en héxadécimal" + flair_preview_icon: "Prévisualiser l'icône" + flair_preview_image: "Prévisualiser l'image" + flair_note: "Note : la vignette d'avatar sera uniquement affichée pour le groupe principal d'un utilisateur." user_action_groups: '1': "J'aime donnés" '2': "J'aime reçus" @@ -431,6 +482,8 @@ fr: download_archive: button_text: "Télécharger mes messages" confirm: "Êtes-vous sûr de vouloir télécharger vos messages ?" + success: "Le téléchargement a démarré ; vous serez notifié par message lorsqu'il est terminé." + rate_limit_error: "Les messages peuvent être téléchargés une fois par jour, veuillez ressayer demain." new_private_message: "Créer un message privé" private_message: "Message privé" private_messages: "Messages privés" @@ -693,11 +746,10 @@ fr: link_generated: "Lien d'invitation généré avec succés !" valid_for: "Le lien d'invitation est seulement valide pour cette adresse courriel : %{email}" bulk_invite: - none: "Vous n'avez encore invité personne. Vous pouvez envoyé des invitations individuelles, ou en masse en envoyant un fichier d'invitation contenant la liste des courriels." + none: "Vous n'avez invité personne pour le moment. Vous pouvez envoyer des invitations individuelles ou inviter plusieurs personnes à la fois en envoyant un fichier CSV." text: "Invitation massive depuis un fichier" - uploading: "Envoi en cours…" success: "Le fichier a été correctement importé. Vous serez notifié par message privé lorsque le traitement sera terminé." - error: "Il y a eu une erreur lors de l'envoi de « {{filename}} » : {{message}}" + error: "Désolé, le fichier doit être au format CSV." password: title: "Mot de passe" too_short: "Votre mot de passe est trop court." @@ -962,8 +1014,10 @@ fr: title: "ou appuyez sur Ctrl+Entrée" users_placeholder: "Ajouter un utilisateur" title_placeholder: "Quel est le sujet en une courte phrase ?" + title_or_link_placeholder: "Entrez un titre, ou copiez un lien ici" edit_reason_placeholder: "pourquoi modifiez-vous le message ?" show_edit_reason: "(ajouter la raison de la modification)" + topic_featured_link_placeholder: "Entrez un lien affiché avec le titre." reply_placeholder: "Écrivez ici. Utilisez Markdown, BBCode, ou HTML pour mettre en forme. Glissez ou collez des images." view_new_post: "Voir votre nouveau message." saving: "Sauvegarde" @@ -1008,7 +1062,7 @@ fr: body: "Pour le moment, ce message est uniquement envoyé à vous-même !" admin_options_title: "Paramètres optionnels pour ce sujet" auto_close: - label: "Heure de fermeture automatique de ce sujet :" + label: "Heure de fermeture automatique du sujet :" error: "Merci d'entrer une valeur valide." based_on_last_post: "Ne pas fermer tant que le dernier message du sujet n'a pas atteint cette ancienneté." all: @@ -1277,7 +1331,8 @@ fr: go_bottom: "bas" go: "aller" jump_bottom: "aller au dernier message" - jump_prompt: "aller au message" + jump_prompt: "aller à…" + jump_prompt_of: "de %{count} messages" jump_prompt_long: "À quel message voulez-vous aller ?" jump_bottom_with_number: "aller au message %{post_number}" total: total de messages @@ -1509,7 +1564,7 @@ fr: file_too_large: "Désolé, ce fichier est trop gros (la taille maximale est {{max_size_kb}}kb). Pourquoi ne pas télécharger votre gros fichier sur un service partagé cloud, puis partager le lien?" too_many_uploads: "Désolé, vous ne pouvez envoyer qu'un seul fichier à la fois." too_many_dragged_and_dropped_files: "Désolé, vous ne pouvez télécharger que 10 fichiers à la fois." - upload_not_authorized: "Désolé, le fichier que vous êtes en train d'envoyer n'est pas autorisé (extensions autorisées : {{authorized_extensions}})." + upload_not_authorized: "Désolé, le fichier que vous essayez d'envoyer n'est pas autorisé (extensions autorisées : {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Désolé, les nouveaux utilisateurs ne peuvent pas envoyer d'images." attachment_upload_not_allowed_for_new_user: "Désolé, les nouveaux utilisateurs ne peuvent pas envoyer de fichier." attachment_download_requires_login: "Désolé, vous devez être connecté pour télécharger une pièce jointe." @@ -1666,7 +1721,7 @@ fr: choose: 'Sélectionner une catégorie…' edit: 'modifier' edit_long: "Modifier" - view: 'Voir les sujets dans cette catégorie' + view: 'Voir les sujets dans la catégorie' general: 'Général' settings: 'Paramètres' topic_template: "Modèle de sujet" @@ -1675,6 +1730,7 @@ fr: tags_allowed_tag_groups: "Groupes de tags pouvant être utilisés uniquement dans cette catégorie :" tags_placeholder: "(Facultatif) liste des tags autorisés" tag_groups_placeholder: "(Facultatif) liste des groupes de tags autorisés" + topic_featured_link_allowed: "Autoriser les sujets avec lien dans cette catégorie" delete: 'Supprimer la catégorie' create: 'Nouvelle catégorie' create_long: 'Créer une nouvelle catégorie' @@ -1709,6 +1765,7 @@ fr: email_in_disabled: "La possibilité de créer des nouveaux sujets via courriel est désactivé dans les Paramètres. Pour l'activer," email_in_disabled_click: 'activer le paramètre "email in".' suppress_from_homepage: "Retirer cette catégorie de la page d'accueil" + all_topics_wiki: "Faire des nouveaux sujets des Wikis par défaut" sort_order: "Tri par défaut :" allow_badges_label: "Autoriser les badges à être accordé dans cette catégorie" edit_permissions: "Modifier les permissions" @@ -1831,7 +1888,6 @@ fr: one: "vue" other: "vues" replies: "Réponses" - views_long: "ce sujet a été vu {{number}} fois" activity: "Activité" likes: "J'aime" likes_lowercase: @@ -2136,8 +2192,6 @@ fr: backups: "sauvegardes" traffic_short: "Trafic" traffic: "Requêtes Web Application" - page_views: "Requêtes API" - page_views_short: "Requêtes API" show_traffic_report: "Afficher le rapport de trafic détaillé" reports: today: "Aujourd'hui" @@ -2227,15 +2281,12 @@ fr: refresh: "Actualiser" new: "Nouveau" selector_placeholder: "entrer le pseudo" - name_placeholder: "Nom du groupe, sans espace, mêmes règles que pour les pseudos" about: "Modifier votre adhésion et les noms ici" group_members: "Membres du groupe" delete: "Supprimer" delete_confirm: "Supprimer ce groupe ?" delete_failed: "Impossible de supprimer le groupe. Si c'est un groupe automatique il ne peut être détruit." - delete_member_confirm: "Enlever %{username} du groupe « %{group} » ?" delete_owner_confirm: "Retirer les privilèges de propriétaire pour %{username} ?" - name: "Nom" add: "Ajouter" add_members: "Ajouter des membres" custom: "Personnalisé" @@ -2247,19 +2298,11 @@ fr: automatic_membership_email_domains: "Les utilisateurs qui s'enregistrent avec un domaine courriel qui correspond exactement à un élément de cette liste seront automatiquement ajoutés à ce groupe:" automatic_membership_retroactive: "Appliquer la même règle de domaine courriel pour les utilisateurs existants" default_title: "Titre par défaut pour tous les utilisateurs de ce groupe" - primary_group: "Définir comme groupe primaire automatiquement" + primary_group: "Définir comme groupe principal automatiquement" group_owners: Propriétaires add_owners: Ajouter des propriétaires incoming_email: "Adresse de courriel entrant personnalisée" incoming_email_placeholder: "Entrer une adresse de courriel" - flair_url: "Image de la vignette d'avatar" - flair_url_placeholder: "(Facultatif) URL de l'image ou classe Font Awesome" - flair_bg_color: "Couleur de l'arrière-plan de la vignette d'avatar" - flair_bg_color_placeholder: "(Facultatif) Couleur en héxadécimal" - flair_color: "Couleur de la vignette d'avatar" - flair_color_placeholder: "(Facultatif) Couleur en héxadécimal" - flair_preview: "Prévisualiser" - flair_note: "Note : la vignette d'avatar sera uniquement affichée pour le groupe principal d'un utilisateur." api: generate_master: "Générer une clé d'API maître" none: "Il n'y a pas de clés API actives en ce moment." @@ -2291,7 +2334,6 @@ fr: warn_local_payload_url: "Il semble que vous essayez de configurer le Webhook vers une URL locale. Les événements délivrés à une adresse locale peuvent causer des effets de bords ou des comportements inattendus. Continuer ?" secret_invalid: "La clé secrète ne doit pas contenir d'espaces." secret_too_short: "La clé secrète doit contenir au moins 12 caractères." - secret_placeholder: "Une chaîne de caractères facultative pour générer la signature" event_type_missing: "Vous devez configurer au moins un type d'évènement." content_type: "Type de contenu" secret: "Clé secrète" @@ -2314,7 +2356,7 @@ fr: details: "Quand il y a une réponse nouvelle, modifiée, supprimée ou rétablie." user_event: name: "Événement d'utilisateur" - details: "Quand un utilisateur est créé ou approuvé." + details: "Quand un utilisateur est créé, approuvé ou mis à jour." delivery_status: title: "État de l'envoi" inactive: "Inactif" @@ -2530,7 +2572,7 @@ fr: send_test: "Envoyer un courriel de test" sent_test: "Envoyé !" delivery_method: "Méthode d'envoi" - preview_digest_desc: "Prévisualiser le contenu des courriels hebdomadaires sommaires envoyés aux utilisateurs inactifs." + preview_digest_desc: "Prévisualiser le contenu des résumés par courriel envoyés aux utilisateurs inactifs." refresh: "Rafraîchir" send_digest_label: "Envoyer ce résultat à :" send_digest: "Envoyer" @@ -2935,6 +2977,7 @@ fr: user_preferences: "Préférences" tags: "Tags" search: "Rechercher" + groups: "Groupes" badges: title: Badges new_badge: Nouveau badge diff --git a/config/locales/client.gl.yml b/config/locales/client.gl.yml index 31a9589feaa..08373c1cbea 100644 --- a/config/locales/client.gl.yml +++ b/config/locales/client.gl.yml @@ -27,6 +27,7 @@ gl: millions: "{{number}}M" dates: time: "h:mm a" + timeline_date: "MMM YYYY" long_no_year: "D MMM h:mm a" long_no_year_no_time: "D MMM" full_no_year_no_time: "D MMMM" @@ -38,6 +39,7 @@ gl: long_date_with_year_without_time: "D MMM, 'YY" long_date_without_year_with_linebreak: "D MMM
    LT" long_date_with_year_with_linebreak: "D MMM, 'YY
    LT" + wrap_ago: "fai %{date}" tiny: half_a_minute: "< 1m" less_than_x_seconds: @@ -108,9 +110,13 @@ gl: google+: 'compartir esta ligazón no Google+' email: 'enviar esta ligazón nun correo electrónico' action_codes: + public_topic: "fixo esta publicación pública no %{when}" + private_topic: "fixo esta publicación privada no %{when}" split_topic: "este tema dividiuse o %{when}" invited_user: "convidou a %{who} %{when}" + invited_group: "invitou %{who} o %{when}" removed_user: "eliminou a %{who} %{when}" + removed_group: "eliminou %{who} o %{when}" autoclosed: enabled: 'pechado o %{when}' disabled: 'aberto o %{when}' @@ -130,6 +136,7 @@ gl: enabled: 'listado o %{when}' disabled: 'retirado da lista o %{when}' topic_admin_menu: "accións do administrador de temas" + wizard_required: "É hora de configura-lo teu foro! Inicie o Asistente de Configuración!" emails_are_disabled: "Todos os correos electrónicos saíntes foron desactivados globalmente por un administrador. Non se enviará ningún tipo de notificación por correo electrónico." s3: regions: @@ -307,12 +314,6 @@ gl: one: "Un usuario" other: "%{count} usuarios" groups: - empty: - posts: "Non hai publicacións de membros deste grupo." - members: "Non hai ningún membro neste grupo." - mentions: "Non hai ningunha mención deste grupo." - messages: "Non hai ningunha mensaxe para este grupo." - topics: "Non hai temas por membros deste grupo." add: "Engadir" selector_placeholder: "Engadir membros" owner: "propietario" @@ -626,11 +627,8 @@ gl: create: "Enviar un convite" generate_link: "Copiar a ligazón do convite" bulk_invite: - none: "Aínda non convidaches a ninguén. Podes enviar convites individuais ou en grupo se subes un ficheiro para convites múltiples." text: "Convidar en grupo desde un ficheiro" - uploading: "Enviando..." success: "O ficheiro enviouse correctamente, notificaráseche por mensaxe cando remate o proceso." - error: "Produciuse un erro ao subir «{{filename}}»: {{message}}" password: title: "Contrasinal" too_short: "O teu contrasinal é demasiado curto." @@ -1296,7 +1294,6 @@ gl: edit: "Sentímolo pero produciuse un erro editando a publicación. Téntao de novo." upload: "Sentímolo pero produciuse un erro enviando a publicación. Téntao de novo." too_many_uploads: "Sentímolo pero só podes enviar un ficheiro de cada vez." - upload_not_authorized: "Sentímolo pero o ficheiro que tentas enviar non está autorizado (extensións autorizadas: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Sentímolo pero os novos usuarios non poden subir imaxes." attachment_upload_not_allowed_for_new_user: "Sentímolo pero os novos usuarios non poden subir anexos." attachment_download_requires_login: "Sentímolo pero debes iniciar sesión para descargar anexos." @@ -1571,7 +1568,6 @@ gl: one: "vista" other: "vistas" replies: "Respostas" - views_long: "este tema visitouse {{number}} veces" activity: "Actividade" likes: "Gústames" likes_lowercase: @@ -1703,8 +1699,6 @@ gl: backups: "copias de seguranza" traffic_short: "Tráfico" traffic: "Peticións web de aplicativos" - page_views: "Peticións API" - page_views_short: "Peticións API" show_traffic_report: "Amosar o informe detallado do tráfico" reports: today: "Hoxe" @@ -1793,15 +1787,12 @@ gl: refresh: "Actualizar" new: "Novo" selector_placeholder: "escribe o nome do usuario" - name_placeholder: "Nome do grupo sen espazos, como na regra do nome do usuario" about: "Edita aquí a túa pertenza a un grupo e nomes" group_members: "Membros do grupo" delete: "Eliminar" delete_confirm: "Eliminar este grupo?" delete_failed: "Non é posíbel eliminar o grupo. Se este é un grupo automático, non se pode destruír." - delete_member_confirm: "Queres eliminar a «%{username}» do grupo «%{group}»?" delete_owner_confirm: "Eliminar os privilexios de usuario de «%{username}»?" - name: "Nome" add: "Engadir" add_members: "Engadir membros" custom: "Personalizar" diff --git a/config/locales/client.he.yml b/config/locales/client.he.yml index 4e98c02ea0e..384de1961d2 100644 --- a/config/locales/client.he.yml +++ b/config/locales/client.he.yml @@ -138,7 +138,7 @@ he: topic_admin_menu: "פעולות ניהול לנושא" wizard_required: "הגיע הזמן לכוונן את הפורום שלכם! התחילו את אשף ההקמה!" emails_are_disabled: "כל הדוא\"ל היוצא נוטרל באופן גורף על ידי מנהל אתר. שום הודעת דוא\"ל, מכל סוג שהוא, לא תשלח." - bootstrap_mode_enabled: "כדי להקל על הקמת האתר החדש שלכם, אתם במצב איתחול-ראשוני. כל המשתמשים החדשים יקבלו רמת אמון 1 ויקבלו סיכומים יומיים במייל. אפשרות זו תכובה אוטומטית כאשר יהיו יותר מ %{min_users} משתמשים." + bootstrap_mode_enabled: "כדי להקל על הקמת האתר החדש שלכם, אתם במצב איתחול-ראשוני. כל המשתמשים החדשים יקבלו רמת אמון 1 ויקבלו תמצות יומי במייל. אפשרות זו תכובה אוטומטית כאשר יהיו יותר מ %{min_users} משתמשים." bootstrap_mode_disabled: "מצב איתחול-ראשוני יכובה ב 24 השעות הקרובות." s3: regions: @@ -183,7 +183,7 @@ he: you: "אתם" or: "או" now: "ממש עכשיו" - read_more: 'קרא עוד' + read_more: 'קראו עוד' more: "עוד" less: "פחות" never: "אף פעם" @@ -321,21 +321,63 @@ he: total_rows: one: "משתמש/ת 1" other: "%{count} משתמשים" + group_histories: + actions: + change_group_setting: "שינוי הגדרות קבוצה" + add_user_to_group: "הוספת משתמש/ת" + remove_user_from_group: "הסרת משתמש/ת" + make_user_group_owner: "הפיכה לבעלים" + remove_user_as_group_owner: "שלילת בעלות" groups: + logs: + title: "לוגים" + when: "מתי" + action: "פעולה" + acting_user: "משתמשים פועלים" + target_user: "משתמשי מטרה" + subject: "נושא" + details: "פרטים" + from: "מאת" + to: "אל" + edit: + title: 'עריכת קבוצה' + full_name: 'שם מלא' + add_members: "הוספת חברים" + delete_member_confirm: "הסרת '%{username}' מהקבוצה '%{group}'?" + request_membership_pm: + title: "בקשת חברות" + body: "הייתי מעוניין להגיש בקשת חברות ב-@%{groupName}." + name_placeholder: "שם קבוצה, ללא רווחים, לפי הכללים של שמות משתמשים" + public: "אפשרו למשתמשים להצטרף/לעזוב את הקבוצה בחופשיות (על הקבוצה להיות נראית)" empty: - posts: "אין פוסט של חברים בקבוצה זו" + posts: "אין פוסטים של חברי קבוצה זו." members: "אין חברים בקבוצה זו." - mentions: "אין אזכורים של קבוצה זו." + mentions: "אין איזכורים של קבוצה זו." messages: "אין הודעות לקבוצה זו." - topics: "אין נושא מטעם חברים בקבוצה זו." + topics: "אין נושאים שנוצרו על ידי חברים של קבוצה זו." + logs: "אין לוגים עבור קבוצה זו." add: "הוספה" + join: "הצטרפות לקבוצה" + leave: "עזיבת קבוצה" + request: "בקשה להצטרפות לקבוצה" + automatic_group: קבוצה אוטומטית + closed_group: קבוצה סגורה + is_group_user: "אתם חברים בקבוצה זו." + allow_membership_requests: "אפשרו למשתמשים לשלוח בקשות חברות לבעלי הקבוצה (מצריך שכולם יוכלו לאזכר את הקבוצה)" + membership: "חברות" + name: "שם" + user_count: "מספר חברים" + bio: "אודות הקבוצה" selector_placeholder: "הוספת חברים וחברות" owner: "מנהל" visible: "הקבוצה זמינה לכל המשתמשים" - index: "קבוצות" + index: + title: "קבוצות" + empty: "אין קבוצות נראות." title: one: "קבוצה" other: "קבוצות" + activity: "פעילות" members: "חברים" topics: "נושאים" posts: "פוסטים" @@ -367,6 +409,15 @@ he: muted: title: "מושתק" description: "לעולם לא תקבלו התראה על נושאים חדשים בקבוצה זו." + flair_url: "תמונת פלייר אווטר" + flair_url_placeholder: "(אופציונלי) URL של תמונה או מחלקה של Font Awesome" + flair_bg_color: "צבע רקע של פלייר לאווטר" + flair_bg_color_placeholder: "(אופציונלי) ערך הקסדצימלי של הצבע" + flair_color: "צבע פלייר אווטר" + flair_color_placeholder: "(אופציונלי) ערך הקסדצימלי של הצבע" + flair_preview_icon: "תצוגה מקדימה של אייקון" + flair_preview_image: "תצוגה מקדימה של תמונה" + flair_note: "שימו לב: פלייר יופיע רק עבור הקבוצה הראשית של משתמשים." user_action_groups: '1': "לייקים שניתנו" '2': "לייקים שהתקבלו" @@ -695,11 +746,10 @@ he: link_generated: "קישור הזמנה יוצר בהצלחה!" valid_for: "קישור הזמנה תקף רק לכתובת המייל הזו: %{email}" bulk_invite: - none: "נכון לעכשיו לא הזמנת לכאן אף אחד. תוכלו לשלוח הזמנות אישיות, או להזמין כמה אנשים בבת אחת באמצעות העלאת קובץ הזמנה קבוצתית." + none: "עדיין לא הזמנתם לכאן אף אחד. תוכלו לשלוח הזמנות פרטניות, או להזמין כמה אנשים יחד על ידי העלאת קובץ CSV." text: "הזמנה קבוצתית מקובץ" - uploading: "העלאה..." success: "העלאת הקובץ החלה בהצלחה, תקבלו התראה באמצעות מסר כאשר התהליך יושלם." - error: "חלה תקלה בהעלאת \"'{{filename}}': \n{{message}}" + error: "מצטערים, הקובץ צריך להיות בפורמט csv." password: title: "סיסמה" too_short: "הסיסמה שלך קצרה מידי." @@ -964,8 +1014,10 @@ he: title: "או לחצו Ctrl+Enter" users_placeholder: "הוספת משתמש" title_placeholder: " במשפט אחד, במה עוסק הדיון הזה?" + title_or_link_placeholder: "הקלידו כותרת, או הדביקו קישור כאן" edit_reason_placeholder: "מדוע ערכת?" show_edit_reason: "(הוספת סיבת עריכה)" + topic_featured_link_placeholder: "הזינו קישור שיוצג עם הכותרת." reply_placeholder: "הקלידו כאן. השתמשו ב Markdown, BBCode או HTML כדי לערוך. גררו או הדביקו תמונות." view_new_post: "צפו בפוסט החדש שלכם." saving: "שומר" @@ -1281,7 +1333,8 @@ he: go_bottom: "למטה" go: "קדימה" jump_bottom: "מעבר לפוסט האחרון" - jump_prompt: "קפיצה לפוסט" + jump_prompt: "קפצו אל..." + jump_prompt_of: "מתוך %{count} פוסטים" jump_prompt_long: "לאיזה פוסט הייתם רוצים לקפוץ?" jump_bottom_with_number: "קפיצה לפוסט %{post_number}" total: סך הכל הפוסטים @@ -1513,7 +1566,7 @@ he: file_too_large: "מצטערים, הקובץ גדול מידי (הגודל המירבי הוא {{max_size_kb}}kb). אולי תקצו להעלות קבצים גדולים לשירות שיתוף בענן ולשתף את הקישור." too_many_uploads: "סליחה, אך ניתן להעלות רק קובץ אחת כל פעם." too_many_dragged_and_dropped_files: "מצטערים, אתם יכולים להעלות עד 10 קבצים בו זמנית." - upload_not_authorized: "סליחה, אך סוג הקובץ שאתם מנסים להעלות אינו מורשה (סיומות מורשות: {{authorized_extensions}})." + upload_not_authorized: "מצטערים, הקובץ שאתם מנסים להעלות אינו מורשה (סיומות מורשות: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "סליחה, משתמשים חדשים לא יכולים להעלות תמונות." attachment_upload_not_allowed_for_new_user: "סליחה, משתמשים חדשים לא יכולים להעלות קבצים." attachment_download_requires_login: "מצטערים, עליכם להיות מחוברים כדי להוריד את הקבצים המצורפים." @@ -1679,6 +1732,7 @@ he: tags_allowed_tag_groups: "קבוצות תגים שניתנות לשימוש בקטגוריה זו:" tags_placeholder: "(אופציונלי) רשימת תגים מותרים" tag_groups_placeholder: "(אופציונלי) רשימת קבוצות תגים" + topic_featured_link_allowed: "אפשרו קישורים מומלצים בקטגוריה זו" delete: 'מחק קטגוריה' create: 'קטגוריה חדשה' create_long: 'יצירת קטגוריה חדשה' @@ -1713,6 +1767,7 @@ he: email_in_disabled: "אפשרות הפרסום של נושאים חדשים דרך דוא\"ל נוטרלה בהגדרות האתר. כדי לאפשר פרסום באמצעות משלוח דוא\"ל," email_in_disabled_click: 'אפשרו את את ההגדרה "דוא"ל נכנס"' suppress_from_homepage: "הרחיקו קטגוריה זו מהעמוד הראשי." + all_topics_wiki: "כברירת מחדל נושאים חדשים יהיו וויקי." sort_order: "סידור ברירת מחדל:" allow_badges_label: "הרשו לעיטורים להיות מוענקים בקטגוריה זו" edit_permissions: "ערוך הרשאות" @@ -1835,7 +1890,9 @@ he: one: "צפיה" other: "צפיות" replies: "תגובות" - views_long: "הנושא הזה נצפה {{number}} פעמים" + views_long: + one: "נושא זה נצפה פעם 1" + other: "נושא זה נצפה {{number}} פעמים" activity: "פעילות" likes: "לייקים" likes_lowercase: @@ -2140,8 +2197,8 @@ he: backups: "גיבויים" traffic_short: "תנועה" traffic: "בקשות יישום web" - page_views: "בקשות API" - page_views_short: "בקשות API" + page_views: "צפיות-דף" + page_views_short: "צפיות-דף" show_traffic_report: "הצגת דו\"ח תנועה מפורט" reports: today: "היום" @@ -2231,15 +2288,12 @@ he: refresh: "רענן" new: "חדש" selector_placeholder: "הזינו שם משתמש/ת" - name_placeholder: "שם הקבוצה, ללא רווחים, בזהה לחוקי שם המשתמש" about: "ערוך את חברות הקבוצה שלך והשמות כאן" group_members: "חברי הקבוצה" delete: "מחק" delete_confirm: "למחוק קבוצה זו?" delete_failed: "לא ניתן למחוק קבוצה זו. אם זו קבוצה אוטומטית, היא בלתי ניתנת למחיקה." - delete_member_confirm: "להסיר את '%{username}' מהקבוצה '%{group}'?" delete_owner_confirm: "הסרת הרשאות מנהל עבור '%{username}'?" - name: "שם" add: "הוספה" add_members: "הוספת חברים וחברות" custom: "מותאם" @@ -2256,14 +2310,6 @@ he: add_owners: הוספת בעלים incoming_email: "התאימו אישית כתובת מייל נכנס" incoming_email_placeholder: "הכניסו כתובת מייל" - flair_url: "תמונת פלייר אווטר" - flair_url_placeholder: "(אופציונלי) URL של תמונה או Font Awesome class" - flair_bg_color: "צבע רקע של פלייר לאווטר" - flair_bg_color_placeholder: "(אופציונלי) ערך צבע ב Hex" - flair_color: "צבע פלייר אווטר" - flair_color_placeholder: "(אופציונלי) ערך צבע הקסדצימלי" - flair_preview: "תצוגה מקדימה" - flair_note: "שימו לב: פלייר יופיע רק עבור הקבוצה הראשית של משתמשים." api: generate_master: "ייצר מפתח מאסטר ל-API" none: "אין מפתחות API פעילים כרגע." @@ -2295,7 +2341,7 @@ he: warn_local_payload_url: "נראה שאתם מנסים להגדיר webhook ל url מקומי. אירוע שנשלח לכתובת מקומית עלול לגרום לתופעות בלתי-צפויות מראש. האם להמשיך?" secret_invalid: "אסור שהסוד יכיל תווי רווח כלשהם." secret_too_short: "הסוד אמור להכיל לפחות 12 תווים." - secret_placeholder: "מחרוזת אופציונלית, משמשת ליצירת חתימות" + secret_placeholder: "מחרוזת אופציונלית, משמשת ליצירת חתימה" event_type_missing: "אתם צריכים לקבוע לפחות סוג אירועים אחד." content_type: "סוג תוכן" secret: "סוד" @@ -2318,7 +2364,7 @@ he: details: "כאשר יש תגובה חדשה, עריכה, מחיקה או שחזור." user_event: name: "אירוע משתמש" - details: "כאשר משתמש נוצר או מאושר." + details: "כאשר משתמש נוצר, מאושר, או מעודכן." delivery_status: title: "מצב שליחה" inactive: "לא פעיל" @@ -2387,7 +2433,7 @@ he: error: "הייתה שגיאה במהלך העלאת '{{filename}}': {{message}}" operations: is_running: "פעולה רצה כרגע..." - failed: "ה{{operation}} נכשלה. אנא בדוק את הלוגים." + failed: "ה-{{operation}} נכשל/ה. אנא בידקו את הלוגים." cancel: label: "ביטול" title: "בטל את הפעולה הנוכחית" @@ -2516,7 +2562,7 @@ he: title: "מיילים" settings: "הגדרות" templates: "תבניות" - preview_digest: "תצוגה מקדימה של סיכום" + preview_digest: "תצוגה מקדימה של תמצית" sending_test: "שולח דואר אלקטרוני לבדיקה..." error: "שגיאה - %{server_error}" test_error: "הייתה בעיה בשליחת הדואר האלקטרוני. בבקשה בידקו את ההגדרות שלכם ונסו שנית." @@ -2534,7 +2580,7 @@ he: send_test: "שליחת מייל בדיקה" sent_test: "נשלח!" delivery_method: "שיטת העברה" - preview_digest_desc: "תצוגה מקדימה של מייל סיכום שנשלח למשתמשים לא פעילים. " + preview_digest_desc: "תצוגה מקדימה של מייל תמצות שנשלח למשתמשים לא פעילים. " refresh: "רענן" send_digest_label: "שילחו תוצאה זו אל:" send_digest: "שליחה" @@ -2543,7 +2589,7 @@ he: html: "html" text: "טקסט" last_seen_user: "משתמש שנראה לאחרונה:" - no_result: "לא נמצאו תוצאות לסיכום." + no_result: "לא נמצאו תוצאות לתמצית." reply_key: "מפתח תגובה" skipped_reason: "דלג על סיבה" incoming_emails: @@ -2572,7 +2618,7 @@ he: title: "סינון" user_placeholder: "שם משתמש" address_placeholder: "name@example.com" - type_placeholder: "סיכום, הרשמה..." + type_placeholder: "תמצית, הרשמה..." reply_key_placeholder: "מפתח תגובה" skipped_reason_placeholder: "סיבה" logs: @@ -2639,6 +2685,11 @@ he: deleted_tag: "תגית נמחקה" renamed_tag: "תגית שונתה" revoke_email: "שללו מייל" + lock_trust_level: "נעילת רמת אמון" + unlock_trust_level: "שחרור רמת אמון מנעילה" + activate_user: "הפעלת משתמש/ת" + deactivate_user: "ניטרול משתמש/ת" + change_readonly_mode: "שינוי מצב קריאה בלבד" screened_emails: title: "הודעות דואר מסוננות" description: "כשמישהו מנסה ליצור חשבון חדש, כתובות הדואר האלקטרוני הבאות ייבדקו וההרשמה תחסם או שיבוצו פעולות אחרות." @@ -2939,6 +2990,7 @@ he: user_preferences: "העדפות משתמש" tags: "תגיות" search: "חיפוש" + groups: "קבוצות" badges: title: עיטורים new_badge: עיטור חדש @@ -2975,7 +3027,7 @@ he: enabled: אפשרו עיטור icon: סמליל image: תמונה - icon_help: "השתמשו ב-class בשם Font Awesome או ב-URL לתמונה" + icon_help: "השתמשו במחלקה של Font Awesome או ב-URL לתמונה" query: שאילתת עיטור (SQL) target_posts: פרסומי מטרות שאילתה auto_revoke: הפעלת שאילתת ביטול יומית diff --git a/config/locales/client.id.yml b/config/locales/client.id.yml index dd3dcb0df7c..ec61709eea4 100644 --- a/config/locales/client.id.yml +++ b/config/locales/client.id.yml @@ -292,17 +292,10 @@ id: total_rows: other: "%{count} pengguna" groups: - empty: - posts: "Tidak ada posting dari anggota kelompok ini." - members: "TIdak ada anggota pada kelompok ini." - mentions: "Tidak ada balasan oleh kelompok ini." - messages: "Tidak ada pesan untuk kelompok ini." - topics: "Tidak ada topik dari anggota kelompok ini." add: "Menambahkan" selector_placeholder: "Menambahkan anggota" owner: "pemilik" visible: "Grup terlihat oleh semua pengguna" - index: "Grup" title: other: "Grup" members: "Anggota" @@ -591,8 +584,6 @@ id: generate_link: "Salin Tautan Undangan" bulk_invite: text: "Undangan Massal dari Berkas" - uploading: "Mengunggah..." - error: "Terdapat gangguan mengunggah '{{filename}}': {{message}}" password: title: "Kata sandi" too_short: "Password kamu terlalu pendek." diff --git a/config/locales/client.it.yml b/config/locales/client.it.yml index fb00c6f98c1..b971589b97c 100644 --- a/config/locales/client.it.yml +++ b/config/locales/client.it.yml @@ -321,21 +321,63 @@ it: total_rows: one: "1 utente" other: "%{count} utenti" + group_histories: + actions: + change_group_setting: "Cambia le impostazioni del gruppo" + add_user_to_group: "Aggiunti utente" + remove_user_from_group: "Rimuovi utente" + make_user_group_owner: "Assegna proprietà" + remove_user_as_group_owner: "Revoca proprietà" groups: + logs: + title: "Log" + when: "Quando" + action: "Azione" + acting_user: "Utente attore" + target_user: "Utente destinatario" + subject: "Oggetto" + details: "Dettagli" + from: "Da" + to: "A" + edit: + title: 'Modifica Gruppo' + full_name: 'Nome Completo' + add_members: "Aggiungi Membri" + delete_member_confirm: "Rimuovere '%{username}' dal gruppo '%{group}'?" + request_membership_pm: + title: "Richiesta di Iscrizione" + body: "Vorrei iscrivermi a @%{groupName}." + name_placeholder: "Nome del gruppo, senza spazi, stesse regole del nome utente" + public: "Permetti agli utenti di aggiungersi/togliersi liberamente dal gruppo (il gruppo deve essere visibile)" empty: - posts: "Non ci sono messaggi dai membri di questo gruppo." + posts: "Non ci sono messaggi da membri di questo gruppo." members: "Non ci sono membri in questo gruppo." - mentions: "Non ci sono menzioni a questo gruppo." + mentions: "Questo gruppo non è stato menzionato." messages: "Non ci sono messaggi per questo gruppo." topics: "Non ci sono argomenti da membri di questo gruppo." + logs: "Non ci sono log per questo gruppo." add: "Aggiungi" + join: "Partecipa al Gruppo" + leave: "Abbandona il Gruppo" + request: "Richiedi di partecipare al gruppo" + automatic_group: Gruppo Automatico + closed_group: Gruppo Chiuso + is_group_user: "Sei un membro di questo gruppo" + allow_membership_requests: "Permetti agli utenti di richiedere l'invito ai proprietari del gruppo (il gruppo deve essere menzionabile da chiunque)" + membership: "Iscrizione" + name: "Nome" + user_count: "Numero di Membri" + bio: "Informazioni sul Gruppo" selector_placeholder: "Aggiungi membri" owner: "proprietario" visible: "Il Gruppo è visibile a tutti gli utenti" - index: "Gruppi" + index: + title: "Gruppi" + empty: "Non ci sono gruppi visibili." title: one: "gruppo" other: "gruppi" + activity: "Attività" members: "Membri" topics: "Argomenti" posts: "Messaggi" @@ -367,6 +409,11 @@ it: muted: title: "Silenziato" description: "Non verrai mai avvertito per i nuovi argomenti in questo gruppo." + flair_url_placeholder: "(Facoltativo) URL Immagine o classe Font Awesome" + flair_bg_color_placeholder: "(Facoltativo) Codice esadecimale del colore" + flair_color_placeholder: "(Facoltativo) Codice esadecimale del colore" + flair_preview_icon: "Anteprima Icona" + flair_preview_image: "Anteprima Immagine" user_action_groups: '1': "Mi piace - Assegnati" '2': "Mi piace - Ricevuti" @@ -428,6 +475,11 @@ it: profile: "Profilo" mute: "Ignora" edit: "Modifica opzioni" + download_archive: + button_text: "Scarica i Miei Messaggi" + confirm: "Sei sicuro di voler scaricare i tuoi messaggi?" + success: "Esportazione iniziata, verrai avvertito con un messaggio al termine del processo." + rate_limit_error: "I messaggi possono essere scaricati una volta al giorno, riprova domani." new_private_message: "Nuovo Messaggio" private_message: "Messaggio" private_messages: "Messaggi" @@ -468,7 +520,7 @@ it: email_activity_summary: "Riassunto Attività" mailing_list_mode: label: "Modalità Mailing list" - enabled: "Abilita la modalità Mailing list" + enabled: "Abilita la modalità mailing list" instructions: | Questa impostazione modifica il riassunto attività.
    Gli argomenti e le categorie silenziate non sono incluse in queste email. @@ -489,9 +541,9 @@ it: tracked_categories: "Seguite" tracked_categories_instructions: "Seguirai automaticamente tutti gli argomenti appartenenti a queste categorie. Accanto all'argomento comparirà il conteggio dei nuovi messaggi." watched_first_post_categories: "Osservando Primo Messaggio" - watched_first_post_categories_instructions: "Riceverai solo la notifica per il primo messaggio di ogni nuovo argomento in queste categorie." + watched_first_post_categories_instructions: "Riceverai la notifica per il primo messaggio di ogni nuovo argomento in queste categorie." watched_first_post_tags: "Osservando Primo Messaggio" - watched_first_post_tags_instructions: "Riceverai solo la notifica per il primo messaggio di ogni nuovo argomento con queste etichette." + watched_first_post_tags_instructions: "Riceverai la notifica per il primo messaggio di ogni nuovo argomento con queste etichette." muted_categories: "Silenziate" muted_categories_instructions: "Non ti verrà notificato nulla sui nuovi argomenti in queste categorie, e non compariranno nell'elenco Ultimi." delete_account: "Cancella il mio account" @@ -623,7 +675,7 @@ it: always: "sempre" never: "mai" email_digests: - title: "Se non dovessi visitare questo sito, inviami un riassunto via email degli argomenti più discussi e delle risposte" + title: "Quando non visito il sito, inviami un riassunto via email degli argomenti più discussi e delle risposte" every_30_minutes: "ogni 30 minuti" every_hour: "ogni ora" daily: "ogni giorno" @@ -687,14 +739,12 @@ it: account_age_days: "Età dell'utente in giorni" create: "Invia un Invito" generate_link: "Copia il collegamento di invito" - link_generated: "Link di invito generato con successo!" - valid_for: "Questo link di invito è valido solamente per questo indirizzo email: %{email}" + link_generated: "Collegamento di invito generato con successo!" + valid_for: "Questo collegamento di invito è valido solamente per il seguente indirizzo email: %{email}" bulk_invite: - none: "Non hai ancora invitato nessuno qui. Puoi inviare inviti individuali, o invitare un gruppo di persone caricando un file di invito di massa." + none: "Non hai ancora invitato nessuno. Puoi invitare persone singole, o più persone insieme caricando un file CSV." text: "Invito di Massa da File" - uploading: "In caricamento..." success: "Il file è stato caricato con successo, riceverai un messaggio di notifica quando il processo sarà completato." - error: "Si è verificato un errore durante il caricamento {{filename}}': {{message}}" password: title: "Password" too_short: "La password è troppo breve." @@ -799,7 +849,7 @@ it: other: "%{count} errori/%{duration}" learn_more: "per saperne di più..." all_time: 'totale' - all_time_desc: 'numero totale di argomenti creati' + all_time_desc: 'totale argomenti creati' year: 'all''anno' year_desc: 'argomenti creati negli ultimi 365 giorni' month: 'al mese' @@ -846,7 +896,7 @@ it: trust_level: 'Livello Esperienza' search_hint: 'nome utente, email o indirizzo IP' create_account: - disclaimer: "Registrandoti, accetti la privacy policy e i termini di servizio." + disclaimer: "Registrandoti, accetti la politica di riservatezza e i termini di servizio." title: "Crea Nuovo Account" failed: "Qualcosa non ha funzionato. Forse questa email è già registrata, prova a usare il link di recupero password" forgot_password: @@ -906,7 +956,7 @@ it: title: "con GitHub" message: "Autenticazione con GitHub (assicurati che il blocco pop up non sia attivo)" emoji_set: - apple_international: "Apple/International" + apple_international: "Apple/Internazionale" google: "Google" twitter: "Twitter" emoji_one: "Emoji One" @@ -959,6 +1009,7 @@ it: title: "O premi Ctrl+Enter" users_placeholder: "Aggiunti un utente" title_placeholder: "In breve, di cosa tratta questo argomento?" + title_or_link_placeholder: "Digita il titolo, o incolla qui il collegamento " edit_reason_placeholder: "perché stai scrivendo?" show_edit_reason: "(aggiungi motivo della modifica)" reply_placeholder: "Scrivi qui. Per formattare il testo usa Markdown, BBCode o HTML. Trascina o incolla le immagini." @@ -991,7 +1042,7 @@ it: olist_title: "Elenco Numerato" ulist_title: "Elenco Puntato" list_item: "Elemento lista" - heading_label: "T" + heading_label: "I" heading_title: "Intestazione" heading_text: "Intestazione" hr_title: "Linea Orizzontale" @@ -1002,7 +1053,7 @@ it: cant_send_pm: "Spiacenti, non puoi inviare un messaggio a %{username}." yourself_confirm: title: "Hai dimenticato di aggiungere i destinatari?" - body: "In questo momento questo messaggio è visibile solo a te!" + body: "Per ora il messaggio sarà inviato solo a te stesso!" admin_options_title: "Impostazioni dello staff opzionali per l'argomento" auto_close: label: "Tempo per auto-chiusura argomento:" @@ -1105,27 +1156,27 @@ it: posted_by: label: Pubblicato da in_category: - label: In Categoria + label: Nella Categoria in_group: - label: In Gruppo + label: Nel Gruppo with_badge: label: Con Distintivo with_tags: label: Con Etichette filters: - label: Mostra solamente argomenti/post che... - likes: Ho messo "Mi Piace" - posted: Ho pubblicato in - watching: Sto' osservando - tracking: Sto' seguendo - private: sono nei miei messaggi - bookmarks: Ho aggiunto ai segnalibri + label: 'Mostra solamente argomenti/messaggi:' + likes: su cui ho messo "Mi Piace" + posted: ho pubblicato in + watching: sto osservando + tracking: sto seguendo + private: sono messaggi scritti da me + bookmarks: ho aggiunto ai segnalibri first: sono il primissimo post pinned: sono appuntati unpinned: non sono appuntati wiki: sono wiki statuses: - label: Dove gli argomenti + label: In cui gli argomenti open: sono aperti closed: sono chiusi archived: sono archiviati @@ -1136,8 +1187,8 @@ it: label: Conteggio Messaggi Minimo time: label: Pubblicato - before: prima - after: dopo + before: prima del + after: dopo il hamburger_menu: "vai ad un'altra lista di argomenti o categoria" new_item: "nuovo" go_back: 'indietro' @@ -1146,6 +1197,8 @@ it: topics: new_messages_marker: "ultima visita" bulk: + select_all: "Seleziona Tutti" + clear_all: "Deseleziona Tutto" unlist_topics: "Deselezione Topics" reset_read: "Reimposta Lettura" delete: "Elimina Argomenti" @@ -1260,8 +1313,8 @@ it: auto_close_save: "Salva" auto_close_remove: "Non chiudere automaticamente questo argomento" auto_close_immediate: - one: "L'ultimo messaggio nell'argomento è già vecchio di 1 ora, per cui l'argomento verrà chiuso immediatamente." - other: "L'ultimo messaggio nell'argomento è già vecchio di %{count} ore, per cui l'argomento verrà chiuso immediatamente." + one: "L'ultimo messaggio nell'argomento ha già 1 ora, per cui l'argomento verrà chiuso immediatamente." + other: "L'ultimo messaggio nell'argomento ha già %{count} ore, per cui l'argomento verrà chiuso immediatamente." timeline: back: "Indietro" back_description: "Torna indietro al tuo ultimo messaggio non letto" @@ -1272,7 +1325,8 @@ it: go_bottom: "basso" go: "vai" jump_bottom: "salta all'ultimo messaggio" - jump_prompt: "salta al messaggio" + jump_prompt: "vai a..." + jump_prompt_of: "di %{count} messaggi" jump_prompt_long: "A quale messaggio vuoi saltare?" jump_bottom_with_number: "Passa al messaggio %{post_number}" total: totale messaggi @@ -1281,7 +1335,7 @@ it: title: cambia la frequenza con cui sarai avvertito su questo argomento reasons: mailing_list_mode: "Hai la modalità mailing list abilitata, verrai notificato delle risposte a questo argomento via email." - '3_10': 'Riceverai notifiche perché stai osservando una etichetta in questo argomento.' + '3_10': 'Riceverai notifiche perché stai osservando un''etichetta in questo argomento.' '3_6': 'Riceverai notifiche perché stai osservando questa categoria.' '3_5': 'Riceverai notifiche poiché hai iniziato ad osservare questo argomento automaticamente.' '3_2': 'Riceverai notifiche perché stai osservando questo argomento.' @@ -1334,8 +1388,8 @@ it: invisible: "Rendi Invisibile" visible: "Rendi Visibile" reset_read: "Reimposta Dati Letti" - make_public: "Rendi Pubblico questo Argomento" - make_private: "Rendi un Messaggio Privato" + make_public: "Rendi Argomento Pubblico" + make_private: "Rendi Privato il Messaggio " feature: pin: "Appunta Argomento" unpin: "Spunta Argomento" @@ -1353,7 +1407,7 @@ it: help: 'condividi un collegamento a questo argomento' print: title: 'Stampa' - help: 'Apri una versione da stampa di questo argomento' + help: 'Apri una versione da stampabile di questo argomento' flag_topic: title: 'Segnala' help: 'segnala questo argomento o invia una notifica privata' @@ -1392,7 +1446,7 @@ it: email_or_username_placeholder: "indirizzo email o nome utente" action: "Invita" success: "Abbiamo invitato l'utente a partecipare a questo messaggio." - success_group: "Abbiamo invitato quel gruppo a partecipare a questo messaggio." + success_group: "Abbiamo invitato il gruppo a partecipare a questo messaggio." error: "Spiacenti, si è verificato un errore durante l'invito dell'utente." group_name: "nome gruppo" controls: "Impostazioni Argomento" @@ -1466,6 +1520,7 @@ it: post: reply: " {{replyAvatar}} {{usernameLink}}" reply_topic: " {{link}}" + quote_reply: "Cita" edit: "Modifica in corso {{link}} {{replyAvatar}} {{username}}" edit_reason: "Motivo:" post_number: "messaggio {{number}}" @@ -1500,7 +1555,7 @@ it: create: "Spiacenti, si è verificato un errore nel creare il tuo messaggio. Prova di nuovo." edit: "Spiacenti, si è verificato un errore nel modificare il tuo messaggio. Prova di nuovo." upload: "Spiacenti, si è verificato un errore durante il caricamento del file. Prova di nuovo." - file_too_large: "Spiacente, questo file è troppo grande (la grandezza massima è {{max_size_kb}}kb). Perché non carichi il tuo file in un servizio di cloud sharing e poi condividi il link?" + file_too_large: "Spiacenti, il file è troppo grande (la grandezza massima è {{max_size_kb}}kb). Perché non carichi il file con un servizio di cloud sharing e poi ne condividi il collegamento?" too_many_uploads: "Spiacenti, puoi caricare un solo file per volta." too_many_dragged_and_dropped_files: "Spiacenti, puoi caricare solo 10 file alla volta." upload_not_authorized: "Spiacenti, il file che stai cercando di caricare non è autorizzato (estensioni autorizzate: {{authorized_extensions}})." @@ -1512,7 +1567,7 @@ it: no_value: "No, mantienilo" yes_value: "Si, abbandona" via_email: "questo messaggio è arrivato via email" - via_auto_generated_email: "questo post è arrivato tramite una mail auto generata" + via_auto_generated_email: "questo messaggio è arrivato tramite una email auto generata" whisper: "questo messaggio è un sussurro privato per i moderatori" wiki: about: "questo messaggio è una guida" @@ -1669,6 +1724,7 @@ it: tags_allowed_tag_groups: "Aggiungi etichette ai gruppi che possono essere utilizzati unicamente in questa categoria:" tags_placeholder: "Elenco (opzionale) delle etichette permesse" tag_groups_placeholder: "Elenco (opzionale) dei gruppi di etichette permessi" + topic_featured_link_allowed: "Consenti collegamenti in primo piano in questa categoria" delete: 'Elimina Categoria' create: 'Crea Categoria' create_long: 'Crea una nuova categoria' @@ -1703,7 +1759,7 @@ it: email_in_disabled: "Le Impostazioni Sito non permettono di creare nuovi argomenti via email. Per abilitare la creazione di argomenti via email," email_in_disabled_click: 'abilita l''impostazione "email entrante".' suppress_from_homepage: "Elimina questa categoria dalla homepage." - sort_order: "Ordinamento di Default:" + sort_order: "Ordinamento Predefinito:" allow_badges_label: "Permetti l'assegnazione di distintivi in questa categoria" edit_permissions: "Modifica Permessi" add_permission: "Aggiungi Permesso" @@ -1716,6 +1772,10 @@ it: notifications: watching: title: "In osservazione" + description: "Osserverai automaticamente tutti gli argomenti in queste categorie. Riceverai notifiche per ogni nuovo messaggio in ogni argomento, e apparirà il conteggio delle nuove risposte." + watching_first_post: + title: "Osservando il Primo Messaggio" + description: "Riceverai una notifica soltanto per il primo messaggio di ogni nuovo argomento in queste categorie." tracking: title: "Seguendo" regular: @@ -1727,14 +1787,21 @@ it: sort_options: default: "predefinito" likes: "Mi piace" - op_likes: "\"Mi Piace\" del Post Originale" + op_likes: "\"Mi Piace\" del Messaggio Originale" views: "Visualizzazioni" posts: "Messaggi" + activity: "Attività" + posters: "Partecipanti" + category: "Categoria" + created: "Creazione" + sort_ascending: 'Crescente' + sort_descending: 'Decrescente' flagging: title: 'Grazie per aiutarci a mantenere la nostra comunità civile!' action: 'Segnala Messaggio' take_action: "Procedi" notify_action: 'Messaggio' + official_warning: 'Avvertimento Ufficiale' delete_spammer: "Cancella Spammer" yes_delete_spammer: "Sì, cancella lo spammer" ip_address_missing: "(N/D)" @@ -1749,6 +1816,16 @@ it: spam: "E' Spam" custom_placeholder_notify_user: "Sii dettagliato, costruttivo e sempre gentile." custom_placeholder_notify_moderators: "Facci sapere esattamente cosa ti preoccupa, fornendo collegamenti pertinenti ed esempi ove possibile." + custom_message: + at_least: + one: "inserisci almeno 1 carattere" + other: "inserisci almeno {{n}} caratteri" + more: + one: "1 mancante..." + other: "{{count}} mancanti..." + left: + one: "1 mancante" + other: "{{count}} mancanti..." flagging_topic: title: "Grazie per aiutarci a mantenere la nostra comunità civile!" action: "Segnala Argomento" @@ -1757,9 +1834,14 @@ it: title: "Riassunto Argomento" participants_title: "Autori Assidui" links_title: "Collegamenti Di Successo" + links_shown: "mostra altri collegamenti..." clicks: one: "1 click" other: "%{count} click" + post_links: + title: + one: "un altro" + other: "altri %{count}" topic_statuses: warning: help: "Questo è un avvertimento ufficiale." @@ -1792,7 +1874,6 @@ it: one: "visita" other: "visite" replies: "Risposte" - views_long: "questo argomento è stato visto {{number}} volte" activity: "Attività" likes: "Mi piace" likes_lowercase: @@ -1901,6 +1982,7 @@ it: new: 'g, n Nuovi' unread: 'g, u Non letti' categories: 'g, c Categorie' + top: 'g, t Inizio' bookmarks: 'g, b Segnalibri' profile: 'g, p Profilo' messages: 'g, m Messaggi' @@ -1942,6 +2024,7 @@ it: mark_regular: 'm, r Argomento normale (default)' mark_tracking: 'm, t Segui argomento' mark_watching: 'm, w Osserva argomento' + print: 'ctrl+p Stampa argomento' badges: earned_n_times: one: "Guadagnato questo distintivo 1 volta" @@ -1954,6 +2037,12 @@ it: badge_count: one: "1 Distintivo" other: "%{count} Distintivi" + more_badges: + one: "+1 altro" + other: "+ altri %{count}" + granted: + one: "1 assegnato" + other: "%{count} assegnati" select_badge_for_title: Seleziona un distintivo da usare come tuo titolo none: "" badge_grouping: @@ -1987,6 +2076,8 @@ it: delete_confirm: "Sicuro di voler cancellare questa etichetta?" rename_tag: "Rinomina Etichetta" rename_instructions: "Scegli un altro nome per l'etichetta:" + sort_by: "Ordina per:" + sort_by_count: "conteggio" sort_by_name: "nome" manage_groups: "Gestisci Gruppi Etichette" manage_groups_description: "Definisci gruppi per organizzare le etichette" @@ -2050,6 +2141,9 @@ it: custom_message_link: "messaggio personalizzato" custom_message_placeholder: "Inserisci il tuo messaggio personalizzato" custom_message_template_forum: "Ehi, unisciti a questo forum!" + custom_message_template_topic: "Ehi, credo che questo argomento ti possa interessare!" + safe_mode: + enabled: "La modalità sicura è attiva, per disattivarla chiudi il browser" admin_js: type_to_filter: "digita per filtrare..." admin: @@ -2084,8 +2178,6 @@ it: backups: "backup" traffic_short: "Traffico" traffic: "Richieste web dell'applicazione" - page_views: "Richieste API" - page_views_short: "Richieste API" show_traffic_report: "Mostra rapporto di traffico dettagliato" reports: today: "Oggi" @@ -2097,6 +2189,7 @@ it: 30_days_ago: "30 Giorni Fa" all: "Tutti" view_table: "tabella" + view_graph: "grafico" refresh_report: "Aggiorna Rapporto" start_date: "Data Inizio" end_date: "Data Fine" @@ -2174,15 +2267,12 @@ it: refresh: "Aggiorna" new: "Nuovo" selector_placeholder: "inserisci nome utente" - name_placeholder: "Nome del gruppo, senza spazi, stesse regole del nome utente" about: "Modifica qui la tua appartenenza ai gruppi e i loro nomi" group_members: "Membri del gruppo" delete: "Cancella" delete_confirm: "Cancellare questo gruppo?" delete_failed: "Impossibile cancellare il gruppo. Se questo è un gruppo automatico, non può essere eliminato." - delete_member_confirm: "Rimuovere '%{username}' dal gruppo '%{group}'?" delete_owner_confirm: "Rimuovere i privilegi per '%{username}'?" - name: "Nome" add: "Aggiungi" add_members: "Aggiungi membri" custom: "Personalizzato" @@ -2199,14 +2289,6 @@ it: add_owners: Aggiungi proprietari incoming_email: "Indirizzo email personalizzato" incoming_email_placeholder: "inserisci l'indirizzo e-mail" - flair_url: "Immagine Avatar" - flair_url_placeholder: "(Facoltativo) URL Immagine o categoria Font Awesome" - flair_bg_color: "Colore di sfondo Avatar" - flair_bg_color_placeholder: "(Facoltativo) Codice Hex colore" - flair_color: "Colore Avatar" - flair_color_placeholder: "(Facoltativo) Codice Hex colore" - flair_preview: "Anteprima" - flair_note: "Nota: l'Avatar verrà mostrato solo per il gruppo principale dell'utente." api: generate_master: "Genera una Master API Key" none: "Non ci sono chiavi API attive al momento." @@ -2224,8 +2306,8 @@ it: web_hooks: title: "Webhook" none: "Non ci sono webhook disponibili adesso." - instruction: "Webhook consente a Discourse di notificare servizi esterni quando sul tuo sito si verificano determinati eventi. Quando un webhook viene innescato, una richiesta di MESSAGGIO viene inviata agli URL forniti." - detailed_instruction: "Una richiesta di MESSAGGIO verrà inviata agli URL forniti quando si verifica un evento scelto." + instruction: "I Webhook consentono a Discourse di notificare i servizi esterni quando sul tuo sito si verificano determinati eventi. Quando un webhook viene innescato, viene inviata una richiesta di tipo POST agli URL forniti." + detailed_instruction: "Una richiesta di tipo POST verrà inviata agli URL forniti quando si verifica uno degli eventi scelti." new: "Nuovo Webhook" create: "Crea" save: "Salva" @@ -2233,8 +2315,58 @@ it: description: "Descrizione" controls: "Componenti" go_back: "Torna all'elenco" - payload_url: "Aggiungi URL" + payload_url: "URL di Payload" payload_url_placeholder: "https://example.com/postreceive" + warn_local_payload_url: "Stai impostando un webhook che punta ad un indirizzo locale. Eventi inviati ad un indirizzo locale possono causare effetti collaterali o risultati inaspettati. Vuoi continuare?" + secret_invalid: "La chiave segreta non può contenere spazi vuoti." + secret_too_short: "La chiave segreta deve contenere almeno 12 caratteri." + event_type_missing: "Devi impostare almeno un tipo di evento." + content_type: "Tipo Contenuto" + secret: "Chiave segreta" + event_chooser: "Quali eventi vuoi che attivino questo webhook?" + wildcard_event: "Inviami tutto." + individual_event: "Seleziona eventi singoli." + verify_certificate: "Verifica il certificato TLS della URL payload" + active: "Attivo" + delete_confirm: "Eliminare questo webhook?" + topic_event: + name: "Evento Argomento" + details: "Quando c'è un nuovo argomento, revisionato, modificato o cancellato." + post_event: + name: "Evento Messaggio" + details: "Quando c'è una nuova risposta, modifica, cancellazione o recupero." + user_event: + name: "Evento Utente" + details: "Quando un utente viene creato, approvato o aggiornato." + delivery_status: + title: "Stato di Consegna" + inactive: "Non attivo" + failed: "Fallito" + successful: "Completato" + events: + none: "Non ci sono eventi correlati." + redeliver: "Riconsegna " + incoming: + one: "C'è un nuovo evento." + other: "Ci sono {{count}} nuovi eventi." + completed_in: + one: "Compleato in 1 secondo." + other: "Completato in {{count}} secondi." + request: "Richiesta" + response: "Risposta" + redeliver_confirm: "Sicuro di voler rispedire lo stesso payload?" + headers: "Intestazioni" + payload: "Payload" + body: "Corpo" + go_list: "Vai all'elenco" + go_details: "Modifica webhook" + go_events: "Vai agli eventi" + ping: "Ping" + status: "Codice Stato" + event_id: "ID" + timestamp: "Creazione" + completion: "Tempo Completamento" + actions: "Azioni" plugins: title: "Plugin" installed: "Plugin Installati" @@ -2409,6 +2541,7 @@ it: test_error: "C'è stato un problema nell'invio dell'email di test. Controlla nuovamente le impostazioni email, verifica che il tuo host non blocchi le connessioni email e riprova." sent: "Inviato" skipped: "Omesso" + bounced: "Ritornate" received: "Ricevute" rejected: "Rifiutate" sent_at: "Inviato Alle" @@ -2422,10 +2555,14 @@ it: delivery_method: "Metodo di consegna" preview_digest_desc: "Vedi in anteprima il contenuto delle email di riepilogo inviate agli utenti inattivi." refresh: "Aggiorna" + send_digest_label: "Invia questo risultato a:" + send_digest: "Invia" + sending_email: "Invio email in corso..." format: "Formato" html: "html" text: "testo" last_seen_user: "Ultimo Utente Visto:" + no_result: "Nessun risultato trovato per il riepilogo. " reply_key: "Chiave di risposta" skipped_reason: "Motivo Omissione" incoming_emails: @@ -2520,6 +2657,7 @@ it: backup_operation: "operazione di backup" deleted_tag: "etichetta cancellata" renamed_tag: "etichetta rinominata" + revoke_email: "revoca email" screened_emails: title: "Email Scansionate" description: "Quando qualcuno cerca di creare un nuovo account, verrando controllati i seguenti indirizzi email e la registrazione viene bloccata, o eseguita qualche altra azione." @@ -2614,6 +2752,7 @@ it: suspend_reason: "Motivo" suspended_by: "Sospeso da" delete_all_posts: "Cancella tutti i messaggi" + delete_all_posts_confirm_MF: "Stai per cancellare {POSTS, plural, one {1 messaggio} other {# messaggi}} e {TOPICS, plural, one {1 argomento} other {# argomenti}}. Sei sicuro?" suspend: "Sospendi" unsuspend: "Riabilita" suspended: "Sospeso?" @@ -2687,9 +2826,17 @@ it: block_failed: 'Si è verificato un errore durante il blocco dell''utente.' block_confirm: 'Sei sicuro di voler bloccare questo utente? Non sarà più in grado di creare alcun nuovo argomento o messaggio.' block_accept: 'Sì, blocca questo utente' + bounce_score: "Errori di Ritorno" + reset_bounce_score: + label: "Azzera" + title: "Azzera il conteggio degli errori di ritorno." deactivate_explanation: "Un utente disattivato deve riconvalidare la propria email." suspended_explanation: "Un utente sospeso non può connettersi." block_explanation: "Un utente bloccato non può pubblicare messaggi o iniziare argomenti." + bounce_score_explanation: + none: "L'indirizzo email non ha causato nessun errore di ritorno recentemente." + some: "Sono stati ricevuti alcuni errori di ritorno per quell'indirizzo email." + threshold_reached: "Quella email ha ricevuto troppi errori di ritorno." trust_level_change_failed: "C'è stato un problema nel cambio di livello di esperienza di questo utente. " suspend_modal_title: "Sospendi Utente" trust_level_2_users: "Utenti con Livello Esperienza 2" @@ -2700,6 +2847,9 @@ it: unlock_trust_level: "Sblocca Livello Esperienza" tl3_requirements: title: "Requisiti per Livello Esperienza 3" + table_title: + one: "Nell'ultimo giorno:" + other: "Negli ultimi %{count} giorni:" value_heading: "Valore" requirement_heading: "Requisito" visits: "Visite" @@ -2799,12 +2949,15 @@ it: developer: 'Sviluppatore' embedding: "Incorporo" legal: "Legale" + user_api: 'API Utente' uncategorized: 'Altro' backups: "Backup" login: "Connessione" plugins: "Plugin" user_preferences: "Preferenze Utente" tags: "Etichette" + search: "Cerca" + groups: "Gruppi" badges: title: Distintivi new_badge: Nuovo Distintivo @@ -2897,9 +3050,11 @@ it: embed_by_username: "Nome utente per la creazione dell'argomento" embed_post_limit: "Numero massimo di messaggi da includere" embed_username_key_from_feed: "Chiave per ottenere il nome utente discourse dal feed" + embed_title_scrubber: "Espressione regolare usata per ripulire i titoli dei messaggi" embed_truncate: "Tronca i messaggi incorporati" embed_whitelist_selector: "Selettore CSS per gli elementi da permettere negli embed" embed_blacklist_selector: "Selettore CSS per gli elementi da rimuovere dagli embed" + embed_classname_whitelist: "Classi CSS autorizzate" feed_polling_enabled: "Importa i messaggi via RSS/ATOM" feed_polling_url: "URL del feed RSS/ATOM da recuperare" save: "Salva Impostazioni Inclusione" @@ -2932,6 +3087,7 @@ it: other: "La tua comunità ha %{count} membri dello staff." invites: add_user: "aggiungi" + none_added: "Non hai invitato nessuno dello staff. Sicuro di voler proseguire?" roles: admin: "Amministratore" moderator: "Moderatore" diff --git a/config/locales/client.ja.yml b/config/locales/client.ja.yml index c2b9f0d7e56..17527c90362 100644 --- a/config/locales/client.ja.yml +++ b/config/locales/client.ja.yml @@ -188,8 +188,8 @@ ja: like_count: "いいね!" topic_count: "トピック" post_count: "投稿" - user_count: "新規ユーザ" - active_user_count: "アクティブユーザ" + user_count: "新規ユーザー" + active_user_count: "アクティブユーザー" contact: "お問い合わせ" contact_info: "このサイトに影響を与える重要な問題や緊急の問題が発生した場合は、 %{contact_info}までご連絡ください" bookmarked: @@ -238,7 +238,7 @@ ja: topic: "トピック:" approve: '承認' reject: 'リジェクト' - delete_user: '削除されたユーザ' + delete_user: '削除されたユーザー' title: "承認待ち" none: "レビュー待ちの投稿はありません。" edit: "編集" @@ -269,8 +269,8 @@ ja: sent_by_user: "{{user}} が送信" sent_by_you: "あなた が送信" directory: - filter_name: "ユーザ名でフィルタ" - title: "ユーザ" + filter_name: "ユーザー名でフィルタ" + title: "ユーザー" likes_given: "与えた" likes_received: "もらった" topics_entered: "閲覧数" @@ -286,18 +286,22 @@ ja: posts_read: "既読" posts_read_long: "投稿の閲覧数" total_rows: - other: "%{count}人のユーザ" + other: "%{count}人のユーザー" groups: - empty: - posts: "このグループのメンバーからの投稿はありません。" - members: "このグループからの投稿はありません。" - mentions: "このグループのメンションはありません。" - messages: "このグループへのメッセージはありません。" - topics: "このグループのメンバーのトピックは何もありません。" + request_membership_pm: + title: "メンバーシップリクエスト" add: "追加" + automatic_group: 自動作成グループ + closed_group: クローズドグループ + allow_membership_requests: "ユーザーがグループオーナーに対してメンバーシップリクエストを送信できるようにする(全ユーザーがグループへメンション出来るようにする必要があります。)" + membership: "メンバーシップ" + user_count: "メンバー数" selector_placeholder: "メンバーを追加" owner: "オーナー" - visible: "このグループは全てのユーザに表示されています。" + visible: "このグループは全てのユーザーに表示されています。" + index: + title: "グループ" + empty: "表示するグループはありません。" title: other: "グループ" members: "メンバー" @@ -367,7 +371,7 @@ ja: phone: 電話 other_accounts: "同じIPアドレスを持つアカウント" delete_other_accounts: "%{count}件削除" - username: "ユーザ名" + username: "ユーザー名" trust_level: "トラストレベル" read_time: "読んだ時間" topics_entered: "入力したトピック" @@ -401,6 +405,7 @@ ja: disable: "通知を無効にする" enable: "通知を有効にする" each_browser_note: "注意: 利用するすべてのブラウザでこの設定を変更する必要があります" + dismiss_notifications: "すべて既読にする" dismiss_notifications_tooltip: "全ての未読の通知を既読にします" disable_jump_reply: "返信した後に投稿へ移動しない" dynamic_favicon: "新規/更新トピックの件数をブラウザのアイコンに表示する" @@ -409,10 +414,10 @@ ja: change: "変更" moderator: "{{user}} はモデレータです" admin: "{{user}} は管理者です" - moderator_tooltip: "このユーザはモデレータです" - admin_tooltip: "このユーザは管理者です" - blocked_tooltip: "このユーザはブロックされています" - suspended_notice: "このユーザは {{date}} まで凍結状態です。" + moderator_tooltip: "このユーザーはモデレータです" + admin_tooltip: "このユーザーは管理者です" + blocked_tooltip: "このユーザーはブロックされています" + suspended_notice: "このユーザーは {{date}} まで凍結状態です。" suspended_reason: "理由: " github_profile: "Github" email_activity_summary: "アクティビティの情報" @@ -433,9 +438,9 @@ ja: delete_yourself_not_allowed: "アカウントを削除できませんでした。サイトの管理者へ連絡してください。" unread_message_count: "メッセージ" admin_delete: "削除" - users: "ユーザ" + users: "ユーザー" muted_users: "ミュート" - muted_users_instructions: "ユーザからの通知をすべて行いません" + muted_users_instructions: "ユーザーからの通知をすべて行いません" muted_topics_link: "ミュートしたトピックを表示する" staff_counters: flags_given: "役に立った通報" @@ -464,10 +469,10 @@ ja: title: "プロフィールを変更" error: "変更中にエラーが発生しました。" change_username: - title: "ユーザ名を変更" - taken: "このユーザ名は既に使われています。" - error: "ユーザ名変更中にエラーが発生しました。" - invalid: "このユーザ名は無効です。英数字のみ利用可能です。" + title: "ユーザー名を変更" + taken: "このユーザー名は既に使われています。" + error: "ユーザー名の変更中にエラーが発生しました。" + invalid: "このユーザー名は無効です。英数字のみ利用可能です。" change_email: title: "メールアドレスを変更" taken: "このメールアドレスは既に使われています。" @@ -489,7 +494,7 @@ ja: title: "プロフィールの背景画像" instructions: "プロフィールの背景画像は、幅850pxで中央揃えになります" change_card_background: - title: "ユーザカードの背景画像" + title: "ユーザーカードの背景画像" instructions: "背景画像は、幅590pxで中央揃えになります" email: title: "メールアドレス" @@ -506,7 +511,7 @@ ja: too_short: "名前が短いです" ok: "問題ありません" username: - title: "ユーザ名" + title: "ユーザー名" instructions: "空白を含まず、被らない名前を入力してください" short_instructions: "@{{username}} であなたにメンションを送ることができます" available: "ユーザ名は利用可能です" @@ -596,11 +601,8 @@ ja: create: "招待を送る" generate_link: "招待リンクをコピー" bulk_invite: - none: "まだだれも招待していません。ひとりひとりを招待することもできますが、一括招待ファイルをアップロードすることで、一度に複数のユーザを招待する事ができます。" text: "ファイルからまとめて招待をする" - uploading: "アップロードしています..." success: "ファイルは無事にアップロードされました。完了されましたらメッセージでお知らせをさせていただきます。" - error: "ファイルアップロードエラー:'{{filename}}': {{message}}" password: title: "パスワード" too_short: "パスワードが短すぎます。" @@ -941,6 +943,10 @@ ja: unlist_topics: "トピックをリストから非表示にする" reset_read: "未読に設定" delete: "トピックを削除" + dismiss: "既読" + dismiss_read: "未読をすべて既読にする" + dismiss_button: "既読..." + dismiss_tooltip: "新規投稿を既読にしてトピックの追跡を停止" dismiss_new: "既読にする" toggle: "選択したトピックを切り替え" actions: "操作" @@ -1037,7 +1043,6 @@ ja: go_bottom: "下" go: "へ" jump_bottom: "最後の投稿へ" - jump_prompt: "投稿へジャンプ" jump_prompt_long: "どの投稿へジャンプしますか?" jump_bottom_with_number: "%{post_number}番へジャンプ" total: 投稿の合計 @@ -1229,7 +1234,6 @@ ja: edit: "申し訳ありませんが、投稿の編集中にエラーが発生しました。もう一度やり直してください。" upload: "申し訳ありません、ファイルのアップロード中にエラーが発生しました。再度お試しください。" too_many_uploads: "申し訳ありませんが、複数のファイルは同時にアップロードできません。" - upload_not_authorized: "申し訳ありませんが、対象ファイルをアップロードする権限がありません (利用可能な拡張子: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "申し訳ありませんが、新規ユーザは画像のアップロードができません。" attachment_upload_not_allowed_for_new_user: "申し訳ありませんが、新規ユーザはファイルの添付ができません。" attachment_download_requires_login: "ファイルをダウンロードするには、ログインする必要があります" @@ -1470,7 +1474,6 @@ ja: views_lowercase: other: " 閲覧" replies: "返信" - views_long: "このトピックは{{number}}回閲覧されました" activity: "アクティビティ" likes: "いいね!" likes_lowercase: @@ -1572,21 +1575,26 @@ ja: profile: 'g, p プロフィール' messages: 'g, m メッセージ' navigation: + title: 'ナビゲーション' jump: '# # 投稿へ' back: 'u 戻る' + up_down: 'k/j 選択を移動 ↑ ↓' open: 'o or Enter トピックへ' + next_prev: 'shift+j/shift+k 選択を次/前へ移動' application: + title: 'アプリケーション' create: 'c 新しいトピックを作成' notifications: 'n お知らせを開く' hamburger_menu: '= メニューを開く' - user_profile_menu: 'p ユーザメニュを開く' + user_profile_menu: 'p ユーザーメニューを開く' show_incoming_updated_topics: '. 更新されたトピックを表示する' search: '/ 検索' help: '? キーボードヘルプを表示する' - dismiss_new_posts: 'x, r 新しい投稿を非表示にする' - dismiss_topics: 'Dismiss Topics' + dismiss_new_posts: 'x, r 新規投稿を非表示にする' + dismiss_topics: 'x, t トピックを既読にする' log_out: 'shift+j/shift+k 次のセクション/前のセクション' actions: + title: 'アクション' bookmark_topic: 'f トピックのブックマークを切り替え' pin_unpin_topic: 'shift+pトピックを ピン留め/ピン留め解除' share_topic: 'shift+s トピックをシェア' @@ -1650,8 +1658,6 @@ ja: backups: "バックアップ" traffic_short: "トラフィック" traffic: "Application web requests" - page_views: "API Requests" - page_views_short: "API Requests" show_traffic_report: "Show Detailed Traffic Report" reports: today: "今日" @@ -1666,6 +1672,7 @@ ja: refresh_report: "Refresh Report" start_date: "Start Date" end_date: "End Date" + groups: "すべてのグループ" commits: latest_changes: "最新の更新内容:" by: "by" @@ -1734,14 +1741,11 @@ ja: refresh: "更新" new: "新規" selector_placeholder: "ユーザ名を入力" - name_placeholder: "グループ名を入力 (ユーザ名同様にスペースなし)" about: "グループメンバーとグループ名を編集" group_members: "グループメンバー" delete: "削除" delete_confirm: "このグループを削除しますか?" delete_failed: "グループの削除に失敗しました。自動作成グループを削除することはできません。" - delete_member_confirm: "'%{group}' グループから'%{username}' を削除しますか?" - name: "名前" add: "追加" add_members: "メンバーを追加" custom: "カスタム" @@ -1773,6 +1777,8 @@ ja: web_hooks: title: "Webhooks" none: "現在、Webhooksはありません。" + events: + actions: "アクション" plugins: title: "プラグイン" installed: "インストール済みプラグイン" @@ -2307,6 +2313,7 @@ ja: login: "ログイン" plugins: "プラグイン" user_preferences: "ユーザ設定" + groups: "グループ" badges: title: バッジ new_badge: 新しいバッジ diff --git a/config/locales/client.ko.yml b/config/locales/client.ko.yml index 4b452c1e7fd..39797de845f 100644 --- a/config/locales/client.ko.yml +++ b/config/locales/client.ko.yml @@ -294,17 +294,10 @@ ko: total_rows: other: "%{count} 사용자" groups: - empty: - posts: "이 그룹의 구성원에 의해 작성된 게시물은 없습니다." - members: "이 그룹에는 구성원이 없습니다." - mentions: "이 그룹에 대한 언급이 없습니다." - messages: "이 그룹에 대한 메시지는 없습니다." - topics: "이 그룹의 구성원에 의해 작성된 주제글이 없습니다." add: "추가" selector_placeholder: "멤버 추가" owner: "소유자" visible: "모든 사용자에게 보이는 그룹입니다." - index: "그룹" title: other: "그룹" members: "멤버" @@ -624,11 +617,8 @@ ko: create: "이 포럼에 친구를 초대하기" generate_link: "초대 링크 복사" bulk_invite: - none: "아직 아무도 초대하지 않았습니다. 초대장을 각각 보내거나, uploading a bulk invite file을 이용하여 단체 초대를 보낼 수 있습니다." text: "파일로 대량 초대하기" - uploading: "업로드 중..." success: "파일이 성공적으로 업로드되었습니다. 완료되면 메시지로 알려드리겠습니다." - error: "'{{filename}}': {{message}} 업로드중 에러가 있었습니다." password: title: "비밀번호" too_short: "암호가 너무 짧습니다." @@ -765,13 +755,13 @@ ko: complete_email_not_found: "%{email}과 일치하는 계정이 없습니다." login: title: "로그인" - username: "사용자" + username: "아이디" password: "비밀번호" - email_placeholder: "이메일 주소 또는 사용자 이름" + email_placeholder: "이메일 주소 또는 아이디" caps_lock_warning: "Caps Lock 켜짐" error: "알 수없는 오류" rate_limit: "다시 로그인 하기전에 잠시만 기다려주세요." - blank_username_or_password: "이메일 또는 사용자명과 비밀번호를 입력해 주세요." + blank_username_or_password: "이메일 또는 아이디, 비밀번호를 입력해 주세요." reset_password: '암호 재설정' logging_in: "로그인 중.." or: "또는" @@ -1272,7 +1262,6 @@ ko: edit: "죄송합니다. 글을 수정하는 중에 오류가 발생했습니다. 다시 시도하십시오." upload: "죄송합니다. 파일을 업로드하는 동안 오류가 발생했습니다. 다시 시도하십시오." too_many_uploads: "한번에 한 파일만 업로드 하실 수 있습니다." - upload_not_authorized: "업로드 하시려는 파일 확장자는 사용이 불가능합니다 (사용가능 확장자: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "죄송합니다. 새로운 유저는 이미지를 업로드 하실 수 없습니다." attachment_upload_not_allowed_for_new_user: "죄송합니다. 새로운 유저는 파일 첨부를 업로드 하실 수 없습니다." attachment_download_requires_login: "죄송합니다. 첨부 파일을 받으려면 로그인이 필요합니다." @@ -1519,7 +1508,6 @@ ko: views_lowercase: other: "조회" replies: "답변" - views_long: "이 주제는 {{number}}번 읽혔습니다." activity: "활동" likes: "좋아요" likes_lowercase: @@ -1650,8 +1638,6 @@ ko: backups: "백업" traffic_short: "트래픽" traffic: "어플리케이션 웹 요청" - page_views: "API 요청" - page_views_short: "API 응답" show_traffic_report: "자세한 트래픽 리포트 보기" reports: today: "오늘" @@ -1735,15 +1721,12 @@ ko: refresh: "새로고침" new: "새로운" selector_placeholder: "아이디를 입력하세요" - name_placeholder: "그룹 이름, 사용자 이름처럼 빈칸 없이 작성" about: "회원과 이름을 변경" group_members: "그룹 멤버" delete: "삭제" delete_confirm: "이 그룹을 삭제 하시겠습니까?" delete_failed: "이것은 자동으로 생성된 그룹입니다. 삭제할 수 없습니다." - delete_member_confirm: "'%{group}' 그룹에서 '%{username}'을 제외시키겠습니까?" delete_owner_confirm: "'%{username}' 님에게서 소유자권한을 제거할까요?" - name: "이름" add: "추가" add_members: "사용자 추가하기" custom: "Custom" @@ -1979,7 +1962,7 @@ ko: none: "로그가 없습니다." filters: title: "필터" - user_placeholder: "사용자명" + user_placeholder: "아이디" address_placeholder: "name@example.com" type_placeholder: "다이제스트, 가입..." reply_key_placeholder: "답글 키" @@ -2002,7 +1985,7 @@ ko: do_nothing: "아무것도 하지 않음" staff_actions: title: "스태프 기록" - instructions: "사용자 이름을 클릭하여 목록에서 차단하십시오. 프로필 사진을 클릭하여 사용자 페이지로 갑니다." + instructions: "사용자 아이디을 클릭하여 목록에서 차단하십시오. 프로필 사진을 클릭하여 사용자 페이지로 갑니다." clear_filters: "전체 보기" staff_user: "스태프 사용자" target_user: "타겟 사용자" diff --git a/config/locales/client.nb_NO.yml b/config/locales/client.nb_NO.yml index 516927aa313..2f27326f782 100644 --- a/config/locales/client.nb_NO.yml +++ b/config/locales/client.nb_NO.yml @@ -27,17 +27,18 @@ nb_NO: millions: "{{number}}M" dates: time: "h:mm a" + timeline_date: "MMM YYYY" long_no_year: "D MMM h:mm a" long_no_year_no_time: "D MMM" - full_no_year_no_time: "MMMM Do" + full_no_year_no_time: "D. MMMM" long_with_year: "D MMM, YYYY h:mm a" long_with_year_no_time: "D MMM, YYYY" - full_with_year_no_time: "MMMM Do, YYYY" + full_with_year_no_time: "D. MMMM, YYYY" long_date_with_year: "D MMM, 'YY LT" long_date_without_year: "D MMM, LT" long_date_with_year_without_time: "D MMM, 'YY" long_date_without_year_with_linebreak: "D MMM
    LT" - long_date_with_year_with_linebreak: "D MMM, 'YY
    LT" + long_date_with_year_with_linebreak: "D. MMM, 'YY
    LT" wrap_ago: "%{date} siden" tiny: half_a_minute: "< 1m" @@ -77,7 +78,7 @@ nb_NO: x_days: one: "1 dag" other: "%{count} dager" - date_year: "D MMM, 'YY" + date_year: "D. MMM, 'YY" medium_with_ago: x_minutes: one: "1 minutt siden" @@ -98,8 +99,8 @@ nb_NO: x_years: one: "1 år senere" other: "%{count} år senere" - previous_month: 'Forrige Måned' - next_month: 'Neste Måned' + previous_month: 'Forrige måned' + next_month: 'Neste måned' share: topic: 'del en lenke til dette emnet' post: 'innlegg #%{postNumber}' @@ -111,6 +112,7 @@ nb_NO: action_codes: public_topic: "gjorde dette emnet offentlig %{when}" private_topic: "gjorde dette emnet privat %{when}" + split_topic: "splittet dette emnet %{when}" invited_user: "inviterte %{who} %{when}" invited_group: "inviterte %{who} %{when}" removed_user: "fjernet %{who} %{when}" @@ -126,17 +128,32 @@ nb_NO: disabled: 'fjernet fra arkiv %{when}' pinned: enabled: 'festet %{when}' - disabled: 'avfestet %{when}' + disabled: 'feste fjernet %{when}' pinned_globally: enabled: 'festet globalt %{when}' + disabled: 'feste fjernet %{when}' + visible: + enabled: 'gjort synlig %{when}' + disabled: 'skjult %{when}' topic_admin_menu: "admin-handlinger for emne" + wizard_required: "Det er på tide å sette opp forumet! Start veiviseren!" emails_are_disabled: "All utgående e-post har blitt deaktivert globalt av en administrator. Ingen e-postvarslinger vil bli sendt." - bootstrap_mode_enabled: "For å gjøre det enklere å lansere det nye nettstedet ditt er det i bootstrap-modus. Alle nye brukere vil få tillitsnivå 1 og ha daglige oppdateringer på e-post aktivert. Dette vil automatisk bli slått av når antallet brukere overstiger %{min_users}." - bootstrap_mode_disabled: "Bootstrap modus vil være deaktivert i de neste 24 timene" + bootstrap_mode_enabled: "For å gjøre det enklere å lansere det nye nettstedet ditt er det i bootstrap-modus. Alle nye brukere vil få tillitsnivå 1 og få daglige oppdateringer på e-post aktivert. Dette vil automatisk bli slått av når antallet brukere overstiger %{min_users}." + bootstrap_mode_disabled: "Bootstrap modus vil bli deaktivert i løpet av de neste 24 timene." s3: regions: + us_east_1: "USA øst (N. Virginia)" + us_west_1: "USA vest (N. California)" + us_west_2: "USA vest (Oregon)" + us_gov_west_1: "AWS GovCloud (USA)" eu_west_1: "EU (Irland)" eu_central_1: "EU (Frankfurt)" + ap_southeast_1: "Asia/Stillehavsregionen (Singapore)" + ap_southeast_2: "Asia/Stillehavsregionen (Sydney)" + ap_south_1: "Asia/Stillehavsregionen (Mumbai)" + ap_northeast_1: "Asia/Stillehavsregionen (Tokyo)" + ap_northeast_2: "Asia/Stillehavsregionen (Seoul)" + sa_east_1: "Asia/Stillehavsregionen (Sao Paulo)" cn_north_1: "Kina (Beijing)" edit: 'rediger tittelen og kategorien til dette emnet' not_implemented: "Beklager, denne funksjonen har ikke blitt implementert enda." @@ -155,7 +172,7 @@ nb_NO: links: "Lenker" links_lowercase: one: "link" - other: "linker" + other: "lenker" faq: "FAQ" guidelines: "Retningslinjer" privacy_policy: "Personvernerklæring" @@ -170,7 +187,7 @@ nb_NO: more: "Mer" less: "Mindre" never: "aldri" - every_30_minutes: "hvert 30 minutt" + every_30_minutes: "hvert 30. minutt" every_hour: "hver time" daily: "daglig" weekly: "ukentlig" @@ -183,7 +200,7 @@ nb_NO: other: "{{count}} tegn" suggested_topics: title: "Anbefalte emner" - pm_title: "Foreslåtte Meldinger" + pm_title: "Anbefalte meldinger" about: simple_title: "Om" title: "Om %{title}" @@ -199,8 +216,8 @@ nb_NO: post_count: "Innlegg" user_count: "Nye brukere" active_user_count: "Aktive brukere" - contact: "Kontakt Oss" - contact_info: "Hvis noe kritisk skulle oppstå eller det er en hastesak som påvirker siden, ta kontakt på %{contact_info}." + contact: "Kontakt oss" + contact_info: "I tilfelle en kritisk hendelse skulle inntreffe eller det er en hastesak som påvirker siden, ta kontakt på %{contact_info}." bookmarked: title: "Bokmerke" clear_bookmarks: "Fjern bokmerker" @@ -238,6 +255,8 @@ nb_NO: undo: "Angre" revert: "Reverser" failed: "Mislykket" + switch_to_anon: "Start inkognitomodus" + switch_from_anon: "Avslutt inkognitomodus" banner: close: "Fjern denne banneren" edit: "Endre denne banneren >>" @@ -255,14 +274,15 @@ nb_NO: none: "Det er ingen innlegg som må evalueres." edit: "Rediger" cancel: "Avbryt" - view_pending: "vis påventende innlegg" + view_pending: "vis ventende innlegg" has_pending_posts: one: "Dette emnet har 1 innlegg som venter på godkjenning" other: "Dette emnet har {{count}} innlegg som venter på godkjenning" confirm: "Lagre endringer" + delete_prompt: "Er du sikker du ønsker å slette %{username}? Dette vil fjerne alle brukerens innlegg og blokkere brukerens epost- og IP-adresse." approval: - title: "Innlegg Behøver Godkjenning" - description: "Vi har mottatt ditt nye innlegg men det krever godkjenning av en moderator før det vises. Venligst vær tålmodig." + title: "Innlegg trenger godkjenning" + description: "Vi har mottatt ditt nye innlegg men det krever godkjenning av en moderator før det vises. Ha tolmod." pending_posts: one: "Du har 1 innlegg som venter på godkjenning." other: "Du har {{count}} innlegg som venter på godkjenning." @@ -286,6 +306,7 @@ nb_NO: title: "Brukere" likes_given: "Gitt" likes_received: "Mottatt" + topics_entered: "Lest" topics_entered_long: "Emner Sett" time_read: "Tid lest" topic_count: "Emner" @@ -296,45 +317,107 @@ nb_NO: days_visited: "Besøk" days_visited_long: "Dager besøkt" posts_read: "Lest" - posts_read_long: "Lest" + posts_read_long: "Innlegg lest" total_rows: one: "1 bruker" other: "%{count} brukere" + group_histories: + actions: + change_group_setting: "Endre gruppeinnstillinger" + add_user_to_group: "Legg til bruker" + remove_user_from_group: "Slett bruker" + make_user_group_owner: "Gjør til eier" + remove_user_as_group_owner: "Fjern som eier" groups: + logs: + title: "Logger" + when: "Når" + action: "Handling" + acting_user: "Utførende bruker" + target_user: "Målbruker" + subject: "Emne" + details: "Detaljer" + from: "Fra" + to: "Til" + edit: + title: 'Rediger gruppe' + full_name: 'Fullt navn' + add_members: "Legg til medlemmer" + delete_member_confirm: "Fjern '%{username}' fra gruppen '%{group}'?" + request_membership_pm: + title: "Ønske om medlemskap" + body: "Jeg vil be om å bli medlem av gruppen @%{groupName}." + name_placeholder: "Gruppenavn, ingen mellomrom, samme regler som for brukernavn" + public: "Tillatt brukere å bli medlem av og forlate gruppen fritt (Krever at gruppen er synlig)" empty: - posts: "Det er ingen innlegg av medlemmene i denne gruppen." - members: "Det er ingen medlemmer i denne gruppen." - messages: "Det er ingen meldinger for denne gruppen." + posts: "Det er ingen innlegg av medlemmer i denne gruppen." + members: "Det er ingen medlemmer av denne gruppen." + mentions: "Denne gruppen har aldri blitt nevnt." + messages: "Det er ingen meldinger til denne gruppen." + topics: "Det er ingen emner av medlemmer av denne gruppen." + logs: "Det er ingen logger for denne gruppen." add: "Legg til" + join: "Bli medlem av gruppe" + leave: "Forlat gruppe" + request: "Be om gruppemedlemskap" + automatic_group: Automatisk gruppe + closed_group: Lukket gruppe + is_group_user: "Du er medlem av denne gruppen" + allow_membership_requests: "Tillat brukere å sende forespørsler om medlemskap av gruppen til eiere (Krever at alle kan nevne gruppen)" + membership: "Medlemskap" + name: "Navn" + user_count: "Antall medlemmer" + bio: "Om gruppe" selector_placeholder: "Legg til medlemmer" owner: "eier" visible: "Gruppen er synlig for alle brukere" + index: + title: "Grupper" + empty: "Det er ingen synlige grupper" title: one: "gruppe" other: "grupper" + activity: "Aktivitet" members: "Medlemmer" topics: "Emner" posts: "Innlegg" mentions: "Omtalelser" messages: "Meldinger" alias_levels: + title: "Hvem kan sende meldinger til og @nevne denne gruppen?" nobody: "Ingen" only_admins: "Kun administratorer" mods_and_admins: "Kun moderatorer og administratorer" members_mods_and_admins: "Kun gruppemedlemmer, moderatorer og administratorer" everyone: "Alle" trust_levels: + title: "Tillitsnivå som automatisk gis til nye medlemmer når de legges til:" none: "ingen" notifications: watching: title: "Følger" + description: "Du vil bli varslet om hvert nye innlegg i hver beskjed, og antallet nye svar vil bli vist." + watching_first_post: + title: "Følger første innlegg" + description: "Du vil bare bli varslet om det første innlegget i hvert nye emne i denne gruppen." tracking: - title: "Sporer" + title: "Overvåker" + description: "Du vil få beskjeddersom nevner @navnet_ditt eller svarer deg, og antallet nye svar vil bli vist." regular: title: "Normal" description: "Du vil bli varslet hvis noen nevner ditt @navn eller svarer deg." muted: - title: "Dempet" + title: "Ignorert" + description: "Du vil aldri bli varslet om noe angående nye emner i denne gruppen." + flair_url: "Bilde for gruppetilhørighet på avatar" + flair_url_placeholder: "(Valgfritt) Font Awesome-klasse eller URL til bilde" + flair_bg_color: "Bakgrunnsfarge for gruppetilhørighetsbilde på avatar" + flair_bg_color_placeholder: "(Valgfritt) Fargekode som hex-verdi" + flair_color: "Farge på bilde for gruppetilhørighet på avatar" + flair_color_placeholder: "(Valgfritt) Fargekode som hex-verdi" + flair_preview_icon: "Forhåndsvis ikon" + flair_preview_image: "Forhåndsvis bilde" + flair_note: "Merk: Bilde for gruppetilhørighet på avatar vil bare vises for brukerens primære gruppe." user_action_groups: '1': "Liker tildelt" '2': "Liker mottatt" @@ -353,21 +436,31 @@ nb_NO: all_subcategories: "alle" no_subcategory: "ingen" category: "Kategori" + category_list: "Vis kategoriliste" reorder: + title: "Endre rekkefølge på kategorier" + title_long: "Reorganiser kategorilisten" + fix_order: "Lås posisjoner" + fix_order_tooltip: "Ikke alle kategoriene har et unikt posisjonsnummer. Det kan gi uventede resultater." save: "Lagre Rekkefølge" + apply_all: "Bruk" + position: "Posisjon" posts: "Innlegg" topics: "Emner" latest: "Siste" latest_by: "siste av" toggle_ordering: "veksle rekkefølge" subcategories: "Underkategorier" + topic_sentence: + one: "1 emne" + other: "%{count} nye emner" topic_stat_sentence: one: "%{count} nytt emner de siste %{unit}." other: "%{count} nye emner de siste %{unit}." ip_lookup: title: Slå opp IP-adresse hostname: Vertsnavn - location: Posisjon + location: Sted location_not_found: (ukjent) organisation: Organisasjon phone: Telefon @@ -384,13 +477,19 @@ nb_NO: user: said: "{{username}}:" profile: "Profil" - mute: "Demp" + mute: "Ignorer" edit: "Rediger innstillinger" + download_archive: + button_text: "Last ned mine innlegg" + confirm: "Er du sikker på at du vil laste ned dine innlegg?" + success: "Nedlasting iverksatt. Du vil bli varslet med en melding når prosessen er fullført." + rate_limit_error: "Innlegg kan lastes ned en gang om dagen, prøv igjen i morgen." new_private_message: "Ny Melding" private_message: "Melding" private_messages: "Meldinger" activity_stream: "Aktivitet" preferences: "Innstillinger" + expand_profile: "Utvid" bookmarks: "Bokmerker" bio: "Om meg" invited_by: "Invitert av" @@ -399,12 +498,16 @@ nb_NO: statistics: "Statistikk" desktop_notifications: label: "Skrivebordsvarslinger" + not_supported: "Varsler er ikke støttet på denne nettleseren. Beklager." perm_default: "Slå på varslinger" perm_denied_btn: "Tillatelse avslått" + perm_denied_expl: "Du tillot ikke varsler. Tillat varsler via innstillingene i din nettleser." disable: "Slå av varslinger" enable: "Slå på varslinger" each_browser_note: "Merk: Du må endre denne innstillinger for hver nettleser du bruker." + dismiss_notifications: "Avslå alt" dismiss_notifications_tooltip: "Merk alle uleste varslinger som lest" + first_notification: "Ditt første varsel! Velg det for å komme i gang." disable_jump_reply: "Ikke hopp til ditt nye innlegg etter svar" dynamic_favicon: "Vis antall nye / oppdaterte emner på nettleser ikonet" external_links_in_new_tab: "Åpne alle eksterne lenker i ny fane" @@ -418,9 +521,35 @@ nb_NO: suspended_notice: "Denne brukeren er bannlyst til {{date}}." suspended_reason: "Begrunnelse:" github_profile: "Github" - watched_categories: "Følger" - tracked_categories: "Sporet" - muted_categories: "Dempet" + email_activity_summary: "Oppsummering av aktivitet" + mailing_list_mode: + label: "E-postlistemodus" + enabled: "Slå på e-postlistemodus" + instructions: | + Denne innstillingen overstyrer oppsummeringen av aktivitet.
    + Ignorerte emner og kategorier blir ikke inkludert i disse e-postene. + daily: "Send daglige oppdateringer" + individual: "Send en e-post for hvert nye innlegg" + individual_no_echo: "Send en e-post for hvert nye innlegg bortsett fra mine egne" + many_per_day: "Send meg en e-post for hvert nye innlegg (rundt {{dailyEmailEstimate}} per deg)" + few_per_day: "Send meg en e-post for hvert nye innlegg (rundt to ganger om dagen)" + tag_settings: "Stikkord" + watched_tags: "Fulgt" + watched_tags_instructions: "Du vil automatisk følge alle emner med disse stikkordene. Du vil bli varslet om alle nye innlegg og emner, og tallet på nye innlegg til også vises ved siden av emnet." + tracked_tags: "Overvåkes" + tracked_tags_instructions: "Du vil automatisk overvåke alle emner med disse stikkordene. Tallet på nye innlegg vil vises ved siden av emnet." + muted_tags: "Ignorert" + muted_tags_instructions: "Du vil ikke bli varslet om noe med tanke på nye emner med disse stikkordene, og de vil ikke vises i siste." + watched_categories: "Fulgt" + watched_categories_instructions: "Du vil automatisk følge alle emner i disse kategoriene. Du vil bli varslet om alle nye innlegg og emner, og tallet på nye innlegg vil vises ved siden av emnet." + tracked_categories: "Overvåkes" + tracked_categories_instructions: "Du vil automatisk overvåke alle emner i disse kategoriene. Tallet på nye innlegg vil vises ved siden av emnet." + watched_first_post_categories: "Følger første innlegg" + watched_first_post_categories_instructions: "Du vil bli varslet om det første innlegget i hvert nye emne i disse kategoriene." + watched_first_post_tags: "Følger første innlegg" + watched_first_post_tags_instructions: "Du vil bli varslet om det første innlegget i hvert nye emne med disse stikkordene." + muted_categories: "Ignorert" + muted_categories_instructions: "Du vil ikke bli varslet om noe med tanke på nye emner i disse kategoriene, og de vil ikke vises i siste." delete_account: "Slett kontoen min" delete_account_confirm: "Er du sikker på at du vil slette kontoen din permanent? Denne handlingen kan ikke angres!" deleted_yourself: "Slettingen av din konto har vært vellykket." @@ -428,8 +557,15 @@ nb_NO: unread_message_count: "Meldinger" admin_delete: "Slett" users: "Brukere" - muted_users: "Dempet" + muted_users: "Ignorert" muted_users_instructions: "Skjul alle varsler fra denne brukeren" + muted_topics_link: "Vis ignorerte emner" + watched_topics_link: "Se emner som følges" + automatically_unpin_topics: "Automatisk fjern feste for emner når jeg når bunnen." + apps: "Apper" + revoke_access: "Trekk tilbake tilgang" + undo_revoke_access: "Angre \"trekk tilbake tilgang\"" + api_approved: "Godkjent:" staff_counters: flags_given: "nyttige rapporteringer" flagged_posts: "rapporterte innlegg" @@ -440,20 +576,25 @@ nb_NO: all: "Alle" inbox: "Innboks" sent: "Sendt" + archive: "Arkiver" groups: "Mine grupper" bulk_select: "Velg meldinger" move_to_inbox: "Flytt til inboks" - select_all: "Velg Alle" + move_to_archive: "Arkiver" + failed_to_move: "Kunne ikke flytte valgte meldinger (kanskje nettforbindelsen din er nede)" + select_all: "Velg alle" change_password: success: "(e-post sendt)" in_progress: "(sender e-post)" error: "(feil)" - action: "Send e-post for passordnullstilling" + action: "Send e-post for nullstilling av passord" set_password: "Sett passord" change_about: title: "Rediger om meg" + error: "Det oppstod en feil ved endring av denne verdien." change_username: title: "Endre brukernavn" + confirm: "Hvis du endrer brukernavnet ditt, vil alle gamle sitater av dine innlegg og @navn-nevninger feile. Er du helt sikker på at du vil bytte brukernavn?" taken: "Beklager, det brukernavnet er tatt." error: "Det skjedde en feil ved endring av ditt brukernavn." invalid: "Det brukernavnet er ugyldig. Det kan bare inneholde nummer og bokstaver." @@ -461,7 +602,7 @@ nb_NO: title: "Endre e-postadresse" taken: "Beklager, den e-postadressen er ikke tilgjengelig." error: "Det oppsto en feil ved endring av din e-postadresse. Kanskje den adressen allerede er i bruk?" - success: "Vi har sendt en e-post til den adressen. Vennligst følg meldingens instruksjoner for bekreftelse." + success: "Vi har sendt en e-post til den adressen. Følg meldingens instruksjoner for bekreftelse." change_avatar: title: "Bytt profilbilde" gravatar: "Gravatar, basert på" @@ -473,18 +614,23 @@ nb_NO: upload_title: "Last opp bilde" upload_picture: "Last opp bilde" image_is_not_a_square: "Vi har beskjært bildet ditt, høyde og bredde er ikke lik" + cache_notice: "Profilbildet ditt er oppdatert, men på grunn av mellomlagring i nettlesere kan det ta litt tid før det synes." change_profile_background: title: "Profilbakgrunn" - instructions: "Profil bakgrunner vil bli sentrert med en standard bredde på 850px" + instructions: "Profilbakgrunner vil bli sentrert med en forvalgt bredde på 850 piksler." change_card_background: title: "Brukerkort bakgrunn" - instructions: "Bakgrunnsbilder vil bli sentrert og ha en standard bredde på 590px." + instructions: "Bakgrunnsbilder vil bli sentrert og ha en forvalgt bredde på 590 piksler." email: title: "E-post" instructions: "Blir aldri vist offentlig" ok: "Vi sender deg en e-post for å bekrefte" - invalid: "Vennligst oppgi en gyldig e-postadresse" + invalid: "Oppgi en gyldig e-postadresse" authenticated: "Din e-post har blitt autentisert av {{provider}}" + frequency_immediately: "Vi sender deg umiddelbart en e-post hvis du ikke har lest det vi sender e-post om." + frequency: + one: "Vi sender deg bare e-post hvis vi ikke har sett deg deg det siste minuttet." + other: "Vi sender deg bare e-post hvis vi ikke har sett deg de siste {{count}} minuttene." name: title: "Navn" instructions: "Ditt fulle navn (valgfritt)" @@ -507,7 +653,8 @@ nb_NO: locale: title: "Språk for grensesnitt" instructions: "Språk for grensesnitt. Endringen vil tre i kraft når du oppdaterer siden." - default: "(standard)" + default: "(forvalg)" + any: "hvilken som helst" password_confirmation: title: "Passord igjen" last_posted: "Siste Innlegg" @@ -515,73 +662,94 @@ nb_NO: last_seen: "Sist sett" created: "Medlem fra" log_out: "Logg ut" - location: "Posisjon" + location: "Sted" card_badge: - title: "Brukerkort merke" + title: "Brukerkort-merke" website: "Nettsted" email_settings: "E-post" like_notification_frequency: title: "Varsle når likt" always: "Alltid" - first_time_and_daily: "Første gnag et innlegg blir likt og daglig" + first_time_and_daily: "Første gang et innlegg blir likt, og daglig" first_time: "Første gang et innlegg blir likt" never: "Aldri" email_previous_replies: + title: "Inkludér tidligere svar nederst i e-poster" + unless_emailed: "med mindre sendt tidligere" always: "alltid" never: "aldri" email_digests: + title: "Send meg en oppsummering på e-post av populære emner og svar dersom jeg ikke besøker siden" every_30_minutes: "hvert 30 minutt" every_hour: "hver time" daily: "daglig" every_three_days: "hver tredje dag" weekly: "ukentlig" every_two_weeks: "annenhver uke" + include_tl0_in_digests: "Inkludér innhold fra nye brukere i oppsummerings-eposter" + email_in_reply_to: "Inkluder et utdrag i e-poster av innlegget man svarer på" email_direct: "Motta en e-post når noen siterer meg, svarer på innlegget mitt, nevner @brukernavnet mitt eller inviterer meg til et emne" - email_private_messages: "Motta en e-post når noen sender deg en melding" - email_always: "Send meg varsler på epost selv når jeg er aktiv på nettstedet" + email_private_messages: "Motta en e-post når noen sender meg en melding" + email_always: "Send meg varsler på e-post selv når jeg er aktiv på nettstedet" other_settings: "Annet" categories_settings: "Kategorier" new_topic_duration: label: "Anse emner som nye når" - not_viewed: "Jeg har ikke sett på dem enda." + not_viewed: "jeg ikke har sett dem ennå" last_here: "opprettet siden jeg var her sist" - auto_track_topics: "Følg automatisk emner jeg åpner" + after_1_day: "opprettet i løpet av det siste døgnet" + after_2_days: "opprettet i løpet av de siste 2 døgnene" + after_1_week: "opprettet i løpet av sist uke" + after_2_weeks: "opprettet i løpet av de siste 2 ukene" + auto_track_topics: "Overvåk automatisk emner jeg åpner" auto_track_options: never: "aldri" immediately: "øyeblikkelig" + after_30_seconds: "etter 30 sekunder" after_1_minute: "etter 1 minutt" after_2_minutes: "etter 2 minutt" after_3_minutes: "etter 3 minutt" after_4_minutes: "etter 4 minutt" - after_5_minutes: "etter 5 minut" + after_5_minutes: "etter 5 minutt" after_10_minutes: "etter 10 minutt" + notification_level_when_replying: "Når jeg publiserer noe i et emner, sett det emnet til" invited: search: "skriv for å søke etter invitasjoner..." title: "invitasjoner" user: "Invitert bruker" sent: "Sendt" + none: "Det er ingen ventende invitasjoner å vise." + truncated: + one: "Viser den første invitasjonen." + other: "Viser de {{count}} første invitisajonene." redeemed: "Løs inn invitasjoner" redeemed_tab: "Brukt" + redeemed_tab_with_count: "Innløste ({{count}})" redeemed_at: "Løst inn ved" pending: "Ventende invitasjoner" pending_tab: "På vent" + pending_tab_with_count: "Ventende ({{count}})" topics_entered: "Emner vist" posts_read_count: "Innlegg lest" expired: "Denne invitasjonen har utløpt" rescind: "Fjern" rescinded: "Invitasjon fjernet" reinvite: "Send invitasjon igjen" + reinvite_all: "Send alle invitasjoner på nytt" reinvited: "Invitasjon sendt igjen" + reinvited_all: "Alle invitasjoner sendt på nytt!" time_read: "Lesetid" days_visited: "Dager besøkt" account_age_days: "Kontoalder i dager" create: "Send en invitasjon" + generate_link: "Kopier invitasjonslenke" + link_generated: "Invitasjonslenke har blitt generert!" + valid_for: "Invitasjonslenke er kun gyldig for denne e-postadressen: %{email}" bulk_invite: - none: "Du har ikke invitert noen hit enda. Du kan sende individuelle invitasjoner, eller invitere en gruppe folk på en gang ved å laste opp en fil med flere invitasjoner." + none: "Du har ikke invitert noen hit enda. Du kan sende individuelle invitasjoner, eller du kan invitere flere personer samtidig ved å laste opp en CSV-fil." text: "Masseinvitasjon fra fil" - uploading: "Laster opp..." success: "Filen er lastet opp, du vil motta en melding når prosessesen er ferdig" - error: "En feil oppsto ved opplastingen av '{{filename}}': {{message}}" + error: "Beklager, filen skal være i CSV-format." password: title: "Passord" too_short: "Passordet ditt er for kort" @@ -593,9 +761,43 @@ nb_NO: summary: title: "Oppsummering" stats: "Statistikk" + time_read: "lesetid" + topic_count: + one: "emne opprettet" + other: "emner opprettet" + post_count: + one: "innlegg skrevet" + other: "innlegg skrevet" + likes_given: + one: " gitt" + other: " gitt" + likes_received: + one: " mottatt" + other: " mottatt" + days_visited: + one: "dag besøkt" + other: "dager besøkt" + posts_read: + one: "innlegg lest" + other: "innlegg lest" + bookmark_count: + one: "bokmerke" + other: "bokmerker" top_replies: "Mest Populære Svar" + no_replies: "Ingen svar enda." + more_replies: "Flere svar" top_topics: "Mest Populære Emner" + no_topics: "Ingen emner enda." more_topics: "Flere Emner" + top_badges: "Toppmerker" + no_badges: "Ennå ingen merker." + more_badges: "Flere merker" + top_links: "Topplenker" + no_links: "Ingen lenker enda" + most_liked_by: "Mest likt av" + most_liked_users: "Mest likt" + most_replied_to_users: "Mest besvart" + no_likes: "Ingen liker dette enda." associated_accounts: "Innloggingsforsøk" ip_address: title: "Siste IP-adresse" @@ -623,7 +825,7 @@ nb_NO: unknown: "Feil" not_found: "Side Ikke funnet" desc: - network: "Vennligst sjekk nettverkstilkoblingen din" + network: "Sjekk nettverkstilkoblingen din" network_fixed: "Ser ut som om den er tilbake." server: "Feilkode: {{status}}" forbidden: "Du har ikke tilgang til dette." @@ -634,15 +836,25 @@ nb_NO: again: "Prøv igjen" fixed: "Last side" close: "Lukk" - assets_changed_confirm: "Dette nettstedet ble nettopp oppdatert. Oppdater nå for nyeste versjon?" + assets_changed_confirm: "Dette nettstedet ble nettopp oppdatert. Oppdater nå for siste versjon?" logout: "Du ble logget ut" refresh: "Refresh" read_only_mode: + enabled: "Dette nettstedet er i lese-modus. Fortsett gjerne, men du kan ikke svare, trykke liker eller utføre andre handlinger som er slått av." login_disabled: "Innlogging er deaktivert mens nettsiden er i skrivebeskyttet modus." + logout_disabled: "Du kan ikke logge ut når nettstedet er i lese-modus." too_few_topics_and_posts_notice: "La oss få i gang diskusjonen. Det finnes for øyeblikket %{currentTopics} / %{requiredTopics} emner og %{currentPosts} / %{requiredPosts} innlegg. Nye brukere trenger noen samtaler å lese og svare på." too_few_topics_notice: "La oss få i gang diskusjonen. Det finnes for øyeblikket %{currentTopics} / %{requiredTopics} emner. Nye brukere trenger noen samtaler å lese og svare på." too_few_posts_notice: "La oss få i gang diskusjonen. Det finnes for øyeblikket %{currentPosts} / %{requiredPosts} innlegg. Nye brukere trenger noen samtaler å lese og svare på." + logs_error_rate_notice: + reached: "%{relativeAge}%{rate} nådde innstillingsgrensen satt i %{siteSettingRate}." + exceeded: "%{relativeAge}%{rate} overstiger innstillingsgrensen satt i %{siteSettingRate}." + rate: + one: "1 feil/%{duration}" + other: "%{count} feil/%{duration}" learn_more: "lær mer..." + all_time: 'totalt' + all_time_desc: 'totalt antall emner opprettet' year: 'år' year_desc: 'emner opprettet de siste 365 dagene' month: 'måned' @@ -651,8 +863,8 @@ nb_NO: week_desc: 'emner opprettet de siste 7 dagene' day: 'dag' first_post: Første innlegg - mute: Demp - unmute: Fjern demping + mute: Ignorer + unmute: Fjern ignorering last_post: Siste innlegg last_reply_lowercase: siste svar replies_lowercase: @@ -666,7 +878,9 @@ nb_NO: intro: "Hei du! :heart_eyes: Det ser ut som du følger diskusjonen, men ikke har registrert deg enda." value_prop: "Når du registrerer deg husker vi hvor langt du har lest, så du starter på riktig sted neste gang du åpner en tråd. Du får også varsler, her og på e-post når det skjer ting i diskusjonene du vil følge. I tillegg kan du like innlegg :heartbeat:" summary: - enabled_description: "Du ser for øyeblikket en oppsummering av dette emnet: de mest interessante innleggene i følge nettsamfunnet." + enabled_description: "Du ser for øyeblikket en oppsummering av dette emnet: de mest interessante innleggene ifølge fellesskapet." + description: "Det er {{replyCount}} svar." + description_time: "Det er {{replyCount}} svar med en forventet lesetid på {{readingTime}} minutter." enable: 'Oppsummer dette emnet' disable: 'Vis alle innlegg' deleted_filter: @@ -678,6 +892,7 @@ nb_NO: title: "Send" invite: "Invitér andre..." remove_allowed_user: "Er du sikker på at du vil fjerne {{name}} fra denne meldingen?" + remove_allowed_group: "Vil du virkelig fjerne {{name}} fra denne meldingen?" email: 'E-post' username: 'Brukernavn' last_seen: 'Sist sett' @@ -707,21 +922,21 @@ nb_NO: email_placeholder: "e-postadresse eller brukernavn" caps_lock_warning: "Caps Lock er på" error: "Ukjent feil" - rate_limit: "Vennligst vent litt før du logger inn igjen." - blank_username_or_password: "Vennligst oppgi din e-postadresse eller brukernavn og ditt passord." + rate_limit: "Vent litt før du logger inn igjen." + blank_username_or_password: "Oppgi din e-postadresse eller brukernavn og ditt passord." reset_password: 'Nullstill passord' logging_in: "Logger på..." or: "Eller" authenticating: "Autentiserer..." awaiting_confirmation: "Din konto avventer aktivering. Bruk lenken for glemt passord for å sende en ny e-post for aktivering." awaiting_approval: "Din konto har ikke blitt godkjent av en moderator ennå. Du vil motta en e-post når den er godkjent." - requires_invite: "Beklager, tilgang til dette forumet er kun ved invitasjon." - not_activated: "Du kan ikke logge inn ennå. Vi sendte en e-post for aktivering til deg på {{sentTo}}. Vennligst følg instruksjonene i den e-posten for å aktivere din konto." + requires_invite: "Beklager, tilgang til dette forumet kun ved invitasjon." + not_activated: "Du kan ikke logge inn ennå. Vi sendte en e-post for aktivering til deg på {{sentTo}}. Følg instruksjonene i den e-posten for å aktivere din konto." not_allowed_from_ip_address: "Du kan ikke logge inn fra den IP-adressen." admin_not_allowed_from_ip_address: "Du kan ikke logge inn som administrator fra den IP-adressen." resend_activation_email: "Klikk her for å sende e-posten for aktivering igjen." sent_activation_email_again: "Vi sendte deg en ny e-post for aktivering på {{currentEmail}}. Det kan ta noen minutter før den kommer fram; sørg for at du sjekker nettsøppel om du ikke finner den." - to_continue: "Vennligst Logg Inn" + to_continue: "Logg inn" preferences: "Du må være innlogget for å endre brukerinnstillinger." forgot: "I husker ikke mine kontodetaljer" google: @@ -733,6 +948,9 @@ nb_NO: twitter: title: "med Twitter" message: "Autentiserer med Twitter (sørg for at du tillater pop-up vindu)" + instagram: + title: "med Instagram" + message: "Logger på med Instagram. Sørg for at du ikke har programvare som blokkerer forgrunnsvinduer." facebook: title: "med Facebook" message: "Autentiserer med Facebook (sørg for at du tillater pop-up vindu)" @@ -742,6 +960,16 @@ nb_NO: github: title: "med GitHub" message: "Autentiserer med GitHub (sørg for at du tillater pop-up vindu)" + emoji_set: + apple_international: "Apple/Internasjonalt" + google: "Google" + twitter: "Twitter" + emoji_one: "Emoji One" + win10: "Win10" + category_page_style: + categories_only: "Kun kategorier" + categories_with_featured_topics: "Kategorier med framhevede emner" + categories_and_latest_topics: "Kategorier og siste emner" shortcut_modifier_key: shift: 'Shift' ctrl: 'Ctrl' @@ -751,19 +979,29 @@ nb_NO: more_emoji: "mer..." options: "Alternativer" whisper: "hvisker" + unlist: "skjult" add_warning: "Dette er en offisiell advarsel." + toggle_whisper: "Veksle hvisking" + toggle_unlisted: "Skjul eller gjør synlig" posting_not_on_topic: "Du svarer på emnet \"{{title}}\", men for øyeblikket ser du på et annet emne." saving_draft_tip: "lagrer..." saved_draft_tip: "lagret" saved_local_draft_tip: "lagret lokalt" similar_topics: "Emnet ditt har likheter med..." drafts_offline: "utkast offline" + group_mentioned: + one: "Ved å nevne {{group}}, er du i ferd med å henvende deg til {{count}} én person – er du sikker?" + other: "Ved å nevne {{group}}, er du i ferd med å henvende deg til {{count}} folk – er du sikker?" + cannot_see_mention: + category: "Du nevnte {{username}}, men de vil ikke ikke bli varslet fordi de ikke hara tilgang til denne kategorien. Du må legge dem til en gruppe som har tilgang til denne kategorien." + private: "Du nevnte {{username}}, men de vil ikke bli varslet fordi de ikke kan se denne samtalen. Du må invitere dem til samtalen." + duplicate_link: "Det ser ut til at {{domain}} allerede finnes som innlegg om emnet av @{{username}} i et svar {{ago}} – er du sikker på at du vil gjenta det?" error: title_missing: "Tittel er påkrevd" - title_too_short: "Tittel må være minst {{min}} tegn" + title_too_short: "Tittel må være på minst {{min}} tegn" title_too_long: "Tittel kan ikke være mer enn {{max}} tegn" post_missing: "Innlegget kan ikke være tomt" - post_length: "Innlegget må være minst {{min}} tegn" + post_length: "Innlegget må være på minst {{min}} tegn" try_like: 'Har du prøvd knappen?' category_missing: "Du må velge en kategori" save_edit: "Lagre endring" @@ -771,13 +1009,16 @@ nb_NO: reply_here: "Svar her" reply: "Svar" cancel: "Avbryt" - create_topic: "Nytt Emne" + create_topic: "Opprett emne" create_pm: "Melding" title: "Eller trykk Ctrl+Enter" users_placeholder: "Legg til en bruker" title_placeholder: "Oppsummert i en setning, hva handler denne diskusjonen om?" + title_or_link_placeholder: "Skriv inn tittel eller lim inn en lenke her" edit_reason_placeholder: "hvorfor endrer du?" show_edit_reason: "(legg till endringsbegrunnelse)" + topic_featured_link_placeholder: "Skriv inn lenke vist med tittel." + reply_placeholder: "Skriv her. Bruk Markdown, BBCode eller HTML for å formattere. Dra og slipp bilder." view_new_post: "Se ditt nye innlegg." saving: "Lagrer" saved: "Lagret!" @@ -786,23 +1027,28 @@ nb_NO: show_preview: 'se forhånsvisning »' hide_preview: '« skjul forhåndsvisning' quote_post_title: "Siter hele innlegget" + bold_label: "F" bold_title: "Sterk" bold_text: "sterk tekst" + italic_label: "K" italic_title: "Kursiv" italic_text: "kursiv tekst" link_title: "Hyperlenke" link_description: "beskriv lenken her" link_dialog_title: "Sett inn hyperlenke" link_optional_text: "valgfri tittel" + link_url_placeholder: "http://example.com" quote_title: "Sitatramme" quote_text: "Sitatramme" code_title: "Kode Utsnitt" code_text: "Skriv inn preformattert tekst med 4 mellomroms innrykk." + paste_code_text: "skriv inn eller kopier kode her" upload_title: "Bilde" upload_description: "beskriv bildet her" olist_title: "Nummerert Liste" ulist_title: "Kulepunkt Liste" list_item: "Listeelement" + heading_label: "O" heading_title: "Overskrift" heading_text: "Overskrift" hr_title: "Horisontalt Skille" @@ -810,11 +1056,15 @@ nb_NO: toggler: "gjem eller vis redigeringspanelet" modal_ok: "OK" modal_cancel: "Avbryt" - admin_options_title: "Valgfrie emne-instillinger for ansatte" + cant_send_pm: "Beklager, du kan ikke sende privat melding til %{username}." + yourself_confirm: + title: "Glemte du å legge til mottagere?" + body: "Nå sender du denne meldingen bare til deg selv!" + admin_options_title: "Valgfrie emne-instillinger for stab" auto_close: label: "Tid for auto-lukking av emnet:" - error: "Vennligst skriv en gyldig verdi." - based_on_last_post: "Ikke lukk før den siste posten i emnet er minst så gammel." + error: "Skriv inn en gyldig verdi." + based_on_last_post: "Ikke lukk før det siste innlegget i emnet er minst så gammelt." all: examples: 'Før inn antall timer (24), absolutt tid (17:30) eller tidsstempel (2013-11-22 14:00).' limited: @@ -823,30 +1073,49 @@ nb_NO: notifications: title: "varsler om at ditt @navn blir nevnt, svar på dine innlegg, emner, meldinger, osv" none: "Notifikasjoner er ikke tilgjengelig for øyeblikket." + empty: "Ingen varsler funnet." more: "se gamle varsler" total_flagged: "totalt rapporterte innlegg" mentioned: "

    {{username}} {{description}}

    " + group_mentioned: "

    {{username}} {{description}}

    " quoted: "

    {{username}} {{description}}

    " replied: "

    {{username}} {{description}}

    " + posted: "

    {{username}} {{description}}

    " edited: "

    {{username}} {{description}}

    " liked: "

    {{username}} {{description}}

    " + liked_2: "

    {{username}}, {{username2}} {{description}}

    " + liked_many: + one: "

    {{username}}, {{username2}} og 1 anne {{description}}

    " + other: "

    {{username}}, {{username2}} og {{count}} andre {{description}}

    " private_message: "

    {{username}} {{description}}

    " invited_to_private_message: "

    {{username}} {{description}}

    " invited_to_topic: "

    {{username}} {{description}}

    " invitee_accepted: "

    {{username}} accepted your invitation

    " moved_post: "

    {{username}} moved {{description}}

    " + linked: "

    {{username}} {{description}}

    " granted_badge: "

    Ble tildelt '{{description}}'

    " + watching_first_post: "

    Nytt emne {{description}}

    " + group_message_summary: + one: "

    {{count}} melding i {{group_name}}-gruppens innboks

    " + other: "

    {{count}} meldinger i {{group_name}}-gruppens innboks

    " alt: mentioned: "Nevnt av" quoted: "Sitert av" replied: "Svart" posted: "Innlegg av" + edited: "Rediger din melding innen" liked: "Likte innlegget ditt" private_message: "Privat melding fra" + invited_to_private_message: "Invitert til privat korrespondanse av" + invited_to_topic: "Invitert til et emne fra" + invitee_accepted: "Invitiasjon akseptert av" + moved_post: "Ditt innlegg ble flyttet av" linked: "Link til innlegget ditt" granted_badge: "Merke innvilget" + group_message_summary: "Meldinger i gruppeinnboks" popup: mentioned: '{{username}} nevnte deg i "{{topic}}" - {{site_title}}' + group_mentioned: '{{username}} nevnte deg i "{{topic}}" - {{site_title}}' quoted: '{{username}} siterte deg i "{{topic}}" - {{site_title}}' replied: '{{username}} svarte deg i "{{topic}}" - {{site_title}}' posted: '{{username}} skrev i "{{topic}}" - {{site_title}}' @@ -858,37 +1127,92 @@ nb_NO: from_my_computer: "Fra Min Enhet" from_the_web: "Fra nettet" remote_tip: "link til bilde" + remote_tip_with_attachments: "lenke til bilde eller fil {{authorized_extensions}}" local_tip: "velg bilder fra din enhet" - hint: "(du kan også drag & drop inn i editoren for å laste dem opp)" + local_tip_with_attachments: "velg bilde eller fil fra din enhet {{authorized_extensions}}" + hint: "(du kan også dra og slippe inn i tekstbehandleren for å laste dem opp)" + hint_for_supported_browsers: "du kan også dra og slippe eller lime inn bilder i tekstbehandleren" uploading: "Laster opp bilde" - select_file: "Velg Fil" + select_file: "Velg fil" image_link: "lenken som bildet skal peke til" search: sort_by: "Sorter etter" relevance: "Relevanse" - latest_post: "Nyeste Innlegg" + latest_post: "Siste innlegg" most_viewed: "Mest Lest" most_liked: "Mest Likt" - select_all: "Velg Alle" + select_all: "Velg alle" clear_all: "Fjern Alle" + too_short: "Din søketekst er for kort." + result_count: + one: "Ett resultat for \"{{term}}\"" + other: "{{count}} resultater for \"{{term}}\"" title: "søk etter emner, innlegg, brukere eller kategorier" no_results: "Ingen resultater funnet." no_more_results: "Ingen flere resultater funnet." searching: "Søker ..." post_format: "#{{post_number}} av {{username}}" context: - user: "Søk innleggene av @{{username}}" + user: "Søk i innleggene av @{{username}}" + category: "Søk i kategorien #{{category}}" topic: "Søk i dette emnet" private_messages: "Søk i meldinger" + advanced: + title: Avansert søk + posted_by: + label: Skrevet av + in_category: + label: I kategorien + in_group: + label: I gruppen + with_badge: + label: Med merke + with_tags: + label: Med stikkord + filters: + label: Returner bare emner/innlegg som... + likes: Jeg likte + posted: jeg skrev innlegg i + watching: Jeg følger + tracking: Jeg overvåker + private: er i mine meldinger + bookmarks: Jeg har bokmerket + first: er det første innlegget + pinned: er festet + unpinned: er ikke festet + wiki: er wiki + statuses: + label: Der emner + open: er åpen + closed: er lukket + archived: er arkivert + noreplies: har ingen svar + single_user: inneholder en enkelt bruker + post: + count: + label: Minimum antall innlegg + time: + label: Skrevet + before: før + after: etter hamburger_menu: "gå til en annen emneliste eller kategori" new_item: "ny" go_back: 'gå tilbake' - not_logged_in_user: 'brukerside med oppsummering av nylig aktivtet og preferanser.' + not_logged_in_user: 'brukerside med oppsummering av nåværende aktivtet og preferanser.' current_user: 'go til din brukerside' topics: + new_messages_marker: "siste besøk" bulk: + select_all: "Velg alle" + clear_all: "Fjern alle" + unlist_topics: "Avlist emner" reset_read: "Nullstill lest" - delete: "Slett Emne" + delete: "Slett emne" + dismiss: "Avslå" + dismiss_read: "Merk alle som lest" + dismiss_button: "Avslå…" + dismiss_tooltip: "Avslå bare nye innlegg eller slutt å overvåke emner" + also_dismiss_topics: "Slutt å overvåke disse emnene slik at de aldri igjen vises til meg som ulest" dismiss_new: "Lest" toggle: "Veksle mellom massevelging av emner" actions: "Massehandlinger" @@ -900,21 +1224,27 @@ nb_NO: selected: one: "Du har valgt 1 emne." other: "Du har valgt {{count}} emner." + change_tags: "Endre stikkord" + choose_new_tags: "Velg nye stikkord for disse emnene:" + changed_tags: "Stikkordene på disse innleggene ble endret." none: unread: "Du har ingen uleste emner å lese." new: "Du har ingen nye emner å lese." read: "Du har ikke lest noen emner enda." - posted: "Du har ikke postet i noen emner enda." - latest: "Det er ingen nylige emner. Det er trist." + posted: "Du har ikke sendt inn innlegg i noen emner enda." + latest: "Det finnes ingen siste emner. Det var synd." hot: "Det er ingen populære emner." bookmarks: "Du har ingen bokmerkede emner." category: "Det er ingen {{category}} emner." top: "Det er ingen populære emner." search: "Det er ingen søkeresultater" + educate: + new: '

    Dine nye emner vil komme til syne her.

    Som forvalg anses emner som nye og viser ennyindikator hvis de be opprettet i løpet av de siste to dagene.

    Gå til innstillinger for å endre dette.

    ' + unread: '

    Dine uleste emner vil vises her.

    Som forvalg anses emner for å være ulest og vil vise ulest-tall 1 dersom du:

    • Opprettet emnet
    • Svarte på emnet
    • Leste emnet i mer enn 4 minutter

    Eller dersom du uttrykkelig har satt emnet som overvåkes eller sett via varselkontrollen nederst i hvert emne.

    Gå tilinnstillingene dine for å endre dette.

    ' bottom: - latest: "Det er ingen nylige emner igjen å lese." + latest: "Det er ingen siste emner igjen å lese." hot: "Det er ingen populære emner igjen å lese." - posted: "Det er ingen postede emner igjen å lese." + posted: "Det er ingen emner med innlegg igjen å lese." read: "Det er ingen leste emner igjen å lese." new: "Det er ingen nye emner igjen å lese." unread: "Det er ingen uleste emner igjen å lese." @@ -923,10 +1253,17 @@ nb_NO: bookmarks: "Det er ingen bokmerkede emner." search: "Det er ingen flere søkeresultater" topic: + unsubscribe: + stop_notifications: "Du vil nå få færre varsler for {{title}}" + change_notification_state: "Din nåværende varslingsstatus er" + filter_to: + one: "1 innlegg i emne" + other: "{{count}} innlegg i emne" create: 'Nytt emne' create_long: 'Opprett et nytt emne' private_message: 'Begynn en melding' archive_message: + help: 'Flytt meldinger til arkivet ditt' title: 'Arkiver' move_to_inbox: title: 'Flytt til Inbox' @@ -947,7 +1284,7 @@ nb_NO: login_required: "Du må være logget inn for å lese dette emnet." server_error: title: "Emnet kunne ikke bli behandlet" - description: "Beklager, vi kunne ikke behanldle det emnet, muligens på grunn av et tilkoblingsproblem. Vennligst prøv igjen. Om problemet vedvarer, fortell oss." + description: "Beklager, vi kunne ikke behandle det emnet, muligens på grunn av et tilkoblingsproblem. Prøv igjen. Om problemet vedvarer, fortell oss om det." not_found: title: "Emnet kunne ikke bli funnet" description: "Beklager, vi kunne ikke finne det emnet. Kanskjer det ble fjernet av en moderator?" @@ -971,35 +1308,48 @@ nb_NO: read_more: "Vil du lese mer? {{catLink}} eller {{latestLink}}." read_more_MF: "There { UNREAD, plural, =0 {} one { is 1 unread } other { are # unread } } { NEW, plural, =0 {} one { {BOTH, select, true{and } false {is } other{}} 1 new topic} other { {BOTH, select, true{and } false {are } other{}} # new topics} } remaining, or {CATEGORY, select, true {browse other topics in {catLink}} false {{latestLink}} other {}}" browse_all_categories: Se alle kategorier - view_latest_topics: se nylige emner + view_latest_topics: se siste emner suggest_create_topic: Hvorfor ikke opprette et emne? jump_reply_up: hopp til tidligere svar jump_reply_down: hopp til senere svar deleted: "Emnet har blitt slettet" auto_close_notice: "Dette emnet vil automatisk lukkes %{timeLeft}." auto_close_notice_based_on_last_post: "Dette emnet vil bli lukket %{duration} etter det siste innlegget." - auto_close_title: 'Auto-Lukk Innstillinger' + auto_close_title: 'Auto-lukk innstillinger' auto_close_save: "Lagre" auto_close_remove: "Ikke lukk dette emnet automatisk" + auto_close_immediate: + one: "Det siste innlegget i emnet er allerede en time gammelt, så emnet vil stenges umiddelbart." + other: "Det siste innlegget i emnet er allerede %{count} timer gammelt, så emnet vil stenges umiddelbart." + timeline: + back: "Tilbake" + back_description: "Gå tilbake til forrige uleste innlegg" + replies_short: "%{current} / %{total}" progress: - title: emnefrangang + title: emneframgang go_top: "topp" go_bottom: "bunn" - go: "Gå" + go: "gå" jump_bottom: "Hopp til nyeste innlegg" + jump_prompt: "hopp til..." + jump_prompt_of: "av %{count} innlegg" + jump_prompt_long: "Hvilken melding vil du gå til?" jump_bottom_with_number: "hopp til innlegg %{post_number}" total: innlegg totalt current: gjeldende innlegg notifications: + title: endre hvor ofte du blir varslet om dette emnet reasons: + mailing_list_mode: "Du har slått på e-postlistemodus, så du vil bli varslet på e-post om svar på dette emnet." + '3_10': 'Du vil motta varsler fordi du følger et stikkord for dette emnet' '3_6': 'Du vil motta varsler fordi du følger denne kategorien' '3_5': 'Du vil motta varsler fordi du startet å følge dette emnet automatisk.' '3_2': 'Du vil motta varsler fordi du følger dette emnet.' '3_1': 'Du vil motta varsler fordi du opprettet dette emnet.' '3': 'Du vil motta varsler fordi du følger dette emnet.' - '2_8': 'Du vil motta varsler fordi du følger denne kategorien.' + '2_8': 'Du vil motta varsler fordi du overvåker denne kategorien.' '2_4': 'Du vil motta varsler fordi du svarte på dette emnet.' - '2_2': 'Du vil motta varsler fordi du følger dette emnet.' + '2_2': 'Du vil motta varsler fordi du overvåker dette emnet.' '2': 'Du vil motta varsler fordi du read this topic.' '1_2': 'Du vil bli varslet om noen nevner ditt @navn eller svarer på ditt innlegg.' '1': 'Du vil bli varslet om noen nevner ditt @navn eller svarer på ditt innlegg.' @@ -1013,10 +1363,10 @@ nb_NO: title: "Følger" description: "Du vil bli varslet om hvert nye innlegg i dette emnet. Antall nye tilbakemeldinger vil også bli vist. " tracking_pm: - title: "Følger" + title: "Overvåker" description: "Antall nye tilbakemeldinger vil bli vist for denne meldingen. Du vil bli varslet om noen nevner ditt @name eller svarer på din melding. " tracking: - title: "Følger" + title: "Overvåker" description: "Antall nye svar vil bli vist for dette emnet. Du vil bli varslet om noen nevner ditt @name eller svarer på ditt innlegg.. " regular: title: "Normal" @@ -1025,61 +1375,84 @@ nb_NO: title: "Normal" description: "Du vil bli varslet om noen nevner ditt @navn eller svarer på ditt innlegg." muted_pm: - title: "Dempet" + title: "Ignorert" description: "Du vil ikke få varslinger om noe i denne meldingnen. " muted: - title: "Dempet" + title: "Ignorert" + description: "Du vil bli varslet om alt som har med dette emnet og gjøre, og det vil ikke vises i siste." actions: recover: "Gjenopprett emne" - delete: "slett emne" - open: "Åpne Emne" - close: "Lukk Emne" - multi_select: "Velg Innlegg..." - auto_close: "Lukk Automatisk" - pin: "Feste emnet..." - unpin: "Løsgjør Emne" - unarchive: "Uarkiver Emne" - archive: "Arkiver Emne" - invisible: "Skjul Emnet" - visible: "Vist Emnet" - reset_read: "Tilbakestill Lesedata" + delete: "Slett emne" + open: "Åpne emne" + close: "Lukk emne" + multi_select: "Velg innlegg..." + auto_close: "Lukk automatisk" + pin: "Fest emnet…" + unpin: "Løsne emne…" + unarchive: "Opphev arkivering av emne" + archive: "Arkiver emne" + invisible: "Skjul emnet" + visible: "Gjør synlig" + reset_read: "Tilbakestill lesedata" + make_public: "Gjør emnet offentlig" + make_private: "Gjør om til privat melding" feature: - pin: "Fest Emnet" - unpin: "Løsgjør Emnet" - pin_globally: "Fest Emnet Globalt" + pin: "Fest emnet" + unpin: "Løsne emnet" + pin_globally: "Fest emnet globalt" make_banner: "Banneremne" - remove_banner: "Fjern Banneremne" + remove_banner: "Fjern banneremne" reply: title: 'Svar' help: 'begynn å skrive et svar til dette emnet' clear_pin: - title: "Løsgjør emne" - help: "Løsgjør fastsatt-statusen til dette emnet så det ikke lenger vises på toppen av din emneliste" + title: "Løsne emne" + help: "Løsne feste-statusen til dette emnet slik at det ikke lenger vises på toppen av din emneliste" share: title: 'Del' help: 'del en lenke til dette emnet' + print: + title: 'Skriv ut' + help: 'Åpne en utskriftsvennlig utgave av dette emnet.' flag_topic: - title: 'Rapportér' - help: 'rapportér dette innlegget (ikke offentlig) eller send et privat varsel om det' + title: 'Rapporter' + help: 'rapporter dette innlegget privat eller send et privat varsel om det' success_message: 'Du har rapportert dette emnet' feature_topic: title: "Fremhev dette emnet" - confirm_pin: "Du har allerede {{count}} låste emner. For mange låste emner kan være et problem for nye og anonyme brukere. Er du sikker på at du ønsker å låse et til emne i denne kategorien?" + pin: "La dette emnet få stå på toppen av {{categoryLink}} kategorien til" + confirm_pin: "Du har allerede {{count}} festede emner. For mange festede emner kan være et problem for nye og anonyme brukere. Er du sikker på at du ønsker å feste enda et emne i denne kategorien?" unpin: "Fjern dette emnet fra toppen av {{categoryLink}} kategorien." - pin_note: "Brukere kan låse opp emnet selv." - confirm_pin_globally: "Du har allerede {{count}} globalt låste emner. For mange låste emner kan bli en byrde for nye og anonyme brukere. Er du sikker på at du vil låse et til emne globalt? " + unpin_until: "Fjern dette emnet fra toppen av {{categoryLink}} kategorien, eller vent til %{until}." + pin_note: "Brukere kan selv fjerne festet for dette emnet." + pin_validation: "En dato kreves for å feste dette emnet." + not_pinned: "Det er ingen festede emner i {{categoryLink}}." + already_pinned: + one: "Emner for øyeblikket låst i {{categoryLink}}: Ett" + other: "Emne for øyeblikket låst i {{categoryLink}}: {{count}}" + pin_globally: "Få dette emnet til å figurere på toppen av alle emnelistene til" + confirm_pin_globally: "Du har allerede {{count}} globalt festede emner. For mange festede emner kan bli en byrde for nye og anonyme brukere. Er du sikker på at du vil feste enda et emne globalt? " unpin_globally: "Fjern dette emnet fra toppen av alle emnelister. " - global_pin_note: "Brukere kan låse opp emner for dem selv. " + unpin_globally_until: "Fjern dette emnet fra toppen av alle emnelister eller vent til %{until}." + global_pin_note: "Brukere kan fjerne festet for emnet for seg selv" + not_pinned_globally: "Det er ingen festede emner globalt." + already_pinned_globally: + one: "Emner for øyeblikket festet globalt: 1" + other: "Dette enmnet er festet globalt: {{count}}" make_banner: "Gjør dette emnet til et banner som dukker opp på toppen av alle sider." remove_banner: "Fjern banneret som dukker opp på toppen av alle sider. " banner_note: "Brukere kan fjerne banneret ved å lukke det. Kun et emne kan være banner på en og samme tid. " + no_banner_exists: "Det er ingen banneremner. " + banner_exists: "Det er for øyeblikket et banneremne. " inviting: "Inviterer..." + automatically_add_to_groups: "Denne invitasjonen inkluderer også tilgang til disse gruppene:" invite_private: title: 'Invitér til samtale' email_or_username: "Invitertes e-post eller brukernavn." email_or_username_placeholder: "e-postadresse eller brukernavn" action: "Invitér" success: "Vi har invitert denne brukeren til å delta i denne meldingen." + success_group: "Vi har invitert denne gruppen til å delta i denne meldingen." error: "Beklager, det oppstod en feil ved å invitere den brukeren." group_name: "gruppenavn" controls: "Emnefunksjoner" @@ -1087,15 +1460,15 @@ nb_NO: title: 'Invitér' username_placeholder: "brukernavn" action: 'Send Invitasjon' - help: 'Inviter andre til dette emnet via epost eller varsler' + help: 'Inviter andre til dette emnet via e-post eller varsler' to_forum: "Vi sender en kortfattet e-post som gjør det mulig for en venn å umiddelbart registreres ved å klikke på en lenke. Ingen innlogging er nødvendig." sso_enabled: "Oppgi brukernavnet til personen du ønsker å invitere til dette emnet." - to_topic_blank: "Oppgi brukernavnet eller epost-adressen til personen du ønsker å invitere til dette emnet." - to_topic_email: "Du har oppgitt en epostadresse. Vi vil sende invitasjonen som later vennen din umiddelbart svare på dette emnet." + to_topic_blank: "Oppgi brukernavnet eller e-post-adressen til personen du ønsker å invitere til dette emnet." + to_topic_email: "Du har oppgitt en e-postadresse. Vi vil sende invitasjonen som lar vennen din svare på dette emnet umiddelbart." to_topic_username: "Du har oppgitt et brukernavn. Vi sender et varsel med en link som inviterer dem til dette emnet." to_username: "Oppgi brukernavnet til personen du ønsker å invitere. Vi sender et varsel med en lenke som inviterer dem til dette emnet." email_placeholder: 'navn@example.com' - success_email: "Vi har sendt ut en invitasjon til {{emailOrUsername}}. Vi varsler deg når invitasjonen er godtatt. Sjekk invitiasjonsfanen på brukersiden din for å holde styr på invitasjonene dine." + success_email: "Vi har sendt ut en invitasjon til {{emailOrUsername}}. Vi varsler deg når invitasjonen er godtatt. Sjekk invitiasjonsfanen på brukersiden din for å beholde oversikten over invitasjonene dine." success_username: "Vi har invitert brukeren til å delta i dette emnet." error: "Beklager, vi kunne ikke invitere den brukeren. De har muligens allerede blitt invitert?" login_reply: 'Logg Inn for å svare' @@ -1105,9 +1478,9 @@ nb_NO: other: "{{count}} innlegg" cancel: "Fjern filter" split_topic: - title: "Del opp Emne" + title: "Del opp emne" action: "del opp emne" - topic_name: "Nytt Emnenavn:" + topic_name: "Nytt emnenavn:" error: "Det oppsto en feil ved deling av dette emnet." instructions: one: "Du er i ferd med å lage et nytt emne basert på innlegget du har valgt.." @@ -1117,8 +1490,12 @@ nb_NO: action: "slå sammen emne" error: "Det oppsto en feil ved sammenslåing av dette emnet." instructions: - one: "Vennligst velg det emnet du vil flytte det innlegget til." - other: "Vennligst velg emnet du vil flytte de {{count}} innleggene til." + one: "Velg det emnet du vil flytte det innlegget til." + other: "Velg emnet du vil flytte de {{count}} innleggene til." + merge_posts: + title: "Slå sammen valgte innlegg" + action: "slå sammen valgte innlegg" + error: "Feil ved fletting av valgte innlegg." change_owner: title: "Endre innleggenes eier" action: "Endre eierskap" @@ -1129,6 +1506,12 @@ nb_NO: one: "Velg den nye eieren til innlegget av {{old_user}}." other: "Velg den nye eieren til {{count}} innlegg av {{old_user}}." instructions_warn: "Merk at ingen varsler om dette innlegget vil overføres til den nye eieren i etterkant.
    Advarsel: For øyeblikket blir ingen innleggsavhengige data overført til den nye brukeren. Bruk med omhu." + change_timestamp: + title: "Endre tidsstempel" + action: "endre tidsstempel" + invalid_timestamp: "Tidsstempel kan ikke være i framtiden." + error: "Det oppstod en feil ved endring av tidsstempel for emnet." + instructions: "Velg et nytt tidsstempel for emnet. Innlegg i emnet blir oppdatert med samme tidsforksjell." multi_select: select: 'velg' selected: 'valgte ({{count}})' @@ -1141,14 +1524,17 @@ nb_NO: one: Du har valgt 1 innlegg. other: Du har valgt {{count}} innlegg. post: + reply: " {{replyAvatar}} {{usernameLink}}" + reply_topic: " {{link}}" + quote_reply: "Sitat" edit: "Redigerer {{link}} {{replyAvatar}} {{username}}" edit_reason: "Begrunnelse:" - post_number: "post {{number}}" + post_number: "innlegg {{number}}" last_edited_on: "innlegg sist redigert" reply_as_new_topic: "Svar med lenket emne" continue_discussion: "Fortsetter diskusjonen fra {{postLink}}:" follow_quote: "gå til det siterte innlegget" - show_full: "Vis hele posten" + show_full: "Vis hele innlegget" show_hidden: 'Se skjult innhold' deleted_by_author: one: "(innlegg som er trukket tilbake av forfatter, blir automatisk slettet etter % {count} time, med mindre de blir flagget)" @@ -1159,8 +1545,8 @@ nb_NO: other: "vis {{count}} skjulte svar" unread: "Innlegget er ulest" has_replies: - one: "{{count}} Svar" - other: "{{count}} Svar" + one: "{{count}} svar" + other: "{{count}} svar" has_likes: one: "{{count}} Like" other: "{{count}} liker" @@ -1172,11 +1558,13 @@ nb_NO: one: "du og 1 annen bruker likte dette innlegget" other: "du og {{count}} andre likte dette innlegget" errors: - create: "Beklager, det oppstod en feil ved å publisere ditt innlegg. Vennligst prøv igjen." + create: "Beklager, det oppstod en feil ved å publisere ditt innlegg. Prøv igjen." edit: "Beklager, det oppstod en feil ved redigeringen av ditt innlegg. Vennligst prøv igjen." upload: "Sorry, there was an error uploading that file. Please try again." + file_too_large: "Beklager, den filen er for stor. Største tillatte størrelse er {{max_size_kb}} kb. Hvorfor ikke heller laste opp filen til en fildelingstjeneste og dele lenken?" too_many_uploads: "Beklager, du kan bare laste opp ett bilde om gangen." - upload_not_authorized: "Beklager, filen du prøver å laste opp er ikke godkjent (godkjente filtyper: {{authorized_extensions}})." + too_many_dragged_and_dropped_files: "Beklager, du kan bare laste opp 10 filer om gangen." + upload_not_authorized: "Beklager, filen du forsøket å laste opp er ikke tillatt. Tillatte filendelser er {{authorized_extensions}}." image_upload_not_allowed_for_new_user: "Beklager, nye brukere kan ikke laste opp bilder" attachment_upload_not_allowed_for_new_user: "Beklager, nye brukere kan ikke laste opp vedlegg." attachment_download_requires_login: "Beklager, du må være logget inn for å laste ned vedlegg." @@ -1185,8 +1573,13 @@ nb_NO: no_value: "Nei" yes_value: "Ja" via_email: "Dette innlegget ankom via e-post" + via_auto_generated_email: "dette innlegget kommer fra en automatisk generert e-post" + whisper: "dette innlegget er et privat hvisken for moderatorer" + wiki: + about: "dette innlegget er en wiki" archetypes: save: 'Lagre Alternativene' + few_likes_left: "Takk for at du sprer kjærlighet! Du vil nå grensen for antall ting du kan like i dag ganske snart." controls: reply: "begynn å skrive et svar til dette innlegget" like: "lik dette innlegget" @@ -1194,7 +1587,7 @@ nb_NO: undo_like: "angre liker" edit: "rediger dette innlegget" edit_anonymous: "Beklager, du må være innlogget for å endre dette innlegget." - flag: "rapportér dette innlegget (ikke offentlig) eller send et privat varsel om det" + flag: "rapporter dette innlegget privat eller send et privat varsel om det" delete: "slett dette innlegget" undelete: "gjenopprett dette innlegget" share: "del en lenke til dette innlegget" @@ -1212,6 +1605,7 @@ nb_NO: revert_to_regular: "Fjern stabsfarge" rebake: "Gjenoppbygg HTML" unhide: "Vis" + change_owner: "Endre eierskap" actions: flag: 'Rapportering' defer_flags: @@ -1225,10 +1619,12 @@ nb_NO: like: "Angre liker" vote: "Angre stemme" people: + off_topic: "markerte dette som urelatert" spam: "flagget dette som spam" inappropriate: "flagget dette som upassende" notify_moderators: "varslet moderatorer" notify_user: "sendte en melding" + bookmark: "bokmerket dette" like: "likte dette" vote: "stemte for dette" by_you: @@ -1294,14 +1690,19 @@ nb_NO: confirm: one: "Er du sikker på at du vil slette det innlegget?" other: "Er du sikker på at du vil slette alle de innleggene?" + merge: + confirm: + one: "Er du sikker på at du vil flette de innleggene?" + other: "Er du sikker på at du vil flette disse {{count}} innleggene?" revisions: controls: - first: "Første revisjon" - previous: "Forrige revisjon" - next: "Neste revisjon" - last: "Siste revisjon" - hide: "Skjul revisjon" - show: "Vis revisjon" + first: "Første versjon" + previous: "Forrige versjon" + next: "Neste versjon" + last: "Siste versjon" + hide: "Skjul versjon" + show: "Vis versjon" + revert: "Gå tilbake til denne versjonen" comparing_previous_to_current_out_of_total: "{{previous}} {{current}} / {{total}}" displays: inline: @@ -1324,12 +1725,18 @@ nb_NO: general: 'Generellt' settings: 'Innstillinger' topic_template: "Emnemal" + tags: "Stikkord" + tags_allowed_tags: "Stikkord som bare kan brukes i denne kategorien:" + tags_allowed_tag_groups: "Stikkord som bare kan brukes i denne kategorien:" + tags_placeholder: "(Valgfritt) Liste over tillatte stikkord" + tag_groups_placeholder: "(Valgfritt) Liste over tillatte stikkordgrupper" + topic_featured_link_allowed: "Tillat fremhevede lenker i denne kategorien" delete: 'Slett kategori' create: 'Ny Kategori' create_long: 'Opprett en ny kategori' save: 'Lagre Kategori' slug: 'Kategorinavn i URL' - slug_placeholder: '(valgfritt) sammensatte ord for bruk i URL' + slug_placeholder: '(valgfritt) Sammensatte ord for bruk i URL' creation_error: Det oppstod en feil ved å lage denne kategorien. save_error: Det oppstod en feil ved lagrinen av denne kategorien. name: "Kategorinavn" @@ -1345,10 +1752,11 @@ nb_NO: delete_confirm: "Er du sikker på at du vil slette denne kategorien?" delete_error: "Det oppstod en feil ved å slette denne kategorien." list: "List Kategorier" - no_description: "Vennligst legg til en beskrivelse for denne kategorien." + no_description: "Legg til en beskrivelse for denne kategorien." change_in_category_topic: "Rediger Beskrivelse" already_used: 'Denne fargen er i bruk av en annen kategori' security: "Sikkerhet" + special_warning: "Advarsel: Denne kategorien er en forhåndsbestemt kategori og dens sikkerhetsinnstillinger kan ikke endres. Hvis du ikke vil bruke denne kategorien, slett den i stedet for å bruke den til noe annet." images: "Bilder" auto_close_label: "Lukk emner automatisk etter:" auto_close_units: "timer" @@ -1356,55 +1764,94 @@ nb_NO: email_in_allow_strangers: "Godta e-post fra anonyme brukere uten brukerkonto" email_in_disabled: "Posting av nye emner via e-post er deaktivert i nettstedsinstillingene. For å aktivere posting av nye emner via e-post," email_in_disabled_click: 'aktiver innstillingen "e-post inn".' + suppress_from_homepage: "Utelat denne kategorien fra hjemmesiden." + all_topics_wiki: "Gjør nye emner til wiki-er som forvalg." + sort_order: "Forvalgt sortering:" allow_badges_label: "Tillat merker å bli tildelt i denne kategorien" edit_permissions: "Rediger tillatelser" add_permission: "Legg til tillatelser" this_year: "dette året" position: "posisjon" - default_position: "Standard posisjon" + default_position: "Forvalgt posisjon" position_disabled: "Kategorier vil bli vist i henhold til aktivitet. For å styre rekkefølgen av kategorier i listen" - position_disabled_click: 'kan du aktivere "faste kategoriposisjoner" i innstillinger.' + position_disabled_click: 'aktivere "faste kategoriposisjoner"-innstillingen.' parent: "Foreldrekategori" notifications: watching: title: "Følger" + description: "Du vil automatisk følge alle emnene i disse kategoriene. Du vil bli varslet om hvert nye innlegg i hvert emne, og antall nye svar vil bli vist." + watching_first_post: + title: "Følger første innlegg" + description: "Du vil bare bli varslet om det første innlegget i hvert nye emne i disse kategoriene." tracking: - title: "Sporing" + title: "Overvåkning" + description: "Du vil automatisk overvåke alle emner i disse kategoriene. Du vil bli varslet dersom noen nevner @navnet ditt eller svarer deg, og antallet nye svar vil bli vist." regular: title: "Normal" description: "Du vil bli varslet om noen nevner ditt @navn eller svarer deg." muted: - title: "Dempet" + title: "Ignorert" + description: "Du vil aldri bli varslet om noe med tanke på nye emner i disse kategoriene, og de vil ikke vises i siste." + sort_options: + default: "forvalg" + likes: "Gunst" + op_likes: "Gunst gitt orginalinnlegget" + views: "Visninger" + posts: "Innlegg" + activity: "Aktivitet" + posters: "Bidragsytere" + category: "Kategori" + created: "Opprettet" + sort_ascending: 'Stigende' + sort_descending: 'Synkende' flagging: title: 'Takk for at du hjelper å holde forumet ryddig!' - action: 'Rapportér innlegg' + action: 'Rapporter innlegg' take_action: "Ta Handling" notify_action: 'Melding' official_warning: 'Offisiell Advarsel' delete_spammer: "Slett spammer" + delete_confirm_MF: "Du er i ferd med å slette {POSTS, flere, ett {1 innlegg} andre {# innlegg}} og {EMNER, flere, ett {1 emne} andre {# emner}} av denne brukeren, fjern kontoen deres, blokker påmeldinger fra deres IP-adresse {ip_address}, og legg til deres e-postadresse {email} til en permanent blokkeringsliste. Er du sikker på at denne brukeren virkelig sender søppelpost?" yes_delete_spammer: "Ja, slett spammer" ip_address_missing: "(N/A)" hidden_email_address: "(skjult)" - submit_tooltip: "Rapportér privat" + submit_tooltip: "Rapporter privat" take_action_tooltip: "Oppnå rapporteringsterskel umiddelbart, i stedet for å vente på flere rapporteringer." cant: "Beklager, du kan ikke rapportere dette innlegget nå." + notify_staff: 'Gjør stab oppmerksom på dette privat' formatted_name: - off_topic: "Det er off-topic " + off_topic: "Det er urelatert" inappropriate: "Det er upassende" spam: "Det er reklame" custom_placeholder_notify_user: "Vær spesifikk, konstruktiv og snill." custom_placeholder_notify_moderators: "La oss vite nøyaktig hva problemet er, og del relevante lenker og eksempler hvorvidt det er mulig." + custom_message: + at_least: + one: "skriv inn minst ett tegn" + other: "skriv inn minst {{count}} tegn" + more: + one: "Én igjen…" + other: "{{count}} igjen…" + left: + one: "ett gjenstående" + other: "{{count}} gjenstående" flagging_topic: title: "Takk for at du hjelper med å vedlikeholde god skikk i samfundet vårt!" - action: "Rapportér emne" + action: "Rapporter emne" notify_action: "Melding" topic_map: title: "Emneoppsummering" participants_title: "Hyppige Bidragsytere" links_title: "Populære Lenker" + links_shown: "vis flere lenker…" clicks: one: "1 klikk" other: "%{count} klikk" + post_links: + about: "utvid flere lenker for dette innlegget" + title: + one: "Én til" + other: "%{count} flere" topic_statuses: warning: help: "Dette er en offisiell advarsel." @@ -1414,16 +1861,19 @@ nb_NO: help: "dette emnet er låst; det aksepterer ikke lenger nye svar" archived: help: "dette emnet er arkivert; det er fryst og kan ikke bli aktivert" + locked_and_archived: + help: "Dette emnet er lukket og akrivert; nye innlegg godtas ikke og tidligere svar kan ikke endres" unpinned: - title: "Løsgjort" - help: "Dette emnet er ikke lenger fastsatt, det vil vises i vanlig rekkefølge" + title: "Feste fjernet" + help: "Dette emnet er ikke lenger festet, det vil vises i vanlig rekkefølge" pinned_globally: title: "Globalt fastsatt" + help: "Emnet er festet globalt; det vil vises på toppen av seneste og i egen kategori" pinned: title: "Fastsatt" help: "Dette emnet er fastsatt for deg; det vil vises i toppen av sin kategori" invisible: - help: "Dette emnet er ikke listet; det vil ikke vises i emnelister, og kan kun leses via en direktelenke" + help: "Dette emnet er ikke synlig; det vil ikke vises i emnelister, og kan kun leses via en direktelenke" posts: "Innlegg" posts_long: "{{number}} innlegg i dette emnet" posts_likes_MF: | @@ -1438,7 +1888,9 @@ nb_NO: one: "visninger" other: "visninger" replies: "Svar" - views_long: "dette emnet har blit sett {{number}} ganger" + views_long: + one: "dette emnet er vist 1 gang" + other: "dette emnet er vist {{number}} ganger" activity: "Aktivitet" likes: "Liker" likes_lowercase: @@ -1479,11 +1931,11 @@ nb_NO: title_in: "Kategori - {{categoryName}}" help: "alle emner sortert etter kategori" unread: - title: "Ulest" + title: "Uleste" title_with_count: one: "Ulest (1)" other: "Ulest ({{count}})" - help: "emner du for øyeblikket følger eller sporer med uleste innlegg" + help: "emner med uleste innlegg du for øyeblikket følger eller overvåker" lower_title_with_count: one: "1 ulest" other: "{{count}} uleste" @@ -1492,14 +1944,14 @@ nb_NO: one: "1 ny" other: "{{count}} nye" lower_title: "ny" - title: "Ny" + title: "Nye" title_with_count: one: "Nye (1)" other: "Nye ({{count}})" help: "emner opprettet de siste dagene" posted: title: "Mine Innlegg" - help: "emner du har postet i" + help: "emner du har bidratt med innlegg i" bookmarks: title: "Bokmerker" help: "emner du har bokmerket" @@ -1508,7 +1960,7 @@ nb_NO: title_with_count: one: "{{categoryName}} (1)" other: "{{categoryName}} ({{count}})" - help: "nylige emner i {{categoryName}}-kategorien" + help: "siste emner i {{categoryName}}-kategorien" top: title: "Aktive" help: "de mest aktive emnene det siste året, den siste måneden, den siste uken eller i dag" @@ -1525,17 +1977,190 @@ nb_NO: daily: title: "Daglig" all_time: "Totalt" - this_year: "År" - this_quarter: "Kvartal" - this_month: "Måned" - this_week: "Uke" + this_year: "Det siste året" + this_quarter: "Det siste kvartalet" + this_month: "Den siste måneden" + this_week: "Den siste uken" today: "I dag" other_periods: "se toppen" - browser_update: 'Dessverre, Din nettleser er for gammel og fungerer ikke med dette nettstedet.. Vennligst oppgrader nettleseren din.' + browser_update: 'Dessverre, Din nettleser er for gammel og fungerer ikke med dette nettstedet.. Oppgrader nettleseren din.' permission_types: full: "Opprett / Svar / Se" create_post: "Svar / Se" readonly: "Se" + lightbox: + download: "last ned" + keyboard_shortcuts_help: + title: 'Tastatursnarveier' + jump_to: + title: 'Hopp til' + home: 'g, h Hjem' + latest: 'g, l Siste' + new: 'g, n Nye' + unread: 'g, u Uleste' + categories: 'g, c Kategorier' + top: 'g, t Topp' + bookmarks: 'g, b Bokmerker' + profile: 'g, p Profil' + messages: 'g, m Meldinger' + navigation: + title: 'Navigasjon' + jump: '# Gå til innlegg #' + back: 'u Tilbake' + up_down: 'k/j Flytt utvalg ↑ ↓' + open: 'o or Enter Åpne valgt emne' + next_prev: 'shift+j/shift+k Neste/forrige del' + application: + title: 'Applikasjon' + create: 'c Opprett nytt emne' + notifications: 'n Åpne varsler' + hamburger_menu: '= Åpne hamburgermeny' + user_profile_menu: 'p Åpne brukermenyen' + show_incoming_updated_topics: '. Vis oppdaterte emner' + search: '/ Søk' + help: '? Åpne tastaturhjelp' + dismiss_new_posts: 'x, r Avvis Nye/Innlegg' + dismiss_topics: 'x, t Avvis emner' + log_out: 'shift+z shift+z Logg ut' + actions: + title: 'Handlinger' + bookmark_topic: 'f Bokmerk emne / Fjern bokmerke' + pin_unpin_topic: 'shift+p Fest/fjern feste for emne' + share_topic: 'shift+s Del emne' + share_post: 's Del innlegg' + reply_as_new_topic: 't Svar som lenket emne' + reply_topic: 'shift+r Svar på emne' + reply_post: 'r Svar på innlegg' + quote_post: 'q Siter innlegg' + like: 'l Lik innlegg' + flag: '! Rapporter innlegg' + bookmark: 'b Bokmerk innlegg' + edit: 'e Rediger innlegg' + delete: 'd Slett innlegg' + mark_muted: 'm, m Ignorer emnet' + mark_regular: 'm, r Vanlig (forvalgt) emne' + mark_tracking: 'm, t Overvåk emne' + mark_watching: 'm, w Følg emne' + print: 'ctrl+p Skriv ut emne' + badges: + earned_n_times: + one: "Har gjort seg fortjent til dette merket" + other: "Har gjort seg fortjent til dette merket %{count} ganger" + granted_on: "Tildelt %{date}" + others_count: "(%{count}) andre har dette merket" + title: Merker + allow_title: "tilgjengelig tittel" + multiple_grant: "tildelt flere ganger" + badge_count: + one: "Étt merke" + other: "%{count} Merker" + more_badges: + one: "+1 mer" + other: "+%{count} Flere" + granted: + one: "ett tildelt" + other: "%{count} tildelt" + select_badge_for_title: Velg et merke å bruke som din tittel + none: "" + badge_grouping: + getting_started: + name: Kom i gang + community: + name: Gemenskap + trust_level: + name: Tillitsnivå + other: + name: Annet + posting: + name: Publisering + google_search: | +

    Søk med Google

    +

    +

    +

    + tagging: + all_tags: "Alle stikkord" + selector_all_tags: "alle stikkord" + selector_no_tags: "ingen stikkord" + changed: "stikkord endret:" + tags: "Stikkord" + choose_for_topic: "velg alternative stikkord for dette emnet" + delete_tag: "Slett stikkord" + delete_confirm: "Er du sikker på at du vil slette det stikkordet?" + rename_tag: "Gi stikkord nytt navn" + rename_instructions: "Velg et nytt navn for dette stikkordet:" + sort_by: "Sorter etter:" + sort_by_count: "antall" + sort_by_name: "navn" + manage_groups: "Behandle stikkordgrupper" + manage_groups_description: "Definer grupper for å organisere stikkord" + filters: + without_category: "%{filter} %{tag} emner" + with_category: "%{filter} %{tag} emner i %{category}" + untagged_without_category: "%{filter} emner uten stikkord" + untagged_with_category: "%{filter} emner uten stikkord i %{category}" + notifications: + watching: + title: "Følger" + description: "Du vil automatisk følge alle emnene med dette stikkordet. Du vil bli varslet om alle nye innlegg og emner; i tillegg vil antallet uleste og nye innlegg vises ved siden av emnet." + watching_first_post: + title: "Følger første innlegg" + description: "Du vil bare bli varslet om det første innlegget i hvert nye emne som gjør bruk av dette stikkordet." + tracking: + title: "Overvåkning" + description: "Du vil automatisk overvåke alle emner med dette stikkordet. Antallet uleste og nye innlegg vil vises ved siden av emnet." + regular: + title: "Aktivt medlem" + description: "Du vil bli varslet hvis noen nevner ditt @navn eller svarer på ditt innlegg." + muted: + title: "Ignorert" + description: "Du vil ikke bli varslet om noe vedrørende disse emner som bruker dette stikkordet, og de vil ikke vises i din ulest-liste." + groups: + title: "Stikkordgrupper" + about: "Legg stikkord til grupper for å kunne organisere dem enklere." + new: "Ny gruppe" + tags_label: "Stikkord i denne gruppen:" + parent_tag_label: "Foreldrestikkord:" + parent_tag_placeholder: "Valgfritt" + parent_tag_description: "Stikkord fra denne gruppen kan ikke brukes, med mindre foreldrestikkordet er til stede." + one_per_topic_label: "Sett grense på ett stikkord for hvert emne for denne gruppen" + new_name: "Ny stikkordgruppe" + save: "Lagre" + delete: "Slett" + confirm_delete: "Er du sikker på at du vil slette denne stikkordgruppen?" + topics: + none: + unread: "Du har ingen uleste emner." + new: "Du har ingen nye emner." + read: "Du har ikke lest noen emner enda." + posted: "Du har ikke opprettet noen emner enda." + latest: "Det er ingen siste emner igjen å lese." + hot: "Det er ingen populære emner." + bookmarks: "Du har ikke bokmerket noen emner enda." + top: "Det er ingen populære emner." + search: "Det er ingen søkeresultater." + bottom: + latest: "Det er ingen siste emner igjen å lese." + hot: "Det er ingen populære emner igjen å lese." + posted: "Det er ingen emner med innlegg igjen å lese." + read: "Det er ingen leste emner igjen å lese." + new: "Det er ingen nye emner igjen å lese." + unread: "Det er ingen uleste emner igjen å lese." + top: "Det er ingen flere populære emner." + bookmarks: "Det er ingen bokmerkede emner." + search: "Det er ingen flere søkeresultater" + invite: + custom_message: "Gjør din invitasjon litt mer personlig ved å skrive ett" + custom_message_link: "egendefinert melding" + custom_message_placeholder: "Skriv inn din egendefinerte melding" + custom_message_template_forum: "Hei, du burde ta del i dette forumet!" + custom_message_template_topic: "Hei, jeg tenkte du fattet interesse for dette emnet!" + safe_mode: + enabled: "Sikkert modus er påskrudd, for å gå ut av sikkert modus, lukk dette nettleservinduet" admin_js: type_to_filter: "skriv for å filtrere..." admin: @@ -1548,12 +2173,12 @@ nb_NO: up_to_date: "Du har den seneste versjonen!" critical_available: "En kritisk oppdatering er tilgjengelig." updates_available: "Oppdateringer er tilgjengelig." - please_upgrade: "Vennligst oppgrader!" + please_upgrade: "Oppgrader!" no_check_performed: "En sjekk for oppdateringer har ikke blitt utført. Verifiser at sidekiq kjører." stale_data: "Det har ikke vært sjekket for oppdateringer på en stund. Sjekk at sidekiq kjører." version_check_pending: "Ser ut som om du oppgraderte nylig. Fantastisk!" installed_version: "Installert" - latest_version: "Seneste" + latest_version: "Siste" problems_found: "Det har oppstått noen problemer med din installasjon av Discourse:" last_checked: "Sist sjekket" refresh_problems: "Last inn siden på nytt" @@ -1570,8 +2195,8 @@ nb_NO: backups: "sikkerhetskopier" traffic_short: "Trafikk" traffic: "Applikasjon webforespørsler" - page_views: "API forespørsler" - page_views_short: "API forespørsler" + page_views: "Sidevisninger" + page_views_short: "Sidevisninger" show_traffic_report: "Vis detaljert trafikkrapport" reports: today: "I dag" @@ -1589,7 +2214,7 @@ nb_NO: end_date: "Sluttdato" groups: "Alle grupper" commits: - latest_changes: "Siste endringer: Vennligst oppgrader ofte!" + latest_changes: "Siste endringer: Oppgrader ofte!" by: "av" flags: title: "Rapporteringer" @@ -1661,25 +2286,28 @@ nb_NO: refresh: "Last inn på nytt" new: "Ny" selector_placeholder: "oppgi brukernavn" - name_placeholder: "Gruppenavn, ingen mellomrom, samme regler som for brukernavn" about: "Rediger gruppemedlemskap og navn her." group_members: "Gruppemedlemmer" delete: "Slett" delete_confirm: "Slette denne grupper?" delete_failed: "Unable to delete group. If this is an automatic group, it cannot be destroyed." - delete_member_confirm: "Fjern '%{username}' fra '%{group}' gruppen?" - name: "Navn" + delete_owner_confirm: "Frata '%{username}' eier-privilegium?" add: "Legg til" add_members: "Legg til medlemmer" custom: "Egendefinert" + bulk_complete: "Brukeren er lagt til i gruppen." + bulk: "Legg flere til i gruppe" + bulk_paste: "Lim inn en liste med brukernavn eller e-postadresser, en per linje:" + bulk_select: "(velg en gruppe)" automatic: "Automatisk" - automatic_membership_email_domains: "Brukere som registererer seg med et epostdomene som matcher en i denne listen vil automatisk bli lagt til i denne gruppen." - automatic_membership_retroactive: "Benytt samme epostdomeneregel for å legge til eksisterende brukere" - default_title: "Standardtittel for alle brukere i denne gruppen" + automatic_membership_email_domains: "Brukere som registererer seg med et e-postdomene som er det samme som et i denne listen, vil automatisk bli lagt til i denne gruppen." + automatic_membership_retroactive: "Benytt samme e-postdomeneregel for å legge til eksisterende brukere" + default_title: "Forvalgt tittel for alle brukere i denne gruppen" primary_group: "Sett som primærgruppe automatisk" group_owners: Eiere add_owners: Legg til eiere - incoming_email_placeholder: "oppgi epostadresse" + incoming_email: "Egendefinert innkommende e-postadresse" + incoming_email_placeholder: "oppgi e-postadresse" api: generate_master: "Generer Master API-nøkkel" none: "Det er ingen aktive API-nøkler akkurat nå." @@ -1694,6 +2322,76 @@ nb_NO: info_html: "Din API nøkkel vil tillate deg å lage og oppdatere emner ved å bruke JSON samteler." all_users: "Alle brukere" note_html: "Hold denne nøkkelen hemmelig. Alle brukere som har den vil kunne opprette vilkårlige innlegg som en hvilken som helst bruker. " + web_hooks: + title: "Webhooker" + none: "Det finnes ingen webhooker for tiden." + instruction: "Webhooker lar Discourse sender meldinger til eksterne tjenester når spesifiserte situasjoner oppstår på nettstedet. Når en webhook utløses, sendes en POST-forespørsel til nettadressene du angir." + detailed_instruction: "En POST-forespørsel sendes til den angitte URL-en når den valgte hendelsen skjer." + new: "Ny webhook" + create: "Opprett" + save: "Lagre" + destroy: "Slett" + description: "Beskrivelse" + controls: "Kontroller" + go_back: "Tilbake til liste" + payload_url: "Payload URL" + payload_url_placeholder: "https://eksempel.no/postmottak" + warn_local_payload_url: "Det ser ut som du prøver å sende webhooken til en lokal URL. Hendelser som sendes til lokale adresser kan gi sideeffekter eller føre til uventet oppførsel. Fortsette?" + secret_invalid: "Delt hemmelighet kan ikke inneholde blanke tegn." + secret_too_short: "Delt hemmelighet må være minst 12 tegn." + secret_placeholder: "En valgfri streng som brukes for å lage signatur" + event_type_missing: "Du må sette opp minst en type hendelse." + content_type: "Content Type" + secret: "Delt hemmelighet" + event_chooser: "Hvilke hendelser skal utløse denne webhooken?" + wildcard_event: "Send meg alt" + individual_event: "Velg hendelser enkeltvis." + verify_certificate: "Kontroller TLSs-sertifikat til payload url" + active: "Aktiv" + active_notice: "Vi sender hendelsesdetaljer når det skjer." + categories_filter_instructions: "Relevante webhooker vil bare bli utløst hvis hendelsene er relatert til valgte kategorier. La være blank for å utløse webhooker for alle kategorier." + categories_filter: "Utløste kategorier" + groups_filter_instructions: "Relevante webhooker vil bare bli utløst hvis hendelsene er relatert til valgte grupper. La være blank for å utløse webhooker for alle grupper." + groups_filter: "Utløse grupper" + delete_confirm: "Slette denne webhooken?" + topic_event: + name: "Emnehendelse" + details: "Når det et nytt, revidert, endret eller slettet emne." + post_event: + name: "Innleggshendelse" + details: "Når det er et nytt, redigert, slettet eller gjenopprettet innlegg." + user_event: + name: "Brukerhendelse" + details: "Når en bruker blir opprettet, godkjent eller oppdatert." + delivery_status: + title: "Sendingsstatus" + inactive: "Inaktiv" + failed: "Feilet" + successful: "Vellykket" + events: + none: "Det er ingen relaterte hendelser." + redeliver: "Send på nytt" + incoming: + one: "Det er en ny hendelse." + other: "Det er {{count}} nye hendelser." + completed_in: + one: "Ferdig på 1 sekund." + other: "Ferdig på {{count}} sekunder." + request: "Forespørsel" + response: "Svar" + redeliver_confirm: "Er du sikker på at du vil sende samme payload på nytt?" + headers: "Headere" + payload: "Payload" + body: "Body" + go_list: "Gå til liste" + go_details: "Rediger webhook" + go_events: "Gå til hendelser" + ping: "Ping" + status: "Statuskode" + event_id: "ID" + timestamp: "Opprettet" + completion: "Gjennomføringstid" + actions: "Handlinger" plugins: title: "Utvidelser" installed: "Installerte Utvidelser" @@ -1712,6 +2410,14 @@ nb_NO: backups: "Sikkerhetskopieringer" logs: "Logger" none: "Ingen sikkerhetskopiering er tilgjengelig." + read_only: + enable: + title: "Aktiver skrivebeskyttet modus" + label: "Aktiver skrivebeskytting" + confirm: "Er du sikker på at du vil skru på skrivebeskyttelsesmodus?" + disable: + title: "Skru av skrivebeskyttet modus" + label: "Skru av skrivebeskytting" logs: none: "Ingen logger enda..." columns: @@ -1745,9 +2451,11 @@ nb_NO: is_disabled: "Gjenoppretting er deaktivert i nettstedsinnstillingene." label: "Gjenooprett" title: "Gjenopprett sikkerhetskopien" + confirm: "Er du sikker på at du vil gjenopprette denne sikkerhetskopien?" rollback: label: "Gjenopprett" title: "Gjenopprett databasen til en tidligere fungerende tilstand" + confirm: "Er du sikker på at du vil gjenopprette databasen til den tidligere fungerende tilstanden?" export_csv: success: "Eksportering iverksatt. Du vil bli varslet med en melding når prosessen er fullført." failed: "Eksporteringen feilet. Venligst undersøk loggene." @@ -1755,7 +2463,7 @@ nb_NO: button_title: user: "Eksporter full medlemsliste i CSV format." staff_action: "Eksporter full handligslogg i CSV format." - screened_email: "Eksporter komplett liste over filtrerte epostadresser i CSV format." + screened_email: "Eksporter komplett liste over filtrerte e-postadresser i CSV format." screened_ip: "Eksporter komplett liste over filtrerte IP-addresser i CSV format." screened_url: "Eksporter komplett liste over filtrerte URL'er i CSV format." export_json: @@ -1777,14 +2485,14 @@ nb_NO: body_tag: text: "" title: "HTML som settes inn før taggen." - override_default: "Ikke inkluder standard stilark" + override_default: "Ikke inkluder forvalgt stilark" enabled: "Aktivert?" preview: "forhåndsvisning" undo_preview: "avbryt forhåndsvisning" - rescue_preview: "standard stil" + rescue_preview: "forvalgt stil" explain_preview: "Se nettstedet med dette skreddersydde stilarket" explain_undo_preview: "Gå tilbake til nåværende aktivert tilpasset stilark" - explain_rescue_preview: "Se nettstedet med standard stilark" + explain_rescue_preview: "Se nettstedet med forvalgt stilark" save: "Lagre" new: "Ny" new_style: "Ny Stil" @@ -1797,7 +2505,13 @@ nb_NO: opacity: "Opacity" copy: "Kopier" email_templates: + title: "E-postmaler" subject: "Emne" + multiple_subjects: "Denne e-postmalen har flerfoldige emner." + body: "Meldingstekst" + none_selected: "Velg en e-postmal for å begynne å redigere." + revert: "Tilbakestill endringer" + revert_confirm: "Er du sikker på at du vil tilbakestille dine endringer?" css_html: title: "CSS/HTML" long_title: "CSS og HTML-tilpasninger" @@ -1811,7 +2525,7 @@ nb_NO: undo: "angre" undo_title: "Fjern endringer av denne fargen siden sist den ble lagret." revert: "gå tilbake" - revert_title: "Nullstill denne fargen til standard fargeskjema for Discourse" + revert_title: "Nullstill denne fargen til forvalg i fargepaletten for Discourse" primary: name: 'primær' description: 'Det meste av tekst, ikoner og kanter.' @@ -1843,14 +2557,18 @@ nb_NO: name: 'liker' description: "Fargen til Liker-knappen." email: - title: "Eposter" + title: "E-poster" settings: "Instillinger" + templates: "Maler" preview_digest: "Forhåndsvis Oppsummering" sending_test: "Sender e-post for testing" error: "ERROR - %{server_error}" test_error: "Det oppsto et problem ved utsendelse av e-post for testing. Sjekk e-postinnstillinger nøye, sjekk at verten ikke blokkerer e-posttilkoblinger, og prøv igjen." sent: "Sendt" skipped: "Hoppet over" + bounced: "Tilbakesendt" + received: "Mottatt" + rejected: "Avvist" sent_at: "Sendt" time: "Tid" user: "Bruker" @@ -1860,19 +2578,37 @@ nb_NO: send_test: "Send e-post for testing" sent_test: "sendt!" delivery_method: "Leveringsmetode" + preview_digest_desc: "Forhåndsvis innholde i føljetong-e-postene som sendes til inaktive brukere." refresh: "Refresh" + send_digest_label: "Send dette resultatet til:" + send_digest: "Send" + sending_email: "Sender e-post…" format: "Format" html: "html" text: "tekst" last_seen_user: "Sist Sett Bruker:" + no_result: "Ingen resultater funnet for føljetong." reply_key: "Svar ID" skipped_reason: "Hopp over grunn" incoming_emails: from_address: "Fra" to_addresses: "Til" + cc_addresses: "CC" subject: "Emne" error: "Feil" + none: "Fant ingen innkommende e-poster." + modal: + title: "Innkommende e-postdetaljer" + error: "Feil" + headers: "Hoder" + subject: "Emne" + body: "Meldingstekst" + rejection_message: "Avvisningse-post" filters: + from_placeholder: "fra@eksempel.no" + to_placeholder: "til@eksempel.no" + cc_placeholder: "cc@eksempel.no" + subject_placeholder: "Emne…" error_placeholder: "Feil" logs: none: "Ingen logger funnet" @@ -1923,6 +2659,7 @@ nb_NO: change_site_setting: "endre nettstedsinnstilling" change_site_customization: "endre tilpasninger for nettstedet" delete_site_customization: "slett tilpasninger for nettstedet" + change_site_text: "endre sidens tekst" suspend_user: "bannlys bruker" unsuspend_user: "gjeninnsett bruker" grant_badge: "tildel merke" @@ -1933,8 +2670,21 @@ nb_NO: impersonate: "overta brukerkonto" anonymize_user: "anonymiser bruker" roll_up: "rull opp IP-blokker" + change_category_settings: "endre kategori-innstillinger" delete_category: "slett kategori" create_category: "opprett kategori" + block_user: "blokker bruker" + unblock_user: "fjern blokkering av bruker" + grant_admin: "innvilg admin" + revoke_admin: "tilbakekall admin" + grant_moderation: "innvilg moderering" + revoke_moderation: "tilbakekall moderering" + backup_operation: "sikkerhetskopier operasjon" + deleted_tag: "slettet stikkord" + renamed_tag: "stikkord med nytt navn" + revoke_email: "tilbakekall e-post" + lock_trust_level: "lås tillitsnivå" + unlock_trust_level: "lås opp tillitsnivå" screened_emails: title: "Kontrollerte e-poster" description: "Når noen forsøker å lage en ny konto, vil de følgende e-postadressene bli sjekket, og registreringen vil bli blokkert, eller en annen handling vil bli utført." @@ -1942,14 +2692,15 @@ nb_NO: actions: allow: "Tillat" screened_urls: - title: "Kontrollerte URLs" - description: "URLer listet her ble brukt i innlegg av brukere som har blitt identifisert som spammere." + title: "Kontrollerte URL-er" + description: "Disse URLene ble brukt i innlegg av brukere som har blitt identifisert som spammere." url: "URL" domain: "Domene" screened_ips: title: "Kontrollerte IPs" description: 'IP-adresser som blir fulgt. Benytt "Tillat" for å hvitliste IP-adresser.' delete_confirm: "Er du sikker på at du vil fjerne regelen for %{ip_address}?" + roll_up_confirm: "Er du sikker på at du vil rulle opp vanligvis undersøkte IP-adresser i delnett?" rolled_up_some_subnets: "Fullførte sammenslåingen av blokkerte IP-addresser til disse subnettene: %{subnets}." rolled_up_no_subnet: "Det var ingenting å slå sammen." actions: @@ -1998,8 +2749,11 @@ nb_NO: active: 'Aktive Brukere' new: 'Nye Brukere' pending: 'Brukere som venter på evaluering' - newuser: 'Brukere med tillitsnivå 0 (Ny Bruker)' - basic: 'Brukere med tillitsnivå 1 (Juniormedlem)' + newuser: 'Brukere på tillitsnivå 0 (Ny Bruker)' + basic: 'Brukere på tillitsnivå 1 (Juniormedlem)' + member: 'Brukere på tillitsnivå 2 (Medlem)' + regular: 'Brukere på tillitsnivå 3 (Aktivt medlem)' + leader: 'Brukere på tillitsnivå 4 (Leder)' staff: "Stab" admins: 'Admins' moderators: 'Moderatorer' @@ -2025,12 +2779,14 @@ nb_NO: suspend_reason: "Begrunnelse" suspended_by: "Bannlyst av" delete_all_posts: "Slett alle innlegg" + delete_all_posts_confirm_MF: "Du er i ferd med å slette {INNLEGG, flertall, ett {ett innlegg} andre {# innlegg}} og {INNLEGG, flertall, ett {ett emne} andre {# emner}}. Er du sikker?" suspend: "Bannlyst" unsuspend: "Gjeninnsett\"" suspended: "Bannlyst?" moderator: "Moderator?" admin: "Admin?" blocked: "Blokkert?" + staged: "Arrangert?" show_admin_profile: "Admin" edit_title: "Rediger Tittel" save_title: "Lagre Tittel" @@ -2040,7 +2796,7 @@ nb_NO: impersonate: 'Gi deg ut for å være en annen' ip_lookup: "IP Lookup" log_out: "Logg ut" - logged_out: "Brukeren ble logget ut med alle enheter" + logged_out: "Brukeren ble logget ut på alle enheter" revoke_admin: 'Tilbakedra Admin' grant_admin: 'Innvilg admin' revoke_moderation: 'Tilbakedra Moderering' @@ -2095,12 +2851,23 @@ nb_NO: deactivate_failed: "Det oppstod et problem ved deaktiveringen av den brukeren." unblock_failed: 'Det oppstod et problem med å oppheve blokkeringen av brukeren.' block_failed: 'Det oppstod et problem med blokkeringen av brukeren.' + block_confirm: 'Er du sikker på at du vil blokkere denne brukeren? Vedkommende vil ikke kunne opprette nye emner eller innlegg.' + block_accept: 'Ja, blokker denne brukeren' + bounce_score: "Antall tilbakesendinger" + reset_bounce_score: + label: "Tilbakestill" + title: "Sett antall tilbakesendinger tilbake til 0" deactivate_explanation: "En deaktivert bruker må re-validere sin e-post." suspended_explanation: "En bannlyst bruker kan ikke logge inn." block_explanation: "En blokkert bruker kan ikke poste eller starte emner." + staged_explanation: "En arrangert bruker kan bare skrive innlegg via e-post i gitte emner." + bounce_score_explanation: + none: "Ingen tilbakesendinger ble mottatt nylig fra den e-posten." + some: "Noen tilbakesendinger ble mottatt nylig fra den e-posten." + threshold_reached: "Mottok for mange tilbakesendinger fra den e-posten." trust_level_change_failed: "Det oppsto et problem ved endring av brukerens tillitsnivå." suspend_modal_title: "Bannlys bruker" - trust_level_2_users: "Brukere med tillitsnivå 2" + trust_level_2_users: "Brukere på tillitsnivå 2" trust_level_3_requirements: "Krav til tillitsnivå 3" trust_level_locked_tip: "tillitsnivå er låst, systemet vil ikke forfremme eller degradere bruker" trust_level_unlocked_tip: "tillitsnivå er ulåst, systemet kan forfremme eller degradere bruker" @@ -2108,6 +2875,9 @@ nb_NO: unlock_trust_level: "Lås opp tillitsnivå" tl3_requirements: title: "Krav til tillitsnivå 3" + table_title: + one: "Den siste dagen:" + other: "De siste %{count} dagene:" value_heading: "Verdi" requirement_heading: "Krav" visits: "Besøk" @@ -2163,12 +2933,24 @@ nb_NO: title: "Vis på offentlig profil?" enabled: "vises på profil" disabled: "vises ikke på profil" + show_on_user_card: + title: "Vis på brukerkort?" + enabled: "vist på brukerkort" + disabled: "ikke vist på brukerkort" field_types: text: 'Tekstfelt' confirm: 'Bekreftelse' dropdown: "Nedtrekk" site_text: + description: "Du kan skreddersy all tekst på forumet ditt. Start ved å søke nedenfor:" + search: "Søk etter tekst du ønsker å endre" title: 'Tekstinnhold' + edit: 'rediger' + revert: "Tilbakestill endringer" + revert_confirm: "Er du sikker på at du ønsker å tilbakestille dine endringer?" + go_back: "Tilbake til søk" + recommended: "Skreddersøm av følgende tekst for å kle dine behov anbefales:" + show_overriden: 'Bare vis overstyrte' site_settings: show_overriden: 'Bare vis overstyrte' title: 'Innstillinger' @@ -2177,13 +2959,13 @@ nb_NO: no_results: "Ingen treff funnet." clear_filter: "Tøm" add_url: "legg til URL" - add_host: "legg til host" + add_host: "legg til vert" categories: all_results: 'Alle' required: 'Påkrevd' basic: 'Grunnleggende oppsett' users: 'Brukere' - posting: 'Posting' + posting: 'Innlegg' email: 'E-post' files: 'Filer' trust: 'Tillitsnivå' @@ -2193,12 +2975,17 @@ nb_NO: spam: 'Spam' rate_limits: 'Frekvensbegresninger' developer: 'Utvikler' - embedding: "Embedding" + embedding: "Innebygging" legal: "Juridisk" + user_api: 'Bruker-API' uncategorized: 'Annet' backups: "Sikkerhetskopier" login: "Login" plugins: "Utvidelser" + user_preferences: "Brukerinnstillinger" + tags: "Stikkord" + search: "Søk" + groups: "Grupper" badges: title: Merker new_badge: Nytt merke @@ -2207,6 +2994,7 @@ nb_NO: badge: Merke display_name: Visningsnavn description: Beskrivelse + long_description: Helhetlig beskrivelse badge_type: Merketype badge_grouping: Gruppe badge_groupings: @@ -2246,6 +3034,7 @@ nb_NO: post_revision: "Når en bruker redigerer eller lager et nytt innlegg" trust_level_change: "Når bruker endrer tillitsnivå" user_change: "Når en bruker blir redigert eller registrert" + post_processed: "Etter at et innlegg er behandlet" preview: link_text: "Forhåndsvis tildelte merker" plan_text: "Forhåndsvis med plan for spørring" @@ -2254,7 +3043,11 @@ nb_NO: error_help: "Se følgende lenker for hjelp til spørringer for merker." bad_count_warning: header: "ADVARSEL!" - text: "Det er manglende grant samples. Dette skjer når badge søket returnerer bruker-IDer eller post IDer som ikke eksisterer. Dette kan føre til uventede resultater senere - vennligst dobbeltsjekk søket ditt." + text: "Det er manglende grant samples. Dette skjer når merke-søket returnerer bruker-IDer eller innleggs-ID-er som ikke eksisterer. Dette kan føre til uventede resultater senere - dobbeltsjekk søket ditt." + no_grant_count: "Ingen merker å tildele." + grant_count: + one: "Ett merke å tildele." + other: "%{count} merker å tildele." sample: "Eksempel:" grant: with: %{username} @@ -2268,6 +3061,32 @@ nb_NO: name: "Navn" image: "Bilde" delete_confirm: "Sikker på at du vil slette: %{name}: emoji?" + embedding: + get_started: "Hvis du vil bygge inn Discourse på en annen nettside, begynn med å legge til dens vert." + confirm_delete: "Er du sikker på at du vil slette den verten?" + sample: "Bruk følgende HTML-kode på siden din for å bygge inn Discourse-emner. Erstatt ERSTATT_MEG med kanonisk nettadresse fra siden du bygger den inn i." + title: "Innbygging" + host: "Tillatte verter" + path_whitelist: "Tillatte stier" + edit: "rediger" + category: "Legg til innlegg i kategori" + add_host: "Legg til vert" + settings: "Innbyggingsinnstillinger" + feed_settings: "Informasjonskanals-innstillinger" + feed_description: "Å tilby en RSS/ATOM-informasjonskanal for din side kan forbedre Discourse sin evne til å importere ditt innhold." + crawling_settings: "Innstillinger for søkeroboter" + crawling_description: "Når Discourse oppretter emner for dine innlegg, og ingen RSS/ATOM-informasjonskanal finnes, vil den prøve å tolke innholdet ditt fra din HTML-kode. Noen ganger kan det være utfordrende å hente ut innhold, så muligheten til å oppgi CSS-regler er der for å gjøre uthentingen enklere." + embed_by_username: "Brukernavn for emneopprettelse" + embed_post_limit: "Maksimalt antall innlegg som skal bygges inn" + embed_username_key_from_feed: "Nøkkel for å hente Discourse-brukernavn fra informasjonskanal" + embed_title_scrubber: "Regulære uttrykk brukt til å finne og korrigere feil i titler" + embed_truncate: "Forkort de innebygde innleggene" + embed_whitelist_selector: "CSS-velger for elementer som tillates i innbygginger" + embed_blacklist_selector: "CSS-velger for element som fjernes fra innbygginger" + embed_classname_whitelist: "Tillatte navn for CSS-klasser" + feed_polling_enabled: "Importer innlegg via RSS/ATOM" + feed_polling_url: "Nettadresse for RSS/ATOM-informasjonskanal å gjennomgangssøke" + save: "Lagre innbyggingsinnstillinger" permalink: title: "Permalenker" url: "URL" @@ -2283,3 +3102,22 @@ nb_NO: label: "Ny:" add: "Legg til" filter: "Søk (URL eller ekstern URL)" + wizard_js: + wizard: + done: "Ferdig" + back: "Forrige" + next: "Neste" + step: "%{current} av %{total}" + upload: "Last opp" + uploading: "Laster opp…" + quit: "Kanskje senere" + staff_count: + one: "Din gemenskap har ett stabsmedlem." + other: "Din gemenskap har %{count} stabsmedlemmer." + invites: + add_user: "legg til" + none_added: "Du har ikke invitert noen til staben. Er du sikker på at du vil fortsette?" + roles: + admin: "Administrator" + moderator: "Moderator" + regular: "Regelmessig bruker" diff --git a/config/locales/client.nl.yml b/config/locales/client.nl.yml index 34abe389b56..b628324cff3 100644 --- a/config/locales/client.nl.yml +++ b/config/locales/client.nl.yml @@ -321,18 +321,23 @@ nl: total_rows: one: "1 lid" other: "%{count} leden" + group_histories: + actions: + change_group_setting: "Wijzig groepsinstellingen" + add_user_to_group: "Gebruiker toevoegen" + remove_user_from_group: "Gebruiker verwijderen" + make_user_group_owner: "Maak eigenaar" + remove_user_as_group_owner: "Eigenaar intrekken" groups: - empty: - posts: "Er is geen enkel bericht door leden van deze groep." - members: "Er zijn geen leden in deze groep." - mentions: "Deze groep wordt niet benoemd." - messages: "Er zijn geen berichten voor deze groep." - topics: "Er is geen topic gemaakt door de leden van deze groep." + edit: + title: 'Wijzig groep' + full_name: 'Volledige Naam' + add_members: "Voeg leden toe" + delete_member_confirm: "Verwijder '%{username}' uit de '%{group}' groep?" add: "Voeg toe" selector_placeholder: "Voeg leden toe" owner: "eigenaar" visible: "Groep is zichtbaar voor alle gebruikers" - index: "Groepen" title: one: "groep" other: "groepen" @@ -428,6 +433,11 @@ nl: profile: "Profiel" mute: "Negeer" edit: "Wijzig voorkeuren" + download_archive: + button_text: "Download mijn berichten" + confirm: "Weet je zeker dat je je berichten wilt downloaden?" + success: "Downloaden is gestart, je krijgt een bericht als het proces is afgerond." + rate_limit_error: "Berichten kunnen slechts één keer per dag gedownload worden, probeer het morgen nog eens." new_private_message: "Nieuw bericht" private_message: "Bericht" private_messages: "Berichten" @@ -451,6 +461,7 @@ nl: each_browser_note: "Let op: Je moet deze optie instellen voor elke browser die je gebruikt." dismiss_notifications: "Markeer alles als gelezen" dismiss_notifications_tooltip: "Markeer alle ongelezen berichten als gelezen" + first_notification: "Je eerste notificatie! Selecteer het om te beginnen." disable_jump_reply: "Niet naar je nieuwe bericht gaan na reageren" dynamic_favicon: "Laat aantal nieuwe / bijgewerkte topics zien in favicon" external_links_in_new_tab: "Open alle externe links in een nieuw tabblad" @@ -473,6 +484,7 @@ nl: Genegeerde topics en categorieën zitten niet in deze e-mails. daily: "Verzend dagelijkse updates" individual: "Verstuur een e-mail voor elk nieuw bericht" + individual_no_echo: "Stuur een e-mail voor elk nieuw bericht behalve die van mijzelf." many_per_day: "Stuur mij een e-mail voor elk nieuw bericht (ongeveer {{dailyEmailEstimate}} per dag)" few_per_day: "Stuur mij een e-mail voor elk nieuw bericht (ongeveer 2 per dag)" tag_settings: "Tags" @@ -685,12 +697,12 @@ nl: account_age_days: "leeftijd van account in dagen" create: "Stuur een uitnodiging" generate_link: "Kopieer uitnodigingslink" + link_generated: "Uitnodigingslink is succesvol aangemaakt!" + valid_for: "De uitnodigingslink is alleen geldig voor dit e-mailadres: %{email}" bulk_invite: - none: "Je hebt nog niemand uitgenodigd. Je kan individueel uitnodigen of een groep mensen tegelijk door een groepsuitnodiging-bestand te uploaden" + none: "Je hebt nog niemand hier uitgenodigd. Je kunt individueel uitnodigen, of een groep mensen tegelijk uitnodigen door een CSV-bestand te uploaden." text: "Groepsuitnodiging via bestand" - uploading: "Uploaden..." success: "Het uploaden van het bestand is gelukt, je krijgt een notificatie via een bericht als het proces afgerond is." - error: "Het uploaden van '{{filename}}' is niet gelukt: {{message}}" password: title: "Wachtwoord" too_short: "Je wachtwoord is te kort." @@ -932,6 +944,9 @@ nl: group_mentioned: one: "Door het noemen van de groep {{group}}, sta je op het punt om 1 persoon op de hoogte te brengen – weet je dit zeker?" other: "Door het noemen van de groep {{group}}, sta je op het punt om {{count}} personen op de hoogte te brengen – weet je dit zeker?" + cannot_see_mention: + category: "Je hebt {{username}} genoemd, maar het lid zal geen notificatie krijgen omdat het geen toegang heeft tot deze categorie. Je zult {{username}} moeten toevoegen aan een groep die toegang heeft tot deze categorie." + private: "Je hebt {{username}} genoemd, maar het lid zal geen notificatie krijgen omdat het dit persoonlijke bericht niet kan zien. Je zult {{username}} moeten uitnodigen voor dit PB." duplicate_link: "Het ziet er naar uit dat je link naar {{domain}} al genoemd is in deze topic door @{{username}} in een bericht {{ago}} – weet je zeker dat je dit opnieuw wilt plaatsen?" error: title_missing: "Titel is verplicht" @@ -953,6 +968,7 @@ nl: title_placeholder: "Waar gaat de discussie over in één korte zin?" edit_reason_placeholder: "vanwaar de wijziging?" show_edit_reason: "(geef een reden)" + topic_featured_link_placeholder: "Plaats gegeven link met titel." reply_placeholder: "Typ hier. Gebruik Markdown, BBCode, of HTML om op te maken. Sleep of plak afbeeldingen." view_new_post: "Bekijk je nieuwe bericht." saving: "Opslaan" @@ -1138,6 +1154,8 @@ nl: topics: new_messages_marker: "laatste bezoek" bulk: + select_all: "Alles selecteren" + clear_all: "Alles wissen" unlist_topics: "Topics van lijst halen" reset_read: "markeer als ongelezen" delete: "Verwijder topics" @@ -1264,7 +1282,6 @@ nl: go_bottom: "onderkant" go: "ga" jump_bottom: "spring naar laatste bericht" - jump_prompt: "spring naar bericht" jump_prompt_long: "Naar welk bericht wil je springen?" jump_bottom_with_number: "spring naar bericht %{post_number}" total: totaal aantal berichten @@ -1458,6 +1475,7 @@ nl: post: reply: " {{replyAvatar}} {{usernameLink}}" reply_topic: " {{link}}" + quote_reply: "Citeer" edit: "Aan het bewerken {{link}} {{replyAvatar}} {{username}}" edit_reason: "Reden: " post_number: "bericht {{number}}" @@ -1495,7 +1513,6 @@ nl: file_too_large: "Sorry, dit bestand is te groot (maximumgrootte is {{max_size_kb}}kb). Misschien kun je dit bestand uploaden naar een cloudopslagdienst en de link er naar delen?" too_many_uploads: "Sorry, je kan maar één afbeelding tegelijk uploaden." too_many_dragged_and_dropped_files: "Sorry, je kan maar 10 bestanden tegelijk uploaden." - upload_not_authorized: "Sorry, je mag dat type bestand niet uploaden (toegestane extensies: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Sorry, nieuwe gebruikers mogen nog geen afbeeldingen uploaden." attachment_upload_not_allowed_for_new_user: "Sorry, nieuwe gebruikers mogen nog geen bestanden uploaden." attachment_download_requires_login: "Sorry, maar je moet ingelogd zijn om bijlages te downloaden." @@ -1695,6 +1712,7 @@ nl: email_in_disabled: "Het plaatsen van nieuwe topics via e-mail is uitgeschakeld in de webite-instellingen. Om het plaatsen van nieuwe topic via e-mail mogelijk te maken," email_in_disabled_click: 'schakel "e-mail in" instelling in.' suppress_from_homepage: "Negeer deze categorie op de homepage" + sort_order: "Standaardsortering:" allow_badges_label: "Laat badges toekennen voor deze categorie" edit_permissions: "Wijzig permissies" add_permission: "Nieuwe permissie" @@ -1720,6 +1738,11 @@ nl: muted: title: "Genegeerd" description: "Je zult niet op de hoogte worden gebracht over nieuwe topics in deze categorie en ze zullen niet verschijnen in Recent." + sort_options: + default: "standaard" + category: "Categorie" + sort_ascending: 'Oplopend' + sort_descending: 'Aflopend' flagging: title: 'Bedankt voor het beleefd houden van onze gemeenschap!' action: 'Meld bericht' @@ -1804,7 +1827,6 @@ nl: one: "weergave" other: "weergaves" replies: "Reacties" - views_long: "deze topic is {{number}} keer bekeken" activity: "Activiteit" likes: "Likes" likes_lowercase: @@ -2107,8 +2129,6 @@ nl: backups: "backups" traffic_short: "Verkeer" traffic: "Applicatie webverzoeken" - page_views: "API-verzoeken" - page_views_short: "API-verzoeken" show_traffic_report: "Laat gedetailleerd verkeersrapport zien" reports: today: "Vandaag" @@ -2198,15 +2218,12 @@ nl: refresh: "Herlaad" new: "Nieuw" selector_placeholder: "vul gebruikersnaam in" - name_placeholder: "Groepsnaam, geen spaties, zelfde regels als bij een gebruikersnaam" about: "Wijzig hier je deelname aan groepen en je namen" group_members: "Groepsleden" delete: "Verwijder" delete_confirm: "Verwijder deze groepen?" delete_failed: "Kan groep niet verwijderen. Als dit een automatische groep is, kan deze niet verwijderd worden." - delete_member_confirm: "Verwijder '%{username}' uit de '%{group'} groep?" delete_owner_confirm: "Verwijder eigenaarsprivileges van '% {username}'?" - name: "Naam" add: "Voeg toe" add_members: "Voeg leden toe" custom: "Aangepast" @@ -2223,14 +2240,6 @@ nl: add_owners: Eigenaren toevoegen incoming_email: "Aangepaste inkomende e-mailadressen " incoming_email_placeholder: "Voer je e-mailadres in" - flair_url: "Avatar flair afbeelding" - flair_url_placeholder: "(Optioneel) Afbeeldings-URL of Font Awesome class" - flair_bg_color: "Avatar flair achtergrondkleur" - flair_bg_color_placeholder: "(Optioneel) Hexadecimale kleurwaarde" - flair_color: "Avatar flair kleur" - flair_color_placeholder: "(Optioneel) Hexadecimale kleurwaarde" - flair_preview: "Voorbeeld" - flair_note: "Noot: Flair wordt alleen getoond voor de primaire groep van een gebruiker." api: generate_master: "Genereer Master API Key" none: "Er zijn geen actieve API keys" @@ -2262,7 +2271,6 @@ nl: warn_local_payload_url: "Zo te zien probeer je een webhook naar een lokale URL te laten wijzen. Gebeurtenissen die hierheen gestuurd worden kunnen mogelijk resulteren in onverwacht gedrag. Doorgaan?" secret_invalid: "Secret mag geen lege tekens bevatten." secret_too_short: "Secret moet uit minimaal 12 tekens bestaan." - secret_placeholder: "Een optionele waarde, gebruikt bij het maken van een handtekening" event_type_missing: "Stel minstens één event type in." content_type: "Type inhoud" secret: "Secret" @@ -2285,7 +2293,6 @@ nl: details: "Wanneer een nieuw bericht geplaatst, bewerkt, verwijderd of hersteld wordt." user_event: name: "Gebruikersgebeurtenis" - details: "Wanneer een gebruiker wordt aangemaakt of goedgekeurd." delivery_status: title: "Afleveringsstatus" inactive: "Inactief" @@ -2503,6 +2510,8 @@ nl: delivery_method: "Verzendmethode" preview_digest_desc: "Bekijk een voorbeeld van de digest e-mails die gestuurd worden naar inactieve leden." refresh: "Verniew" + send_digest_label: "Stuur dit resultaat naar:" + sending_email: "E-mail wordt verzonden..." format: "Formaat" html: "html" text: "text" @@ -2902,6 +2911,7 @@ nl: user_preferences: "Gebruikersvoorkeuren" tags: "Tags" search: "Zoek" + groups: "Groepen" badges: title: Badges new_badge: Nieuwe badge diff --git a/config/locales/client.pl_PL.yml b/config/locales/client.pl_PL.yml index 4f549eb45df..872692909e8 100644 --- a/config/locales/client.pl_PL.yml +++ b/config/locales/client.pl_PL.yml @@ -154,6 +154,7 @@ pl_PL: enabled: 'wylistowanie %{when}' disabled: 'odlistowanie %{when}' topic_admin_menu: "akcje administratora" + wizard_required: "Teraz czas na konfigurację twojego forum! Rozpocznij Kreator Konfiguracji!" emails_are_disabled: "Wysyłanie e-maili zostało globalnie wyłączone przez administrację. Powiadomienia e-mail nie będą dostarczane." bootstrap_mode_enabled: "Aby ułatwić uruchomienie Twojego nowego serwisu, znajdujesz się w trybie bootstrap. Wszyscy nowi użytkownicy otrzymają 1. poziom zaufania i będą otrzymywać codzienne podsumowania drogą mailową. To się zmieni, gdy liczba użytkowników przekroczy liczbę %{min_users}." bootstrap_mode_disabled: "Tryb Bootstrap zostanie wyłączony w ciągu najbliższych 24 godzin." @@ -346,22 +347,62 @@ pl_PL: one: "1 użytkownik" few: "%{count} użytkownicy" other: "%{count} użytkowników" + group_histories: + actions: + change_group_setting: "Zmień ustawienia grupy" + add_user_to_group: "Dodaj użytkownika" + remove_user_from_group: "Usuń użytkownika" + make_user_group_owner: "Nadaj prawa właściciela" + remove_user_as_group_owner: "Usuń prawa właściciela" groups: + logs: + title: "Logi" + when: "Kiedy" + action: "Akcja" + subject: "Kontekst" + details: "Szczegóły" + from: "Od" + to: "Do" + edit: + title: 'Edytuj grupę' + full_name: 'Pełna nazwa' + add_members: "Dodaj użytkowników" + delete_member_confirm: "Usuń '%{username}' z grupy '%{group}'?" + request_membership_pm: + title: "Prośba o członkostwo" + body: "Chciałbym(-am) poprosić o członkostwo w grupie @%{groupName}." + name_placeholder: "Nazwa grupy, bez spacji, takie same zasady jak przy nazwie użytkownika" + public: "Zezwalaj użytkownikom na zapraszanie/opuszczanie grupy (Grupa musi być widoczna)" empty: posts: "Członkowie tej grupy nie opublikowali żadnych postów." - members: "W tej grupie nie ma żadnych członków." - mentions: "Nie ma wzmianki w tej grupie." - messages: "Nie ma żadnej wiadomości dla tej grupy." - topics: "Członkowie tej grupy nie opublikowali żadnych postów." + members: "Nie ma użytkowników w tej grupie" + mentions: "Nie ma wspomnień tej grupy" + messages: "Nie ma wiadomości dla tej grupy" + topics: "Nie ma wątków stworzonych przez użytkowników tej grupy" + logs: "Nie ma logów dla tej grupy" add: "Dodaj" + join: "Dołącz do grupy" + leave: "Opuść grupę" + request: "Żądanie dołączenia do grupy" + automatic_group: Automatyczna grupa + closed_group: Zamknięta grupa + is_group_user: "Jesteś członkiem tej grupy" + allow_membership_requests: "Pozwalaj użytkownikom wysyłać prośby o członkostwo do właścicieli grup (Wymagane jest aby wszyscy mogli wspominać grupę)" + membership: "Członkostwo" + name: "Nazwa" + user_count: "Ilość użytkowników" + bio: "O grupie" selector_placeholder: "Dodaj członków" owner: "właściciel" visible: "Grupa jest widoczna dla wszystkich użytkowników" - index: "Grupy" + index: + title: "Grupy" + empty: "Nie ma widocznych grup" title: one: "grupa" few: "grupy" other: "grupy" + activity: "Aktywność" members: "Członkowie" topics: "Tematy" posts: "Wpisów" @@ -393,6 +434,12 @@ pl_PL: muted: title: "Wyciszony" description: "Nie otrzymasz powiadomień o nowych tematach w tej grupie." + flair_url: "Awatar " + flair_url_placeholder: "(Opconalne) Link do obrazka lub klasa Font Awesome" + flair_bg_color_placeholder: "(Opcjonalne) Kolor w formacie Hex" + flair_color_placeholder: "(Opcjonalne) Kolor w formacie Hex" + flair_preview_icon: "Podgląd ikony" + flair_preview_image: "Podgląd obrazka" user_action_groups: '1': "Przyznane lajki" '2': "Otrzymane lajki" @@ -456,6 +503,11 @@ pl_PL: profile: "Profil" mute: "Wycisz" edit: "Edytuj ustawienia" + download_archive: + button_text: "Pobierz moje wpisy" + confirm: "Czy na pewno chcesz pobrać swoje wszystkie wpisy?" + success: "Rozpoczęto eksport: otrzymasz wiadomość, gdy proces zostanie zakończony." + rate_limit_error: "Wpisy mogą być pobierane raz dziennie, spróbuj ponownie jutro." new_private_message: "Nowa wiadomość" private_message: "Wiadomość" private_messages: "Wiadomości" @@ -479,6 +531,7 @@ pl_PL: each_browser_note: "Uwaga: to ustawienie musisz zmienić w każdej przeglądarce której używasz." dismiss_notifications: "Odrzuć wszystkie" dismiss_notifications_tooltip: "Oznacz wszystkie powiadomienia jako przeczytane" + first_notification: "Twoje pierwsze powiadomienie! Kliknij aby zacząć." disable_jump_reply: "Po odpowiedzi nie przechodź do nowego wpisu" dynamic_favicon: "Pokazuj licznik powiadomień na karcie jako dynamiczny favicon" external_links_in_new_tab: "Otwieraj wszystkie zewnętrzne odnośniki w nowej karcie" @@ -496,13 +549,18 @@ pl_PL: mailing_list_mode: label: "Tryb listy mailingowej" enabled: "Włącz tryb listy mailingowej" + instructions: | + To ustawienie nadpisuje podsumowanie aktywności.
    daily: "Wyślij codzienne aktualizacje" individual: "Wyślij e-mail dla każdego nowego postu" + individual_no_echo: "Wysyłaj emaile dla każdego nowego postu oprócz mojego" many_per_day: "Wyślij mi e-mail dla każdego nowego posta (około {{dailyEmailEstimate}} na dzień)" few_per_day: "Wyślij mi e-mail dla każdego nowego posta (około 2 dziennie)" tag_settings: "Tagi" watched_tags: "Obserwowane" + watched_tags_instructions: "Będziesz automatycznie śledzić wszystkie nowe tematy z tymi tagami, będziesz otrzymywać powiadomienie o każdym nowym wpisie i temacie, a liczba nieprzeczytanych i nowych wpisów będzie wyświetlana obok tytułów na liście tematów. " tracked_tags: "Śledzone" + tracked_tags_instructions: "Będziesz automatycznie śledzić wszystkie nowe tematy z tymi tagami. Licznik nowych wpisów pojawi się obok tytułu na liście tematów." muted_tags: "Wyciszone" watched_categories: "Obserwowane" tracked_categories: "Śledzone" @@ -615,6 +673,7 @@ pl_PL: title: "Język interfejsu" instructions: "Język interfejsu użytkownika. Zmieni się, gdy odświeżysz stronę." default: "(domyślny)" + any: "każdy" password_confirmation: title: "Powtórz hasło" last_posted: "Ostatni wpis" @@ -699,12 +758,10 @@ pl_PL: account_age_days: "Wiek konta w dniach" create: "Wyślij zaproszenie" generate_link: "Skopiuj link z zaproszeniem" + link_generated: "Link z zaproszenie został poprawnie wygenerowany!" bulk_invite: - none: "Jeszcze nikogo nie zaproszono. Możesz wysłać pojedyncze zaproszenie lub zaprosić wiele osób na raz wysyłając odpowiedni plik." text: "Zaproszenia hurtowe z pliku" - uploading: "Wysyłanie…" success: "Plik został przesłany pomyślnie: otrzymasz prywatną wiadomość, gdy proces zostanie zakończony." - error: "Podczas przesyłania wystąpił błąd '{{filename}}': {{message}}" password: title: "Hasło" too_short: "Hasło jest za krótkie." @@ -725,6 +782,14 @@ pl_PL: one: "utworzono post" few: "utworzonych postów" other: "utworzono posty" + likes_given: + one: "dano" + few: "dano" + other: "dano" + likes_received: + one: "otrzymano" + few: "otrzymano" + other: "otrzymano" days_visited: one: "dzień odwiedzin" few: "dni odwiedzin" @@ -802,6 +867,7 @@ pl_PL: too_few_posts_notice: "Pora rozruszać dyskusję! Aktualnie istnieje %{currentPosts} / %{requiredPosts} wpisów. Odwiedzający potrzebują więcej tematów i konwersacji do czytania i pisania na ich temat." learn_more: "dowiedz się więcej…" all_time: 'łącznie' + all_time_desc: 'łącznie utworzonych tematów' year: 'rok' year_desc: 'tematy dodane w ciągu ostatnich 365 dni' month: 'miesiąc' @@ -961,8 +1027,10 @@ pl_PL: show_preview: 'pokaż podgląd »' hide_preview: '« schowaj podgląd' quote_post_title: "Cytuj cały wpis" + bold_label: "Pogrubienie" bold_title: "Pogrubienie" bold_text: "pogrubiony tekst" + italic_label: "Kursywa" italic_title: "Wyróżnienie" italic_text: "wyróżniony tekst" link_title: "Odnośnik" @@ -980,6 +1048,7 @@ pl_PL: olist_title: "Lista numerowana" ulist_title: "Lista wypunktowana" list_item: "Element listy" + heading_label: "Nagłówek" heading_title: "Nagłówek" heading_text: "Nagłówek" hr_title: "Pozioma linia" @@ -990,6 +1059,7 @@ pl_PL: cant_send_pm: "Przepraszamy, niestety nie możesz wysłać prywatnej wiadomości do %{username}." yourself_confirm: title: "Nie zapomniałeś dodać odbiorców?" + body: "Aktualnie ta wiadomość będzie wysłana tylko do ciebie!" admin_options_title: "Opcjonalne ustawienia obsługi dla tego tematu" auto_close: label: "Automatycznie zamykaj tematy po:" @@ -1013,6 +1083,7 @@ pl_PL: posted: "

    {{username}} {{description}}

    " edited: "

    {{username}} {{description}}

    " liked: "

    {{username}} {{description}}

    " + liked_2: "

    {{username}} {{description}}

    " liked_many: one: "

    {{username}}, {{username2}} oraz 1 inna osoba {{description}}

    " few: "

    {{username}}, {{username2}} i {{count}} innych osób {{description}}

    " @@ -1087,13 +1158,48 @@ pl_PL: category: "Szukaj w kategorii #{{category}}" topic: "Szukaj w tym temacie" private_messages: "Wyszukiwanie wiadomości" + advanced: + title: Zaawansowane wyszukiwanie + posted_by: + label: Wysłane przez + in_category: + label: W kategorii + in_group: + label: W grupie + with_badge: + label: Z odnaką + with_tags: + label: Z tagami + filters: + likes: Lubię + watching: Obserwuję + tracking: Śledzę + private: są w moich wiadomościach + bookmarks: Dodałeś do zakładek + pinned: są przypięte + unpinned: są nie przypięte + wiki: są postami wiki + statuses: + label: Tematy gdzie + open: są otwarte + closed: są zamknięte + archived: są archiwizowane + noreplies: ma zero odpowiedzi + single_user: zawierają użytkownika + post: + time: + before: przed + after: po hamburger_menu: "przejdź do innej listy lub kategorii" new_item: "nowy" go_back: 'wróć' not_logged_in_user: 'strona użytkownika z podsumowaniem bieżących działań i ustawień' current_user: 'idź do swojej strony użytkowanika' topics: + new_messages_marker: "ostatnia wizyta" bulk: + select_all: "Zaznacz wszystkie" + clear_all: "Wyczyść wszystko" unlist_topics: "Ukryj tematy" reset_read: "Wyzeruj przeczytane" delete: "Usuń tematy" @@ -1198,6 +1304,7 @@ pl_PL: toggle_information: "przełącz szczegóły tematu" read_more_in_category: "Chcesz przeczytać więcej? Przeglądaj inne tematy w {{catLink}} lub {{latestLink}}." read_more: "Chcesz przeczytać więcej? {{catLink}} lub {{latestLink}}." + read_more_MF: "Masz do zobaczenia { UNREAD, plural, =0 {} one { is 1 nieprzeczytany } other { are # nieprzeczytanych } } { NEW, plural, =0 {} one { {BOTH, select, true{and } false {is } other{}} 1 nowy temat} other { {BOTH, select, true{and } false {are } other{}} # nowych tematów} }, lub {CATEGORY, select, true {przeglądaj inne tematy w {catLink}} false {{latestLink}} other {}}" browse_all_categories: Przeglądaj wszystkie kategorie view_latest_topics: pokaż aktualne tematy suggest_create_topic: Może rozpoczniesz temat? @@ -1219,7 +1326,7 @@ pl_PL: go_bottom: "koniec" go: "idź" jump_bottom: "Przejdź na koniec" - jump_prompt: "przejdź do postu" + jump_prompt: "skocz do..." jump_bottom_with_number: "przeskocz do wpisu %{post_number}" total: w sumie wpisów current: obecny wpis @@ -1294,6 +1401,8 @@ pl_PL: share: title: 'Udostępnij' help: 'udostępnij odnośnik do tego tematu' + print: + title: 'Drukuj' flag_topic: title: 'Zgłoś' help: 'zgłoś ten temat, aby zwrócić uwagę moderacji lub wyślij powiadomienie o nim' @@ -1410,6 +1519,7 @@ pl_PL: post: reply: " {{replyAvatar}} {{usernameLink}}" reply_topic: " {{link}}" + quote_reply: "Cytuj" edit: "Edycja {{link}} {{replyAvatar}} {{username}}" edit_reason: "Powód" post_number: "wpis {{number}}" @@ -1452,7 +1562,6 @@ pl_PL: upload: "Przepraszamy, wystąpił błąd podczas wczytywania Twojego pliku. Proszę, spróbuj ponownie." too_many_uploads: "Przepraszamy, ale możesz wgrać tylko jeden plik naraz." too_many_dragged_and_dropped_files: "Przepraszamy, ale możesz wgrać tylko 10 plików naraz." - upload_not_authorized: "Przepraszamy, ale plik który chcesz wgrać jest niedozwolony (dozwolone rozszerzenia: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Przepraszamy, ale nowi użytkownicy nie mogą wgrywać obrazów." attachment_upload_not_allowed_for_new_user: "Przepraszamy, ale nowi użytkownicy nie mogą wgrywać załączników." attachment_download_requires_login: "Przepraszamy, musisz się zalogować, aby pobierać załączniki." @@ -1669,6 +1778,7 @@ pl_PL: email_in_disabled: "Tworzenie nowych tematów emailem jest wyłączone w ustawieniach serwisu. " email_in_disabled_click: 'Kliknij tu, aby włączyć.' suppress_from_homepage: "Nie wyświetlaj tej kategorii na stronie głównej." + sort_order: "Domyślnie sortuj:" allow_badges_label: "Włącz przyznawanie odznak na podstawie aktywności w tej kategorii" edit_permissions: "Edytuj uprawnienia" add_permission: "Dodaj uprawnienie" @@ -1685,12 +1795,23 @@ pl_PL: title: "Oglądasz pierwszy post" tracking: title: "Śledzona" + description: "Będziesz automatycznie śledzić wszystkie nowe tematy w tych kategoriach. Dostaniesz powiadomienie, gdy ktoś ci odpowie lub wspomni twoją @nazwę. Zobaczysz również liczbę odpowiedzi." regular: title: "Normalny" description: "Dostaniesz powiadomienie jedynie, gdy ktoś wspomni twoją @nazwę lub odpowie na twój wpis." muted: title: "Wyciszone" description: "Nie otrzymasz powiadomień o nowych tematach w tych kategoriach. Nie pojawią się na liście nieprzeczytanych." + sort_options: + default: "domyślny" + likes: "Polubienia" + views: "Odsłony" + posts: "Posty" + activity: "Aktywność" + category: "Kategoria" + created: "Utworzony" + sort_ascending: 'Rosnąco' + sort_descending: 'Malejąco' flagging: title: 'Dziękujemy za pomoc w utrzymaniu porządku w naszej społeczności!' action: 'Oflaguj wpis' @@ -1704,6 +1825,7 @@ pl_PL: submit_tooltip: "Zapisz prywatną flagę." take_action_tooltip: "Nie czekaj, aż wpis zostanie zgłoszony przez innych, natychmiast oflaguj do działania . " cant: "Przepraszamy, nie możesz oflagować teraz tego wpisu." + notify_staff: 'Powiadom zespół wiadomością prywatną' formatted_name: off_topic: "Jest nie-na-temat" inappropriate: "Jest nieodpowiednie" @@ -1754,7 +1876,6 @@ pl_PL: few: "odsłony" other: "odsłon" replies: "Odpowiedzi" - views_long: "ten temat był oglądany {number}} razy" activity: "Aktywność" likes: "Lajki" likes_lowercase: @@ -1871,6 +1992,7 @@ pl_PL: new: 'g, n Nowe' unread: 'g, u Nieprzeczytane' categories: 'g, c Kategorie' + top: 'g, t Góra' bookmarks: 'g, b Zakładki' profile: 'g, p Profil' messages: 'g, m Wiadomości' @@ -1888,6 +2010,8 @@ pl_PL: user_profile_menu: 'p Otwórz menu użytkownika' show_incoming_updated_topics: '. Pokaż zaktualizowane tematy' search: '/ Wyszukaj' + help: '? Pokaż skróty klawiszowe' + dismiss_new_posts: 'x, r wyczyść listę wpisów' dismiss_topics: 'x, t wyczyść listę tematów' log_out: 'shift+z shift+z Wyloguj' actions: @@ -1896,6 +2020,7 @@ pl_PL: pin_unpin_topic: 'shift+p przypnij/odepnij temat' share_topic: 'shift+s Udostępnij temat' share_post: 's Udostępnij post' + reply_as_new_topic: 't Odpowiedz w nowym temacie' reply_topic: 'shift+r Odpowiedz w temacie' reply_post: 'r Odpowiedz na post' quote_post: 'q cytuj post' @@ -1905,6 +2030,7 @@ pl_PL: edit: 'e Edytuj post' delete: 'd Usuń post' mark_tracking: 'm, t śledź temat' + mark_watching: 'm, w Obserwuj wątek' badges: earned_n_times: one: "Otrzymano tą odznakę 1 raz" @@ -1940,6 +2066,15 @@ pl_PL: name: Inne posting: name: Pisanie + google_search: | +

    Szukaj z Google

    +

    +

    +

    tagging: all_tags: "Wszystkie tagi" selector_all_tags: "wszystkie tagi" @@ -1982,6 +2117,7 @@ pl_PL: new_name: "Nowa grupa tagów" save: "Zapisz" delete: "Usuń" + confirm_delete: "Czy na pewno chcesz usunąć ten tag grupy?" topics: none: unread: "Nie masz nieprzeczytanych tematów." @@ -2041,8 +2177,6 @@ pl_PL: backups: "kopie zapasowe" traffic_short: "Ruch" traffic: "Zapytania do aplikacji" - page_views: "Zapytania API" - page_views_short: "Zapytania API" show_traffic_report: "Pokaż szczegółowy raport ruchu" reports: today: "Dzisiaj" @@ -2137,15 +2271,12 @@ pl_PL: refresh: "Odśwież" new: "Nowa" selector_placeholder: "nazwa użytkownika" - name_placeholder: "Nazwa grupy: bez spacji, takie same zasady jak przy nazwie użytkownika" about: "Tu możesz edytować przypisania do grup oraz ich nazwy" group_members: "Członkowie grupy" delete: "Usuń" delete_confirm: "Usunąć tę grupę?" delete_failed: "Nie można usunąć grupy. Jeżeli jest to grupa automatyczna, nie może zostać zniszczona." - delete_member_confirm: "Usunąć '%{username}' z grupy '%{group}' ?" delete_owner_confirm: "Usunąć status właściciela dla '%{username}'?" - name: "Nazwa" add: "Dodaj" add_members: "Dodaj członków" custom: "Niestandardowe" @@ -2162,7 +2293,6 @@ pl_PL: add_owners: Dodaj właścicieli incoming_email: "Niestandardowy adres poczty przychodzącej" incoming_email_placeholder: "podaj adres e-mail" - flair_preview: "Podgląd" api: generate_master: "Generuj Master API Key" none: "Nie ma teraz aktywnych kluczy API." @@ -2177,6 +2307,34 @@ pl_PL: 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." + web_hooks: + new: "Nowy webhook" + create: "Stwórz" + save: "Zapisz" + destroy: "Usuń" + description: "Opis" + go_back: "Powrót do listy" + payload_url_placeholder: "https://example.com/postreceive" + wildcard_event: "Wysyłaj mi wszystko." + active: "Aktywny" + delete_confirm: "Usunąć ten webhook?" + topic_event: + details: "Kiedy pojawia się nowy temat, poprawiony, zmieniony lub usunięty." + delivery_status: + title: "Status dostarczenia" + inactive: "Nieaktywny" + failed: "Niepowodzenie" + events: + request: "Żądanie" + response: "Odpowiedź" + headers: "Nagłówki" + go_list: "Przejdź do listy" + go_events: "Przejdź do wydarzeń" + ping: "Ping" + event_id: "ID" + timestamp: "Utworzono" + completion: "Czas wykonania" + actions: "Akcje" plugins: title: "Wtyczki" installed: "Zainstalowane wtyczki" @@ -2341,6 +2499,7 @@ pl_PL: name: 'polubienie' description: "Kolor przycisku lajkuj" email: + title: "Emaile" settings: "Ustawienia" templates: "Szablony" preview_digest: "Pokaż zestawienie aktywności" @@ -2363,6 +2522,9 @@ pl_PL: delivery_method: "Metoda Dostarczenia" preview_digest_desc: "Podgląd treści zestawienia wysyłanego e-mailem do nieaktywnych użytkowników." refresh: "Odśwież" + send_digest_label: "Wyślij ten wynik do:" + send_digest: "Wyślij" + sending_email: "Wysyłanie wiadomości e-mail ..." format: "Format" html: "html" text: "text" @@ -2372,8 +2534,10 @@ pl_PL: incoming_emails: from_address: "Od" to_addresses: "Do" + cc_addresses: "Cc" subject: "Temat" error: "Błąd" + none: "Brak przychodzących emaili." modal: title: "Szczegóły przychodzącego emaila" error: "Błąd" @@ -2451,8 +2615,12 @@ pl_PL: create_category: "Dodaj nową kategorię" block_user: "zablokuj użytkownika" unblock_user: "odblokuj użytkownika" + grant_admin: "nadaj prawa admina" + revoke_admin: "odbierz prawa admina" + revoke_moderation: "cofnąć moderację" backup_operation: "operacja tworzenia kopii zapasowej" deleted_tag: "usunięty tag" + revoke_email: "cofnąć e-mail" screened_emails: title: "Ekranowane emaile" description: "Kiedy ktoś próbuje założyć nowe konto, jego adres email zostaje sprawdzony i rejestracja zostaje zablokowana, lub inna akcja jest podejmowana." @@ -2596,7 +2764,7 @@ pl_PL: anonymize_yes: "Tak, anonimizuj to konto." anonymize_failed: "Wystąpił problem podczas anonimizacji konta." delete: "Usuń użytkownika" - delete_forbidden_because_staff: "Admini i moderatorzy nie mogą zostać usunięci." + delete_forbidden_because_staff: "Administratorzy i moderatorzy nie mogą zostać usunięci." delete_posts_forbidden_because_staff: "Nie można usunąć wszystkich wpisów administratorów i moderatorów." delete_forbidden: one: "Użytkownik nie może zostać usunięty jeśli posiada wpisy. Usuń wszystkie jego wpisy przed usunięciem użytkownika. (Nie można usunąć wpisów starszych niż %{count} dzień.)" @@ -2625,6 +2793,7 @@ pl_PL: unblock_failed: 'Wystąpił problem podczaj odblokowania użytkownika.' block_failed: 'Wystąpił problem podczas blokowania użytkownika.' block_accept: 'Tak, zablokuj tego użytkownika' + bounce_score: "Wskaźnik odbić" reset_bounce_score: label: "Przywróć" deactivate_explanation: "Wymusza ponowne potwierdzenie adresu email tego konta." @@ -2750,6 +2919,7 @@ pl_PL: user_preferences: "Ustawienia użytk." tags: "Tagi" search: "Wyszukaj" + groups: "Grupy" badges: title: Odznaki new_badge: Nowa odznaka @@ -2864,3 +3034,23 @@ pl_PL: label: "Nowy:" add: "Dodaj" filter: "Wyszukaj (URL or zewnętrzny URL)" + wizard_js: + wizard: + done: "Zrobione" + back: "Poprzednia" + next: "Następna" + step: "%{current} z %{total}" + upload: "Wyślij" + uploading: "Wysyłanie…" + quit: "Może później" + staff_count: + one: "W twojej społeczności jest 1 pracownik." + few: "W twojej społeczności jest %{count} pracowników." + other: "W twojej społeczności jest %{count} pracowników." + invites: + add_user: "dodaj" + none_added: "Nie zaprosiłeś nikogo. Czy na pewno chcesz kontynuować?" + roles: + admin: "Administratorzy" + moderator: "Moderatoratorzy" + regular: "Zwykli użytkownicy" diff --git a/config/locales/client.pt.yml b/config/locales/client.pt.yml index e8693841bb3..c65fe3099f2 100644 --- a/config/locales/client.pt.yml +++ b/config/locales/client.pt.yml @@ -321,18 +321,37 @@ pt: total_rows: one: "1 utilizador" other: "%{count} utilizadores" + group_histories: + actions: + change_group_setting: "Mudar configuração do grupo" + add_user_to_group: "Adicionar utilizador" + remove_user_from_group: "Remover utilizador" + make_user_group_owner: "Tornar dono" + remove_user_as_group_owner: "Remover dono" groups: - empty: - posts: "Não há nenhuma publicação feita por membros deste grupo." - members: "Não há nenhum membro neste grupo." - mentions: "Não há nenhuma menção deste grupo." - messages: "Não há nenhuma mensagem para este grupo." - topics: "Não há nenhum tópico feito por membros deste grupo." + logs: + title: "Registos" + when: "Quando" + action: "Ação" + acting_user: "Utlizador ator" + target_user: "Utilizador alvo" + subject: "Assunto" + details: "Detalhes" + from: "De" + to: "Para" + edit: + title: 'Editar Grupo' + full_name: 'Nome Completo' + add_members: "Adicionar membros" + delete_member_confirm: "Remover '%{username}' do grupo '%{group}'?" + request_membership_pm: + title: "Pedido de Adesão" + body: "Eu gostaria de aderir a @%{groupName}." + name_placeholder: "Nome do grupo, sem espaços, com as mesmas regras do nome de utilizador" add: "Adicionar" selector_placeholder: "Adicionar membros" owner: "proprietário" visible: "O grupo é visível para todos os utilizadores" - index: "Grupos" title: one: "grupo" other: "grupos" @@ -695,11 +714,9 @@ pt: link_generated: "Ligação de convite gerada com sucesso!" valid_for: "Ligação de convite é válida apenas para este endereço de email: %{email}" bulk_invite: - none: "Ainda não convidou ninguém. Pode enviar convites individuais, ou convidar um grupo de pessoas de uma única vez carregando um ficheiro com convites em massa." + none: "Ainda não convidou ninguém. Pode enviar convites individuais, ou convidar um grupo de pessoas de uma única vez carregando um ficheiro CSV." text: "Convite em massa a partir de ficheiro" - uploading: "A carregar…" success: "Ficheiro carregado corretamente, será notificado via mensagem assim que o processo esteja concluído." - error: "Erro de carregamento '{{filename}}': {{message}}" password: title: "Palavra-passe" too_short: "A sua palavra-passe é muito curta." @@ -966,6 +983,7 @@ pt: title_placeholder: "Numa breve frase, de que se trata esta discussão?" edit_reason_placeholder: "Porque está a editar?" show_edit_reason: "(adicione a razão para a edição)" + topic_featured_link_placeholder: "Inserir ligação mostrada com o título." reply_placeholder: "Digite aqui. Utilize Markdown, BBCode, ou HTML para formatar. Arraste ou cole imagens." view_new_post: "Ver a sua nova publicação" saving: "A Guardar" @@ -1279,7 +1297,6 @@ pt: go_bottom: "fim" go: "ir" jump_bottom: "ir para a última publicação" - jump_prompt: "ir para publicação" jump_prompt_long: "Para que publicação gostaria de ir?" jump_bottom_with_number: "ir para a publicação %{post_number}" total: total de publicações @@ -1511,7 +1528,6 @@ pt: file_too_large: "Lamentamos mas esse ficheiro é demasiado grande (o tamanho máximo é de {{max_size_kb}}kb). Porque não carregar o seu ficheiro grande para um serviço de partilha na nuvem e depois partilhar o link?" too_many_uploads: "Pedimos desculpa, só pode carregar um ficheiro de cada vez." too_many_dragged_and_dropped_files: "Lamentamos mas só pode carregar 10 ficheiros de cada vez." - upload_not_authorized: "Pedimos desculpa, o tipo de ficheiro que está a carregar não está autorizado (extensões autorizadas: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Pedimos desculpa, os novos utilizadores não podem carregar imagens." attachment_upload_not_allowed_for_new_user: "Pedimos desculpa, os novos utilizadores não podem carregar anexos." attachment_download_requires_login: "Pedimos desculpa, os novos utilizadores não podem carregar anexos." @@ -1833,7 +1849,6 @@ pt: one: "vista" other: "vistas" replies: "Respostas" - views_long: "este tópico foi visto {{number}} vezes" activity: "Atividade" likes: "Gostos" likes_lowercase: @@ -2138,8 +2153,6 @@ pt: backups: "fazer cópias de segurança" traffic_short: "Tráfego" traffic: "Pedidos de aplicação web" - page_views: "Pedidos API" - page_views_short: "Pedidos API" show_traffic_report: "Mostrar Relatório Detalhado do Tráfego" reports: today: "Hoje" @@ -2229,15 +2242,12 @@ pt: refresh: "Atualizar" new: "Novo" selector_placeholder: "insira o nome de utilizador" - name_placeholder: "Nome do grupo, sem espaços, com as mesmas regras do nome de utilizador" about: "Editar aqui a sua participação e nomes no grupo" group_members: "Membros do grupo" delete: "Eliminar" delete_confirm: "Eliminar este grupo?" delete_failed: "Impossível eliminar grupo. Se se trata de um grupo automático, não pode ser eliminado." - delete_member_confirm: "Remova o '%{username}' do grupo '%{group}'?" delete_owner_confirm: "Remover privilégios do proprietário para '%{username}'?" - name: "Nome" add: "Adicionar" add_members: "Adicionar membros" custom: "Personalizar" @@ -2254,14 +2264,6 @@ pt: add_owners: Adicionar proprietários incoming_email: "Endereço de email de entrada personalizado" incoming_email_placeholder: "introduza o endereço de email" - flair_url: "Imagem da Marca de Avatar" - flair_url_placeholder: "(Opcional) URL da Imagem ou classe de Font Awesome" - flair_bg_color: "Cor de fundo da Marca de Avatar" - flair_bg_color_placeholder: "(Opcional) Valor Hexadecimal da cor" - flair_color: "Cor da Marca de Avatar" - flair_color_placeholder: "(Opcional) Valor Hexadecimal da cor" - flair_preview: "Pré-visualização" - flair_note: "Nota: a Marca de um utilizador só aparecerá para o seu grupo primário." api: generate_master: "Gerar Chave Mestra API " none: "Não existem chaves API ativas neste momento." @@ -2293,7 +2295,6 @@ pt: warn_local_payload_url: "Parece que está a tentar configurar um webhook para um url local. Eventos entregues num endereço local poderão causar efeitos secundários ou comportamentos inesperados. Continuar?" secret_invalid: "O segredo não pode ter espaços." secret_too_short: "O segredo tem de ter pelo menos 12 caracteres." - secret_placeholder: "Um texto adicional, usado para gerar uma assinatura" event_type_missing: "Tem de configurar pelo menos um tipo de evento." content_type: "Tipo de Conteúdo" secret: "Segredo" @@ -2316,7 +2317,6 @@ pt: details: "Quando uma resposta é nova, editada, apagada ou recuperada. " user_event: name: "Evento de Utilizador" - details: "Quando um utilizador é criado ou aprovado." delivery_status: title: "Estado de Entrega" inactive: "Inativo" diff --git a/config/locales/client.pt_BR.yml b/config/locales/client.pt_BR.yml index 1fe941ca2a6..3b9bd220d38 100644 --- a/config/locales/client.pt_BR.yml +++ b/config/locales/client.pt_BR.yml @@ -321,18 +321,15 @@ pt_BR: total_rows: one: "1 usuário" other: "%{count} usuários" + group_histories: + actions: + add_user_to_group: "Adicionar usuário" + remove_user_from_group: "Remover usuário" groups: - empty: - posts: "Não há postagens por membros deste grupo." - members: "Não há membros neste grupo." - mentions: "Não há menção a este grupo." - messages: "Não há mensagens para este grupo." - topics: "Não há topicos por membros deste grupo." add: "Adicionar" selector_placeholder: "Adicionar membros" owner: "proprietário" visible: "Grupo é visível para todos os usuários" - index: "Grupos" title: one: "grupo" other: "grupos" @@ -428,6 +425,10 @@ pt_BR: profile: "Perfil" mute: "Silenciar" edit: "Editar Preferências" + download_archive: + button_text: "Baixar Minhas Publicações" + confirm: "Você tem certeza de que quer baixar as suas publicações?" + rate_limit_error: "Publicações podem ser baixadas somente uma vez por dia, por favor tente novamente amanhã." new_private_message: "Nova Mensagem" private_message: "Mensagem" private_messages: "Mensagens" @@ -690,11 +691,8 @@ pt_BR: link_generated: "Link de convite gerado com sucesso!" valid_for: "Link de convite é válido apenas para esse endereço de email: %{email}" bulk_invite: - none: "Você ainda não convidou ninguém. Você pode enviar convites individuais, ou enviar vários de uma vez através da ferramenta de enviar em massa." text: "Convidar em massa a partir de arquivo" - uploading: "Subindo..." success: "Arquivo enviado com sucesso, você será notificado por mensagem quando o processo estiver completo." - error: "Houve um erro ao enviar '{{filename}}': {{message}}" password: title: "Senha" too_short: "A sua senha é muito curta." @@ -961,6 +959,7 @@ pt_BR: title_placeholder: "Sobre o que é esta discussão em uma pequena frase?" edit_reason_placeholder: "por que você está editando?" show_edit_reason: "(adicione motivo da edição)" + topic_featured_link_placeholder: "Entre com o link mostrado no título." reply_placeholder: "Escreva aqui. Use Markdown, BBCode ou HTML para formatar. Arraste ou cole uma imagens." view_new_post: "Ver sua nova resposta." saving: "Salvando" @@ -1120,6 +1119,7 @@ pt_BR: tracking: Eu estou rastreando private: estão em minhas mensagens bookmarks: Eu marquei + first: são a primeira publicação pinned: está fixado unpinned: não está fixado statuses: @@ -1143,6 +1143,7 @@ pt_BR: topics: new_messages_marker: "última visita" bulk: + select_all: "Selecionar Tudo" unlist_topics: "Tópicos Não Listados" reset_read: "Redefinir Lido" delete: "Apagar Tópicos" @@ -1269,7 +1270,6 @@ pt_BR: go_bottom: "último" go: "ir" jump_bottom: "ir para a última mensagem" - jump_prompt: "ir para a mensagem" jump_prompt_long: "Gostaria de ir para qual mensagem?" jump_bottom_with_number: "ir para a mensagem %{post_number}" total: total de mensagens @@ -1463,6 +1463,7 @@ pt_BR: post: reply: " {{replyAvatar}} {{usernameLink}}" reply_topic: " {{link}}" + quote_reply: "Citação" edit: "Em resposta a {{link}} por {{replyAvatar}} {{username}}" edit_reason: "Motivo:" post_number: "resposta {{number}}" @@ -1500,7 +1501,6 @@ pt_BR: file_too_large: "Desculpe, o arquivo que você está tentando enviar é muito grande (o tamanho máximo permitido é {{max_size_kb}}kb). Que tal enviar o seu arquivo grande para um serviço de hospedagem na nuvem e depois compartilhar o link?" too_many_uploads: "Desculpe, você pode enviar apenas um arquivos por vez." too_many_dragged_and_dropped_files: "Desculpe, você só pode subir até 10 arquivos de cada vez." - upload_not_authorized: "Desculpe, o tipo de arquivo que você está tentando enviar não está autorizado (extensões autorizadas: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Desculpe, novos usuário não podem enviar imagens." attachment_upload_not_allowed_for_new_user: "Desculpe, usuários novos não podem enviar anexos." attachment_download_requires_login: "Desculpe, você precisa estar logado para baixar arquivos anexos." @@ -1821,7 +1821,6 @@ pt_BR: one: "visualizar" other: "visualizações" replies: "Respostas" - views_long: "este tópico foi visto {{number}} vezes" activity: "Atividade" likes: "Curtidas" likes_lowercase: @@ -2124,8 +2123,6 @@ pt_BR: backups: "backups" traffic_short: "Tráfego" traffic: "Solicitações do aplicativo pela web" - page_views: "Solicitações de API" - page_views_short: "Solicitações de API" show_traffic_report: "Mostrar Relatório de Tráfego Detalhado" reports: today: "Hoje" @@ -2215,15 +2212,12 @@ pt_BR: refresh: "Atualizar" new: "Novo" selector_placeholder: "digite o nome de usuário" - name_placeholder: "Nome do grupo, sem espaços, regras iguais ao nome de usuário" about: "Editar participação no grupo e nomes aqui" group_members: "Membros do grupo" delete: "Apagar" delete_confirm: "Apagar este grupos?" delete_failed: "Unable to delete group. If this is an automatic group, it cannot be destroyed." - delete_member_confirm: "Remover '%{username}' do grupo '%{group}'?" delete_owner_confirm: "Remover privilégio de proprietário de '%{username}'?" - name: "Nome" add: "Adicionar" add_members: "Adicionar membros" custom: "Definidos" @@ -2240,10 +2234,6 @@ pt_BR: add_owners: Adicionar proprietários incoming_email: "Endereço de email de entrada personalizado" incoming_email_placeholder: "Insira um endereço de email" - flair_url_placeholder: "(Opcional) URL de imagem ou classe Font Awesome" - flair_bg_color_placeholder: "(Opcional) Valor em hexadecimal da cor" - flair_color_placeholder: "(Opcional) Valor em hexadecimal da cor" - flair_preview: "Pré-visualizar" api: generate_master: "Gerar chave Mestra de API" none: "Não existem chaves API ativas no momento." @@ -2275,7 +2265,6 @@ pt_BR: warn_local_payload_url: "Parece que você está tentando configurar um webhook para uma URL local. Eventos entregues a endereços locais podem causar efeitos colaterais ou comportamentos inesperados. Continuar?" secret_invalid: "O segredo não deve conter caracteres em branco." secret_too_short: "O segredo deve ter pelo menos 12 caracteres." - secret_placeholder: "Uma string opcional, usada para gerar assinaturas" event_type_missing: "Você deve configurar apenas um tipo de evento." content_type: "Tipo de Conteúdo" secret: "Segredo" @@ -2297,7 +2286,6 @@ pt_BR: details: "Quando existir uma nova resposta, edição, deleção ou recuperação." user_event: name: "Evento de Usuário" - details: "When um usuário é criado ou aprovado." delivery_status: title: "Status de Entrega" inactive: "Inativo" @@ -2515,6 +2503,9 @@ pt_BR: delivery_method: "Delivery Method" preview_digest_desc: "Pré-visualizar o conteúdo do e-mail de resumo enviado para usuários inativos." refresh: "Atualizar" + send_digest_label: "Enviar esse resultado para:" + send_digest: "Enviar" + sending_email: "Enviando email..." format: "Formato" html: "html" text: "texto" diff --git a/config/locales/client.ro.yml b/config/locales/client.ro.yml index d65040f90b8..a556f3b4a96 100644 --- a/config/locales/client.ro.yml +++ b/config/locales/client.ro.yml @@ -347,18 +347,59 @@ ro: one: "1 utilizator" few: "%{count} utilizatori" other: "%{count} de utilizatori" + group_histories: + actions: + change_group_setting: "Schimbă setarea grupului" + add_user_to_group: "Adaugă utilizator" + remove_user_from_group: "Șterge utilizator" + make_user_group_owner: "Fă proprietar" + remove_user_as_group_owner: "Revocă proprietar" groups: + logs: + title: "Jurnale" + when: "Când" + action: "Acțiune" + acting_user: "Utilizator temporar" + target_user: "Utilizator țintă" + subject: "Subiect" + details: "Detalii" + from: "De la" + to: "Către" + edit: + title: 'Editează grup' + full_name: 'Nume complet' + add_members: "Adaugă membri" + delete_member_confirm: "Șterge utilizatorul '%{username}' din grupul '%{group}'?" + request_membership_pm: + title: "Cerere de adăugare ca membru" + body: "Aș dori să fac o cerere de adăugare ca membru în @%{groupName}." + name_placeholder: "Numele grupului, fără spații, la fel ca regula pentru nume utilizator" + public: "Permite utilizatorilor să intre/iasă din grup fără restricții. (Presupune ca grupul să fie vizibil)" empty: - posts: "Nu există nici o postare a membrilor acestui grup." + posts: "Nu există postări ale membrilor acestui grup." members: "Nu există nici un membru în acest grup." - mentions: "Nu sunt mențiuni ale acestui grup." - messages: "Nu este nici un mesaj pentru acest grup." - topics: "Nu exista nici un subiect postat de membrii acestui grup." + mentions: "Nu există nicio menționare în acest grup." + messages: "Nu există nici un mesaj în acest grup." + topics: "Nu există nici un subiect creat de vreun membru al acestui grup." + logs: "Nu există nici un jurnal pentru acest grup." add: "Adaugă" + join: "Alătură-te grupului" + leave: "Părăsește grupul" + request: "Cere să te alături grupului" + automatic_group: Grup automat + closed_group: Grup închis + is_group_user: "Ești membru al acestui grup" + allow_membership_requests: "Permite utilizatorilor să trimită cereri de adăugare ca membri către proprietarii grupului. (Presupune ca toată lumea să aibă posibilitatea de a menționa grupul)" + membership: "Apartenență" + name: "Nume" + user_count: "Număr de membri" + bio: "Despre grup" selector_placeholder: "Adaugă membri" owner: "Proprietar" visible: "Grupul este vizibil tuturor utilizatorilor" - index: "Grupuri" + index: + title: "Grupuri" + empty: "Nu există nici un grup vizibil." title: one: "Grup" few: "Grupuri" @@ -394,6 +435,15 @@ ro: muted: title: "Setat pe silențios" description: "Nu vei fi niciodată notificat despre nimic legat de noile subiecte din acest grup." + flair_url: "Imagine avatar cu element distinct" + flair_url_placeholder: "(Opțional) URL imagine sau clasă Font Awesome" + flair_bg_color: "Culoarea de fundal a avatarului cu element distinct" + flair_bg_color_placeholder: "(Opțional) Valoarea Hex a culorii" + flair_color: "Culoarea avatarului cu element distinct" + flair_color_placeholder: "(Opțional) Valoarea Hex a culorii" + flair_preview_icon: "Previzualizează iconiță" + flair_preview_image: "Previzualizează imagine" + flair_note: "Observație: Elementul distinct va fi afișat doar pentru grupul principal al utilizatorului." user_action_groups: '1': "Aprecieri date" '2': "Aprecieri primite" @@ -726,11 +776,9 @@ ro: link_generated: "Link de invitare generat cu succes!" valid_for: "Link-ul de invitare este valid doar pentru următoarele adrese de email: %{email}" bulk_invite: - none: "Nu ai invitat încă pe nimeni. Poți trimite invitații individuale sau mai multor oameni deodată prin încărcarea fișierului de invitații multiple." + none: "Nu ai invitat încă pe nimeni aici. Poți trimite invitații individuale sau poți invita mai multe persoane odată încărcând un fișier CSV." text: "Invitație multiplă din fișier" - uploading: "Se încarcă..." success: "Fișier încărcat cu succes, vei fi înștiințat printr-un mesaj când procesarea este completă." - error: "A apărut o eroare la încărcarea fișierului '{{filename}}': {{message}}" password: title: "Parolă" too_short: "Parola este prea scurtă." @@ -1005,8 +1053,10 @@ ro: title: "Sau apasă Ctrl+Enter" users_placeholder: "Adaugă un utilizator" title_placeholder: "Despre ce e vorba în acest subiect - pe scurt?" + title_or_link_placeholder: "Introdu titlul, sau copiază aici un link" edit_reason_placeholder: "de ce editezi?" show_edit_reason: "(adaugă motivul editării)" + topic_featured_link_placeholder: "Introdu link afișat cu titlu." reply_placeholder: "Scrie aici. Utilizează formatarea Markdown, BBCode sau HTML. Trage sau lipește imagini." view_new_post: "Vezi noua ta postare." saving: "Se salvează" @@ -1332,7 +1382,6 @@ ro: go_bottom: "sfârșit" go: "mergi" jump_bottom: "sari la ultimul mesaj" - jump_prompt: "sari la postarea" jump_prompt_long: "La ce postare dorești să sari?" jump_bottom_with_number: "sari la mesajul %{post_number}" total: toate postările @@ -1577,7 +1626,6 @@ ro: file_too_large: "Ne pare rău, fișierul este prea mare (mărimea maximă este {{max_size_kb}}kb). De ce nu încarci acest fișier mare pe un serviciu de distribuție prin cloud și apoi să îi partajezi link-ul?" too_many_uploads: "Ne pare rău, poți încărca doar câte un fișier." too_many_dragged_and_dropped_files: "Ne pare rău, poți încărca doar 10 fișiere simultan." - upload_not_authorized: "Ne pare rău, fișierul pe care-l încarci nu este permis (extensii permise: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Ne pare rău, un utilizator nou nu poate încărca imagini." attachment_upload_not_allowed_for_new_user: "Ne pare rău, un utilizator nou nu poate încărca atașamente." attachment_download_requires_login: "Ne pare rău, dar trebuie să fii autentificat pentru a descărca ataşamente." @@ -1763,6 +1811,7 @@ ro: tags_allowed_tag_groups: "În această categorie se pot folosi numai grupurile de etichete:" tags_placeholder: "(Opțional) lista etichetelor permise" tag_groups_placeholder: "(Opțional) lista grupurilor de etichete permise" + topic_featured_link_allowed: "Permite link-uri promovate în această categorie." delete: 'Șterge categorie' create: 'Categorie nouă' create_long: 'Creează o categorie nouă' @@ -1797,6 +1846,7 @@ ro: email_in_disabled: "Postarea subiectelor noi prin email este dezactivată din setările siteului. Pentru a activa postarea subiectelor noi prin email," email_in_disabled_click: 'activează opțiunea "primire email ".' suppress_from_homepage: "Elimină această categorie de pe pagina principală." + all_topics_wiki: "Transformă subiectele noi în wiki-uri, implicit." sort_order: "Sortare implicită:" allow_badges_label: "Permite acordarea de ecusoane în această categorie" edit_permissions: "Editează permisiuni" @@ -1925,7 +1975,6 @@ ro: few: "vizualizări" other: "de vizualizări" replies: "Răspunsuri" - views_long: "acest subiect a fost vizualizat de {{number}} (de) ori" activity: "Activitate" likes: "Aprecieri" likes_lowercase: @@ -2242,8 +2291,6 @@ ro: backups: "back-up" traffic_short: "Trafic" traffic: "Cereri web" - page_views: "Cereri API" - page_views_short: "Cereri API" show_traffic_report: "Arată raportul detaliat cu privire la trafic" reports: today: "Astăzi" @@ -2338,15 +2385,12 @@ ro: refresh: "Reîmprospătează" new: "Noi" selector_placeholder: "introdu nume de utilizator" - name_placeholder: "Numele grupului, fără spații, asemenea regulii de la numele de utilizator" about: "Editează aici numele și apartenența la grupuri" group_members: "Membrii grupului" delete: "Șterge" delete_confirm: "Ștergi acest grup?" delete_failed: "Imposibil de șters grupul. Dacă este unul automat, nu se poate șterge." - delete_member_confirm: "Şterge '%{username}' din grupul '%{group}'?" delete_owner_confirm: "Revocă dreptul de proprietar pentru '%{username}'?" - name: "Nume" add: "Adaugă" add_members: "Adaugă membri" custom: "Personalizat" @@ -2363,14 +2407,6 @@ ro: add_owners: Adaugă proprietari incoming_email: "Adresă de primire emailuri personalizată" incoming_email_placeholder: "introducere adresă de email" - flair_url: "Imagine avatar cu element distinct" - flair_url_placeholder: "(Opțional) URL-ul imagine sau clasă Font Awesome" - flair_bg_color: "Culoarea de fundal a avatarului cu element distinct" - flair_bg_color_placeholder: "(Opțional) Valoarea Hex a culorii" - flair_color: "Culoarea avatarului cu element distinct" - flair_color_placeholder: "(Opțional) Valoarea Hex a culorii" - flair_preview: "Previzualizare" - flair_note: "Observație: Elementul distinct va fi afișat doar pentru grupul principal al utilizatorului." api: generate_master: "Generează cheie API principală" none: "Nu sunt chei API principale active deocamdată." @@ -2402,7 +2438,6 @@ ro: warn_local_payload_url: "Se pare că dorești să setezi un webhook pentru un url local. Un eveniment livrat către o adresă locală ar putea avea efecte secundare și genera comportamente neașteptate. Continuă?" secret_invalid: "Secretul nu trebuie să aibă nici un caracter spațiu-gol." secret_too_short: "Secretul trebuie sa conțină cel puțin 12 caractere." - secret_placeholder: "Un șir opțional, folosit la generarea semnăturii" event_type_missing: "Va trebui să setezi cel puțin un tip de evenimente." content_type: "Tip conținut" secret: "Secret" @@ -2425,7 +2460,7 @@ ro: details: "Atunci când exista un răspuns nou, editat, șters sau recuperat." user_event: name: "Eveniment utilizator" - details: "Atunci când un utilizator este creat sau aprobat." + details: "Când un utilizator este creat, aprobat sau actualizat." delivery_status: title: "Starea livrării" inactive: "Inactivă" diff --git a/config/locales/client.ru.yml b/config/locales/client.ru.yml index 2df09f06548..2b4ef33c7de 100644 --- a/config/locales/client.ru.yml +++ b/config/locales/client.ru.yml @@ -285,7 +285,7 @@ ru: few: "{{count}} новые темы." many: "{{count}} новых тем." other: "{{count}} новых тем." - click_to_show: "Показать." + click_to_show: "Нажмите чтобы показать." preview: "предпросмотр" cancel: "отмена" save: "Сохранить" @@ -372,23 +372,65 @@ ru: few: "%{count} пользователя" many: "%{count} пользователей" other: "%{count} пользователей" + group_histories: + actions: + change_group_setting: "Настроить группу" + add_user_to_group: "Добавить пользователя" + remove_user_from_group: "Удалить пользователя" + make_user_group_owner: "Сделать владельцем" + remove_user_as_group_owner: "Лишить прав владельца" groups: + logs: + title: "Логи" + when: "Когда" + action: "Действие" + acting_user: "Действующий пользователь" + target_user: "Целевой пользователь" + subject: "Тема" + details: "Подробности" + from: "От" + to: "Кому" + edit: + title: 'Редактировать Группу' + full_name: 'Полное Имя' + add_members: "Добавить Участников" + delete_member_confirm: "Удалить '%{username}' из группы '%{group}'?" + request_membership_pm: + title: "Запрос на Вступление" + body: "Я бы хотел вступить в @%{groupName}." + name_placeholder: "Название группы, без пробелов, по тем же правилам, что и для псевдонимов." + public: "Позволить пользователям свободно вступать/покидать группу (Группа должна быть видимой)" empty: - posts: "Участники этой группы не отправили ни одного сообщения" - members: "В этой группе нет участников" - mentions: "Упоминаний этой группы нет" - messages: "Для этой группы нет сообщений" - topics: "Участниками этой группы не создано ни одной темы" + posts: "Участниками этой группы не создано ни одной записи." + members: "Нет участников в этой группе." + mentions: "Нет ссылок на эту группу." + messages: "Нет сообщений для этой группы." + topics: "Нет тем от участников этой группы." + logs: "Нет логов для этой группы." add: "Добавить" + join: "Вступить в Группу" + leave: "Покинуть Группу" + request: "Попроситься в Группу" + automatic_group: Автоматическая Группа + closed_group: Закрытая Группа + is_group_user: "Вы участник этой группы" + allow_membership_requests: "Позволить пользователям проситься в группу владельцев (Необходима возможность упоминания группы всеми)" + membership: "Участие" + name: "Название" + user_count: "Количество Участников" + bio: "О Группе" selector_placeholder: "Добавить участников" owner: "владелец" visible: "Группа видима всем пользователям" - index: "Группы" + index: + title: "Группы" + empty: "Нет видимых групп." title: one: "группа" few: "группы" many: "групп" other: "групп" + activity: "Деятельность" members: "Участники" topics: "Темы" posts: "Сообщения" @@ -420,6 +462,15 @@ ru: muted: title: "Выключено" description: "Не уведомлять о новых темах в этой группе." + flair_url: "Изображение Аватара" + flair_url_placeholder: "(Необязательно) Ссылка на изображение или класс шрифта Font Awesome" + flair_bg_color: "Фоновый Цвет Аватара" + flair_bg_color_placeholder: "(Необязательно) Hex-код цвета" + flair_color: "Цвет Аватара" + flair_color_placeholder: "(Необязательно) Hex-код цвета" + flair_preview_icon: "Иконка Предпросмотра" + flair_preview_image: "Изображение Предпросмотра" + flair_note: "Внимание: Флаер будет показываться только основной группе пользователей." user_action_groups: '1': "Выразил симпатий" '2': "Получил симпатий" @@ -485,6 +536,11 @@ ru: profile: "Профиль" mute: "Отключить" edit: "Настройки" + download_archive: + button_text: "Скачать мои сообщения" + confirm: "Вы уверены, что хотите скачать свои сообщения?" + success: "Скачивание началось, вы будете уведомлены, когда процесс завершится." + rate_limit_error: "Сообщения могут быть скачаны лишь раз в день, попробуйте завтра." new_private_message: "Новое сообщение" private_message: "Личное сообщение" private_messages: "Личные сообщения" @@ -508,6 +564,7 @@ ru: each_browser_note: "Примечание: эта настройка устанавливается в каждом браузере индивидуально." dismiss_notifications: "Отложить все" dismiss_notifications_tooltip: "Пометить все непрочитанные уведомления прочитанными" + first_notification: "Ваше первое уведомление! Выберите его, чтобы начать." disable_jump_reply: "Не переходить к вашему новому сообщению после ответа" dynamic_favicon: "Показывать количество новых / обновленных тем на иконке сообщений" external_links_in_new_tab: "Открывать все внешние ссылки в новой вкладке" @@ -537,7 +594,7 @@ ru: watched_tags: "Наблюдение" watched_tags_instructions: "Вы будете автоматически отслеживать все новые темы в этих тэгах. Вам будут приходить уведомления о новых сообщениях и темах, а также количество непрочитанных и новых сообщений будет показано рядом с названиями тем. " tracked_tags: "Отслеживаемая" - tracked_tags_instructions: "Вы будете автоматически отслеживать новые темы в этих разделах. Рядом со списком тем будет отображено количество непрочитанных и новых сообщений." + tracked_tags_instructions: "Вы будете автоматически отслеживать новые темы с этими тегами. Рядом со списком тем будет отображено количество непрочитанных и новых сообщений." muted_tags: "Выключено" muted_tags_instructions: "Вы не будете получать уведомления о новых темах в этих разделах. Также, они не будут показываться во вкладке Непрочитанное." watched_categories: "Наблюдение" @@ -627,6 +684,7 @@ ru: ok: "Мы вышлем вам письмо для подтверждения" invalid: "Введите действующий адрес электронной почты" authenticated: "Ваш адрес электронной почты подтвержден {{provider}}" + frequency_immediately: "Получать уведомления о новых непрочитанных сообщениях незамедлительно." frequency: one: "Мы отправим вам письмо только в том случае, если вы более {{count}} минуты находитесь оффлайн." few: "Мы отправим вам письмо только в том случае, если вы не были онлайн последние {{count}} минуты." @@ -746,12 +804,13 @@ ru: account_age_days: "Дней с момента регистрации" create: "Отправить приглашение" generate_link: "Скопировать ссылку для приглашений" + link_generated: "Пригласительная ссылка успешно создана!" + valid_for: "Пригласительная ссылка действительна только для этого адреса электропочты: %{email}" bulk_invite: - none: "Вы еще никого не приглашали на этот форум. Можно отправить индивидуальные приглашения по одному, или же пригласить сразу несколько людей из файла." + none: "Вы еще никого не приглашали сюда. Вы можете отправить индивидуальные приглашения или пригласить группу людей сразу загрузив CSV файл." text: "Пригласить всех из файла" - uploading: "Загрузка..." success: "Файл успешно загружен, вы получите сообщение, когда процесс будет завершен." - error: "В процессе загрузки файла '{{filename}}' произошла ошибка: {{message}}" + error: "Извините, но файл должен быть в csv формате." password: title: "Пароль" too_short: "Пароль слишком короткий." @@ -863,6 +922,8 @@ ru: too_few_topics_notice: "Давайте приступим к обсуждению! Сейчас %{currentTopics} / %{requiredTopics} тем. Новым пользователям будет интереснее тут, если появится больше тем для обсуждений." too_few_posts_notice: "Давайте приступим к обсуждению! Сейчас %{currentPosts} / %{requiredPosts} сообщений. Новым пользователям будет интереснее тут, если появится больше сообщений для обсуждения." logs_error_rate_notice: + reached: "%{relativeAge}%{rate} достигнут установленный для сайта предел %{siteSettingRate}." + exceeded: "%{relativeAge}%{rate} превышен установленный для сайта предел %{siteSettingRate}." rate: one: "1 ошибка/%{duration}" few: "%{count} ошибок/%{duration}" @@ -918,6 +979,7 @@ ru: trust_level: 'Уровень доверия' search_hint: 'Псевдоним, e-mail или IP адрес' create_account: + disclaimer: "Регистрируясь, Вы соглашаетесь с политикой конфиденциальности и условиями предоставления услуг." title: "Зарегистрироваться" failed: "Произошла ошибка. Возможно, этот Email уже используется. Попробуйте восстановить пароль" forgot_password: @@ -1010,6 +1072,9 @@ ru: few: "Упоминая группу {{group}}, вы тем самым отправите уведомление {{count}} пользователям – вы уверены?" many: "Упоминая группу {{group}}, вы тем самым отправите уведомление {{count}} пользователям – вы уверены?" other: "Упоминая группу {{group}}, вы тем самым отправите уведомление {{count}} пользователям – вы уверены?" + cannot_see_mention: + category: "Вы упомянули {{username}}, но они не будут уведомлены, потому что у них нет доступа к этому разделу. Вам нужно добавить их в группу, имеющую доступ к этому разделу." + private: "Вы упомянули {{username}}, но они не будут уведомлены, потому что они не могут видеть это личное сообщение. Вам нужно пригласить их в это ЛС." duplicate_link: "Эту же самую ссылку на {{domain}} уже писал @{{username}} в своем ответе {{ago}} – вы уверены, что хотите повторить ссылку снова?" error: title_missing: "Требуется название темы" @@ -1029,8 +1094,10 @@ ru: title: "Или нажмите Ctrl+Enter" users_placeholder: "Добавить пользователя" title_placeholder: "Название: суть темы коротким предложением" + title_or_link_placeholder: "Введите название или вставьте здесь ссылку" edit_reason_placeholder: "Причина редактирования..." show_edit_reason: "(добавить причину редактирования)" + topic_featured_link_placeholder: "Введите ссылку, отображаемую с названием." reply_placeholder: "Поддерживаемые форматы: Markdown, BBCode и HTML. Чтобы вставить картинку, перетащите ее сюда или вставьте с помощью Ctrl+V, Command-V, или нажмите правой кнопкой мыши и выберите меню \"вставить\"." view_new_post: "Посмотреть созданное вами сообщение." saving: "Сохранение..." @@ -1090,10 +1157,13 @@ ru: more: "посмотреть более ранние уведомления" total_flagged: "всего сообщений с жалобами" mentioned: "

    {{username}} {{description}}

    " + group_mentioned: "

    {{username}} {{description}}

    " quoted: "

    {{username}} {{description}}

    " replied: "

    {{username}} {{description}}

    " + posted: "

    {{username}} {{description}}

    " edited: "

    {{username}} {{description}}

    " liked: "

    {{username}} {{description}}

    " + liked_2: "

    {{username}}, {{username2}} {{description}}

    " liked_many: one: "

    {{username}}, {{username2}} и ещё {{count}} {{description}}

    " few: "

    {{username}}, {{username2}} и ещё {{count}} {{description}}

    " @@ -1104,7 +1174,14 @@ ru: invited_to_topic: "

    {{username}} {{description}}

    " invitee_accepted: "

    {{username}} принял(а) ваше приглашение

    " moved_post: "

    {{username}} переместил(а) {{description}}

    " + linked: "

    {{username}} {{description}}

    " granted_badge: "

    Вы награждены: {{description}}

    " + watching_first_post: "

    Новая Тема {{description}}

    " + group_message_summary: + one: "

    {{count}} входящее сообщение в Вашей группе {{group_name}}

    " + few: "

    {{count}} входящих сообщения в Вашей группе {{group_name}}

    " + many: "

    {{count}} входящих сообщений в Вашей группе {{group_name}}

    " + other: "

    {{count}} входящих сообщений в Вашей группе {{group_name}}

    " alt: mentioned: "Упомянуто" quoted: "Процитировано пользователем" @@ -1119,6 +1196,7 @@ ru: moved_post: "Ваша тема перенесена участником " linked: "Ссылка на ваше сообщение" granted_badge: "Награда получена от" + group_message_summary: "Входящие сообщения группы" popup: mentioned: '{{username}} упомянул вас в "{{topic}}" - {{site_title}}' group_mentioned: '{{username}} упомянул вас в "{{topic}}" - {{site_title}}' @@ -1264,12 +1342,13 @@ ru: search: "Больше ничего не найдено." topic: unsubscribe: + stop_notifications: "Вы будете получать меньше уведомлений для {{title}}" change_notification_state: "Ваше текущее состояние уведомлений" filter_to: one: "1 сообщение в теме" few: "{{post_count}} сообщений в теме" many: "{{post_count}} сообщений в теме" - other: "{{post_count}} сообщений в теме" + other: "{{count}} сообщений в теме" create: 'Создать Тему' create_long: 'Создать новую тему' private_message: 'Новое личное соощение' @@ -1341,6 +1420,11 @@ ru: auto_close_title: 'Настройки закрытия темы' auto_close_save: "Сохранить" auto_close_remove: "Не закрывать тему автоматически" + auto_close_immediate: + one: "Последнее сообщение в этой теме отправлено 1 час назад, поэтому данная тема будет закрыта незамедлительно." + few: "Последнее сообщение в этой теме отправлено %{count} часа назад, поэтому данная тема будет закрыта незамедлительно." + many: "Последнее сообщение в этой теме отправлено %{count} часов назад, поэтому данная тема будет закрыта незамедлительно." + other: "Последнее сообщение в этой теме отправлено %{count} часов назад, поэтому данная тема будет закрыта незамедлительно." timeline: back: "Вернуться" back_description: "Перейти к последнему непрочитанному сообщению" @@ -1351,7 +1435,8 @@ ru: go_bottom: "перейти вниз" go: "=>" jump_bottom: "перейти к последнему сообщению" - jump_prompt: "перейти к сообщению" + jump_prompt: "перейти к..." + jump_prompt_of: "из %{count} сообщений" jump_prompt_long: "К какому сообщению вы хотите перейти?" jump_bottom_with_number: "перейти к сообщению %{post_number}" total: всего сообщений @@ -1359,6 +1444,7 @@ ru: notifications: title: изменить частоту уведомлений об этой теме reasons: + mailing_list_mode: "Вы включили режим почтовой рассылки, поэтому Вы будете получать уведомления об ответах в этой теме через e-mail." '3_10': 'Вы будете получать уведомления, т.к. наблюдаете за тэгом этой темы.' '3_6': 'Вы будете получать уведомления, т.к. наблюдаете за этим разделом.' '3_5': 'Вы будете получать уведомления, т.к. наблюдение темы началось автоматически.' @@ -1474,6 +1560,7 @@ ru: email_or_username_placeholder: "e-mail или псевдоним" action: "Пригласить" success: "Мы пригласили этого пользователя принять участие в беседе." + success_group: "Мы пригласили эту группу принять участие в беседе." error: "К сожалению, в процессе приглашения пользователя произошла ошибка." group_name: "название группы" controls: "Управление темой" @@ -1604,6 +1691,7 @@ ru: create: "К сожалению, не удалось создать сообщение из-за ошибки. Попробуйте еще раз." edit: "К сожалению, не удалось изменить сообщение. Попробуйте еще раз." upload: "К сожалению, не удалось загрузить файл. Попробуйте еще раз." + file_too_large: "К сожалению, этот файл слишком большой (максимально допустимый размер {{max_size_kb}} КБ). Почему бы не загрузить Ваш большой файл в службу облачного обмена, а затем поделиться ссылкой?" too_many_uploads: "К сожалению, за один раз можно загрузить только одно изображение." too_many_dragged_and_dropped_files: "К сожалению, за один раз можно загрузить только 10 файлов." upload_not_authorized: "К сожалению, вы не можете загрузить файл данного типа (список разрешенных типов файлов: {{authorized_extensions}})." @@ -1615,11 +1703,13 @@ ru: no_value: "Нет, оставить" yes_value: "Да, отказаться" via_email: "это сообщение пришло с почты" + via_auto_generated_email: "это сообщение пришло с автосгенерированого e-mail" whisper: "Это внутреннее сообщение, т.е. оно видно только модераторам" wiki: about: "это вики-сообщение" archetypes: save: 'Параметры сохранения' + few_likes_left: "Спасибо, что делитесь любовью. На сегодня у Вас осталось несколько лайков." controls: reply: "начать составление ответа на сообщение" like: "мне нравится" @@ -1808,6 +1898,7 @@ ru: tags_allowed_tag_groups: "Группы тегов, которые могут быть использованы только в этом разделе:" tags_placeholder: "(Необязательно) список доступных тегов" tag_groups_placeholder: "(Необязательно) список доступных групп тегов" + topic_featured_link_allowed: "Разрешить популярные ссылки в этой категории" delete: 'Удалить раздел' create: 'Создать Раздел' create_long: 'Создать новый раздел' @@ -1842,6 +1933,7 @@ ru: email_in_disabled: "Создание новых тем через электронную почту отключено в настройках сайта. Чтобы разрешить создание новых тем через электронную почту," email_in_disabled_click: 'активируйте настройку "email in".' suppress_from_homepage: "Не отображать этот раздел на главной странице." + all_topics_wiki: "Создавать новые темы в вики-формате по умолчанию." sort_order: "Порядок сортировки:" allow_badges_label: "Разрешить вручение наград в этом разделе" edit_permissions: "Изменить права доступа" @@ -1887,6 +1979,7 @@ ru: notify_action: 'Сообщение' official_warning: 'Официальное предупреждение' delete_spammer: "Удалить спамера" + delete_confirm_MF: "Вы собираетесь удалить {POSTS, plural, one {1 сообщение} other {# сообщений}} и {TOPICS, plural, one {1 тему} other {# темы}} этого пользователя, а так же удалить его учетную запись, добавить его IP адрес {ip_address} и его почтовый адрес {email} в черный список. Вы действительно уверены, что ваши помыслы чисты и действия не продиктованы гневом?" yes_delete_spammer: "Да, удалить спамера" ip_address_missing: "(не доступно)" hidden_email_address: "(скрыто)" @@ -1932,6 +2025,11 @@ ru: other: "%{count} кликов" post_links: about: "gjrfpf" + title: + one: "ещё 1" + few: "ещё %{count}" + many: "ещё %{count}" + other: "ещё %{count}" topic_statuses: warning: help: "Это официальное предупреждение." @@ -1969,7 +2067,11 @@ ru: few: "просмотра" other: "просмотров" replies: "Ответов" - views_long: "тема просмотрена {{number}} раз" + views_long: + one: "тема просмотрена 1 раз" + few: "тема просмотрена {{number}} раза" + many: "тема просмотрена {{number}} раз" + other: "тема просмотрена {{number}} раз" activity: "Активность" likes: "Нрав." likes_lowercase: @@ -2136,9 +2238,16 @@ ru: mark_watching: 'm, w Наблюдать за темой' print: 'ctrl+p Печатать тему' badges: + earned_n_times: + one: "Заработал эту награду 1 раз" + few: "Заработали эту награду %{count} раз" + many: "Заработали эту награду %{count} раз" + other: "Заработали эту награду %{count} раз" granted_on: "Выдана %{date}" others_count: "Другие с этой наградой (%{count})" title: Награды + allow_title: "доступный заголовок" + multiple_grant: "награждён множество раз" badge_count: one: "1 награда" few: "%{count} наград" @@ -2149,6 +2258,12 @@ ru: few: "+ еще %{count}" many: "+ еще %{count}" other: "+ еще %{count}" + granted: + one: "выдано 1" + few: "выдано %{count}" + many: "выдано %{count}" + other: "выдано %{count}" + select_badge_for_title: Использовать награду в качестве Вашего титула none: "<отсутствует>" badge_grouping: getting_started: @@ -2159,6 +2274,8 @@ ru: name: Уровень доверия other: name: Прочее + posting: + name: Публикации google_search: |

    Искать с помощью Google

    @@ -2245,6 +2362,8 @@ ru: custom_message_placeholder: "Напишите сюда ваше личное сообщение" custom_message_template_forum: "Привет. Подумал, что тебе будет интересно зарегистрироваться на этом форуме!" custom_message_template_topic: "Привет! Подумал, что тебя может заинтересовать эта тема!" + safe_mode: + enabled: "Включен безопасный режим, чтобы выйти из безопасного режима, закройте текущее окно браузера" admin_js: type_to_filter: "Введите текст для фильтрации..." admin: @@ -2279,8 +2398,8 @@ ru: backups: "Резервные копии" traffic_short: "Трафик" traffic: "Трафик (веб-запросы)" - page_views: "Запросы API" - page_views_short: "Запросы API" + page_views: "Просмотров Страниц" + page_views_short: "Просмотров" show_traffic_report: "Раширенный отчет по трафику" reports: today: "Сегодня" @@ -2380,15 +2499,12 @@ ru: refresh: "Обновить" new: "Добавить новую" selector_placeholder: "введите псевдоним" - name_placeholder: "Название группы, без пробелов, по тем же правилам, что и для псевдонимов." about: "Здесь можно редактировать группы и имена групп" group_members: "Участники группы" delete: "Удалить" delete_confirm: "Удалить эту группу?" delete_failed: "Невозможно удалить группу. Если группа была создана автоматически, то она не может быть удалена." - delete_member_confirm: "Удалить пользователя '%{username}' из группы '%{group}'?" delete_owner_confirm: "Отозвать права владельца у пользователя '%{username}'?" - name: "Название" add: "Добавить" add_members: "Добавить участников" custom: "Настраиваемые" @@ -2405,10 +2521,6 @@ ru: add_owners: Добавить владельцев incoming_email: "Специальный входящий адрес e-mail" incoming_email_placeholder: "введите e-mail" - flair_url_placeholder: "(Необязательно) Ссылка на изображение или класс шрифта Font Awesome" - flair_bg_color_placeholder: "(Необязательно) Hex-код цвета" - flair_color_placeholder: "(Необязательно) Hex-код цвета" - flair_preview: "Предпросмотр" api: generate_master: "Сгенерировать ключ API" none: "Отсутствует ключ API." @@ -2425,6 +2537,7 @@ ru: note_html: "Никому не сообщайте этот ключ. Тот, у кого он есть, сможет создавать сообщения, выдавая себя за любого пользователя форума." web_hooks: title: "Webhooks" + none: "Сейчас нет веб-перехватчиков." instruction: "Webhooks позволяют Discourse уведомлять внешние службы, когда определенное событие происходит на вашем сайте. При срабатывании webhook, на соответствующий URL будет отправлен POST-запрос." detailed_instruction: "При наступлении выбранного события, на соответствующий URL будет отправлен POST-запрос." new: "Добавить Webhook" @@ -2432,10 +2545,27 @@ ru: save: "Сохранить" destroy: "Удалить" description: "Описание" + controls: "Управление" go_back: "Вернуться к списку" + payload_url: "Ссылка для отправки" payload_url_placeholder: "https://example.com/postreceive" - secret_placeholder: "Необязательная строка, используется для генерации подписи" + warn_local_payload_url: "По-видимому вы пытаетесь настроить веб-перехватчик на локальный URL. Собитие, отправляемое на локальный адрес может иметь побочное действие или неожиданное поведение. Продолжить?" + secret_invalid: "Ключ не должен содержать пустых символов." + secret_too_short: "Ключ должен быть не менее 12 символов." + secret_placeholder: "Допольнительная строка, используется для создания подписи" event_type_missing: "Вам необходимо настроить по крайней мере один тип событий." + content_type: "Тип Содержимого" + secret: "Ключ" + event_chooser: "Какие события должны вызывать веб-перехватчик?" + wildcard_event: "Присылать мне всё." + individual_event: "Выбрать отдельные события." + verify_certificate: "Проверять TLS сертификат ссылки для отправки данных" + active: "Активный" + active_notice: "Мы будем отправлять подробности события, когда оно будет происходить." + categories_filter_instructions: "Подходящие веб-перехватчики будут срабатывать только если событие связано с указанными разделами. Оставьте пустым, чтобы веб-перехватчик срабатывал для всех разделов." + categories_filter: "Только Для Этих Разделов" + groups_filter_instructions: "Подходящие веб-перехватчики будут срабатывать только если событие связано с указанными группами. Оставьте пустым, чтобы веб-перехватчик срабатывал для всех групп." + groups_filter: "Только Для Групп" delete_confirm: "Удалить Webhook?" topic_event: name: "Событие темы" @@ -2445,7 +2575,7 @@ ru: details: "Происходит, когда сообщение создается, редактируется, удаляется или восстанавливается." user_event: name: "Событие пользователя" - details: "Происходит, когда создается или подтверждается пользователь." + details: "Когда пользователь создаётся, утверждается или обновляется." delivery_status: title: "Статус передачи" inactive: "Неактивна" @@ -2454,16 +2584,30 @@ ru: events: none: "Нет связанных событий." redeliver: "Возврат" + incoming: + one: "Есть новое событие." + few: "{{count}} новых события." + many: "{{count}} новых событий." + other: "{{count}} новых событий." + completed_in: + one: "Завершится через 1 секунду." + few: "Завершится через {{count}} секунд." + many: "Завершится через {{count}} секунд." + other: "Завершится через {{count}} секунд." request: "Запрос" response: "Ответ" + redeliver_confirm: "Вы уверены, что хотите повторно отправить теже самые данные?" headers: "Заголовки" + payload: "Данные для отправки" body: "Тело" go_list: "Перейти к списку" go_details: "Редактировать webhook" go_events: "Перейти к событию" ping: "Ping" + status: "Код Состояния" event_id: "Идентификатор (ID)" timestamp: "Создано" + completion: "Время Завершения" actions: "Действия" plugins: title: "Плагины" @@ -2580,9 +2724,11 @@ ru: email_templates: title: "Шаблоны писем" subject: "Тема" + multiple_subjects: "Этот шаблон электронной почты имеет множество тем." body: "Текст сообщения" none_selected: "Выберите шаблон письма, чтобы начать редактирование." revert: "Отменить изменения" + revert_confirm: "Вы уверены, что хотите отменить Ваши изменения?" css_html: title: "CSS/HTML" long_title: "Настройка CSS и HTML" @@ -2651,12 +2797,14 @@ ru: delivery_method: "Метод отправки" preview_digest_desc: "Предпросмотр сводки новостей на отправку неактивным пользователям." refresh: "Обновить" + send_digest_label: "Отправить этот результат на:" send_digest: "Отправить" sending_email: "Отправка письма..." format: "Формат" html: "html" text: "текст" last_seen_user: "Последний раз был:" + no_result: "Ничего не найдено для сводки новостей." reply_key: "Ключ ответа" skipped_reason: "Причина пропуска" incoming_emails: @@ -2750,6 +2898,13 @@ ru: revoke_moderation: "отозваны права модератора" backup_operation: "операции резервного копирования" deleted_tag: "удаленный тег" + renamed_tag: "переименованный тэг" + revoke_email: "отозвать e-mail" + lock_trust_level: "заморозка уровня доверия" + unlock_trust_level: "разморозка уровня доверия" + activate_user: "активация пользователя" + deactivate_user: "деактивация пользователя" + change_readonly_mode: "изменение режима \"только для чтения\"" screened_emails: title: "Почтовые адреса" description: "Когда кто-то создает новую учетную запись, проверяется данный почтовый адрес и регистрация блокируется или производятся другие дополнительные действия." @@ -2852,6 +3007,7 @@ ru: suspend_reason: "Причина" suspended_by: "Заморожен" delete_all_posts: "Удалить все сообщения" + delete_all_posts_confirm_MF: "Вы собираетесь удалить {POSTS, plural, one {1 сообщение} other {# сообщений}} и {TOPICS, plural, one {1 тему} other {# тем}}. Вы уверены?" suspend: "Заморозить" unsuspend: "Разморозить" suspended: "Заморожен?" @@ -2945,6 +3101,11 @@ ru: unlock_trust_level: "Разморозить уровень доверия" tl3_requirements: title: "Требования для 3 уровня доверия" + table_title: + one: "За последний день:" + few: "За последние %{count} дней:" + many: "За последние %{count} дней:" + other: "За последние %{count} дней:" value_heading: "Значение" requirement_heading: "Требование" visits: "Посещений" @@ -3044,6 +3205,7 @@ ru: developer: 'Программистам' embedding: "Встраивание" legal: "Юридическое" + user_api: 'Пользовательский API' uncategorized: 'Вне разделов' backups: "Резервные копии" login: "Учетные записи" @@ -3051,6 +3213,7 @@ ru: user_preferences: "Пользовательские настройки" tags: "Тэги" search: "Поиск" + groups: "Группы" badges: title: Награды new_badge: Новая награда @@ -3177,8 +3340,15 @@ ru: upload: "Загрузить" uploading: "Загрузка..." quit: "Может быть позже" + staff_count: + one: "В Вашем сообществе 1 сотрудник." + few: "В Вашем сообществе %{count} сотрудника." + many: "В Вашем сообществе %{count} сотрудников." + other: "В Вашем сообществе %{count} сотрудников." invites: add_user: "добавить" + none_added: "Вы ещё не пригласили сотрудников. Вы уверены, что хотите продолжить?" roles: admin: "Администратор" moderator: "Модератор" + regular: "Постоянный Пользователь" diff --git a/config/locales/client.sk.yml b/config/locales/client.sk.yml index c8c81ef7dad..27df271ba97 100644 --- a/config/locales/client.sk.yml +++ b/config/locales/client.sk.yml @@ -342,17 +342,10 @@ sk: few: "%{count} používatelia" other: "%{count} používateľov" groups: - empty: - posts: "Neexistuje žiadny príspevok od člena tejto skupiny." - members: "Táto skupina neobsahuje žiadnych členov." - mentions: "Táto skupina nieje nikde zmienená." - messages: "Neexistujú žiadne správy pre túto skupinu." - topics: "Neexistuje žiadna téma od členov tejto skupiny." add: "Pridať" selector_placeholder: "Pridať členov" owner: "vlastník" visible: "Skupina je viditeľná všetkým používateľom" - index: "Skupiny" title: one: "skupina" few: "skupiny" @@ -695,11 +688,8 @@ sk: create: "Poslať Pozvánku" generate_link: "Kopírovať Odkaz Pozvánky" bulk_invite: - none: "Zatiaľ ste tu nikoho nepozvali. Môžete odosielať pozvánky individuálne alebo pozvať skupinu ľudí naraz pomocou nahratia súboru." text: "Hromadná pozvánka zo súboru" - uploading: "Prebieha nahrávanie..." success: "Súbor bol úspešne odoslaný. Keď sa nahrávanie dokončí, budete na to upozornený cez správu." - error: "Pri nahrávaní '{{filename}}' sa vyskytla chyba: {{message}}" password: title: "Heslo" too_short: "Vaše heslo je príliš krátke." @@ -1231,7 +1221,6 @@ sk: go_bottom: "na spodok" go: "Choď" jump_bottom: "choď na posledný príspevok" - jump_prompt: "choď na príspevok" jump_bottom_with_number: "choď na príspevok číslo %{post_number}" total: Všetkých príspevkov current: tento príspevok @@ -1466,7 +1455,6 @@ sk: file_too_large: "Ľutujeme, daný súbor je príliš veľký (maximálna veľkosť je {{max_size_kb}}kB). Čo takto nahrať ten súbor na zdielané cloudové úložisko a nazdielať odkaz?" too_many_uploads: "Ľutujeme, ale naraz je možné nahrať iba jeden súbor." too_many_dragged_and_dropped_files: "Ľutujeme, ale naraz je možné nahrať iba 10 súborov." - upload_not_authorized: "Ľutujeme, súbor, ktorý sa pokúšate nahrať nemá povolenú príponu (povolené prípony sú: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Ľutujeme, noví použivatelia nemôžu nahrávať obrázky." attachment_upload_not_allowed_for_new_user: "Ľutujeme, noví používatelia nemôžu nahrávať prílohy." attachment_download_requires_login: "Ľutujeme, pre stiahnutie príloh musíte byť prihlásený." @@ -1779,7 +1767,6 @@ sk: few: "zobrazenia" other: "zobrazení" replies: "Odpovede" - views_long: "táto téma bola prezeraná {{number}} krát " activity: "Aktivita" likes: "Páči sa mi" likes_lowercase: @@ -2066,8 +2053,6 @@ sk: backups: "zálohy" traffic_short: "Vyťaženie" traffic: "Požiadavky webových aplikácií" - page_views: "Požiadavky API" - page_views_short: "Požiadavky API" show_traffic_report: "Zobraziť detaily vyťaženia" reports: today: "Dnes" @@ -2162,15 +2147,12 @@ sk: refresh: "Obnoviť" new: "Nový" selector_placeholder: "zadať používateľské meno" - name_placeholder: "Názov skupiny, bez medzier, rovnaké pravidlá ako pre používateľa" about: "Tu upravíte Vaše členstvo v skupinách a mená" group_members: "Členovia skupiny" delete: "Odstrániť" delete_confirm: "Zmazať túto skupinu?" delete_failed: "Nepodarilo sa zmazať skupinu. Pokiaľ je skupina automatická, nemôže byť zrušená." - delete_member_confirm: "Odstrániť '%{username}' zo skupiny '%{group}'?" delete_owner_confirm: "Odobrať vlastnícke práva %{username}'?" - name: "Meno" add: "Pridať" add_members: "Pridať členov" custom: "Vlastné" @@ -2187,7 +2169,6 @@ sk: add_owners: Pridať vlastníkov incoming_email: "Vlastná e-mailová adresa pre príchodziu poštu" incoming_email_placeholder: "zadajte emailovú adresu" - flair_preview: "Náhľad" api: generate_master: "Vygenerovať Master API kľúč" none: "V súčasnosti neexistujú žiadne aktívne API kľúče." diff --git a/config/locales/client.sq.yml b/config/locales/client.sq.yml index 35dbf8f25c1..521f7276639 100644 --- a/config/locales/client.sq.yml +++ b/config/locales/client.sq.yml @@ -320,17 +320,10 @@ sq: one: "1 anëtar" other: "%{count} anëtarë" groups: - empty: - posts: "Nuk ka postim nga anëtarët e këtij grupi." - members: "Nuk ka asnjë anëtar në këtë grup." - mentions: "Nuk ka përmendje për këtë grup." - messages: "Nuk ka mesazhe për këtë grup." - topics: "Nuk ka asnjë temë nga anëtarët e këtij grupi." add: "Shto" selector_placeholder: "Shto anëtarë" owner: "autori" visible: "Grupi është i dukshëm për të gjithë përdoruesit" - index: "Grupet" title: one: "grup" other: "grupe" @@ -458,7 +451,7 @@ sq: moderator_tooltip: "Ky anëtar është moderator" admin_tooltip: "Ky anëtar është administrator" blocked_tooltip: "Ky anëtar është i bllokuar" - suspended_notice: "Ky anëtarë është përjashtuar deri më {{date}}." + suspended_notice: "Ky anëtar është përjashtuar deri më {{date}}." suspended_reason: "Arsyeja:" github_profile: "Github" email_activity_summary: "Përmbledhja e aktivitetit" @@ -676,11 +669,8 @@ sq: create: "Dërgo një ftesë" generate_link: "Kopjo lidhjen e ftesës" bulk_invite: - none: "Ju nuk keni ftuar askënd deri tani. Mund të dërgoni ftesa individuale ose mund të ftoni një grup personash duke ngarkuar skedarin." text: "Skedari për ftesat në grup" - uploading: "Duke ngarkuar..." success: "Skedari u ngarkua, do njoftoheni me mesazh kur procesi të mbarojë. " - error: "Pati një gabi gjatë ngarkimit të skedarit '{{filename}}': {{message}}" password: title: "Fjalëkalimi" too_short: "Fjalëkalimi është shumë i shkurër." @@ -1210,7 +1200,6 @@ sq: go_bottom: "poshtë" go: "shko" jump_bottom: "hidhu tek përgjigja e fundit" - jump_prompt: "hidhu tek tema" jump_prompt_long: "Tek cila temë doni të shkoni?" jump_bottom_with_number: "shko tek përgjigja %{post_number}" total: totali i postimeve @@ -1425,7 +1414,6 @@ sq: file_too_large: "Na vjen keq, skedari është shumë i madh (maksimumi i lejuar është {{max_size_kb}}kb). Mund t'a vendosni këtë skedar të madh në një faqe tjetër dhe të vendosni këtu vetëm lidhjen." too_many_uploads: "Na vjen keq, por duhet t'i ngarkoni skedarët një nga një." too_many_dragged_and_dropped_files: "Na vjen keq, po ju mund të ngarkoni vetëm 10 skedarë njëkohësisht. " - upload_not_authorized: "Na vjen keq, skedari që po ngarkoni nuk është i autorizuar (tipet e skedarëve të lejuar: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Na vjen keq, anëtarët e rinj nuk mund të ngarkojnë skedarë. " attachment_upload_not_allowed_for_new_user: "Na vjen keq, anëtarët e rinj nuk mund të ngarkojnë skedarë. " attachment_download_requires_login: "Na vjen keq, duhet të identifikoheni për të shkarkuar një dokument. " @@ -1719,7 +1707,6 @@ sq: one: "shikim" other: "shikime" replies: "Përgjigjet" - views_long: "kjo temë është parë {{number}} herë" activity: "Aktiviteti" likes: "Pëlqimet" likes_lowercase: @@ -2014,8 +2001,6 @@ sq: backups: "backupe" traffic_short: "Trafik" traffic: "Kërkesat web të aplikimit" - page_views: "Kërkesat në API" - page_views_short: "Kërkesat në API" show_traffic_report: "Trego raportin e detajuar të trafikut" reports: today: "Sot" @@ -2104,15 +2089,12 @@ sq: refresh: "Rifresko" new: "I Ri" selector_placeholder: "vendos emrin e përdoruesit" - name_placeholder: "Emri i grupit, pa hapësira, si username-t" about: "Modifiko anëtarët e grupit dhe emrin këtu" group_members: "Përdorues grupi" delete: "Fshij" delete_confirm: "Fshije këtë grup?" delete_failed: "Nuk e fshimë dot grupin. Nëse ky është një grup automatik, nuk fshihet dot. " - delete_member_confirm: "Do të heqësh '%{username}' nga grupi '%{group}'?" delete_owner_confirm: "Hiqe privilegjin e pronarit për '%{username}'?" - name: "Emri" add: "Shto" add_members: "Shto Anëtar" custom: "Grupet e krijuara" @@ -2123,7 +2105,6 @@ sq: automatic: "Automatik" group_owners: Pronarët add_owners: Shto pronarë - flair_preview: "Parashikimi" api: generate_master: "Gjenero Master API Key" none: "Për momentin, nuk ka çelësa API aktivë." diff --git a/config/locales/client.sv.yml b/config/locales/client.sv.yml index 3af09a3a036..70ed37119fd 100644 --- a/config/locales/client.sv.yml +++ b/config/locales/client.sv.yml @@ -322,17 +322,10 @@ sv: one: "1 användare" other: "%{count} användare" groups: - empty: - posts: "Det finns inga inlägg från medlemmar in denna grupp." - members: "Det finns ingen medlem i den här gruppen." - mentions: "Det finns ingen omnämnande i den här gruppen." - messages: "Det finns inget meddelande för den här gruppen." - topics: "Det finns inget ämne från medlemmar i den här gruppen." add: "Lägg till" selector_placeholder: "Lägg till medlemmar" owner: "ägare" visible: "Gruppen är synlig för alla användare" - index: "Grupper" title: one: "grupp" other: "grupper" @@ -695,11 +688,8 @@ sv: link_generated: "Länk för inbjudan framgångsrikt skapad!" valid_for: "Länk för inbjudan är endast giltig för denna email adress: %{email}" bulk_invite: - none: "Du har inte skickat några inbjudningar. Du kan skicka individuella inbjudningar, eller så kan du bjuda in flera på en gång genom att ladda upp en bulkfil." text: "Massinbjudan från fil" - uploading: "Laddar upp..." success: "Filen laddades upp, du blir underrättad via meddelande när processen är klar" - error: "Det blev ett fel vid uppladdning av '{{filename}}': {{message}}" password: title: "Lösenord" too_short: "Ditt lösenord är för kort." @@ -1273,7 +1263,6 @@ sv: go_bottom: "botten" go: "gå" jump_bottom: "hoppa till sista inlägget" - jump_prompt: "hoppa till inlägg" jump_prompt_long: "Vilket inlägg vill du hoppa till?" jump_bottom_with_number: "hoppa till inlägg %{post_number}" total: antal inlägg @@ -1505,7 +1494,6 @@ sv: file_too_large: "Tyvärr, filen är för stor (maximal filstorlek är {{max_size_kb}}kb). Varför inte ladda upp din stora fil till en moln-delningstjänst och sen dela länken?" too_many_uploads: "Tyvärr, du kan bara ladda upp en bild i taget." too_many_dragged_and_dropped_files: "Tyvärr, du kan bara ladda upp 10 filer åt gången." - upload_not_authorized: "Tyvärr, filen du försökte ladda upp är inte tillåten (tillåtna filtyper: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Tyvärr, nya användare kan inte ladda upp bilder." attachment_upload_not_allowed_for_new_user: "Tyvärr, nya användare kan inte bifoga filer." attachment_download_requires_login: "Tyvärr, du måste vara inloggad för att kunna ladda ned bifogade filer." @@ -1823,7 +1811,6 @@ sv: one: "visning" other: "visningar" replies: "Svar" - views_long: "detta ämne har visats {{number}} gånger" activity: "Aktivitet" likes: "Gillningar" likes_lowercase: @@ -2125,8 +2112,6 @@ sv: backups: "säkerhetskopior" traffic_short: "Trafik" traffic: "Applikations-webbegäran" - page_views: "API-förfrågningar" - page_views_short: "API-förfrågningar" show_traffic_report: "Visa detaljerad trafikrapport" reports: today: "Idag" @@ -2216,15 +2201,12 @@ sv: refresh: "Uppdatera" new: "Ny" selector_placeholder: "ange användarnamn" - name_placeholder: "Gruppnamn, inga mellanslag, samma regler som för användarnamn" about: "Redigera dina gruppmedlemskap och -namn här." group_members: "Gruppmedlemmar" delete: "Radera" delete_confirm: "Ta bort den här gruppen?" delete_failed: "Oförmögen att ta bort grupp. Om det här är en automatisk grupp så kan den inte raderas." - delete_member_confirm: "Ta bort '%{username}' från '%{group}' gruppen?" delete_owner_confirm: "Ta bort användarprivilegier för '\"{username}'?" - name: "Namn" add: "Lägg till" add_members: "Lägg till medlemmar" custom: "Anpassad" @@ -2241,9 +2223,6 @@ sv: add_owners: Lägg till ägare incoming_email: "Egenvald inkommande e-postadress" incoming_email_placeholder: "Ange e-postadress" - flair_bg_color_placeholder: "(Valfritt) Hexadecimal färgkod" - flair_color_placeholder: "(Valfritt) Hexadecimal färgkod" - flair_preview: "Förhandsgranska" api: generate_master: "Generera API-huvudnyckel" none: "Det finns inga aktiva API-nycklar just nu." @@ -2271,7 +2250,6 @@ sv: payload_url_placeholder: "https://example.com/postreceive" secret_invalid: "Hemligheten får inte ha några blanka tecken." secret_too_short: "Hemligheten bör vara minst 12 tecken." - secret_placeholder: "En valfri sträng, används för att generera signatur" content_type: "Innehållstyp" secret: "Hemlighet" event_chooser: "Vilka event vill du ska utlösa den här webhooken?" @@ -2292,7 +2270,6 @@ sv: details: "När det finns ett nytt svar, redigerat, borttaget eller återskapat." user_event: name: "Användarevent" - details: "När en användare är skapad eller godkänd." delivery_status: title: "Leveransstatus" inactive: "Inaktiv" diff --git a/config/locales/client.te.yml b/config/locales/client.te.yml index e5e0f62757f..44b0764ac27 100644 --- a/config/locales/client.te.yml +++ b/config/locales/client.te.yml @@ -410,10 +410,7 @@ te: account_age_days: "రోజుల్లో ఖాతా వయసు" create: "ఒక ఆహ్వానం పంపు" bulk_invite: - none: "మీరు ఇంకా ఎవరినీ ఆహ్వానించలేదు. మీరు వ్యక్తిగత ఆహ్వానాలు పంపవచ్చు, లేదా కొంతమందికి ఒకేసారి ఆహ్వాన దస్త్రం ఎగుమతించుట ద్వారా పంపవచ్చు." text: "దస్త్రం నుండి బహుళ ఆహ్వానాలు" - uploading: "ఎగుమతవుతోంది..." - error: "'{{filename}}' ఎగుమతించుటలో దోషం: {{message}}" password: title: "సంకేతపదం" too_short: "మీ సంకేతపదం మరీ చిన్నది." @@ -855,7 +852,6 @@ te: edit: "క్షమించాలి. మీ టపా సవరించుటలో దోషం. మరలా ప్రయత్నించండి" upload: "క్షమించాలి. దస్త్రం ఎగుమతించుటలో దోషం. దయచేసి మరలా ప్రయత్నించండి. " too_many_uploads: "క్షమించాలి. మీరు ఒకసారి ఒక దస్త్రం మాత్రమే ఎగుమతించగలరు" - upload_not_authorized: "క్షమించాలి. మీరు ఎగుమతించాలనుకుంటున్న దస్త్రం అధీకృతమైనది కాదు. (అధీకృత పొడిగింతలు:{{authorized_extensions}})." image_upload_not_allowed_for_new_user: "క్షమించాలి. కొత్త సభ్యులు బొమ్మలు ఎగుమతి చేయలేరు." attachment_upload_not_allowed_for_new_user: "క్షమించాలి. కొత్త సభ్యులు జోడింపులు ఎగుమతి చేయలేరు." attachment_download_requires_login: "క్షమించాలి. జోడింపులు దిగుమతి చేసుకోవడానికి మీరు లాగిన్ అయి ఉండాలి." @@ -1082,7 +1078,6 @@ te: original_post: "మూల టపా" views: "చూపులు" replies: "జవాబులు" - views_long: "ఈ విషయం {{number}} సార్లు చూడబడింది." activity: "కలాపం" likes: "ఇష్టాలు" likes_long: "ఈ విషయానికి {{number}} ఇష్టాలు ఉన్నాయి" @@ -1162,8 +1157,6 @@ te: backups: "బ్యాకప్లు" traffic_short: "ట్రాఫిక్" traffic: "అనువర్తన జాల రిక్వెస్టులు" - page_views: "API అభ్యర్ధనలు" - page_views_short: "API అభ్యర్ధనలు" show_traffic_report: "సవివరణ ట్రాఫిక్ రిపోర్టు చూపు" reports: today: "ఈరోజు" @@ -1250,14 +1243,11 @@ te: refresh: "తాజా పరుచు" new: "కొత్త" selector_placeholder: "సభ్యనామం రాయండి" - name_placeholder: "గంపు పేరు, జాగా లేకుండా, సభ్యనామం వలె" about: "మీ గుంపు మెంబర్షిప్పు మరియు పేర్లు ఇక్కడ సవరించండి" group_members: "గుంపు సభ్యులు" delete: "తొలగించు" delete_confirm: "ఈ గుంపును తొలగించాలనుకుంటున్నారా? " delete_failed: "గుంపును తొలగించలేకున్నాము. ఇది స్వీయ గుంపు అయితే దీన్ని నాశనం చేయలేరు." - delete_member_confirm: " '%{group}' గుంపు నుండి '%{username}' ను తొలగించాలా?" - name: "పేరు" add: "కలుపు" add_members: "సభ్యులను కలుపు" automatic_membership_email_domains: "వినియోగదారుడు ఏ ఈ-మెయిల్ డొమైన్ తో నమోదు చేసుకున్నాడో అది ఖచ్చితంగా ఈ జాబితాలో ఒక దానిని పోలి స్వయంసిధ్ధంగా గ్రూప్ కి కలుస్తాయి:" diff --git a/config/locales/client.tr_TR.yml b/config/locales/client.tr_TR.yml index b2e572f0cd5..2b1ad1d892d 100644 --- a/config/locales/client.tr_TR.yml +++ b/config/locales/client.tr_TR.yml @@ -295,20 +295,62 @@ tr_TR: posts_read_long: "Okunmuş Gönderiler" total_rows: other: "%{count} kullanıcı" + group_histories: + actions: + change_group_setting: "Grup ayarlarını değiştir" + add_user_to_group: "Kullanıcı ekle" + remove_user_from_group: "Kullanıcıyı kaldır" + make_user_group_owner: "Sahip yap" + remove_user_as_group_owner: "Sahipliğini İptal Et" groups: + logs: + title: "Kayıtlar" + when: "Ne zaman" + action: "Eylem" + acting_user: "Temsili Kullanıcılar" + target_user: "Hedef Kullanıcı" + subject: "Konu" + details: "Ayrıntılar" + from: "Gönderen" + to: "Kime" + edit: + title: 'Grubu düzenle' + full_name: 'Tam İsim' + add_members: "Üyeleri ekle" + delete_member_confirm: "'%{username}' adlı kullanıcıyı '%{group}' grubundan çıkart?" + request_membership_pm: + title: "Üyelik isteği" + body: "@%{groupName} adlı gruba üye olarak başvurmak istiyorum." + name_placeholder: "Grup adı, kullanıcı adındaki gibi boşluksuz olmalı" + public: "Kullanıcıların gruptan serbest bir şekilde ayrılıp/katılmasına izin ver (grubun görünür olması gerekmekte)" empty: - posts: "Bu grubun üyelerinden gönderi yok." - members: "Bu grupta üye yok." - mentions: "Bu gruptan söz edilmemiş." - messages: "Bu grup için bir ileti yok." - topics: "Bu grubun üyelerinden konu yok." + posts: "Bu grubun üyelerinden konu yok." + members: "Bu grupta üye bulunmamaktır." + mentions: "Bu grupta kimseden bahsedilmemiştir." + messages: "Bu grupta mesaj bulunmamaktadır." + topics: "Bu grubun üyeleri tarafından oluşturulmuştur başlık yoktur." + logs: "Bu grup için log kaydı bulunmamaktadır." add: "Ekle" + join: "Gruba katıl" + leave: "Gruptan ayrıl" + request: "Gruba katılmak için istek yolla" + automatic_group: Otomatik Grup + closed_group: Kapanmış Grup + is_group_user: "Bu grubun bir üyesisiniz." + allow_membership_requests: "Kullanıcıların Grup başlarına üyelik istekleri göndermelerine izin ver ( Herkesin grupta birbirleri hakkında bahsetme özelliğinin açık olması gerekmektedir.)" + membership: "Üyelik" + name: "İsim" + user_count: "Grup Sayısı" + bio: "Grup Hakkında" selector_placeholder: "Üye ekle" owner: "sahip" visible: "Grup tüm kullanıcılar tarafından görüntülenebiliyor" - index: "Gruplar" + index: + title: "Gruplar" + empty: "Görünen hiç bir grup bulunmamaktadır." title: other: "gruplar" + activity: "Etkinlik" members: "Üyeler" topics: "Konular" posts: "Gönderiler" @@ -340,6 +382,15 @@ tr_TR: muted: title: "Susturuldu" description: "Bu gruptaki herhangi yeni bir konuyla ilgili asla bildirim almayacaksınız." + flair_url: "Avatar Kabiliyet Resmi" + flair_url_placeholder: "(İsteğe bağlı) Resim URL'si veya Font Awesome Class'ı" + flair_bg_color: "Avatar Kabiliyet Arkaplan Rengi" + flair_bg_color_placeholder: "(İsteğe bağlı) Hex renk değeri" + flair_color: "Avatar Kabiliyet Rengi" + flair_color_placeholder: "(İsteğe bağlı) Hex renk değeri" + flair_preview_icon: "İkonu önizle" + flair_preview_image: "Resimi önizle" + flair_note: "Not: Kabiliyet sadece bir kullanıcının birincil grubu için gösterecek." user_action_groups: '1': "Verilen Beğeniler" '2': "Alınan Beğeniler" @@ -399,6 +450,11 @@ tr_TR: profile: "Profil" mute: "Sustur" edit: "Tercihleri Düzenle" + download_archive: + button_text: "Gönderilerimi İndir" + confirm: "Gönderilerinizi indirmek istediğinize emin misiniz?" + success: "İndirme başlatıldı, İşlem tamamlandığında mesaj ile bilgilendirileceksiniz." + rate_limit_error: "Gönderiler günde bir kez indirilebilir, lütfen yarın tekrar deneyin." new_private_message: "Yeni İleti" private_message: "İleti" private_messages: "İletiler" @@ -422,6 +478,7 @@ tr_TR: each_browser_note: "Not: Bu ayarı kullandığınız her tarayıcıda değiştirmelisiniz." dismiss_notifications: "Tümünü Yoksay" dismiss_notifications_tooltip: "Tüm okunmamış bildirileri okunmuş olarak işaretle" + first_notification: "İlk bilidiriminiz! Başlamak için seçiniz" disable_jump_reply: "Cevapladıktan sonra gönderime atlama" dynamic_favicon: "Tarayıcı simgesinde yeni / güncellenen konu sayısını göster" external_links_in_new_tab: "Tüm dış bağlantıları yeni sekmede aç" @@ -444,6 +501,7 @@ tr_TR: Susturulmuş konular ve kategoriler bu e-postalarda yer almaz. daily: "Günlük güncellemeleri gönder" individual: "Her yeni gönderi için bir e-posta gönder" + individual_no_echo: "Benim gönderilerim haricindeki her gönderi için mail gönder" many_per_day: "Her yeni gönderi için bir e-posta gönder (günde yaklaşık {{dailyEmailEstimate}})." few_per_day: "Her yeni gönderi için bana e-posta gönder ( günlük yaklaşık 2 )" tag_settings: "Etiketler" @@ -654,12 +712,13 @@ tr_TR: account_age_days: "Hesabın gün olarak yaşı" create: "Davet Yolla" generate_link: "Davet bağlantısını kopyala" + link_generated: "Davet linki başarılı bir şekilde oluşturuldu" + valid_for: "Davet linki sadece bu adres için geçerlidir: %{email}" bulk_invite: - none: "Henüz kimseyi buraya davet etmediniz. Tek tek davetiye gönderebilirsiniz, ya da toplu bir davetiye dosyası yükleyerek birçok kişiyi aynı anda davet edebilirsiniz. " + none: "Henüz kimseyi davet etmemiş görünüyorsun. İstersen bireysel davetler gönderebilir veya CSV dosyası yükleyerek bir çok insanı aynı anda davet edebilirsin." text: "Dosyadan Toplu Davet Gönder" - uploading: "Yükleniyor..." success: "Dosya başarıyla yüklendi, işlem tamamlandığında iletiyle bilgilendirileceksiniz." - error: "'{{filename}}' yüklenirken bir hata oluştu: {{message}}" + error: "Üzgünüz, Dosya csv formatında olmalı" password: title: "Parola" too_short: "Parolanız çok kısa." @@ -802,6 +861,7 @@ tr_TR: trust_level: 'Güven Seviyesi' search_hint: 'kullanıcı adı, e-posta veya IP adresi' create_account: + disclaimer: "Kayıt olarak, gizlilik ilkesi ve hizmet kullanım şartlarını kabul etmiş olmaktasınız." title: "Yeni Hesap Oluştur" failed: "Bir şeyler ters gitti. Bu e-posta adına daha önce bir kayıt oluşturulmuş olabilir, parolamı unuttum bağlantısını dene." forgot_password: @@ -891,6 +951,9 @@ tr_TR: drafts_offline: "çevrimdışı taslaklar" group_mentioned: other: "{{group}} hakkında konuşarak {{count}} kişiyi bilgilendirmek üzeresin, emin misin?" + cannot_see_mention: + category: "{{username}} adlı kullanıcıdan bahsettiniz fakat Ona bildirim gönderilmeyecek çünkü bu kategoriye ulaşma izni yok. Bunun gerçekleşmesi için kişi bu gruba eklemeniz gerekmektedir." + private: "{{username}} adlı kullanıcıdan bahsettiniz fakat Ona bildirim gönderilmeyecek çünkü bu kişisel mesaja ulaşma izni yok. Bunun gerçekleşmesi için kişiyi bu PM'ye eklemeniz gerekmektedir." duplicate_link: "Görünüşe göre {{domain}} alan adına bağlanan bağlantınız @{{username}} tarafından a cevabı içerisinde {{ago}} yayınlanmış görünüyor. – tekrar yayınlamak istediğinize emin misiniz?" error: title_missing: "Başlık gerekli" @@ -910,8 +973,10 @@ tr_TR: title: "Ya da Ctrl+Enter'a bas" users_placeholder: "Kullanıcı ekle" title_placeholder: "Bir cümlede açıklamak gerekirse bu tartışmanın konusu nedir?" + title_or_link_placeholder: "Buraya bir başlık girin veya bir link paylaşın" edit_reason_placeholder: "neden düzenleme yapıyorsunuz?" show_edit_reason: "(düzenleme sebebi ekle)" + topic_featured_link_placeholder: "Başlığı olan bir link giriniz." reply_placeholder: "Buraya yazın. Biçimlendirmek için Markdown, BBCode ya da HTML kullanabilirsin. Resimleri sürükleyebilir ya da yapıştırabilirsin." view_new_post: "Yeni gönderinizi görüntüleyin." saving: "Kaydediliyor" @@ -1056,6 +1121,8 @@ tr_TR: label: Şu Kategoride in_group: label: Şu Grupta + with_badge: + label: Rozetle with_tags: label: Şu Etiketli filters: @@ -1066,6 +1133,7 @@ tr_TR: tracking: takip ettiğim private: iletilerimde olan bookmarks: imlediğim + first: en ilk gönderidir. pinned: tutturulmuş unpinned: tutturulmamış wiki: wiki olan @@ -1092,6 +1160,7 @@ tr_TR: new_messages_marker: "son ziyaret" bulk: select_all: "Tümünü Seç" + clear_all: "Tümünü Temizle" unlist_topics: "Konuları Listeleme" reset_read: "Okunmuşları Sıfırla" delete: "Konuları Sil" @@ -1209,7 +1278,8 @@ tr_TR: go_bottom: "en alt" go: "git" jump_bottom: "son gönderiye geç" - jump_prompt: "gönderiye git" + jump_prompt: "atla" + jump_prompt_of: " %{count} gönderinin" jump_prompt_long: "Hangi gönderiye gitmek istersin?" jump_bottom_with_number: "%{post_number} numaralı gönderiye geç" total: tüm gönderiler @@ -1396,6 +1466,7 @@ tr_TR: post: reply: " {{replyAvatar}} {{usernameLink}}" reply_topic: " {{link}}" + quote_reply: "Alıntı" edit: "{{link}} {{replyAvatar}} {{username}} düzenleniyor" edit_reason: "Neden: " post_number: "gönderi {{number}}" @@ -1427,7 +1498,7 @@ tr_TR: file_too_large: "Üzgünüz, bu dosya çok büyük (en fazla {{max_size_kb}}kb). Neden büyük boyutlu dosyanı bir paylaşım servisine yükleyip, sonra bağlantını paylaşmıyorsun ?" too_many_uploads: "Üzgünüz, aynı anda birden fazla dosya yükleyemezsiniz." too_many_dragged_and_dropped_files: "Üzgünüz, aynı anda 10'dan fazla dosya yükleyemezsiniz." - upload_not_authorized: "Üzgünüz, yüklemeye çalıştığınız dosya tipine izin verilmiyor. (izin verilen uzantılar: {{authorized_extensions}})." + upload_not_authorized: "Üzgünüz, yüklemeye çalıştığınız dosya izinli değil (authorized extensions: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Üzgünüz, yeni kullanıcılar resim yükleyemezler." attachment_upload_not_allowed_for_new_user: "Üzgünüz, yeni kullanıcılar dosya yükleyemezler." attachment_download_requires_login: "Üzgünüz, eklentileri indirebilmek için oturum açmanız gerekiyor." @@ -1573,6 +1644,7 @@ tr_TR: tags_allowed_tag_groups: "Yalnızca bu kategoride kullanılabilir etiket grupları:" tags_placeholder: "(Seçmeli) izin verilen etiketlerin listesi" tag_groups_placeholder: "(Seçmeli) izin verilen etiket gruplarının listesi" + topic_featured_link_allowed: " Featured link'lere bu kategoride izin ver" delete: 'Kategoriyi Sil' create: 'Yeni Kategori' create_long: 'Yeni bir kategori oluştur' @@ -1607,6 +1679,7 @@ tr_TR: email_in_disabled: "E-posta üzerinden yeni konu oluşturma özelliği Site Ayarları'nda devre dışı bırakılmış. E-posta üzerinden yeni konu oluşturma özelliğini etkinleştirmek için," email_in_disabled_click: '"e-postala" ayarını etkinleştir' suppress_from_homepage: "Bu kategoriyi ana sayfadan gizle" + all_topics_wiki: "Yeni konuyu varsayılan olarak wiki yap" sort_order: "Öntanımlı Sıralama:" allow_badges_label: "Bu kategoride rozet verilmesine izin ver" edit_permissions: "İzinleri Düzenle" @@ -1636,11 +1709,15 @@ tr_TR: sort_options: default: "öntanımlı" likes: "Beğeniler" + op_likes: "Orijinal Gönderi Beğenileri" views: "Gösterimler" posts: "Gönderiler" activity: "Etkinlik" + posters: "Yazanlar" category: "Kategori" created: "Oluşturulma" + sort_ascending: 'Artan' + sort_descending: 'Azalan' flagging: title: 'Topluluğumuzun düzenli kalmasına desteğiniz için teşekkürler!' action: 'Gönderiyi Bildir' @@ -1719,7 +1796,8 @@ tr_TR: views_lowercase: other: "gösterim" replies: "Cevap" - views_long: "bu konu {{number}} defa görüntülendi" + views_long: + other: "bu konu {{number}} defa görüntülendi" activity: "Etkinlik" likes: "Beğeni" likes_lowercase: @@ -2012,8 +2090,8 @@ tr_TR: backups: "yedekler" traffic_short: "Trafik" traffic: "Uygulama web istekleri" - page_views: "API istekleri" - page_views_short: "API istekleri" + page_views: "Sayfa Görüntülemeleri" + page_views_short: "Sayfa Görüntülemeleri" show_traffic_report: "Ayrıntılı Trafik Raporunu Görüntüle" reports: today: "Bugün" @@ -2098,15 +2176,12 @@ tr_TR: refresh: "Yenile" new: "Yeni" selector_placeholder: "kullanıcı adı girin" - name_placeholder: "Grup adı, kullanıcı adındaki gibi boşluksuz olmalı" about: "Grup üyeliğinizi ve isimleri burada düzenleyin" group_members: "Grup üyeleri" delete: "Sil" delete_confirm: "Grup silinsin mi?" delete_failed: "Grup silinemedi. Bu otomatik oluşturulmuş bir grup ise, yok edilemez." - delete_member_confirm: "'%{username}' adlı kullanıcıyı '%{group}' grubundan çıkart?" delete_owner_confirm: "'%{username}' için sahiplik izni kaldırılsın mı?" - name: "Ad" add: "Ekle" add_members: "Üye ekle" custom: "Özel" @@ -2123,14 +2198,6 @@ tr_TR: add_owners: Sahiplik ekle incoming_email: "Özel gelen e-posta adresi" incoming_email_placeholder: "e-posta adresi girin" - flair_url: "Avatar Kabiliyet Resmi" - flair_url_placeholder: "(İsteğe bağlı) Resim URL'i ya da Font Awesome sınıfı" - flair_bg_color: "Avatar Kabiliyet Arkaplan Rengi" - flair_bg_color_placeholder: "(İsteğe bağlı) Hex renk değeri" - flair_color: "Avatar Kabiliyet Resmi" - flair_color_placeholder: "(İsteğe bağlı) Hex renk değeri" - flair_preview: "Önizleme" - flair_note: "Not: Kabiliyet sadece bir kullanıcının birincil grubu için gösterecek." api: generate_master: "Ana API Anahtarı Üret" none: "Şu an etkin API anahtarı bulunmuyor." @@ -2162,7 +2229,7 @@ tr_TR: warn_local_payload_url: "Öyle görünüyor ki, web kancasını yerel bir URL'e ayarlamaya çalışıyorsunuz. Yerel bir adrese iletilen olay yan etki veya beklenmedik davranışlara neden olabilir. Devam edilsin mi?" secret_invalid: "Gizli alanında boş karakter olamaz." secret_too_short: "Gizi en azından 12 karakter olmalı." - secret_placeholder: "İsteğe bağlı bir kelime, imza oluşturmak için kullanılacak" + secret_placeholder: "İmza oluşturmak için isteğe bağlı bir dizi" event_type_missing: "En az bir olay tipi ayarlamalısınız." content_type: "İçerik Türü" secret: "Gizli" @@ -2185,7 +2252,7 @@ tr_TR: details: "Yeni bir cevap oluşturulduğunda, düzenlendiğinde veya silindiğinde." user_event: name: "Kullanıcı Olayı" - details: "Kullanıcı oluşturulduğunda veya onaylandığında." + details: "Bir kullanıcı oluşturulduğunda, onaylandığında veya güncellendiğinde" delivery_status: title: "Teslim Durumu" inactive: "Etkin Değil" @@ -2408,6 +2475,7 @@ tr_TR: html: "html" text: "yazı" last_seen_user: "Son Görülen Kullanıcı:" + no_result: "Derleme için hiç bir sonuç bulunamadı." reply_key: "Cevapla Tuşu" skipped_reason: "Nedeni Atla" incoming_emails: @@ -2503,6 +2571,11 @@ tr_TR: deleted_tag: "silinmiş etiket" renamed_tag: "yeniden adlandırılmış etiket" revoke_email: "e-postayı kaldır" + lock_trust_level: "Güven Seviyesini Kilitle" + unlock_trust_level: "Güvenlik Seviyesi Kilidini Aç" + activate_user: "Kullanıcıyı etkinleştir." + deactivate_user: "Kullanıcıyı dondur" + change_readonly_mode: "Salt-okunur modunu değiştir" screened_emails: title: "Taranmış E-postalar" description: "Biri yeni bir hesap oluşturmaya çalıştığında, aşağıdaki e-posta adresleri kontrol edilecek ve kayıt önlenecek veya başka bir eylem gerçekleşecek." @@ -2795,6 +2868,7 @@ tr_TR: user_preferences: "Kullanıcı Tercihleri" tags: "Etiketler" search: "Arama" + groups: "Gruplar" badges: title: Rozetler new_badge: Yeni Rozet diff --git a/config/locales/client.uk.yml b/config/locales/client.uk.yml index 794b4867277..48af95cb774 100644 --- a/config/locales/client.uk.yml +++ b/config/locales/client.uk.yml @@ -228,15 +228,31 @@ uk: days_visited: "Відвідини" days_visited_long: "Днів відвідано" posts_read: "Прочитані" + posts_read_long: "Повідомлень Прочитано" total_rows: one: "%{count} користувач" few: "%{count} користувачі" other: "%{count} користувачів" + group_histories: + actions: + change_group_setting: "Змінити налаштування групи" + add_user_to_group: "Добавити користувача" + remove_user_from_group: "Видалити користувача" groups: + logs: + subject: "Тема" + details: "Деталі" + from: "Від" + to: "До" + edit: + title: 'Редагувати Групу' + full_name: 'Повне Ім''я' + add_members: "Добавити учасників" + delete_member_confirm: "Видалити '%{username}' з групи '%{group}'?" add: "Додати" + closed_group: Закрита Група selector_placeholder: "Додати учасників" visible: "Група видна всім користувачам" - index: "Групи" title: one: "група" few: "групи" @@ -479,8 +495,6 @@ uk: create: "Надіслати Запрошення" bulk_invite: text: "Масове Запрошення з Файлу" - uploading: "Вивантаження..." - error: "Під час завантаження '{{filename}}' сталася помилка: {{message}}" password: title: "Пароль" too_short: "Ваш пароль надто короткий." @@ -492,6 +506,7 @@ uk: title: "Підсумок" stats: "Статистика" time_read: "час читання" + more_topics: "Більше тем" ip_address: title: "Остання IP-адреса" registration_ip_address: @@ -787,7 +802,6 @@ uk: title: просування по темі go_bottom: "Кнопка" jump_bottom: "перейти до останнього допису" - jump_prompt: "перейти до допису" jump_bottom_with_number: "перейти до допису %{post_number}" total: всього дописів current: поточний допис @@ -899,7 +913,6 @@ uk: edit: "Даруйте, під час редагування допису трапилася помилка. Будь ласка, спробуйте ще раз." upload: "Даруйте, під час завантаження цього файлу трапилася помилка. Будь ласка, спробуйте ще раз." too_many_uploads: "Даруйте, але Ви можете одночасно завантажувати тільки один файл." - upload_not_authorized: "Даруйте, але файл, який Ви намагаєтеся завантажити, є недозволеним (дозволені розширення: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Даруйте, нові користувачі не можуть завантажувати зображення." attachment_upload_not_allowed_for_new_user: "Даруйте, нові користувачі не можуть завантажувати прикріплення." abandon: @@ -1046,7 +1059,6 @@ uk: original_post: "Перший допис" views: "Перегляди" replies: "Відповіді" - views_long: "цю тему переглянули {{number}} разів" activity: "Активність" likes: "Вподобання" likes_long: "в цій темі {{number}} вподобань" @@ -1218,17 +1230,14 @@ uk: refresh: "Оновити" new: "Новий" selector_placeholder: "введіть ім'я користувача" - name_placeholder: "Group name, no spaces, same as username rule" about: "Edit your group membership and names here" group_members: "Учасники групи" delete: "Видалити" delete_confirm: "Видалити цю групу?" delete_failed: "Не вдалося видалити групу. Якщо це - автоматична група, її неможливо знищити." - name: "Ім'я" add: "Додати" add_members: "Додати учасників" bulk_select: "(обрати групу)" - flair_preview: "Попередній перегляд" api: generate_master: "Згенерувати Головний ключ API" none: "Наразі немає жодного активного ключа API." diff --git a/config/locales/client.ur.yml b/config/locales/client.ur.yml index 9061d17f101..b500d837aa0 100644 --- a/config/locales/client.ur.yml +++ b/config/locales/client.ur.yml @@ -1,3322 +1,85 @@ # encoding: utf-8 # -# This file contains content for the client portion of Discourse, sent out -# to the Javascript app. +# Never edit this file. It will be overwritten when translations are pulled from Transifex. # -# To work with us on translations, see: https://www.transifex.com/projects/p/discourse-org/ -# -# This is a "source" file, which is used by Transifex to get translations for other languages. -# After this file is changed, it needs to be pushed by a maintainer to Transifex: -# -# tx push -s -# -# Read more here: https://meta.discourse.org/t/contribute-a-translation-to-discourse/14882 -# -# To validate this YAML file after you change it, please paste it into http://yamllint.com/ +# To work with us on translations, join this project: +# https://www.transifex.com/projects/p/discourse-org/ ur: js: number: format: - # symbol used to separate the integer part from the fractional part of a number separator: "." - # symbol for the thousands separator used in digit grouping - delimiter: "," + delimiter: "،" human: storage_units: - format: '%n %u' units: - byte: - one: Byte - other: Bytes - gb: GB - kb: KB - mb: MB - tb: TB - short: - thousands: "{{number}}k" - millions: "{{number}}M" + gb: جی بی + kb: کے بی + mb: ایم بی + tb: ٹی بی dates: - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ time: "h:mm a" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - timeline_date: "MMM YYYY" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - long_no_year: "MMM D h:mm a" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - long_no_year_no_time: "MMM D" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - full_no_year_no_time: "MMMM Do" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - long_with_year: "MMM D, YYYY h:mm a" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - long_with_year_no_time: "MMM D, YYYY" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - full_with_year_no_time: "MMMM Do, YYYY" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - long_date_with_year: "MMM D, 'YY LT" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - long_date_without_year: "MMM D, LT" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - long_date_with_year_without_time: "MMM D, 'YY" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - long_date_without_year_with_linebreak: "MMM D
    LT" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - long_date_with_year_with_linebreak: "MMM D, 'YY
    LT" - - wrap_ago: "%{date} ago" - - tiny: - half_a_minute: "< 1m" - less_than_x_seconds: - one: "< 1s" - other: "< %{count}s" - x_seconds: - one: "1s" - other: "%{count}s" - x_minutes: - one: "1m" - other: "%{count}m" - about_x_hours: - one: "1h" - other: "%{count}h" - x_days: - one: "1d" - other: "%{count}d" - about_x_years: - one: "1y" - other: "%{count}y" - over_x_years: - one: "> 1y" - other: "> %{count}y" - almost_x_years: - one: "1y" - other: "%{count}y" - date_month: "MMM D" - date_year: "MMM 'YY" medium: x_minutes: - one: "1 min" - other: "%{count} mins" + one: "1 منٹ" + other: "%{گنتی} منٹس" x_hours: - one: "1 hour" - other: "%{count} hours" + one: "1 گھنٹا" + other: "%{گنتی} گھنٹے" x_days: - one: "1 day" - other: "%{count} days" - date_year: "MMM D, 'YY" + one: "1 دن" + other: "%{گنتی} دن" medium_with_ago: x_minutes: - one: "1 min ago" - other: "%{count} mins ago" + one: "1 منٹ قبل" + other: "%{count} منٹ قبل" x_hours: - one: "1 hour ago" - other: "%{count} hours ago" + one: "1 گھنٹہ قبل " + other: " %{count} گھنٹے قبل " x_days: - one: "1 day ago" - other: "%{count} days ago" + one: "1 دن قبل" + other: "%{گنتی} دن قبل" later: x_days: - one: "1 day later" - other: "%{count} days later" + one: "1 دن بعد" + other: "%{گنتی} دن بعد" x_months: - one: "1 month later" - other: "%{count} months later" + one: "1 مہینے بعد" + other: "%{گنتی} مہینے بعد" x_years: - one: "1 year later" - other: "%{count} years later" - previous_month: 'Previous Month' - next_month: 'Next Month' + one: "1 سال بعد" + other: "%{گنتی} سال بعد" + previous_month: 'پچھلے ماہ' + next_month: 'اگلے ماہ' share: - topic: 'share a link to this topic' - post: 'post #%{postNumber}' - close: 'close' - twitter: 'share this link on Twitter' - facebook: 'share this link on Facebook' - google+: 'share this link on Google+' - email: 'send this link in an email' - - action_codes: - public_topic: "made this topic public %{when}" - private_topic: "made this topic private %{when}" - split_topic: "split this topic %{when}" - invited_user: "invited %{who} %{when}" - invited_group: "invited %{who} %{when}" - removed_user: "removed %{who} %{when}" - removed_group: "removed %{who} %{when}" - autoclosed: - enabled: 'closed %{when}' - disabled: 'opened %{when}' - closed: - enabled: 'closed %{when}' - disabled: 'opened %{when}' - archived: - enabled: 'archived %{when}' - disabled: 'unarchived %{when}' - pinned: - enabled: 'pinned %{when}' - disabled: 'unpinned %{when}' - pinned_globally: - enabled: 'pinned globally %{when}' - disabled: 'unpinned %{when}' - visible: - enabled: 'listed %{when}' - disabled: 'unlisted %{when}' - - topic_admin_menu: "topic admin actions" - - wizard_required: "It's time to configure your forum! Start the Setup Wizard!" - emails_are_disabled: "All outgoing email has been globally disabled by an administrator. No email notifications of any kind will be sent." - - bootstrap_mode_enabled: "To make launching your new site easier, you are in bootstrap mode. All new users will be granted trust level 1 and have daily email digest updates enabled. This will be automatically turned off when total user count exceeds %{min_users} users." - bootstrap_mode_disabled: "Bootstrap mode will be disabled in next 24 hours." - - s3: - regions: - us_east_1: "US East (N. Virginia)" - us_west_1: "US West (N. California)" - us_west_2: "US West (Oregon)" - us_gov_west_1: "AWS GovCloud (US)" - eu_west_1: "EU (Ireland)" - eu_central_1: "EU (Frankfurt)" - ap_southeast_1: "Asia Pacific (Singapore)" - ap_southeast_2: "Asia Pacific (Sydney)" - ap_south_1: "Asia Pacific (Mumbai)" - ap_northeast_1: "Asia Pacific (Tokyo)" - ap_northeast_2: "Asia Pacific (Seoul)" - sa_east_1: "South America (Sao Paulo)" - cn_north_1: "China (Beijing)" - - edit: 'edit the title and category of this topic' - not_implemented: "That feature hasn't been implemented yet, sorry!" - no_value: "No" - yes_value: "Yes" - generic_error: "Sorry, an error has occurred." - generic_error_with_reason: "An error occurred: %{error}" - sign_up: "Sign Up" - log_in: "Log In" - age: "Age" - joined: "Joined" - admin_title: "Admin" - flags_title: "Flags" - show_more: "show more" - show_help: "options" - links: "Links" - links_lowercase: - one: "link" - other: "links" - faq: "FAQ" - guidelines: "Guidelines" - privacy_policy: "Privacy Policy" - privacy: "Privacy" - terms_of_service: "Terms of Service" - mobile_view: "Mobile View" - desktop_view: "Desktop View" - you: "You" - or: "or" - now: "just now" - read_more: 'read more' - more: "More" - less: "Less" - never: "never" - every_30_minutes: "every 30 minutes" - every_hour: "every hour" - daily: "daily" - weekly: "weekly" - every_two_weeks: "every two weeks" - every_three_days: "every three days" - max_of_count: "max of {{count}}" - alternation: "or" - character_count: - one: "{{count}} character" - other: "{{count}} characters" - - suggested_topics: - title: "Suggested Topics" - pm_title: "Suggested Messages" - - about: - simple_title: "About" - title: "About %{title}" - stats: "Site Statistics" - our_admins: "Our Admins" - our_moderators: "Our Moderators" - stat: - all_time: "All Time" - last_7_days: "Last 7 Days" - last_30_days: "Last 30 Days" - like_count: "Likes" - topic_count: "Topics" - post_count: "Posts" - user_count: "New Users" - active_user_count: "Active Users" - contact: "Contact Us" - contact_info: "In the event of a critical issue or urgent matter affecting this site, please contact us at %{contact_info}." - - bookmarked: - title: "Bookmark" - clear_bookmarks: "Clear Bookmarks" - help: - bookmark: "Click to bookmark the first post on this topic" - unbookmark: "Click to remove all bookmarks in this topic" - - bookmarks: - not_logged_in: "sorry, you must be logged in to bookmark posts" - created: "you've bookmarked this post" - not_bookmarked: "you've read this post; click to bookmark it" - last_read: "this is the last post you've read; click to bookmark it" - remove: "Remove Bookmark" - confirm_clear: "Are you sure you want to clear all the bookmarks from this topic?" - - topic_count_latest: - one: "{{count}} new or updated topic." - other: "{{count}} new or updated topics." - - topic_count_unread: - one: "{{count}} unread topic." - other: "{{count}} unread topics." - - topic_count_new: - one: "{{count}} new topic." - other: "{{count}} new topics." - - click_to_show: "Click to show." - preview: "preview" - cancel: "cancel" - - save: "Save Changes" - saving: "Saving..." - saved: "Saved!" - - upload: "Upload" - uploading: "Uploading..." - uploading_filename: "Uploading {{filename}}..." - uploaded: "Uploaded!" - - enable: "Enable" - disable: "Disable" - undo: "Undo" - revert: "Revert" - failed: "Failed" - - switch_to_anon: "Enter Anonymous Mode" - switch_from_anon: "Exit Anonymous Mode" - - banner: - close: "Dismiss this banner." - edit: "Edit this banner >>" - - choose_topic: - none_found: "No topics found." - title: - search: "Search for a Topic by name, url or id:" - placeholder: "type the topic title here" - - queue: - topic: "Topic:" - approve: 'Approve' - reject: 'Reject' - delete_user: 'Delete User' - title: "Needs Approval" - none: "There are no posts to review." - edit: "Edit" - cancel: "Cancel" - view_pending: "view pending posts" - has_pending_posts: - one: "This topic has 1 post awaiting approval" - other: "This topic has {{count}} posts awaiting approval" - - confirm: "Save Changes" - delete_prompt: "Are you sure you want to delete %{username}? This will remove all of their posts and block their email and IP address." - - approval: - title: "Post Needs Approval" - description: "We've received your new post but it needs to be approved by a moderator before it will appear. Please be patient." - pending_posts: - one: "You have 1 post pending." - other: "You have {{count}} posts pending." - ok: "OK" - - user_action: - user_posted_topic: "{{user}} posted the topic" - you_posted_topic: "You posted the topic" - user_replied_to_post: "{{user}} replied to {{post_number}}" - you_replied_to_post: "You replied to {{post_number}}" - user_replied_to_topic: "{{user}} replied to the topic" - you_replied_to_topic: "You replied to the topic" - - user_mentioned_user: "{{user}} mentioned {{another_user}}" - user_mentioned_you: "{{user}} mentioned you" - you_mentioned_user: "You mentioned {{another_user}}" - - posted_by_user: "Posted by {{user}}" - posted_by_you: "Posted by you" - sent_by_user: "Sent by {{user}}" - sent_by_you: "Sent by you" - - directory: - filter_name: "filter by username" - title: "Users" - likes_given: "Given" - likes_received: "Received" - topics_entered: "Viewed" - topics_entered_long: "Topics Viewed" - time_read: "Time Read" - topic_count: "Topics" - topic_count_long: "Topics Created" - post_count: "Replies" - post_count_long: "Replies Posted" - no_results: "No results were found." - days_visited: "Visits" - days_visited_long: "Days Visited" - posts_read: "Read" - posts_read_long: "Posts Read" - total_rows: - one: "1 user" - other: "%{count} users" - - groups: - empty: - posts: "There is no post by members of this group." - members: "There is no member in this group." - mentions: "There is no mention of this group." - messages: "There is no message for this group." - topics: "There is no topic by members of this group." - add: "Add" - selector_placeholder: "Add members" - owner: "owner" - visible: "Group is visible to all users" - index: "Groups" - title: - one: "group" - other: "groups" - members: "Members" - topics: "Topics" - posts: "Posts" - mentions: "Mentions" - messages: "Messages" - alias_levels: - title: "Who can message and @mention this group?" - nobody: "Nobody" - only_admins: "Only admins" - mods_and_admins: "Only moderators and Admins" - members_mods_and_admins: "Only group members, moderators and admins" - everyone: "Everyone" - trust_levels: - title: "Trust level automatically granted to members when they're added:" - none: "None" - notifications: - watching: - title: "Watching" - description: "You will be notified of every new post in every message, and a count of new replies will be shown." - watching_first_post: - title: "Watching First Post" - description: "You will only be notified of the first post in each new topic in this group." - tracking: - title: "Tracking" - description: "You will be notified if someone mentions your @name or replies to you, and a count of new replies will be shown." - regular: - title: "Normal" - description: "You will be notified if someone mentions your @name or replies to you." - muted: - title: "Muted" - description: "You will never be notified of anything about new topics in this group." - - user_action_groups: - "1": "Likes Given" - "2": "Likes Received" - "3": "Bookmarks" - "4": "Topics" - "5": "Replies" - "6": "Responses" - "7": "Mentions" - "9": "Quotes" - "11": "Edits" - "12": "Sent Items" - "13": "Inbox" - "14": "Pending" - - categories: - all: "all categories" - all_subcategories: "all" - no_subcategory: "none" - category: "Category" - category_list: "Display category list" - reorder: - title: "Reorder Categories" - title_long: "Reorganize the category list" - fix_order: "Fix Positions" - fix_order_tooltip: "Not all categories have a unique position number, which may cause unexpected results." - save: "Save Order" - apply_all: "Apply" - position: "Position" - posts: "Posts" - topics: "Topics" - latest: "Latest" - latest_by: "latest by" - toggle_ordering: "toggle ordering control" - subcategories: "Subcategories" - topic_sentence: - one: "1 topic" - other: "%{count} topics" - topic_stat_sentence: - one: "%{count} new topic in the past %{unit}." - other: "%{count} new topics in the past %{unit}." - - ip_lookup: - title: IP Address Lookup - hostname: Hostname - location: Location - location_not_found: (unknown) - organisation: Organization - phone: Phone - other_accounts: "Other accounts with this IP address:" - delete_other_accounts: "Delete %{count}" - username: "username" - trust_level: "TL" - read_time: "read time" - topics_entered: "topics entered" - post_count: "# posts" - confirm_delete_other_accounts: "Are you sure you want to delete these accounts?" - - user_fields: - none: "(select an option)" - + topic: 'اس ٹاپک کا لنک شیئرکریں' + no_value: "نہیں " + yes_value: "ہاں " + age: "عمر " + show_more: "مزید " + you: "آپ " + or: "یا " + now: "ابھی " + read_more: 'مزید پڑھیں ' + more: "مزید " + less: "کم " + never: "کبھی نہیں " + daily: "روزانہ " + weekly: "ہفتہ وار " user: - said: "{{username}}:" - profile: "Profile" - mute: "Mute" - edit: "Edit Preferences" - download_archive: - button_text: "Download My Posts" - confirm: "Are you sure you want to download your posts?" - success: "Download initiated, you will be notified via message when the process is complete." - rate_limit_error: "Posts can be downloaded once per day, please try again tomorrow." - new_private_message: "New Message" - private_message: "Message" - private_messages: "Messages" - activity_stream: "Activity" - preferences: "Preferences" - expand_profile: "Expand" - bookmarks: "Bookmarks" - bio: "About me" - invited_by: "Invited By" - trust_level: "Trust Level" - notifications: "Notifications" - statistics: "Stats" desktop_notifications: - label: "Desktop Notifications" - not_supported: "Notifications are not supported on this browser. Sorry." - perm_default: "Turn On Notifications" - perm_denied_btn: "Permission Denied" - perm_denied_expl: "You denied permission for notifications. Allow notifications via your browser settings." - disable: "Disable Notifications" - currently_enabled: "" - enable: "Enable Notifications" - currently_disabled: "" - each_browser_note: "Note: You have to change this setting on every browser you use." - dismiss_notifications: "Dismiss All" - dismiss_notifications_tooltip: "Mark all unread notifications as read" - first_notification: "Your first notification! Select it to begin." - disable_jump_reply: "Don't jump to my post after I reply" - dynamic_favicon: "Show new / updated topic count on browser icon" - external_links_in_new_tab: "Open all external links in a new tab" - enable_quoting: "Enable quote reply for highlighted text" - change: "change" - moderator: "{{user}} is a moderator" - admin: "{{user}} is an admin" - moderator_tooltip: "This user is a moderator" - admin_tooltip: "This user is an admin" - blocked_tooltip: "This user is blocked" - suspended_notice: "This user is suspended until {{date}}." - suspended_reason: "Reason: " - github_profile: "Github" - email_activity_summary: "Activity Summary" - mailing_list_mode: - label: "Mailing list mode" - enabled: "Enable mailing list mode" - instructions: | - This setting overrides the activity summary.
    - Muted topics and categories are not included in these emails. - daily: "Send daily updates" - individual: "Send an email for every new post" - individual_no_echo: "Send an email for every new post except my own" - many_per_day: "Send me an email for every new post (about {{dailyEmailEstimate}} per day)" - few_per_day: "Send me an email for every new post (about 2 per day)" - tag_settings: "Tags" - watched_tags: "Watched" - watched_tags_instructions: "You will automatically watch all topics with these tags. You will be notified of all new posts and topics, and a count of new posts will also appear next to the topic." - tracked_tags: "Tracked" - tracked_tags_instructions: "You will automatically track all topics with these tags. A count of new posts will appear next to the topic." - muted_tags: "Muted" - muted_tags_instructions: "You will not be notified of anything about new topics with these tags, and they will not appear in latest." - watched_categories: "Watched" - watched_categories_instructions: "You will automatically watch all topics in these categories. You will be notified of all new posts and topics, and a count of new posts will also appear next to the topic." - tracked_categories: "Tracked" - tracked_categories_instructions: "You will automatically track all topics in these categories. A count of new posts will appear next to the topic." - watched_first_post_categories: "Watching First Post" - watched_first_post_categories_instructions: "You will be notified of the first post in each new topic in these categories." - watched_first_post_tags: "Watching First Post" - watched_first_post_tags_instructions: "You will be notified of the first post in each new topic with these tags." - - muted_categories: "Muted" - muted_categories_instructions: "You will not be notified of anything about new topics in these categories, and they will not appear in latest." - delete_account: "Delete My Account" - delete_account_confirm: "Are you sure you want to permanently delete your account? This action cannot be undone!" - deleted_yourself: "Your account has been deleted successfully." - delete_yourself_not_allowed: "You cannot delete your account right now. Contact an admin to do delete your account for you." - unread_message_count: "Messages" - admin_delete: "Delete" - users: "Users" - muted_users: "Muted" - muted_users_instructions: "Suppress all notifications from these users." - muted_topics_link: "Show muted topics" - watched_topics_link: "Show watched topics" - automatically_unpin_topics: "Automatically unpin topics when I reach the bottom." - apps: "Apps" - revoke_access: "Revoke Access" - undo_revoke_access: "Undo Revoke Access" - api_approved: "Approved:" - - staff_counters: - flags_given: "helpful flags" - flagged_posts: "flagged posts" - deleted_posts: "deleted posts" - suspensions: "suspensions" - warnings_received: "warnings" - - messages: - all: "All" - inbox: "Inbox" - sent: "Sent" - archive: "Archive" - groups: "My Groups" - bulk_select: "Select messages" - move_to_inbox: "Move to Inbox" - move_to_archive: "Archive" - failed_to_move: "Failed to move selected messages (perhaps your network is down)" - select_all: "Select All" - - change_password: - success: "(email sent)" - in_progress: "(sending email)" - error: "(error)" - action: "Send Password Reset Email" - set_password: "Set Password" - - change_about: - title: "Change About Me" - error: "There was an error changing this value." - - change_username: - title: "Change Username" - confirm: "If you change your username, all prior quotes of your posts and @name mentions will be broken. Are you absolutely sure you want to?" - taken: "Sorry, that username is taken." - error: "There was an error changing your username." - invalid: "That username is invalid. It must only include numbers and letters" - - change_email: - title: "Change Email" - taken: "Sorry, that email is not available." - error: "There was an error changing your email. Perhaps that address is already in use?" - success: "We've sent an email to that address. Please follow the confirmation instructions." - - change_avatar: - title: "Change your profile picture" - gravatar: "Gravatar, based on" - gravatar_title: "Change your avatar on Gravatar's website" - refresh_gravatar_title: "Refresh your Gravatar" - letter_based: "System assigned profile picture" - uploaded_avatar: "Custom picture" - uploaded_avatar_empty: "Add a custom picture" - upload_title: "Upload your picture" - upload_picture: "Upload Picture" - image_is_not_a_square: "Warning: we've cropped your image; width and height were not equal." - cache_notice: "You've successfully changed your profile picture but it might take some time to appear due to browser caching." - - change_profile_background: - title: "Profile Background" - instructions: "Profile backgrounds will be centered and have a default width of 850px." - - change_card_background: - title: "User Card Background" - instructions: "Background images will be centered and have a default width of 590px." - - email: - title: "Email" - instructions: "Never shown to the public" - ok: "We will email you to confirm" - invalid: "Please enter a valid email address" - authenticated: "Your email has been authenticated by {{provider}}" - frequency_immediately: "We'll email you immediately if you haven't read the thing we're emailing you about." - frequency: - one: "We'll only email you if we haven't seen you in the last minute." - other: "We'll only email you if we haven't seen you in the last {{count}} minutes." - + each_browser_note: "نوٹ: آپ کو ہر براؤزر پر اس سیٹنگ کو تبدیل کرنا ہوگا." name: - title: "Name" - instructions: "Your full name (optional)" - instructions_required: "Your full name" - too_short: "Your name is too short" - ok: "Your name looks good" + instructions: "آپ کا پورا نام (اختیاری)" + instructions_required: "آپ کا پورا نام" + too_short: "آپ کا نام بہت چھوٹا ہے" + ok: "آپ کا نام صحیح لگ رہا ہے" username: - title: "Username" - instructions: "Unique, no spaces, short" - short_instructions: "People can mention you as @{{username}}" - available: "Your username is available" - global_match: "Email matches the registered username" - global_mismatch: "Already registered. Try {{suggestion}}?" - not_available: "Not available. Try {{suggestion}}?" - too_short: "Your username is too short" - too_long: "Your username is too long" - checking: "Checking username availability..." - enter_email: 'Username found; enter matching email' - prefilled: "Email matches this registered username" - - locale: - title: "Interface language" - instructions: "User interface language. It will change when you refresh the page." - default: "(default)" - any: "any" - - password_confirmation: - title: "Password Again" - - last_posted: "Last Post" - last_emailed: "Last Emailed" - last_seen: "Seen" - created: "Joined" - log_out: "Log Out" - location: "Location" - card_badge: - title: "User Card Badge" - - website: "Web Site" - email_settings: "Email" - like_notification_frequency: - title: "Notify when liked" - always: "Always" - first_time_and_daily: "First time a post is liked and daily" - first_time: "First time a post is liked" - never: "Never" - email_previous_replies: - title: "Include previous replies at the bottom of emails" - unless_emailed: "unless previously sent" - always: "always" - never: "never" - email_digests: - title: "When I don't visit here, send me an email summary of popular topics and replies" - every_30_minutes: "every 30 minutes" - every_hour: "hourly" - daily: "daily" - every_three_days: "every three days" - weekly: "weekly" - every_two_weeks: "every two weeks" - - include_tl0_in_digests: "Include content from new users in summary emails" - email_in_reply_to: "Include an excerpt of replied to post in emails" - email_direct: "Send me an email when someone quotes me, replies to my post, mentions my @username, or invites me to a topic" - email_private_messages: "Send me an email when someone messages me" - email_always: "Send me email notifications even when I am active on the site" - - other_settings: "Other" - categories_settings: "Categories" - - new_topic_duration: - label: "Consider topics new when" - not_viewed: "I haven't viewed them yet" - last_here: "created since I was here last" - after_1_day: "created in the last day" - after_2_days: "created in the last 2 days" - after_1_week: "created in the last week" - after_2_weeks: "created in the last 2 weeks" - - auto_track_topics: "Automatically track topics I enter" - auto_track_options: - never: "never" - immediately: "immediately" - after_30_seconds: "after 30 seconds" - after_1_minute: "after 1 minute" - after_2_minutes: "after 2 minutes" - after_3_minutes: "after 3 minutes" - after_4_minutes: "after 4 minutes" - after_5_minutes: "after 5 minutes" - after_10_minutes: "after 10 minutes" - - notification_level_when_replying: "When I post in a topic, set that topic to" - - invited: - search: "type to search invites..." - title: "Invites" - user: "Invited User" - sent: "Sent" - none: "There are no pending invites to display." - truncated: - one: "Showing the first invite." - other: "Showing the first {{count}} invites." - redeemed: "Redeemed Invites" - redeemed_tab: "Redeemed" - redeemed_tab_with_count: "Redeemed ({{count}})" - redeemed_at: "Redeemed" - pending: "Pending Invites" - pending_tab: "Pending" - pending_tab_with_count: "Pending ({{count}})" - topics_entered: "Topics Viewed" - posts_read_count: "Posts Read" - expired: "This invite has expired." - rescind: "Remove" - rescinded: "Invite removed" - reinvite: "Resend Invite" - reinvite_all: "Resend all Invites" - reinvited: "Invite re-sent" - reinvited_all: "All Invites re-sent!" - time_read: "Read Time" - days_visited: "Days Visited" - account_age_days: "Account age in days" - create: "Send an Invite" - generate_link: "Copy Invite Link" - link_generated: "Invite link generated successfully!" - valid_for: "Invite link is only valid for this email address: %{email}" - bulk_invite: - none: "You haven't invited anyone here yet. You can send individual invites, or invite a bunch of people at once by uploading a bulk invite file." - text: "Bulk Invite from File" - uploading: "Uploading..." - success: "File uploaded successfully, you will be notified via message when the process is complete." - error: "There was an error uploading '{{filename}}': {{message}}" - - password: - title: "Password" - too_short: "Your password is too short." - common: "That password is too common." - same_as_username: "Your password is the same as your username." - same_as_email: "Your password is the same as your email." - ok: "Your password looks good." - instructions: "At least %{count} characters." - - summary: - title: "Summary" - stats: "Stats" - time_read: "read time" - topic_count: - one: "topic created" - other: "topics created" - post_count: - one: "post created" - other: "posts created" - likes_given: - one: " given" - other: " given" - likes_received: - one: " received" - other: " received" - days_visited: - one: "day visited" - other: "days visited" - posts_read: - one: "post read" - other: "posts read" - bookmark_count: - one: "bookmark" - other: "bookmarks" - top_replies: "Top Replies" - no_replies: "No replies yet." - more_replies: "More Replies" - top_topics: "Top Topics" - no_topics: "No topics yet." - more_topics: "More Topics" - top_badges: "Top Badges" - no_badges: "No badges yet." - more_badges: "More Badges" - top_links: "Top Links" - no_links: "No links yet." - most_liked_by: "Most Liked By" - most_liked_users: "Most Liked" - most_replied_to_users: "Most Replied To" - no_likes: "No likes yet." - - - associated_accounts: "Logins" - ip_address: - title: "Last IP Address" - registration_ip_address: - title: "Registration IP Address" - avatar: - title: "Profile Picture" - header_title: "profile, messages, bookmarks and preferences" - title: - title: "Title" - - filters: - all: "All" - - stream: - posted_by: "Posted by" - sent_by: "Sent by" - private_message: "message" - the_topic: "the topic" - - loading: "Loading..." - errors: - prev_page: "while trying to load" - reasons: - network: "Network Error" - server: "Server Error" - forbidden: "Access Denied" - unknown: "Error" - not_found: "Page Not Found" - desc: - network: "Please check your connection." - network_fixed: "Looks like it's back." - server: "Error code: {{status}}" - forbidden: "You're not allowed to view that." - not_found: "Oops, the application tried to load a URL that doesn't exist." - unknown: "Something went wrong." - buttons: - back: "Go Back" - again: "Try Again" - fixed: "Load Page" - close: "Close" - assets_changed_confirm: "This site was just updated. Refresh now for the latest version?" - logout: "You were logged out." - refresh: "Refresh" - read_only_mode: - enabled: "This site is in read only mode. Please continue to browse, but replying, likes, and other actions are disabled for now." - login_disabled: "Login is disabled while the site is in read only mode." - logout_disabled: "Logout is disabled while the site is in read only mode." - too_few_topics_and_posts_notice: "Let's get this discussion started! There are currently %{currentTopics} / %{requiredTopics} topics and %{currentPosts} / %{requiredPosts} posts. New visitors need some conversations to read and respond to." - too_few_topics_notice: "Let's get this discussion started! There are currently %{currentTopics} / %{requiredTopics} topics. New visitors need some conversations to read and respond to." - too_few_posts_notice: "Let's get this discussion started! There are currently %{currentPosts} / %{requiredPosts} posts. New visitors need some conversations to read and respond to." - logs_error_rate_notice: - reached: "%{relativeAge}%{rate} reached site setting limit of %{siteSettingRate}." - exceeded: "%{relativeAge}%{rate} exceeds site setting limit of %{siteSettingRate}." - rate: - one: "1 error/%{duration}" - other: "%{count} errors/%{duration}" - - learn_more: "learn more..." - - all_time: 'total' - all_time_desc: 'total topics created' - year: 'year' - year_desc: 'topics created in the last 365 days' - month: 'month' - month_desc: 'topics created in the last 30 days' - week: 'week' - week_desc: 'topics created in the last 7 days' - day: 'day' - - first_post: First post - mute: Mute - unmute: Unmute - last_post: Last post - last_reply_lowercase: last reply - replies_lowercase: - one: reply - other: replies - - signup_cta: - sign_up: "Sign Up" - hide_session: "Remind me tomorrow" - hide_forever: "no thanks" - hidden_for_session: "OK, I'll ask you tomorrow. You can always use 'Log In' to create an account, too." - intro: "Hey there! :heart_eyes: Looks like you're enjoying the discussion, but you're not signed up for an account." - value_prop: "When you create an account, we remember exactly what you've read, so you always come right back where you left off. You also get notifications, here and via email, whenever new posts are made. And you can like posts to share the love. :heartbeat:" - - summary: - enabled_description: "You're viewing a summary of this topic: the most interesting posts as determined by the community." - description: "There are {{replyCount}} replies." - description_time: "There are {{replyCount}} replies with an estimated read time of {{readingTime}} minutes." - enable: 'Summarize This Topic' - disable: 'Show All Posts' - - deleted_filter: - enabled_description: "This topic contains deleted posts, which have been hidden. " - disabled_description: "Deleted posts in the topic are shown." - enable: "Hide Deleted Posts" - disable: "Show Deleted Posts" - - private_message_info: - title: "Message" - invite: "Invite Others..." - remove_allowed_user: "Do you really want to remove {{name}} from this message?" - remove_allowed_group: "Do you really want to remove {{name}} from this message?" - - email: 'Email' - username: 'Username' - last_seen: 'Seen' - created: 'Created' - created_lowercase: 'created' - trust_level: 'Trust Level' - search_hint: 'username, email or IP address' - - create_account: - disclaimer: "By registering, you agree to the privacy policy and terms of service." - title: "Create New Account" - failed: "Something went wrong, perhaps this email is already registered, try the forgot password link" - - forgot_password: - title: "Password Reset" - action: "I forgot my password" - invite: "Enter your username or email address, and we'll send you a password reset email." - reset: "Reset Password" - complete_username: "If an account matches the username %{username}, you should receive an email with instructions on how to reset your password shortly." - complete_email: "If an account matches %{email}, you should receive an email with instructions on how to reset your password shortly." - complete_username_found: "We found an account that matches the username %{username}, you should receive an email with instructions on how to reset your password shortly." - complete_email_found: "We found an account that matches %{email}, you should receive an email with instructions on how to reset your password shortly." - - complete_username_not_found: "No account matches the username %{username}" - complete_email_not_found: "No account matches %{email}" - login: - title: "Log In" - username: "User" - password: "Password" - email_placeholder: "email or username" - caps_lock_warning: "Caps Lock is on" - error: "Unknown error" - rate_limit: "Please wait before trying to log in again." - blank_username_or_password: "Please enter your email or username, and password." - reset_password: 'Reset Password' - logging_in: "Signing In..." - or: "Or" - authenticating: "Authenticating..." - awaiting_confirmation: "Your account is awaiting activation, use the forgot password link to issue another activation email." - awaiting_approval: "Your account has not been approved by a staff member yet. You will be sent an email when it is approved." - requires_invite: "Sorry, access to this forum is by invite only." - not_activated: "You can't log in yet. We previously sent an activation email to you at {{sentTo}}. Please follow the instructions in that email to activate your account." - not_allowed_from_ip_address: "You can't login from that IP address." - admin_not_allowed_from_ip_address: "You can't log in as admin from that IP address." - resend_activation_email: "Click here to send the activation email again." - sent_activation_email_again: "We sent another activation email to you at {{currentEmail}}. It might take a few minutes for it to arrive; be sure to check your spam folder." - to_continue: "Please Log In" - preferences: "You need to be logged in to change your user preferences." - forgot: "I don't recall my account details" - google: - title: "with Google" - message: "Authenticating with Google (make sure pop up blockers are not enabled)" - google_oauth2: - title: "with Google" - message: "Authenticating with Google (make sure pop up blockers are not enabled)" - twitter: - title: "with Twitter" - message: "Authenticating with Twitter (make sure pop up blockers are not enabled)" - instagram: - title: "with Instagram" - message: "Authenticating with Instagram (make sure pop up blockers are not enabled)" - facebook: - title: "with Facebook" - message: "Authenticating with Facebook (make sure pop up blockers are not enabled)" - yahoo: - title: "with Yahoo" - message: "Authenticating with Yahoo (make sure pop up blockers are not enabled)" - github: - title: "with GitHub" - message: "Authenticating with GitHub (make sure pop up blockers are not enabled)" - - emoji_set: - apple_international: "Apple/International" - google: "Google" - twitter: "Twitter" - emoji_one: "Emoji One" - win10: "Win10" - - category_page_style: - categories_only: "Categories Only" - categories_with_featured_topics: "Categories with Featured Topics" - categories_and_latest_topics: "Categories and Latest Topics" - - shortcut_modifier_key: - shift: 'Shift' - ctrl: 'Ctrl' - alt: 'Alt' - - composer: - emoji: "Emoji :)" - more_emoji: "more..." - options: "Options" - whisper: "whisper" - unlist: "unlisted" - - add_warning: "This is an official warning." - toggle_whisper: "Toggle Whisper" - toggle_unlisted: "Toggle Unlisted" - posting_not_on_topic: "Which topic do you want to reply to?" - saving_draft_tip: "saving..." - saved_draft_tip: "saved" - saved_local_draft_tip: "saved locally" - similar_topics: "Your topic is similar to..." - drafts_offline: "drafts offline" - - group_mentioned: - one: "By mentioning {{group}}, you are about to notify 1 person – are you sure?" - other: "By mentioning {{group}}, you are about to notify {{count}} people – are you sure?" - cannot_see_mention: - category: "You mentioned {{username}} but they won't be notified because they do not have access to this category. You will need to add them to a group that has access to this category." - private: "You mentioned {{username}} but they won't be notified because they are unable to see this personal message. You will need to invite them to this PM." - duplicate_link: "It looks like your link to {{domain}} was already posted in the topic by @{{username}} in a reply {{ago}} – are you sure you want to post it again?" - - error: - title_missing: "Title is required" - title_too_short: "Title must be at least {{min}} characters" - title_too_long: "Title can't be more than {{max}} characters" - post_missing: "Post can't be empty" - post_length: "Post must be at least {{min}} characters" - try_like: 'Have you tried the button?' - category_missing: "You must choose a category" - - save_edit: "Save Edit" - reply_original: "Reply on Original Topic" - reply_here: "Reply Here" - reply: "Reply" - cancel: "Cancel" - create_topic: "Create Topic" - create_pm: "Message" - title: "Or press Ctrl+Enter" - - users_placeholder: "Add a user" - title_placeholder: "What is this discussion about in one brief sentence?" - edit_reason_placeholder: "why are you editing?" - show_edit_reason: "(add edit reason)" - reply_placeholder: "Type here. Use Markdown, BBCode, or HTML to format. Drag or paste images." - view_new_post: "View your new post." - saving: "Saving" - saved: "Saved!" - saved_draft: "Post draft in progress. Select to resume." - uploading: "Uploading..." - show_preview: 'show preview »' - hide_preview: '« hide preview' - - quote_post_title: "Quote whole post" - bold_label: "B" - bold_title: "Strong" - bold_text: "strong text" - italic_label: "I" - italic_title: "Emphasis" - italic_text: "emphasized text" - link_title: "Hyperlink" - link_description: "enter link description here" - link_dialog_title: "Insert Hyperlink" - link_optional_text: "optional title" - link_url_placeholder: "http://example.com" - quote_title: "Blockquote" - quote_text: "Blockquote" - code_title: "Preformatted text" - code_text: "indent preformatted text by 4 spaces" - paste_code_text: "type or paste code here" - upload_title: "Upload" - upload_description: "enter upload description here" - olist_title: "Numbered List" - ulist_title: "Bulleted List" - list_item: "List item" - heading_label: "H" - heading_title: "Heading" - heading_text: "Heading" - hr_title: "Horizontal Rule" - help: "Markdown Editing Help" - toggler: "hide or show the composer panel" - modal_ok: "OK" - modal_cancel: "Cancel" - cant_send_pm: "Sorry, you can't send a message to %{username}." - yourself_confirm: - title: "Did you forget to add recipients?" - body: "Right now this message is only being sent to yourself!" - - admin_options_title: "Optional staff settings for this topic" - auto_close: - label: "Auto-close topic time:" - error: "Please enter a valid value." - based_on_last_post: "Don't close until the last post in the topic is at least this old." - all: - units: "" - examples: 'Enter number of hours (24), absolute time (17:30) or timestamp (2013-11-22 14:00).' - limited: - units: "(# of hours)" - examples: 'Enter number of hours (24).' - - notifications: - title: "notifications of @name mentions, replies to your posts and topics, messages, etc" - none: "Unable to load notifications at this time." - empty: "No notifications found." - more: "view older notifications" - total_flagged: "total flagged posts" - mentioned: "

    {{username}} {{description}}

    " - group_mentioned: "

    {{username}} {{description}}

    " - quoted: "

    {{username}} {{description}}

    " - replied: "

    {{username}} {{description}}

    " - posted: "

    {{username}} {{description}}

    " - edited: "

    {{username}} {{description}}

    " - liked: "

    {{username}} {{description}}

    " - liked_2: "

    {{username}}, {{username2}} {{description}}

    " - liked_many: - one: "

    {{username}}, {{username2}} and 1 other {{description}}

    " - other: "

    {{username}}, {{username2}} and {{count}} others {{description}}

    " - private_message: "

    {{username}} {{description}}

    " - invited_to_private_message: "

    {{username}} {{description}}

    " - invited_to_topic: "

    {{username}} {{description}}

    " - invitee_accepted: "

    {{username}} accepted your invitation

    " - moved_post: "

    {{username}} moved {{description}}

    " - linked: "

    {{username}} {{description}}

    " - granted_badge: "

    Earned '{{description}}'

    " - - watching_first_post: "

    New Topic {{description}}

    " - - group_message_summary: - one: "

    {{count}} message in your {{group_name}} inbox

    " - other: "

    {{count}} messages in your {{group_name}} inbox

    " - - alt: - mentioned: "Mentioned by" - quoted: "Quoted by" - replied: "Replied" - posted: "Post by" - edited: "Edit your post by" - liked: "Liked your post" - private_message: "Private message from" - invited_to_private_message: "Invited to a private message from" - invited_to_topic: "Invited to a topic from" - invitee_accepted: "Invite accepted by" - moved_post: "Your post was moved by" - linked: "Link to your post" - granted_badge: "Badge granted" - group_message_summary: "Messages in group inbox" - - popup: - mentioned: '{{username}} mentioned you in "{{topic}}" - {{site_title}}' - group_mentioned: '{{username}} mentioned you in "{{topic}}" - {{site_title}}' - quoted: '{{username}} quoted you in "{{topic}}" - {{site_title}}' - replied: '{{username}} replied to you in "{{topic}}" - {{site_title}}' - posted: '{{username}} posted in "{{topic}}" - {{site_title}}' - private_message: '{{username}} sent you a private message in "{{topic}}" - {{site_title}}' - linked: '{{username}} linked to your post from "{{topic}}" - {{site_title}}' - - upload_selector: - title: "Add an image" - title_with_attachments: "Add an image or a file" - from_my_computer: "From my device" - from_the_web: "From the web" - remote_tip: "link to image" - remote_tip_with_attachments: "link to image or file {{authorized_extensions}}" - local_tip: "select images from your device" - local_tip_with_attachments: "select images or files from your device {{authorized_extensions}}" - hint: "(you can also drag & drop into the editor to upload them)" - hint_for_supported_browsers: "you can also drag and drop or paste images into the editor" - uploading: "Uploading" - select_file: "Select File" - image_link: "link your image will point to" - - search: - sort_by: "Sort by" - relevance: "Relevance" - latest_post: "Latest Post" - most_viewed: "Most Viewed" - most_liked: "Most Liked" - select_all: "Select All" - clear_all: "Clear All" - too_short: "Your search term is too short." - result_count: - one: "1 result for \"{{term}}\"" - other: "{{count}} results for \"{{term}}\"" - title: "search topics, posts, users, or categories" - no_results: "No results found." - no_more_results: "No more results found." - searching: "Searching ..." - post_format: "#{{post_number}} by {{username}}" - - context: - user: "Search posts by @{{username}}" - category: "Search the #{{category}} category" - topic: "Search this topic" - private_messages: "Search messages" - - advanced: - title: Advanced Search - posted_by: - label: Posted by - in_category: - label: In Category - in_group: - label: In Group - with_badge: - label: With Badge - with_tags: - label: With Tags - filters: - label: Only return topics/posts that... - likes: I liked - posted: I posted in - watching: I'm watching - tracking: I'm tracking - private: are in my messages - bookmarks: I've bookmarked - first: are the very first post - pinned: are pinned - unpinned: are not pinned - wiki: are wiki - statuses: - label: Where topics - open: are open - closed: are closed - archived: are archived - noreplies: have zero replies - single_user: contain a single user - post: - count: - label: Minimum Post Count - time: - label: Posted - before: before - after: after - - hamburger_menu: "go to another topic list or category" - new_item: "new" - go_back: 'go back' - not_logged_in_user: 'user page with summary of current activity and preferences' - current_user: 'go to your user page' - - topics: - new_messages_marker: "last visit" - bulk: - select_all: "Select All" - clear_all: "Clear All" - unlist_topics: "Unlist Topics" - reset_read: "Reset Read" - delete: "Delete Topics" - dismiss: "Dismiss" - dismiss_read: "Dismiss all unread" - dismiss_button: "Dismiss…" - dismiss_tooltip: "Dismiss just new posts or stop tracking topics" - also_dismiss_topics: "Stop tracking these topics so they never show up as unread for me again" - dismiss_new: "Dismiss New" - toggle: "toggle bulk selection of topics" - actions: "Bulk Actions" - change_category: "Change Category" - close_topics: "Close Topics" - archive_topics: "Archive Topics" - notification_level: "Change Notification Level" - choose_new_category: "Choose the new category for the topics:" - selected: - one: "You have selected 1 topic." - other: "You have selected {{count}} topics." - change_tags: "Change Tags" - choose_new_tags: "Choose new tags for these topics:" - changed_tags: "The tags of those topics were changed." - - none: - unread: "You have no unread topics." - new: "You have no new topics." - read: "You haven't read any topics yet." - posted: "You haven't posted in any topics yet." - latest: "There are no latest topics. That's sad." - hot: "There are no hot topics." - bookmarks: "You have no bookmarked topics yet." - category: "There are no {{category}} topics." - top: "There are no top topics." - search: "There are no search results." - educate: - new: '

    Your new topics appear here.

    By default, topics are considered new and will show a new indicator if they were created in the last 2 days.

    Visit your preferences to change this.

    ' - unread: '

    Your unread topics appear here.

    By default, topics are considered unread and will show unread counts 1 if you:

    • Created the topic
    • Replied to the topic
    • Read the topic for more than 4 minutes

    Or if you have explicitly set the topic to Tracked or Watched via the notification control at the bottom of each topic.

    Visit your preferences to change this.

    ' - bottom: - latest: "There are no more latest topics." - hot: "There are no more hot topics." - posted: "There are no more posted topics." - read: "There are no more read topics." - new: "There are no more new topics." - unread: "There are no more unread topics." - category: "There are no more {{category}} topics." - top: "There are no more top topics." - bookmarks: "There are no more bookmarked topics." - search: "There are no more search results." - - topic: - unsubscribe: - stop_notifications: "You will now receive less notifications for {{title}}" - change_notification_state: "Your current notification state is " - filter_to: - one: "1 post in topic" - other: "{{count}} posts in topic" - create: 'New Topic' - create_long: 'Create a new Topic' - private_message: 'Start a message' - archive_message: - help: 'Move message to your archive' - title: 'Archive' - move_to_inbox: - title: 'Move to Inbox' - help: 'Move message back to Inbox' - list: 'Topics' - new: 'new topic' - unread: 'unread' - new_topics: - one: '1 new topic' - other: '{{count}} new topics' - unread_topics: - one: '1 unread topic' - other: '{{count}} unread topics' - title: 'Topic' - invalid_access: - title: "Topic is private" - description: "Sorry, you don't have access to that topic!" - login_required: "You need to log in to see that topic." - server_error: - title: "Topic failed to load" - description: "Sorry, we couldn't load that topic, possibly due to a connection problem. Please try again. If the problem persists, let us know." - not_found: - title: "Topic not found" - description: "Sorry, we couldn't find that topic. Perhaps it was removed by a moderator?" - total_unread_posts: - one: "you have 1 unread post in this topic" - other: "you have {{count}} unread posts in this topic" - unread_posts: - one: "you have 1 unread old post in this topic" - other: "you have {{count}} unread old posts in this topic" - new_posts: - one: "there is 1 new post in this topic since you last read it" - other: "there are {{count}} new posts in this topic since you last read it" - likes: - one: "there is 1 like in this topic" - other: "there are {{count}} likes in this topic" - back_to_list: "Back to Topic List" - options: "Topic Options" - show_links: "show links within this topic" - toggle_information: "toggle topic details" - read_more_in_category: "Want to read more? Browse other topics in {{catLink}} or {{latestLink}}." - read_more: "Want to read more? {{catLink}} or {{latestLink}}." - - # keys ending with _MF use message format, see https://meta.discourse.org/t/message-format-support-for-localization/7035 for details - read_more_MF: "There { - UNREAD, plural, - =0 {} - one { - is 1 unread - } other { - are # unread - } - } { - NEW, plural, - =0 {} - one { {BOTH, select, true{and } false {is } other{}} 1 new topic} - other { {BOTH, select, true{and } false {are } other{}} # new topics} - } remaining, or {CATEGORY, select, true {browse other topics in {catLink}} false {{latestLink}} other {}}" - - browse_all_categories: Browse all categories - - view_latest_topics: view latest topics - suggest_create_topic: Why not create a topic? - jump_reply_up: jump to earlier reply - jump_reply_down: jump to later reply - deleted: "The topic has been deleted" - - auto_close_notice: "This topic will automatically close %{timeLeft}." - auto_close_notice_based_on_last_post: "This topic will close %{duration} after the last reply." - auto_close_title: 'Auto-Close Settings' - auto_close_save: "Save" - auto_close_remove: "Don't Auto-Close This Topic" - auto_close_immediate: - one: "The last post in the topic is already 1 hour old, so the topic will be closed immediately." - other: "The last post in the topic is already %{count} hours old, so the topic will be closed immediately." - - timeline: - back: "Back" - back_description: "Go back to your last unread post" - replies_short: "%{current} / %{total}" - - progress: - title: topic progress - go_top: "top" - go_bottom: "bottom" - go: "go" - jump_bottom: "jump to last post" - jump_prompt: "jump to post" - jump_prompt_long: "What post would you like to jump to?" - jump_bottom_with_number: "jump to post %{post_number}" - total: total posts - current: current post - - notifications: - title: change how often you get notified about this topic - reasons: - mailing_list_mode: "You have mailing list mode enabled, so you will be notified of replies to this topic via email." - "3_10": 'You will receive notifications because you are watching a tag on this topic.' - "3_6": 'You will receive notifications because you are watching this category.' - "3_5": 'You will receive notifications because you started watching this topic automatically.' - "3_2": 'You will receive notifications because you are watching this topic.' - "3_1": 'You will receive notifications because you created this topic.' - "3": 'You will receive notifications because you are watching this topic.' - "2_8": 'You will receive notifications because you are tracking this category.' - "2_4": 'You will receive notifications because you posted a reply to this topic.' - "2_2": 'You will receive notifications because you are tracking this topic.' - "2": 'You will receive notifications because you read this topic.' - "1_2": 'You will be notified if someone mentions your @name or replies to you.' - "1": 'You will be notified if someone mentions your @name or replies to you.' - "0_7": 'You are ignoring all notifications in this category.' - "0_2": 'You are ignoring all notifications on this topic.' - "0": 'You are ignoring all notifications on this topic.' - watching_pm: - title: "Watching" - description: "You will be notified of every new reply in this message, and a count of new replies will be shown." - watching: - title: "Watching" - description: "You will be notified of every new reply in this topic, and a count of new replies will be shown." - tracking_pm: - title: "Tracking" - description: "A count of new replies will be shown for this message. You will be notified if someone mentions your @name or replies to you." - tracking: - title: "Tracking" - description: "A count of new replies will be shown for this topic. You will be notified if someone mentions your @name or replies to you. " - regular: - title: "Normal" - description: "You will be notified if someone mentions your @name or replies to you." - regular_pm: - title: "Normal" - description: "You will be notified if someone mentions your @name or replies to you." - muted_pm: - title: "Muted" - description: "You will never be notified of anything about this message." - muted: - title: "Muted" - description: "You will never be notified of anything about this topic, and it will not appear in latest." - - actions: - recover: "Un-Delete Topic" - delete: "Delete Topic" - open: "Open Topic" - close: "Close Topic" - multi_select: "Select Posts…" - auto_close: "Auto Close…" - pin: "Pin Topic…" - unpin: "Un-Pin Topic…" - unarchive: "Unarchive Topic" - archive: "Archive Topic" - invisible: "Make Unlisted" - visible: "Make Listed" - reset_read: "Reset Read Data" - make_public: "Make Public Topic" - make_private: "Make Private Message" - - feature: - pin: "Pin Topic" - unpin: "Un-Pin Topic" - pin_globally: "Pin Topic Globally" - make_banner: "Banner Topic" - remove_banner: "Remove Banner Topic" - - reply: - title: 'Reply' - help: 'begin composing a reply to this topic' - - clear_pin: - title: "Clear pin" - help: "Clear the pinned status of this topic so it no longer appears at the top of your topic list" - - share: - title: 'Share' - help: 'share a link to this topic' - - print: - title: 'Print' - help: 'Open a printer friendly version of this topic' - - flag_topic: - title: 'Flag' - help: 'privately flag this topic for attention or send a private notification about it' - success_message: 'You successfully flagged this topic.' - - feature_topic: - title: "Feature this topic" - pin: "Make this topic appear at the top of the {{categoryLink}} category until" - confirm_pin: "You already have {{count}} pinned topics. Too many pinned topics may be a burden for new and anonymous users. Are you sure you want to pin another topic in this category?" - unpin: "Remove this topic from the top of the {{categoryLink}} category." - unpin_until: "Remove this topic from the top of the {{categoryLink}} category or wait until %{until}." - pin_note: "Users can unpin the topic individually for themselves." - pin_validation: "A date is required to pin this topic." - not_pinned: "There are no topics pinned in {{categoryLink}}." - already_pinned: - one: "Topics currently pinned in {{categoryLink}}: 1" - other: "Topics currently pinned in {{categoryLink}}: {{count}}" - pin_globally: "Make this topic appear at the top of all topic lists until" - confirm_pin_globally: "You already have {{count}} globally pinned topics. Too many pinned topics may be a burden for new and anonymous users. Are you sure you want to pin another topic globally?" - unpin_globally: "Remove this topic from the top of all topic lists." - unpin_globally_until: "Remove this topic from the top of all topic lists or wait until %{until}." - global_pin_note: "Users can unpin the topic individually for themselves." - not_pinned_globally: "There are no topics pinned globally." - already_pinned_globally: - one: "Topics currently pinned globally: 1" - other: "Topics currently pinned globally: {{count}}" - make_banner: "Make this topic into a banner that appears at the top of all pages." - remove_banner: "Remove the banner that appears at the top of all pages." - banner_note: "Users can dismiss the banner by closing it. Only one topic can be bannered at any given time." - no_banner_exists: "There is no banner topic." - banner_exists: "There is currently a banner topic." - - inviting: "Inviting..." - automatically_add_to_groups: "This invite also includes access to these groups:" - - invite_private: - title: 'Invite to Message' - email_or_username: "Invitee's Email or Username" - email_or_username_placeholder: "email address or username" - action: "Invite" - success: "We've invited that user to participate in this message." - success_group: "We've invited that group to participate in this message." - error: "Sorry, there was an error inviting that user." - group_name: "group name" - - controls: "Topic Controls" - - invite_reply: - title: 'Invite' - username_placeholder: "username" - action: 'Send Invite' - help: 'invite others to this topic via email or notifications' - to_forum: "We'll send a brief email allowing your friend to immediately join by clicking a link, no login required." - sso_enabled: "Enter the username of the person you'd like to invite to this topic." - to_topic_blank: "Enter the username or email address of the person you'd like to invite to this topic." - to_topic_email: "You've entered an email address. We'll email an invitation that allows your friend to immediately reply to this topic." - to_topic_username: "You've entered a username. We'll send a notification with a link inviting them to this topic." - to_username: "Enter the username of the person you'd like to invite. We'll send a notification with a link inviting them to this topic." - - email_placeholder: 'name@example.com' - success_email: "We mailed out an invitation to {{emailOrUsername}}. We'll notify you when the invitation is redeemed. Check the invitations tab on your user page to keep track of your invites." - success_username: "We've invited that user to participate in this topic." - error: "Sorry, we couldn't invite that person. Perhaps they have already been invited? (Invites are rate limited)" - - login_reply: 'Log In to Reply' - - filters: - n_posts: - one: "1 post" - other: "{{count}} posts" - cancel: "Remove filter" - - split_topic: - title: "Move to New Topic" - action: "move to new topic" - topic_name: "New Topic Name" - error: "There was an error moving posts to the new topic." - instructions: - one: "You are about to create a new topic and populate it with the post you've selected." - other: "You are about to create a new topic and populate it with the {{count}} posts you've selected." - - merge_topic: - title: "Move to Existing Topic" - action: "move to existing topic" - error: "There was an error moving posts into that topic." - instructions: - one: "Please choose the topic you'd like to move that post to." - other: "Please choose the topic you'd like to move those {{count}} posts to." - - merge_posts: - title: "Merge Selected Posts" - action: "merge selected posts" - error: "There was an error merging the selected posts." - - change_owner: - title: "Change Owner of Posts" - action: "change ownership" - error: "There was an error changing the ownership of the posts." - label: "New Owner of Posts" - placeholder: "username of new owner" - instructions: - one: "Please choose the new owner of the post by {{old_user}}." - other: "Please choose the new owner of the {{count}} posts by {{old_user}}." - instructions_warn: "Note that any notifications about this post will not be transferred to the new user retroactively.
    Warning: Currently, no post-dependent data is transferred over to the new user. Use with caution." - - change_timestamp: - title: "Change Timestamp" - action: "change timestamp" - invalid_timestamp: "Timestamp cannot be in the future." - error: "There was an error changing the timestamp of the topic." - instructions: "Please select the new timestamp of the topic. Posts in the topic will be updated to have the same time difference." - - multi_select: - select: 'select' - selected: 'selected ({{count}})' - select_replies: 'select +replies' - delete: delete selected - cancel: cancel selecting - select_all: select all - deselect_all: deselect all - description: - one: You have selected 1 post. - other: "You have selected {{count}} posts." - - post: - reply: " {{replyAvatar}} {{usernameLink}}" - reply_topic: " {{link}}" - quote_reply: "Quote" - edit: "Editing {{link}} {{replyAvatar}} {{username}}" - edit_reason: "Reason: " - post_number: "post {{number}}" - last_edited_on: "post last edited on" - reply_as_new_topic: "Reply as linked Topic" - continue_discussion: "Continuing the discussion from {{postLink}}:" - follow_quote: "go to the quoted post" - show_full: "Show Full Post" - show_hidden: 'View hidden content.' - deleted_by_author: - one: "(post withdrawn by author, will be automatically deleted in %{count} hour unless flagged)" - other: "(post withdrawn by author, will be automatically deleted in %{count} hours unless flagged)" - expand_collapse: "expand/collapse" - gap: - one: "view 1 hidden reply" - other: "view {{count}} hidden replies" - - unread: "Post is unread" - has_replies: - one: "{{count}} Reply" - other: "{{count}} Replies" - has_likes: - one: "{{count}} Like" - other: "{{count}} Likes" - - has_likes_title: - one: "1 person liked this post" - other: "{{count}} people liked this post" - - has_likes_title_only_you: "you liked this post" - has_likes_title_you: - one: "you and 1 other person liked this post" - other: "you and {{count}} other people liked this post" - - errors: - create: "Sorry, there was an error creating your post. Please try again." - edit: "Sorry, there was an error editing your post. Please try again." - upload: "Sorry, there was an error uploading that file. Please try again." - file_too_large: "Sorry, that file is too big (maximum size is {{max_size_kb}}kb). Why not upload your large file to a cloud sharing service, then share the link?" - too_many_uploads: "Sorry, you can only upload one file at a time." - too_many_dragged_and_dropped_files: "Sorry, you can only upload 10 files at a time." - upload_not_authorized: "Sorry, the file you are trying to upload is not authorized (authorized extension: {{authorized_extensions}})." - image_upload_not_allowed_for_new_user: "Sorry, new users can not upload images." - attachment_upload_not_allowed_for_new_user: "Sorry, new users can not upload attachments." - attachment_download_requires_login: "Sorry, you need to be logged in to download attachments." - - abandon: - confirm: "Are you sure you want to abandon your post?" - no_value: "No, keep" - yes_value: "Yes, abandon" - - via_email: "this post arrived via email" - via_auto_generated_email: "this post arrived via an auto generated email" - whisper: "this post is a private whisper for moderators" - - wiki: - about: "this post is a wiki" - - archetypes: - save: 'Save Options' - - few_likes_left: "Thanks for sharing the love! You only have a few likes left for today." - - controls: - reply: "begin composing a reply to this post" - like: "like this post" - has_liked: "you've liked this post" - undo_like: "undo like" - edit: "edit this post" - edit_anonymous: "Sorry, but you need to be logged in to edit this post." - flag: "privately flag this post for attention or send a private notification about it" - delete: "delete this post" - undelete: "undelete this post" - share: "share a link to this post" - more: "More" - delete_replies: - confirm: - one: "Do you also want to delete the direct reply to this post?" - other: "Do you also want to delete the {{count}} direct replies to this post?" - yes_value: "Yes, delete the replies too" - no_value: "No, just this post" - admin: "post admin actions" - wiki: "Make Wiki" - unwiki: "Remove Wiki" - convert_to_moderator: "Add Staff Color" - revert_to_regular: "Remove Staff Color" - rebake: "Rebuild HTML" - unhide: "Unhide" - change_owner: "Change Ownership" - - actions: - flag: 'Flag' - defer_flags: - one: "Defer flag" - other: "Defer flags" - undo: - off_topic: "Undo flag" - spam: "Undo flag" - inappropriate: "Undo flag" - bookmark: "Undo bookmark" - like: "Undo like" - vote: "Undo vote" - people: - off_topic: "flagged this as off-topic" - spam: "flagged this as spam" - inappropriate: "flagged this as inappropriate" - notify_moderators: "notified moderators" - notify_user: "sent a message" - bookmark: "bookmarked this" - like: "liked this" - vote: "voted for this" - by_you: - off_topic: "You flagged this as off-topic" - spam: "You flagged this as spam" - inappropriate: "You flagged this as inappropriate" - notify_moderators: "You flagged this for moderation" - notify_user: "You sent a message to this user" - bookmark: "You bookmarked this post" - like: "You liked this" - vote: "You voted for this post" - by_you_and_others: - off_topic: - one: "You and 1 other flagged this as off-topic" - other: "You and {{count}} other people flagged this as off-topic" - spam: - one: "You and 1 other flagged this as spam" - other: "You and {{count}} other people flagged this as spam" - inappropriate: - one: "You and 1 other flagged this as inappropriate" - other: "You and {{count}} other people flagged this as inappropriate" - notify_moderators: - one: "You and 1 other flagged this for moderation" - other: "You and {{count}} other people flagged this for moderation" - notify_user: - one: "You and 1 other sent a message to this user" - other: "You and {{count}} other people sent a message to this user" - bookmark: - one: "You and 1 other bookmarked this post" - other: "You and {{count}} other people bookmarked this post" - like: - one: "You and 1 other liked this" - other: "You and {{count}} other people liked this" - vote: - one: "You and 1 other voted for this post" - other: "You and {{count}} other people voted for this post" - by_others: - off_topic: - one: "1 person flagged this as off-topic" - other: "{{count}} people flagged this as off-topic" - spam: - one: "1 person flagged this as spam" - other: "{{count}} people flagged this as spam" - inappropriate: - one: "1 person flagged this as inappropriate" - other: "{{count}} people flagged this as inappropriate" - notify_moderators: - one: "1 person flagged this for moderation" - other: "{{count}} people flagged this for moderation" - notify_user: - one: "1 person sent a message to this user" - other: "{{count}} sent a message to this user" - bookmark: - one: "1 person bookmarked this post" - other: "{{count}} people bookmarked this post" - like: - one: "1 person liked this" - other: "{{count}} people liked this" - vote: - one: "1 person voted for this post" - other: "{{count}} people voted for this post" - - delete: - confirm: - one: "Are you sure you want to delete that post?" - other: "Are you sure you want to delete all those posts?" - - merge: - confirm: - one: "Are you sure you want merge those posts?" - other: "Are you sure you want to merge those {{count}} posts?" - - revisions: - controls: - first: "First revision" - previous: "Previous revision" - next: "Next revision" - last: "Last revision" - hide: "Hide revision" - show: "Show revision" - revert: "Revert to this revision" - comparing_previous_to_current_out_of_total: "{{previous}} {{current}} / {{total}}" - displays: - inline: - title: "Show the rendered output with additions and removals inline" - button: ' HTML' - side_by_side: - title: "Show the rendered output diffs side-by-side" - button: ' HTML' - side_by_side_markdown: - title: "Show the raw source diffs side-by-side" - button: ' Raw' - - category: - can: 'can… ' - none: '(no category)' - all: 'All categories' - choose: 'Select a category…' - edit: 'edit' - edit_long: "Edit" - view: 'View Topics in Category' - general: 'General' - settings: 'Settings' - topic_template: "Topic Template" - tags: "Tags" - tags_allowed_tags: "Tags that can only be used in this category:" - tags_allowed_tag_groups: "Tag groups that can only be used in this category:" - tags_placeholder: "(Optional) list of allowed tags" - tag_groups_placeholder: "(Optional) list of allowed tag groups" - delete: 'Delete Category' - create: 'New Category' - create_long: 'Create a new category' - save: 'Save Category' - slug: 'Category Slug' - slug_placeholder: '(Optional) dashed-words for url' - creation_error: There has been an error during the creation of the category. - save_error: There was an error saving the category. - name: "Category Name" - description: "Description" - topic: "category topic" - logo: "Category Logo Image" - background_image: "Category Background Image" - badge_colors: "Badge colors" - background_color: "Background color" - foreground_color: "Foreground color" - name_placeholder: "One or two words maximum" - color_placeholder: "Any web color" - delete_confirm: "Are you sure you want to delete this category?" - delete_error: "There was an error deleting the category." - list: "List Categories" - no_description: "Please add a description for this category." - change_in_category_topic: "Edit Description" - already_used: 'This color has been used by another category' - security: "Security" - special_warning: "Warning: This category is a pre-seeded category and the security settings cannot be edited. If you do not wish to use this category, delete it instead of repurposing it." - images: "Images" - auto_close_label: "Auto-close topics after:" - auto_close_units: "hours" - email_in: "Custom incoming email address:" - email_in_allow_strangers: "Accept emails from anonymous users with no accounts" - email_in_disabled: "Posting new topics via email is disabled in the Site Settings. To enable posting new topics via email, " - email_in_disabled_click: 'enable the "email in" setting.' - suppress_from_homepage: "Suppress this category from the homepage." - sort_order: "Default Sort:" - allow_badges_label: "Allow badges to be awarded in this category" - edit_permissions: "Edit Permissions" - add_permission: "Add Permission" - this_year: "this year" - position: "position" - default_position: "Default Position" - position_disabled: "Categories will be displayed in order of activity. To control the order of categories in lists, " - position_disabled_click: 'enable the "fixed category positions" setting.' - parent: "Parent Category" - notifications: - watching: - title: "Watching" - description: "You will automatically watch all topics in these categories. You will be notified of every new post in every topic, and a count of new replies will be shown." - watching_first_post: - title: "Watching First Post" - description: "You will only be notified of the first post in each new topic in these categories." - tracking: - title: "Tracking" - description: "You will automatically track all topics in these categories. You will be notified if someone mentions your @name or replies to you, and a count of new replies will be shown." - regular: - title: "Normal" - description: "You will be notified if someone mentions your @name or replies to you." - muted: - title: "Muted" - description: "You will never be notified of anything about new topics in these categories, and they will not appear in latest." - sort_options: - default: "default" - likes: "Likes" - op_likes: "Original Post Likes" - views: "Views" - posts: "Posts" - activity: "Activity" - posters: "Posters" - category: "Category" - created: "Created" - sort_ascending: 'Ascending' - sort_descending: 'Descending' - - flagging: - title: 'Thanks for helping to keep our community civil!' - action: 'Flag Post' - take_action: "Take Action" - notify_action: 'Message' - official_warning: 'Official Warning' - delete_spammer: "Delete Spammer" - - # keys ending with _MF use message format, see https://meta.discourse.org/t/message-format-support-for-localization/7035 for details - delete_confirm_MF: "You are about to delete {POSTS, plural, one {1 post} other {# posts}} and {TOPICS, plural, one {1 topic} other {# topics}} from this user, remove their account, block signups from their IP address {ip_address}, and add their email address {email} to a permanent block list. Are you sure this user is really a spammer?" - yes_delete_spammer: "Yes, Delete Spammer" - ip_address_missing: "(N/A)" - hidden_email_address: "(hidden)" - submit_tooltip: "Submit the private flag" - take_action_tooltip: "Reach the flag threshold immediately, rather than waiting for more community flags" - cant: "Sorry, you can't flag this post at this time." - notify_staff: 'Notify staff privately' - formatted_name: - off_topic: "It's Off-Topic" - inappropriate: "It's Inappropriate" - spam: "It's Spam" - custom_placeholder_notify_user: "Be specific, be constructive, and always be kind." - custom_placeholder_notify_moderators: "Let us know specifically what you are concerned about, and provide relevant links and examples where possible." - custom_message: - at_least: - one: "enter at least 1 character" - other: "enter at least {{count}} characters" - more: - one: "1 to go..." - other: "{{count}} to go..." - left: - one: "1 remaining" - other: "{{count}} remaining" - - flagging_topic: - title: "Thanks for helping to keep our community civil!" - action: "Flag Topic" - notify_action: "Message" - - topic_map: - title: "Topic Summary" - participants_title: "Frequent Posters" - links_title: "Popular Links" - links_shown: "show more links..." - clicks: - one: "1 click" - other: "%{count} clicks" - post_links: - about: "expand more links for this post" - title: - one: "1 more" - other: "%{count} more" - - topic_statuses: - warning: - help: "This is an official warning." - bookmarked: - help: "You bookmarked this topic" - locked: - help: "This topic is closed; it no longer accepts new replies" - archived: - help: "This topic is archived; it is frozen and cannot be changed" - locked_and_archived: - help: "This topic is closed and archived; it no longer accepts new replies and cannot be changed" - unpinned: - title: "Unpinned" - help: "This topic is unpinned for you; it will display in regular order" - pinned_globally: - title: "Pinned Globally" - help: "This topic is pinned globally; it will display at the top of latest and its category" - pinned: - title: "Pinned" - help: "This topic is pinned for you; it will display at the top of its category" - invisible: - help: "This topic is unlisted; it will not be displayed in topic lists, and can only be accessed via a direct link" - - posts: "Posts" - posts_long: "there are {{number}} posts in this topic" - - # keys ending with _MF use message format, see https://meta.discourse.org/t/message-format-support-for-localization/7035 for details - posts_likes_MF: | - This topic has {count, plural, one {1 reply} other {# replies}} {ratio, select, - low {with a high like to post ratio} - med {with a very high like to post ratio} - high {with an extremely high like to post ratio} - other {}} - original_post: "Original Post" - views: "Views" - views_lowercase: - one: "view" - other: "views" - replies: "Replies" - views_long: "this topic has been viewed {{number}} times" - activity: "Activity" - likes: "Likes" - likes_lowercase: - one: "like" - other: "likes" - likes_long: "there are {{number}} likes in this topic" - users: "Users" - users_lowercase: - one: "user" - other: "users" - category_title: "Category" - history: "History" - changed_by: "by {{author}}" - - raw_email: - title: "Raw Email" - not_available: "Not available!" - - categories_list: "Categories List" - - filters: - with_topics: "%{filter} topics" - with_category: "%{filter} %{category} topics" - latest: - title: "Latest" - title_with_count: - one: "Latest (1)" - other: "Latest ({{count}})" - help: "topics with recent posts" - hot: - title: "Hot" - help: "a selection of the hottest topics" - read: - title: "Read" - help: "topics you've read, in the order that you last read them" - search: - title: "Search" - help: "search all topics" - categories: - title: "Categories" - title_in: "Category - {{categoryName}}" - help: "all topics grouped by category" - unread: - title: "Unread" - title_with_count: - one: "Unread (1)" - other: "Unread ({{count}})" - help: "topics you are currently watching or tracking with unread posts" - lower_title_with_count: - one: "1 unread" - other: "{{count}} unread" - new: - lower_title_with_count: - one: "1 new" - other: "{{count}} new" - lower_title: "new" - title: "New" - title_with_count: - one: "New (1)" - other: "New ({{count}})" - help: "topics created in the last few days" - posted: - title: "My Posts" - help: "topics you have posted in" - bookmarks: - title: "Bookmarks" - help: "topics you have bookmarked" - category: - title: "{{categoryName}}" - title_with_count: - one: "{{categoryName}} (1)" - other: "{{categoryName}} ({{count}})" - help: "latest topics in the {{categoryName}} category" - top: - title: "Top" - help: "the most active topics in the last year, month, week or day" - all: - title: "All Time" - yearly: - title: "Yearly" - quarterly: - title: "Quarterly" - monthly: - title: "Monthly" - weekly: - title: "Weekly" - daily: - title: "Daily" - all_time: "All Time" - this_year: "Year" - this_quarter: "Quarter" - this_month: "Month" - this_week: "Week" - today: "Today" - other_periods: "see top" - - browser_update: 'Unfortunately, your browser is too old to work on this site. Please upgrade your browser.' - - permission_types: - full: "Create / Reply / See" - create_post: "Reply / See" - readonly: "See" - - lightbox: - download: "download" - - keyboard_shortcuts_help: - title: 'Keyboard Shortcuts' - jump_to: - title: 'Jump To' - home: 'g, h Home' - latest: 'g, l Latest' - new: 'g, n New' - unread: 'g, u Unread' - categories: 'g, c Categories' - top: 'g, t Top' - bookmarks: 'g, b Bookmarks' - profile: 'g, p Profile' - messages: 'g, m Messages' - navigation: - title: 'Navigation' - jump: '# Go to post #' - back: 'u Back' - up_down: 'k/j Move selection ↑ ↓' - open: 'o or Enter Open selected topic' - next_prev: 'shift+j/shift+k Next/previous section' - application: - title: 'Application' - create: 'c Create a new topic' - notifications: 'n Open notifications' - hamburger_menu: '= Open hamburger menu' - user_profile_menu: 'p Open user menu' - show_incoming_updated_topics: '. Show updated topics' - search: '/ Search' - help: '? Open keyboard help' - dismiss_new_posts: 'x, r Dismiss New/Posts' - dismiss_topics: 'x, t Dismiss Topics' - log_out: 'shift+z shift+z Log Out' - actions: - title: 'Actions' - bookmark_topic: 'f Toggle bookmark topic' - pin_unpin_topic: 'shift+p Pin/Unpin topic' - share_topic: 'shift+s Share topic' - share_post: 's Share post' - reply_as_new_topic: 't Reply as linked topic' - reply_topic: 'shift+r Reply to topic' - reply_post: 'r Reply to post' - quote_post: 'q Quote post' - like: 'l Like post' - flag: '! Flag post' - bookmark: 'b Bookmark post' - edit: 'e Edit post' - delete: 'd Delete post' - mark_muted: 'm, m Mute topic' - mark_regular: 'm, r Regular (default) topic' - mark_tracking: 'm, t Track topic' - mark_watching: 'm, w Watch topic' - print: 'ctrl+p Print topic' - - badges: - earned_n_times: - one: "Earned this badge 1 time" - other: "Earned this badge %{count} times" - granted_on: "Granted %{date}" - others_count: "Others with this badge (%{count})" - title: Badges - allow_title: "available title" - multiple_grant: "awarded multiple times" - badge_count: - one: "1 Badge" - other: "%{count} Badges" - more_badges: - one: "+1 More" - other: "+%{count} More" - granted: - one: "1 granted" - other: "%{count} granted" - select_badge_for_title: Select a badge to use as your title - none: "" - badge_grouping: - getting_started: - name: Getting Started - community: - name: Community - trust_level: - name: Trust Level - other: - name: Other - posting: - name: Posting - - google_search: | -

    Search with Google

    -

    -

    -

    - - tagging: - all_tags: "All Tags" - selector_all_tags: "all tags" - selector_no_tags: "no tags" - changed: "tags changed:" - tags: "Tags" - choose_for_topic: "choose optional tags for this topic" - delete_tag: "Delete Tag" - delete_confirm: "Are you sure you want to delete that tag?" - rename_tag: "Rename Tag" - rename_instructions: "Choose a new name for the tag:" - sort_by: "Sort by:" - sort_by_count: "count" - sort_by_name: "name" - manage_groups: "Manage Tag Groups" - manage_groups_description: "Define groups to organize tags" - - filters: - without_category: "%{filter} %{tag} topics" - with_category: "%{filter} %{tag} topics in %{category}" - untagged_without_category: "%{filter} untagged topics" - untagged_with_category: "%{filter} untagged topics in %{category}" - - notifications: - watching: - title: "Watching" - description: "You will automatically watch all topics in this tag. You will be notified of all new posts and topics, plus the count of unread and new posts will also appear next to the topic." - watching_first_post: - title: "Watching First Post" - description: "You will only be notified of the first post in each new topic in this tag." - tracking: - title: "Tracking" - description: "You will automatically track all topics in this tag. A count of unread and new posts will appear next to the topic." - regular: - title: "Regular" - description: "You will be notified if someone mentions your @name or replies to your post." - muted: - title: "Muted" - description: "You will not be notified of anything about new topics in this tag, and they will not appear on your unread tab." - - groups: - title: "Tag Groups" - about: "Add tags to groups to manage them more easily." - new: "New Group" - tags_label: "Tags in this group:" - parent_tag_label: "Parent tag:" - parent_tag_placeholder: "Optional" - parent_tag_description: "Tags from this group can't be used unless the parent tag is present." - one_per_topic_label: "Limit one tag per topic from this group" - new_name: "New Tag Group" - save: "Save" - delete: "Delete" - confirm_delete: "Are you sure you want to delete this tag group?" - - topics: - none: - unread: "You have no unread topics." - new: "You have no new topics." - read: "You haven't read any topics yet." - posted: "You haven't posted in any topics yet." - latest: "There are no latest topics." - hot: "There are no hot topics." - bookmarks: "You have no bookmarked topics yet." - top: "There are no top topics." - search: "There are no search results." - bottom: - latest: "There are no more latest topics." - hot: "There are no more hot topics." - posted: "There are no more posted topics." - read: "There are no more read topics." - new: "There are no more new topics." - unread: "There are no more unread topics." - top: "There are no more top topics." - bookmarks: "There are no more bookmarked topics." - search: "There are no more search results." - - invite: - custom_message: "Make your invite a little bit more personal by writing a" - custom_message_link: "custom message" - custom_message_placeholder: "Enter your custom message" - custom_message_template_forum: "Hey, you should join this forum!" - custom_message_template_topic: "Hey, I thought you might enjoy this topic!" - - safe_mode: - enabled: "Safe mode is enabled, to exit safe mode close this browser window" - - - # This section is exported to the javascript for i18n in the admin section + title: "صارف کا نام" admin_js: - type_to_filter: "type to filter..." - admin: - title: 'Discourse Admin' - moderator: 'Moderator' - - dashboard: - title: "Dashboard" - last_updated: "Dashboard last updated:" - version: "Version" - up_to_date: "You're up to date!" - critical_available: "A critical update is available." - updates_available: "Updates are available." - please_upgrade: "Please upgrade!" - no_check_performed: "A check for updates has not been performed. Ensure sidekiq is running." - stale_data: "A check for updates has not been performed lately. Ensure sidekiq is running." - version_check_pending: "Looks like you upgraded recently. Fantastic!" - installed_version: "Installed" - latest_version: "Latest" - problems_found: "Some problems have been found with your installation of Discourse:" - last_checked: "Last checked" - refresh_problems: "Refresh" - no_problems: "No problems were found." - moderators: 'Moderators:' - admins: 'Admins:' - blocked: 'Blocked:' - suspended: 'Suspended:' - private_messages_short: "Msgs" - private_messages_title: "Messages" - mobile_title: "Mobile" - space_free: "{{size}} free" - uploads: "uploads" - backups: "backups" - traffic_short: "Traffic" - traffic: "Application web requests" - page_views: "API Requests" - page_views_short: "API Requests" - show_traffic_report: "Show Detailed Traffic Report" - - reports: - today: "Today" - yesterday: "Yesterday" - last_7_days: "Last 7 Days" - last_30_days: "Last 30 Days" - all_time: "All Time" - 7_days_ago: "7 Days Ago" - 30_days_ago: "30 Days Ago" - all: "All" - view_table: "table" - view_graph: "graph" - refresh_report: "Refresh Report" - start_date: "Start Date" - end_date: "End Date" - groups: "All groups" - - commits: - latest_changes: "Latest changes: please update often!" - by: "by" - - flags: - title: "Flags" - old: "Old" - active: "Active" - - agree: "Agree" - agree_title: "Confirm this flag as valid and correct" - agree_flag_modal_title: "Agree and..." - agree_flag_hide_post: "Agree (hide post + send PM)" - agree_flag_hide_post_title: "Hide this post and automatically send the user a message urging them to edit it" - agree_flag_restore_post: "Agree (restore post)" - agree_flag_restore_post_title: "Restore this post" - agree_flag: "Agree with flag" - agree_flag_title: "Agree with flag and keep the post unchanged" - defer_flag: "Defer" - defer_flag_title: "Remove this flag; it requires no action at this time." - delete: "Delete" - delete_title: "Delete the post this flag refers to." - delete_post_defer_flag: "Delete post and Defer flag" - delete_post_defer_flag_title: "Delete post; if the first post, delete the topic" - delete_post_agree_flag: "Delete post and Agree with flag" - delete_post_agree_flag_title: "Delete post; if the first post, delete the topic" - delete_flag_modal_title: "Delete and..." - delete_spammer: "Delete Spammer" - delete_spammer_title: "Remove the user and all posts and topics by this user." - disagree_flag_unhide_post: "Disagree (unhide post)" - disagree_flag_unhide_post_title: "Remove any flags from this post and make the post visible again" - disagree_flag: "Disagree" - disagree_flag_title: "Deny this flag as invalid or incorrect" - clear_topic_flags: "Done" - clear_topic_flags_title: "The topic has been investigated and issues have been resolved. Click Done to remove the flags." - more: "(more replies...)" - - dispositions: - agreed: "agreed" - disagreed: "disagreed" - deferred: "deferred" - - flagged_by: "Flagged by" - resolved_by: "Resolved by" - took_action: "Took action" - system: "System" - error: "Something went wrong" - reply_message: "Reply" - no_results: "There are no flags." - topic_flagged: "This topic has been flagged." - visit_topic: "Visit the topic to take action" - was_edited: "Post was edited after the first flag" - previous_flags_count: "This post has already been flagged {{count}} times." - - summary: - action_type_3: - one: "off-topic" - other: "off-topic x{{count}}" - action_type_4: - one: "inappropriate" - other: "inappropriate x{{count}}" - action_type_6: - one: "custom" - other: "custom x{{count}}" - action_type_7: - one: "custom" - other: "custom x{{count}}" - action_type_8: - one: "spam" - other: "spam x{{count}}" - - groups: - primary: "Primary Group" - no_primary: "(no primary group)" - title: "Groups" - edit: "Edit Groups" - refresh: "Refresh" - new: "New" - selector_placeholder: "enter username" - name_placeholder: "Group name, no spaces, same as username rule" - about: "Edit your group membership and names here" - group_members: "Group members" - delete: "Delete" - delete_confirm: "Delete this group?" - delete_failed: "Unable to delete group. If this is an automatic group, it cannot be destroyed." - delete_member_confirm: "Remove '%{username}' from the '%{group}' group?" - delete_owner_confirm: "Remove owner privilege for '%{username}'?" - name: "Name" - add: "Add" - add_members: "Add members" - custom: "Custom" - bulk_complete: "The users have been added to the group." - bulk: "Bulk Add to Group" - bulk_paste: "Paste a list of usernames or emails, one per line:" - bulk_select: "(select a group)" - automatic: "Automatic" - automatic_membership_email_domains: "Users who register with an email domain that exactly matches one in this list will be automatically added to this group:" - automatic_membership_retroactive: "Apply the same email domain rule to add existing registered users" - default_title: "Default title for all users in this group" - primary_group: "Automatically set as primary group" - group_owners: Owners - add_owners: Add owners - incoming_email: "Custom incoming email address" - incoming_email_placeholder: "enter email address" - flair_url: "Avatar Flair Image" - flair_url_placeholder: "(Optional) Image URL or Font Awesome class" - flair_bg_color: "Avatar Flair Background Color" - flair_bg_color_placeholder: "(Optional) Hex color value" - flair_color: "Avatar Flair Color" - flair_color_placeholder: "(Optional) Hex color value" - flair_preview: "Preview" - flair_note: "Note: Flair will only show for a user's primary group." - - api: - generate_master: "Generate Master API Key" - none: "There are no active API keys right now." - user: "User" - title: "API" - key: "API Key" - 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." - - web_hooks: - title: "Webhooks" - none: "There are no webhooks right now." - instruction: "Webhooks allows Discourse to notify external services when certain event happens in your site. When the webhook is triggered, a POST request will send to URLs provided." - detailed_instruction: "A POST request will be sent to provided URL when chosen event happens." - new: "New Webhook" - create: "Create" - save: "Save" - destroy: "Delete" - description: "Description" - controls: "Controls" - go_back: "Back to list" - payload_url: "Payload URL" - payload_url_placeholder: "https://example.com/postreceive" - warn_local_payload_url: "It seems you are trying to set up the webhook to a local url. Event delivered to a local address may cause side-effect or unexpected behaviours. Continue?" - secret_invalid: "Secret must not have any blank characters." - secret_too_short: "Secret should be at least 12 characters." - secret_placeholder: "A optional string, used for generating signature" - event_type_missing: "You need to set up at least one event type." - content_type: "Content Type" - secret: "Secret" - event_chooser: "Which events would you like to trigger this webhook?" - wildcard_event: "Send me everything." - individual_event: "Select individual events." - verify_certificate: "Check TLS certificate of payload url" - active: "Active" - active_notice: "We will deliver event details when it happens." - categories_filter_instructions: "Relevant webhooks will only be triggered if the event is related with specified categories. Leave blank to trigger webhooks for all categories." - categories_filter: "Triggered Categories" - groups_filter_instructions: "Relevant webhooks will only be triggered if the event is related with specified groups. Leave blank to trigger webhooks for all groups." - groups_filter: "Triggered Groups" - delete_confirm: "Delete this webhook?" - topic_event: - name: "Topic Event" - details: "When there is a new topic, revised, changed or deleted." - post_event: - name: "Post Event" - details: "When there is a new reply, edit, deleted or recovered." - user_event: - name: "User Event" - details: "When a user is created or approved." - delivery_status: - title: "Delivery Status" - inactive: "Inactive" - failed: "Failed" - successful: "Successful" - events: - none: "There are no related events." - redeliver: "Redeliver" - incoming: - one: "There is a new event." - other: "There are {{count}} new events." - completed_in: - one: "Completed in 1 second." - other: "Completed in {{count}} seconds." - request: "Request" - response: "Response" - redeliver_confirm: "Are you sure you want to redeliver the same payload?" - headers: "Headers" - payload: "Payload" - body: "Body" - go_list: "Go to list" - go_details: "Edit webhook" - go_events: "Go to events" - ping: "Ping" - status: "Status Code" - event_id: "ID" - timestamp: "Created" - completion: "Completion Time" - actions: "Actions" - plugins: - title: "Plugins" - installed: "Installed Plugins" - name: "Name" - none_installed: "You don't have any plugins installed." - version: "Version" - enabled: "Enabled?" - is_enabled: "Y" - not_enabled: "N" - change_settings: "Change Settings" - change_settings_short: "Settings" - howto: "How do I install plugins?" - - backups: - title: "Backups" - menu: - backups: "Backups" - logs: "Logs" - none: "No backup available." - read_only: - enable: - title: "Enable read-only mode" - label: "Enable read-only" - confirm: "Are you sure you want to enable read-only mode?" - disable: - title: "Disable read-only mode" - label: "Disable read-only" - logs: - none: "No logs yet..." - columns: - filename: "Filename" - size: "Size" - upload: - label: "Upload" - title: "Upload a backup to this instance" - uploading: "Uploading..." - success: "'{{filename}}' has successfully been uploaded." - error: "There has been an error while uploading '{{filename}}': {{message}}" - operations: - is_running: "An operation is currently running..." - failed: "The {{operation}} failed. Please check the logs." - cancel: - label: "Cancel" - title: "Cancel the current operation" - confirm: "Are you sure you want to cancel the current operation?" - backup: - label: "Backup" - title: "Create a backup" - confirm: "Do you want to start a new backup?" - without_uploads: "Yes (do not include files)" - download: - label: "Download" - title: "Download the backup" - destroy: - title: "Remove the backup" - confirm: "Are you sure you want to destroy this backup?" - restore: - is_disabled: "Restore is disabled in the site settings." - label: "Restore" - title: "Restore the backup" - confirm: "Are you sure you want to restore this backup?" - rollback: - label: "Rollback" - title: "Rollback the database to previous working state" - confirm: "Are you sure you want to rollback the database to the previous working state?" - - export_csv: - success: "Export initiated, you will be notified via message when the process is complete." - failed: "Export failed. Please check the logs." - button_text: "Export" - button_title: - user: "Export full user list in CSV format." - staff_action: "Export full staff action log in CSV format." - screened_email: "Export full screened email list in CSV format." - screened_ip: "Export full screened IP list in CSV format." - screened_url: "Export full screened URL list in CSV format." export_json: - button_text: "Export" - - invite: - button_text: "Send Invites" - button_title: "Send Invites" - - customize: - title: "Customize" - long_title: "Site Customizations" - css: "CSS" - header: "Header" - top: "Top" - footer: "Footer" - embedded_css: "Embedded CSS" - head_tag: - text: "" - title: "HTML that will be inserted before the tag" - body_tag: - text: "" - title: "HTML that will be inserted before the tag" - override_default: "Do not include standard style sheet" - enabled: "Enabled?" - preview: "preview" - undo_preview: "remove preview" - rescue_preview: "default style" - explain_preview: "See the site with this custom stylesheet" - explain_undo_preview: "Go back to the currently enabled custom stylesheet" - explain_rescue_preview: "See the site with the default stylesheet" - save: "Save" - new: "New" - new_style: "New Style" - import: "Import" - import_title: "Select a file or paste text" - delete: "Delete" - delete_confirm: "Delete this customization?" - about: "Modify CSS stylesheets and HTML headers on the site. Add a customization to start." - color: "Color" - opacity: "Opacity" - copy: "Copy" - email_templates: - title: "Email Templates" - subject: "Subject" - multiple_subjects: "This email template has multiple subjects." - body: "Body" - none_selected: "Select an email template to begin editing." - revert: "Revert Changes" - revert_confirm: "Are you sure you want to revert your changes?" - - css_html: - title: "CSS/HTML" - long_title: "CSS and HTML Customizations" - colors: - title: "Colors" - long_title: "Color Schemes" - about: "Modify the colors used on the site without writing CSS. Add a scheme to start." - new_name: "New Color Scheme" - copy_name_prefix: "Copy of" - delete_confirm: "Delete this color scheme?" - undo: "undo" - undo_title: "Undo your changes to this color since the last time it was saved." - revert: "revert" - revert_title: "Reset this color to Discourse's default color scheme." - primary: - name: 'primary' - description: 'Most text, icons, and borders.' - secondary: - name: 'secondary' - description: 'The main background color, and text color of some buttons.' - tertiary: - name: 'tertiary' - description: 'Links, some buttons, notifications, and accent color.' - quaternary: - name: "quaternary" - description: "Navigation links." - header_background: - name: "header background" - description: "Background color of the site's header." - header_primary: - name: "header primary" - description: "Text and icons in the site's header." - highlight: - name: 'highlight' - description: 'The background color of highlighted elements on the page, such as posts and topics.' - danger: - name: 'danger' - description: 'Highlight color for actions like deleting posts and topics.' - success: - name: 'success' - description: 'Used to indicate an action was successful.' - love: - name: 'love' - description: "The like button's color." - - email: - title: "Emails" - settings: "Settings" - templates: "Templates" - preview_digest: "Preview Digest" - sending_test: "Sending test Email..." - error: "ERROR - %{server_error}" - test_error: "There was a problem sending the test email. Please double-check your mail settings, verify that your host is not blocking mail connections, and try again." - sent: "Sent" - skipped: "Skipped" - bounced: "Bounced" - received: "Received" - rejected: "Rejected" - sent_at: "Sent At" - time: "Time" - user: "User" - email_type: "Email Type" - to_address: "To Address" - test_email_address: "email address to test" - send_test: "Send Test Email" - sent_test: "sent!" - delivery_method: "Delivery Method" - preview_digest_desc: "Preview the content of the digest emails sent to inactive users." - refresh: "Refresh" - send_digest_label: "Send this result to:" - send_digest: "Send" - sending_email: "Sending email..." - format: "Format" - html: "html" - text: "text" - last_seen_user: "Last Seen User:" - no_result: "No results found for digest." - reply_key: "Reply Key" - skipped_reason: "Skip Reason" - incoming_emails: - from_address: "From" - to_addresses: "To" - cc_addresses: "Cc" - subject: "Subject" - error: "Error" - none: "No incoming emails found." - modal: - title: "Incoming Email Details" - error: "Error" - headers: "Headers" - subject: "Subject" - body: "Body" - rejection_message: "Rejection Mail" - filters: - from_placeholder: "from@example.com" - to_placeholder: "to@example.com" - cc_placeholder: "cc@example.com" - subject_placeholder: "Subject..." - error_placeholder: "Error" - logs: - none: "No logs found." - filters: - title: "Filter" - user_placeholder: "username" - address_placeholder: "name@example.com" - type_placeholder: "digest, signup..." - reply_key_placeholder: "reply key" - skipped_reason_placeholder: "reason" - - logs: - title: "Logs" - action: "Action" - created_at: "Created" - last_match_at: "Last Matched" - match_count: "Matches" - ip_address: "IP" - topic_id: "Topic ID" - post_id: "Post ID" - category_id: "Category ID" - delete: 'Delete' - edit: 'Edit' - save: 'Save' - screened_actions: - block: "block" - do_nothing: "do nothing" - staff_actions: - title: "Staff Actions" - instructions: "Click usernames and actions to filter the list. Click profile pictures to go to user pages." - clear_filters: "Show Everything" - staff_user: "Staff User" - target_user: "Target User" - subject: "Subject" - when: "When" - context: "Context" - details: "Details" - previous_value: "Previous" - new_value: "New" - diff: "Diff" - show: "Show" - modal_title: "Details" - no_previous: "There is no previous value." - deleted: "No new value. The record was deleted." - actions: - delete_user: "delete user" - change_trust_level: "change trust level" - change_username: "change username" - change_site_setting: "change site setting" - change_site_customization: "change site customization" - delete_site_customization: "delete site customization" - change_site_text: "change site text" - suspend_user: "suspend user" - unsuspend_user: "unsuspend user" - grant_badge: "grant badge" - revoke_badge: "revoke badge" - check_email: "check email" - delete_topic: "delete topic" - delete_post: "delete post" - impersonate: "impersonate" - anonymize_user: "anonymize user" - roll_up: "roll up IP blocks" - change_category_settings: "change category settings" - delete_category: "delete category" - create_category: "create category" - block_user: "block user" - unblock_user: "unblock user" - grant_admin: "grant admin" - revoke_admin: "revoke admin" - grant_moderation: "grant moderation" - revoke_moderation: "revoke moderation" - backup_operation: "backup operation" - deleted_tag: "deleted tag" - renamed_tag: "renamed tag" - revoke_email: "revoke email" - screened_emails: - title: "Screened Emails" - description: "When someone tries to create a new account, the following email addresses will be checked and the registration will be blocked, or some other action performed." - email: "Email Address" - actions: - allow: "Allow" - screened_urls: - title: "Screened URLs" - description: "The URLs listed here were used in posts by users who have been identified as spammers." - url: "URL" - domain: "Domain" - screened_ips: - title: "Screened IPs" - description: 'IP addresses that are being watched. Use "Allow" to whitelist IP addresses.' - delete_confirm: "Are you sure you want to remove the rule for %{ip_address}?" - roll_up_confirm: "Are you sure you want to roll up commonly screened IP addresses into subnets?" - rolled_up_some_subnets: "Successfully rolled up IP ban entries to these subnets: %{subnets}." - rolled_up_no_subnet: "There was nothing to roll up." - actions: - block: "Block" - do_nothing: "Allow" - allow_admin: "Allow Admin" - form: - label: "New:" - ip_address: "IP address" - add: "Add" - filter: "Search" - roll_up: - text: "Roll up" - title: "Creates new subnet ban entries if there are at least 'min_ban_entries_for_roll_up' entries." - logster: - title: "Error Logs" - - impersonate: - title: "Impersonate" - help: "Use this tool to impersonate a user account for debugging purposes. You will have to log out once finished." - not_found: "That user can't be found." - invalid: "Sorry, you may not impersonate that user." - - users: - title: 'Users' - create: 'Add Admin User' - last_emailed: "Last Emailed" - not_found: "Sorry, that username doesn't exist in our system." - id_not_found: "Sorry, that user id doesn't exist in our system." - active: "Active" - show_emails: "Show Emails" - nav: - new: "New" - active: "Active" - pending: "Pending" - staff: 'Staff' - suspended: 'Suspended' - blocked: 'Blocked' - suspect: 'Suspect' - approved: "Approved?" - approved_selected: - one: "approve user" - other: "approve users ({{count}})" - reject_selected: - one: "reject user" - other: "reject users ({{count}})" - titles: - active: 'Active Users' - new: 'New Users' - pending: 'Users Pending Review' - newuser: 'Users at Trust Level 0 (New User)' - basic: 'Users at Trust Level 1 (Basic User)' - member: 'Users at Trust Level 2 (Member)' - regular: 'Users at Trust Level 3 (Regular)' - leader: 'Users at Trust Level 4 (Leader)' - staff: "Staff" - admins: 'Admin Users' - moderators: 'Moderators' - blocked: 'Blocked Users' - suspended: 'Suspended Users' - suspect: 'Suspect Users' - reject_successful: - one: "Successfully rejected 1 user." - other: "Successfully rejected %{count} users." - reject_failures: - one: "Failed to reject 1 user." - other: "Failed to reject %{count} users." - not_verified: "Not verified" - check_email: - title: "Reveal this user's email address" - text: "Show" - - user: - suspend_failed: "Something went wrong suspending this user {{error}}" - unsuspend_failed: "Something went wrong unsuspending this user {{error}}" - suspend_duration: "How long will the user be suspended for?" - suspend_duration_units: "(days)" - suspend_reason_label: "Why are you suspending? This text will be visible to everyone on this user's profile page, and will be shown to the user when they try to log in. Keep it short." - suspend_reason: "Reason" - suspended_by: "Suspended by" - delete_all_posts: "Delete all posts" - - # keys ending with _MF use message format, see https://meta.discourse.org/t/message-format-support-for-localization/7035 for details - delete_all_posts_confirm_MF: "You are about to delete {POSTS, plural, one {1 post} other {# posts}} and {TOPICS, plural, one {1 topic} other {# topics}}. Are you sure?" - suspend: "Suspend" - unsuspend: "Unsuspend" - suspended: "Suspended?" - moderator: "Moderator?" - admin: "Admin?" - blocked: "Blocked?" - staged: "Staged?" - show_admin_profile: "Admin" - edit_title: "Edit Title" - save_title: "Save Title" - refresh_browsers: "Force browser refresh" - refresh_browsers_message: "Message sent to all clients!" - show_public_profile: "Show Public Profile" - impersonate: 'Impersonate' - ip_lookup: "IP Lookup" - log_out: "Log Out" - logged_out: "User was logged out on all devices" - revoke_admin: 'Revoke Admin' - grant_admin: 'Grant Admin' - revoke_moderation: 'Revoke Moderation' - grant_moderation: 'Grant Moderation' - unblock: 'Unblock' - block: 'Block' - reputation: Reputation - permissions: Permissions - activity: Activity - like_count: Likes Given / Received - last_100_days: 'in the last 100 days' - private_topics_count: Private Topics - posts_read_count: Posts Read - post_count: Posts Created - topics_entered: Topics Viewed - flags_given_count: Flags Given - flags_received_count: Flags Received - warnings_received_count: Warnings Received - flags_given_received_count: 'Flags Given / Received' - approve: 'Approve' - approved_by: "approved by" - approve_success: "User approved and email sent with activation instructions." - approve_bulk_success: "Success! All selected users have been approved and notified." - time_read: "Read Time" - anonymize: "Anonymize User" - anonymize_confirm: "Are you SURE you want to anonymize this account? This will change the username and email, and reset all profile information." - anonymize_yes: "Yes, anonymize this account" - anonymize_failed: "There was a problem anonymizing the account." - delete: "Delete User" - delete_forbidden_because_staff: "Admins and moderators can't be deleted." - delete_posts_forbidden_because_staff: "Can't delete all posts of admins and moderators." - delete_forbidden: - one: "Users can't be deleted if they have posts. Delete all posts before trying to delete a user. (Posts older than %{count} day old can't be deleted.)" - other: "Users can't be deleted if they have posts. Delete all posts before trying to delete a user. (Posts older than %{count} days old can't be deleted.)" - cant_delete_all_posts: - one: "Can't delete all posts. Some posts are older than %{count} day old. (The delete_user_max_post_age setting.)" - other: "Can't delete all posts. Some posts are older than %{count} days old. (The delete_user_max_post_age setting.)" - cant_delete_all_too_many_posts: - one: "Can't delete all posts because the user has more than 1 post. (delete_all_posts_max)" - other: "Can't delete all posts because the user has more than %{count} posts. (delete_all_posts_max)" - delete_confirm: "Are you SURE you want to delete this user? This is permanent!" - delete_and_block: "Delete and block this email and IP address" - delete_dont_block: "Delete only" - deleted: "The user was deleted." - delete_failed: "There was an error deleting that user. Make sure all posts are deleted before trying to delete the user." - send_activation_email: "Send Activation Email" - activation_email_sent: "An activation email has been sent." - send_activation_email_failed: "There was a problem sending another activation email. %{error}" - activate: "Activate Account" - activate_failed: "There was a problem activating the user." - deactivate_account: "Deactivate Account" - deactivate_failed: "There was a problem deactivating the user." - unblock_failed: 'There was a problem unblocking the user.' - block_failed: 'There was a problem blocking the user.' - block_confirm: 'Are you sure you want to block this user? They will not be able to create any new topics or posts.' - block_accept: 'Yes, block this user' - bounce_score: "Bounce Score" - reset_bounce_score: - label: "Reset" - title: "Reset bounce score back to 0" - deactivate_explanation: "A deactivated user must re-validate their email." - suspended_explanation: "A suspended user can't log in." - block_explanation: "A blocked user can't post or start topics." - staged_explanation: "A staged user can only post via email in specific topics." - bounce_score_explanation: - none: "No bounces were received recently from that email." - some: "Some bounces were received recently from that email." - threshold_reached: "Received too many bounces from that email." - trust_level_change_failed: "There was a problem changing the user's trust level." - suspend_modal_title: "Suspend User" - trust_level_2_users: "Trust Level 2 Users" - trust_level_3_requirements: "Trust Level 3 Requirements" - trust_level_locked_tip: "trust level is locked, system will not promote or demote user" - trust_level_unlocked_tip: "trust level is unlocked, system will may promote or demote user" - lock_trust_level: "Lock Trust Level" - unlock_trust_level: "Unlock Trust Level" - tl3_requirements: - title: "Requirements for Trust Level 3" - table_title: - one: "In the last day:" - other: "In the last %{count} days:" - value_heading: "Value" - requirement_heading: "Requirement" - visits: "Visits" - days: "days" - topics_replied_to: "Topics Replied To" - topics_viewed: "Topics Viewed" - topics_viewed_all_time: "Topics Viewed (all time)" - posts_read: "Posts Read" - posts_read_all_time: "Posts Read (all time)" - flagged_posts: "Flagged Posts" - flagged_by_users: "Users Who Flagged" - likes_given: "Likes Given" - likes_received: "Likes Received" - likes_received_days: "Likes Received: unique days" - likes_received_users: "Likes Received: unique users" - qualifies: "Qualifies for trust level 3." - does_not_qualify: "Doesn't qualify for trust level 3." - will_be_promoted: "Will be promoted soon." - will_be_demoted: "Will be demoted soon." - on_grace_period: "Currently in promotion grace period, will not be demoted." - locked_will_not_be_promoted: "Trust level locked. Will never be promoted." - locked_will_not_be_demoted: "Trust level locked. Will never be demoted." - sso: - title: "Single Sign On" - external_id: "External ID" - external_username: "Username" - external_name: "Name" - external_email: "Email" - external_avatar_url: "Profile Picture URL" - - user_fields: - title: "User Fields" - help: "Add fields that your users can fill out." - create: "Create User Field" - untitled: "Untitled" - name: "Field Name" - type: "Field Type" - description: "Field Description" - save: "Save" - edit: "Edit" - delete: "Delete" - cancel: "Cancel" - delete_confirm: "Are you sure you want to delete that user field?" - options: "Options" - required: - title: "Required at signup?" - enabled: "required" - disabled: "not required" - editable: - title: "Editable after signup?" - enabled: "editable" - disabled: "not editable" - show_on_profile: - title: "Show on public profile?" - enabled: "shown on profile" - disabled: "not shown on profile" - show_on_user_card: - title: "Show on user card?" - enabled: "shown on user card" - disabled: "not shown on user card" - - field_types: - text: 'Text Field' - confirm: 'Confirmation' - dropdown: "Dropdown" - - site_text: - description: "You can customize any of the text on your forum. Please start by searching below:" - search: "Search for the text you'd like to edit" - title: 'Text Content' - edit: 'edit' - revert: "Revert Changes" - revert_confirm: "Are you sure you want to revert your changes?" - go_back: "Back to Search" - recommended: "We recommend customizing the following text to suit your needs:" - show_overriden: 'Only show overridden' - - site_settings: - show_overriden: 'Only show overridden' - title: 'Settings' - reset: 'reset' - none: 'none' - no_results: "No results found." - clear_filter: "Clear" - add_url: "add URL" - add_host: "add host" - categories: - all_results: 'All' - required: 'Required' - basic: 'Basic Setup' - users: 'Users' - posting: 'Posting' - email: 'Email' - files: 'Files' - trust: 'Trust Levels' - security: 'Security' - onebox: "Onebox" - seo: 'SEO' - spam: 'Spam' - rate_limits: 'Rate Limits' - developer: 'Developer' - embedding: "Embedding" - legal: "Legal" - user_api: 'User API' - uncategorized: 'Other' - backups: "Backups" - login: "Login" - plugins: "Plugins" - user_preferences: "User Preferences" - tags: "Tags" - search: "Search" - + button_text: "برآمد" badges: - title: Badges - new_badge: New Badge - new: New - name: Name - badge: Badge - display_name: Display Name - description: Description - long_description: Long Description - badge_type: Badge Type - badge_grouping: Group - badge_groupings: - modal_title: Badge Groupings - granted_by: Granted By - granted_at: Granted At - reason_help: (A link to a post or topic) - save: Save - delete: Delete - delete_confirm: Are you sure you want to delete this badge? - revoke: Revoke - reason: Reason - expand: Expand … - revoke_confirm: Are you sure you want to revoke this badge? - edit_badges: Edit Badges - grant_badge: Grant Badge - granted_badges: Granted Badges - grant: Grant - no_user_badges: "%{name} has not been granted any badges." - no_badges: There are no badges that can be granted. - none_selected: "Select a badge to get started" - allow_title: Allow badge to be used as a title - multiple_grant: Can be granted multiple times - listable: Show badge on the public badges page - enabled: Enable badge - icon: Icon - image: Image - icon_help: "Use either a Font Awesome class or URL to an image" - query: Badge Query (SQL) - target_posts: Query targets posts - auto_revoke: Run revocation query daily - show_posts: Show post granting badge on badge page - trigger: Trigger - trigger_type: - none: "Update daily" - post_action: "When a user acts on post" - post_revision: "When a user edits or creates a post" - trust_level_change: "When a user changes trust level" - user_change: "When a user is edited or created" - post_processed: "After a post is processed" - preview: - link_text: "Preview granted badges" - plan_text: "Preview with query plan" - modal_title: "Badge Query Preview" - sql_error_header: "There was an error with the query." - error_help: "See the following links for help with badge queries." - bad_count_warning: - header: "WARNING!" - text: "There are missing grant samples. This happens when the badge query returns user IDs or post IDs that do not exist. This may cause unexpected results later on - please double-check your query." - no_grant_count: "No badges to be assigned." - grant_count: - one: "1 badge to be assigned." - other: "%{count} badges to be assigned." - sample: "Sample:" - grant: - with: %{username} - with_post: %{username} for post in %{link} - with_post_time: %{username} for post in %{link} at %{time} - with_time: %{username} at %{time} - - emoji: - title: "Emoji" - help: "Add new emoji that will be available to everyone. (PROTIP: drag & drop multiple files at once)" - add: "Add New Emoji" - name: "Name" - image: "Image" - delete_confirm: "Are you sure you want to delete the :%{name}: emoji?" - - embedding: - get_started: "If you'd like to embed Discourse on another website, begin by adding its host." - confirm_delete: "Are you sure you want to delete that host?" - sample: "Use the following HTML code into your site to create and embed discourse topics. Replace REPLACE_ME with the canonical URL of the page you are embedding it on." - title: "Embedding" - host: "Allowed Hosts" - path_whitelist: "Path Whitelist" - edit: "edit" - category: "Post to Category" - add_host: "Add Host" - settings: "Embedding Settings" - feed_settings: "Feed Settings" - feed_description: "Providing an RSS/ATOM feed for your site can improve Discourse's ability to import your content." - crawling_settings: "Crawler Settings" - crawling_description: "When Discourse creates topics for your posts, if no RSS/ATOM feed is present it will attempt to parse your content out of your HTML. Sometimes it can be challenging to extract your content, so we provide the ability to specify CSS rules to make extraction easier." - - embed_by_username: "Username for topic creation" - embed_post_limit: "Maximum number of posts to embed" - embed_username_key_from_feed: "Key to pull discourse username from feed" - embed_title_scrubber: "Regular expression used to scrub the title of posts" - embed_truncate: "Truncate the embedded posts" - embed_whitelist_selector: "CSS selector for elements that are allowed in embeds" - embed_blacklist_selector: "CSS selector for elements that are removed from embeds" - embed_classname_whitelist: "Allowed CSS class names" - feed_polling_enabled: "Import posts via RSS/ATOM" - feed_polling_url: "URL of RSS/ATOM feed to crawl" - save: "Save Embedding Settings" - - permalink: - title: "Permalinks" - url: "URL" - topic_id: "Topic ID" - topic_title: "Topic" - post_id: "Post ID" - post_title: "Post" - category_id: "Category ID" - category_title: "Category" - external_url: "External URL" - delete_confirm: Are you sure you want to delete this permalink? - form: - label: "New:" - add: "Add" - filter: "Search (URL or External URL)" - - wizard_js: - wizard: - done: "Done" - back: "Back" - next: "Next" - step: "%{current} of %{total}" - upload: "Upload" - uploading: "Uploading..." - quit: "Maybe Later" - - staff_count: - one: "Your community has 1 staff member. " - other: "Your community has %{count} staff members." - - invites: - add_user: "add" - none_added: "You haven’t invited any staff. Are you sure you want to continue?" - roles: - admin: "Admin" - moderator: "Moderator" - regular: "Regular User" + name: نام diff --git a/config/locales/client.vi.yml b/config/locales/client.vi.yml index c654d71668c..85ce0c40db8 100644 --- a/config/locales/client.vi.yml +++ b/config/locales/client.vi.yml @@ -291,17 +291,10 @@ vi: total_rows: other: "%{count} người dùng" groups: - empty: - posts: "Không có chủ đề của các thành viên trong nhóm" - members: "Không có thành viên nào trong nhóm" - mentions: "Không có thành viên nào trong nhóm" - messages: "Không có tin nhắn nào trong nhóm" - topics: "Không có chủ đề của các thành viên trong nhóm" add: "Thêm" selector_placeholder: "Thêm thành viên" owner: "chủ" visible: "Mọi thành viên có thể nhìn thấy nhóm" - index: "Nhóm" title: other: "các nhóm" members: "Các thành viên" @@ -620,11 +613,8 @@ vi: create: "Gửi một lời mời" generate_link: "Chép liên kết Mời" bulk_invite: - none: "Bạn đã mời ai ở đây chưa. Bạn có thể mời một hoặc một nhóm bằng tải lên hàng loạt file mời." text: "Mời hàng loạt bằng file" - uploading: "Uploading..." success: "Tải lên thành công, bạn sẽ được thông báo qua tin nhắn khi quá trình hoàn tất." - error: "Có lỗi xảy ra khi upload '{{filename}}': {{message}}" password: title: "Mật khẩu" too_short: "Mật khẩu của bạn quá ngắn." @@ -1282,7 +1272,6 @@ vi: edit: "Xin lỗi, có lỗi xảy ra khi sửa bài viết của bạn. Vui lòng thử lại." upload: "Xin lỗi, có lỗi xảy ra khi tải lên tập tin này. Vui lòng thử lại." too_many_uploads: "Xin lỗi, bạn chỉ có thể tải lên 1 file cùng 1 lúc." - upload_not_authorized: "Xin lỗi, tập tin của bạn tải lên chưa được cho phép (định dạng cho phép: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Xin lỗi, tài khoản mới không thể tải lên ảnh." attachment_upload_not_allowed_for_new_user: "Xin lỗi, tài khoản mới không thể tải lên đính kèm." attachment_download_requires_login: "Xin lỗi, bạn cần đăng nhập để tải về đính kèm." @@ -1537,7 +1526,6 @@ vi: views_lowercase: other: "lượt xem" replies: "Trả lời" - views_long: "chủ đề đã được xem {{number}} lần" activity: "Hoạt động" likes: "Lượt thích" likes_lowercase: @@ -1661,8 +1649,6 @@ vi: backups: "sao lưu" traffic_short: "Băng thông" traffic: "Application web requests" - page_views: "API Requests" - page_views_short: "API Requests" show_traffic_report: "Xem chi tiết Báo cáo Lưu lượng" reports: today: "Hôm nay" @@ -1746,15 +1732,12 @@ vi: refresh: "Làm mới" new: "Mới" selector_placeholder: "nhập tên tài khoản" - name_placeholder: "Tên nhóm, không khoản trắng, cùng luật với tên tài khoản" about: "Chỉnh sửa nhóm thành viên và tên của bạn ở đây" group_members: "Nhóm thành viên" delete: "Xóa" delete_confirm: "Xóa nhóm này?" delete_failed: "Không thể xóa nhóm. Nếu đây là một nhóm tự động, nó không thể hủy bỏ." - delete_member_confirm: "Loại bỏ '%{username}' khỏi nhóm '%{group}'?" delete_owner_confirm: "Loại bỏ quyền sở hữu của '%{username}'?" - name: "Tên" add: "Thêm" add_members: "Thêm thành viên" custom: "Tùy biến" diff --git a/config/locales/client.zh_CN.yml b/config/locales/client.zh_CN.yml index e282110874c..a70f150e4f7 100644 --- a/config/locales/client.zh_CN.yml +++ b/config/locales/client.zh_CN.yml @@ -115,7 +115,7 @@ zh_CN: enabled: '于%{when}全站置顶' disabled: '于%{when}解除全站置顶' visible: - enabled: '于%{when}解除隐藏' + enabled: '%{when}列出' disabled: '于%{when}隐藏' topic_admin_menu: "管理主题" wizard_required: "是时候配置你的论坛啦!点击开始设置向导!" @@ -295,20 +295,62 @@ zh_CN: posts_read_long: "阅读帖子" total_rows: other: "%{count} 位用户" + group_histories: + actions: + change_group_setting: "更改小组设置" + add_user_to_group: "增加用户" + remove_user_from_group: "移除用户" + make_user_group_owner: "设为所有者" + remove_user_as_group_owner: "撤销所有者" groups: + logs: + title: "日志" + when: "时间" + action: "操作" + acting_user: "操作用户" + target_user: "目标用户" + subject: "主题" + details: "详情" + from: "来自" + to: "发至" + edit: + title: '编辑群组' + full_name: '名字' + add_members: "增加组员" + delete_member_confirm: "从“%{group}”群组中移除用户“%{username}'?" + request_membership_pm: + title: "成员申请" + body: "我想申请 @%{groupName} 的成员资格。" + name_placeholder: "群组名,没有空格,和用户名一样的规则" + public: "允许用户自由加入/离开群组(需要群组是可见)" empty: - posts: "群组的成员从未发表帖子。" + posts: "群组成员没有发布帖子。" members: "群组没有成员。" mentions: "群组从未被提及过。" messages: "群组从未发送过消息。" topics: "群组的成员从未发表主题。" + logs: "没有关于群组的日志。" add: "添加" + join: "加入群组" + leave: "离开群组" + request: "请求加入群组" + automatic_group: 自动群组 + closed_group: 封闭群组 + is_group_user: "你是该群组的一个成员" + allow_membership_requests: "允许用户向群组拥有者发送加入小组请求(群组需要能让所有人提及)" + membership: "成员资格" + name: "名字" + user_count: "成员数目" + bio: "关于群组" selector_placeholder: "添加成员" owner: "所有者" visible: "群组对所有用户可见" - index: "群组" + index: + title: "群组" + empty: "没有可见的群组。" title: other: "群组" + activity: "活动" members: "成员" topics: "主题" posts: "帖子" @@ -340,6 +382,15 @@ zh_CN: muted: title: "静音" description: "你不会收到组内关于新主题中的任何通知。" + flair_url: "头像图片" + flair_url_placeholder: "(可选)图片 URL 或 Font Awesome class" + flair_bg_color: "头像背景颜色" + flair_bg_color_placeholder: "(可选)十六进制色彩值" + flair_color: "头像颜色" + flair_color_placeholder: "(可选)十六进制色彩值" + flair_preview_icon: "预览图标" + flair_preview_image: "预览图片" + flair_note: "注意:标示将只在用户的主要群组显示" user_action_groups: '1': "送出赞" '2': "获得赞" @@ -399,6 +450,11 @@ zh_CN: profile: "个人资料" mute: "防打扰" edit: "修改设置" + download_archive: + button_text: "下载我的帖子" + confirm: "你确定要下载你的帖子吗?" + success: "下载开始,完成后将有消息通知你。" + rate_limit_error: "帖子只能每天下载一次,请明天再重试。" new_private_message: "发新私信" private_message: "私信" private_messages: "私信" @@ -659,11 +715,9 @@ zh_CN: link_generated: "邀请链接生成成功!" valid_for: "邀请链接只对这个邮件地址有效:%{email}" bulk_invite: - none: "你从未邀请过他人。你可以发送单个邀请,或者上传批量邀请文件一次邀请多人。" + none: "你还没有邀请过任何人。你可以邀请一个人,或者上传 CSV 文件邀请一批人。" text: "通过文件批量邀请" - uploading: "上传中..." success: "文件上传成功,当操作完成时将通过消息通知你。" - error: "在上传 '{{filename}}' 时出现错误:{{message}}" password: title: "密码" too_short: "密码过短" @@ -795,7 +849,7 @@ zh_CN: disable: "显示已删除的帖子" private_message_info: title: "私信" - invite: "邀请其他..." + invite: "邀请其他人..." remove_allowed_user: "确定将 {{name}} 从本条消息中移除?" remove_allowed_group: "确定将 {{name}} 从本条消息中移除?" email: '邮箱' @@ -887,7 +941,7 @@ zh_CN: unlist: "隐藏" add_warning: "正式警告" toggle_whisper: "折叠或展开密语" - toggle_unlisted: "解除隐藏" + toggle_unlisted: "未列表切换" posting_not_on_topic: "你想回复哪一个主题?" saving_draft_tip: "保存中..." saved_draft_tip: "已保存" @@ -918,8 +972,10 @@ zh_CN: title: "或 Ctrl + 回车" users_placeholder: "添加用户" title_placeholder: "一句话告诉讨论什么..." + title_or_link_placeholder: "键入标题,或粘贴一个链接在这里" edit_reason_placeholder: "编辑理由" show_edit_reason: "添加理由" + topic_featured_link_placeholder: "在标题里输入链接" reply_placeholder: "在此键入。使用Markdown,BBCode,或HTML格式。可拖拽或粘贴图片。" view_new_post: "浏览新帖。" saving: "保存中" @@ -1070,16 +1126,16 @@ zh_CN: label: 有该标签 filters: label: 只返回主题/帖子符合... - likes: 我赞了 - posted: 我曾发表过恢复 + likes: 我给了赞的 + posted: 我参与发帖 watching: 我正在监看 tracking: 我正在追踪 - private: 在我的消息中 + private: 在我的私信中 bookmarks: 我已经收藏了 first: 是第一帖 pinned: 是置顶的 unpinned: 不是置顶的 - wiki: 是协同编辑的 + wiki: 公共编辑 statuses: label: 当主题 open: 是开放的 @@ -1221,7 +1277,8 @@ zh_CN: go_bottom: "底部" go: "前往" jump_bottom: "跳至最后一个帖子" - jump_prompt: "跳至帖子" + jump_prompt: "跳到..." + jump_prompt_of: "%{count} 帖子" jump_prompt_long: "你想跳转至哪一贴?" jump_bottom_with_number: "跳至第 %{post_number} 帖" total: 全部帖子 @@ -1440,7 +1497,7 @@ zh_CN: file_too_large: "文件过大(最大 {{max_size_kb}}KB)。为什么不就大文件上传至云存储服务后再分享链接呢?" too_many_uploads: "抱歉,一次只能上传一张图片。" too_many_dragged_and_dropped_files: "抱歉,一次只能上传 10 个文件。" - upload_not_authorized: "抱歉,你不能上传此类型文件(可上传的文件类型有:{{authorized_extensions}})。" + upload_not_authorized: "抱歉,你没有上传文件的权限 (验证扩展:{{authorized_extensions}})。" image_upload_not_allowed_for_new_user: "抱歉,新用户无法上传图片。" attachment_upload_not_allowed_for_new_user: "抱歉,新用户无法上传附件。" attachment_download_requires_login: "抱歉,你需要登录后才能下载附件。" @@ -1586,6 +1643,7 @@ zh_CN: tags_allowed_tag_groups: "仅在该分类内可以使用的标签组" tags_placeholder: "(可选)允许使用的标签列表" tag_groups_placeholder: "(可选)允许使用的标签组列表" + topic_featured_link_allowed: "运行在该分类中发布特色链接" delete: '删除分类' create: '新分类' create_long: '创建新的分类' @@ -1620,6 +1678,7 @@ zh_CN: email_in_disabled: "站点设置中已经禁用通过邮件发表新主题。欲启用通过邮件发表新主题," email_in_disabled_click: '启用“邮件发表”设置。' suppress_from_homepage: "不在主页中显示这个分类。" + all_topics_wiki: "默认将新主题设为维基主题" sort_order: "默认排序:" allow_badges_label: "允许在这个分类中授予徽章" edit_permissions: "编辑权限" @@ -1736,7 +1795,6 @@ zh_CN: views_lowercase: other: "浏览" replies: "回复" - views_long: "本主题已经被浏览过 {{number}} 次" activity: "活动" likes: "赞" likes_lowercase: @@ -2029,8 +2087,6 @@ zh_CN: backups: "备份" traffic_short: "流量" traffic: "应用 web 请求" - page_views: "API 请求" - page_views_short: "API 请求" show_traffic_report: "显示详细的流量报告" reports: today: "今天" @@ -2115,15 +2171,12 @@ zh_CN: refresh: "刷新" new: "新群组" selector_placeholder: "输入用户名" - name_placeholder: "群组名,不能含有空格,与用户名规则一致" about: "在这里编辑群组的名字和成员" group_members: "群组成员" delete: "删除" delete_confirm: "删除这个群组吗?" delete_failed: "无法删除群组。如果该群组是自动生成的,则不可删除。" - delete_member_confirm: "从群组“%{group}”中移除“%{username}”?" delete_owner_confirm: "移除“%{username}”的权限?" - name: "名字" add: "添加" add_members: "添加成员" custom: "定制" @@ -2140,10 +2193,6 @@ zh_CN: add_owners: 添加所有者 incoming_email: "自定义进站电子邮件地址" incoming_email_placeholder: "输入邮箱地址" - flair_url_placeholder: "(可选)图片 URL 或 Font Awesome class" - flair_bg_color_placeholder: "(可选)十六进制色彩值" - flair_color_placeholder: "(可选)十六进制色彩值" - flair_preview: "预览" api: generate_master: "生成主 API 密钥" none: "当前没有可用的 API 密钥。" @@ -2175,7 +2224,6 @@ zh_CN: warn_local_payload_url: "你好像将 webhook 指向了一个本地地址。把相关事件发送到本地可能产生副作用或未预期的行为。继续吗?" secret_invalid: "密钥不能包含空白字符。" secret_too_short: "密钥必须至少有 12 个字符。" - secret_placeholder: "可选字符串,用于生成签名" event_type_missing: "你必须设置一个事件类型。" content_type: "内容格式" secret: "密钥" @@ -2198,7 +2246,7 @@ zh_CN: details: "当有新回复、编辑、帖子被删除或者恢复时。" user_event: name: "用户事件" - details: "当用户被创建或者通过时。" + details: "当用户被创建、审核通过或更新时。" delivery_status: title: "分发状态" inactive: "不活跃" @@ -2421,6 +2469,7 @@ zh_CN: html: "html" text: "text" last_seen_user: "用户最后登录时间:" + no_result: "没有找到摘要信息。" reply_key: "回复关键字" skipped_reason: "跳过理由" incoming_emails: @@ -2808,6 +2857,7 @@ zh_CN: user_preferences: "用户设置" tags: "标签" search: "搜索" + groups: "群组" badges: title: 徽章 new_badge: 新徽章 diff --git a/config/locales/client.zh_TW.yml b/config/locales/client.zh_TW.yml index 741c358bd98..44a835f88fc 100644 --- a/config/locales/client.zh_TW.yml +++ b/config/locales/client.zh_TW.yml @@ -26,6 +26,7 @@ zh_TW: millions: "{{number}} 百萬" dates: time: "h:mm" + timeline_date: "MMM YYYY" long_no_year: "MMM D h:mm a" long_no_year_no_time: "MMM D" full_no_year_no_time: "MMMM Do" @@ -37,6 +38,7 @@ zh_TW: long_date_with_year_without_time: "'YY MMM D" long_date_without_year_with_linebreak: "MMM D
    LT" long_date_with_year_with_linebreak: "'YY MMM D
    LT" + wrap_ago: "%{date}以前" tiny: half_a_minute: "< 1 分鐘" less_than_x_seconds: @@ -90,9 +92,13 @@ zh_TW: google+: '在 Google+ 分享此連結' email: '以電子郵件分享此連結' action_codes: - split_topic: "於 %{when} 切分此討論話題" + public_topic: "%{when}時讓大家看到這個主題" + private_topic: "%{when}時讓其他人看不到這個主題" + split_topic: "於 %{when} 分割此討論話題" invited_user: "邀請 %{who} 於 %{when} " - removed_user: "移除 %{who} 於 %{when} " + invited_group: "邀請 %{who} %{when}" + removed_user: "刪除 %{who} 於 %{when} " + removed_group: "刪除 %{who} %{when}" autoclosed: enabled: '於 %{when} 關閉' disabled: '於 %{when} 開啟' @@ -111,8 +117,11 @@ zh_TW: visible: enabled: '於 %{when} 列出' disabled: '於 %{when} 除名' - topic_admin_menu: "討論話題管理員操作" + topic_admin_menu: "版區管理員操作" + wizard_required: "是時候配置你的論壇啦!點擊開始設置嚮導!" emails_are_disabled: "管理員已經停用了所有外寄郵件功能。通知信件都不會寄出。" + bootstrap_mode_enabled: "為方便站點準備發佈,現正處於初始化模式中。所有新用戶將被授予信任等級1,並為他們設置接受每日郵件摘要。初始化模式會在用戶數超過 %{min_users} 個時關閉。" + bootstrap_mode_disabled: "初始化模式將會在24小時後關閉。" s3: regions: us_east_1: "美國東部 (北維珍尼亞州)" @@ -123,9 +132,11 @@ zh_TW: eu_central_1: "歐洲 (法蘭克福)" ap_southeast_1: "亞太地區 (新加坡)" ap_southeast_2: "亞太地區 (悉尼)" + ap_south_1: "亞太地區 (孟買)" ap_northeast_1: "亞太地區 (東京)" ap_northeast_2: "亞太地區 (首爾)" sa_east_1: "南美洲 (聖保羅)" + cn_north_1: "中國 (北京)" edit: '編輯此討論話題的標題與分類' not_implemented: "抱歉,此功能尚未開放。" no_value: "否" @@ -221,6 +232,8 @@ zh_TW: undo: "復原" revert: "回復" failed: "失敗" + switch_to_anon: "進入匿名模式" + switch_from_anon: "退出匿名模式" banner: close: "關閉此橫幅" edit: "編輯此橫幅 >>" @@ -268,6 +281,8 @@ zh_TW: title: "用戶" likes_given: "送出的" likes_received: "收到的" + topics_entered: "已觀看" + topics_entered_long: "參與的討論話題" time_read: "閱讀多少次" topic_count: "話題" topic_count_long: "討論話題已建立" @@ -280,16 +295,66 @@ zh_TW: posts_read_long: "讀過的文章" total_rows: other: "%{count} 用戶" + group_histories: + actions: + change_group_setting: "更改群組設定" + add_user_to_group: "增加用戶" + remove_user_from_group: "移除用戶" + make_user_group_owner: "設為所有者" + remove_user_as_group_owner: "撤銷管理員" groups: + logs: + title: "紀錄" + when: "什麼時候" + action: "動作" + acting_user: "啟用中的用戶" + target_user: "目的用戶" + subject: "主旨" + details: "詳情" + from: "從" + to: "至" + edit: + title: '編輯群組' + full_name: '全名' + add_members: "增加成員" + delete_member_confirm: "從「%{group}」群組移除「%{username}」?" + request_membership_pm: + title: "請求會員資格" + body: "我想申請 @%{groupName} 的成員資格。" + name_placeholder: "群組名,沒有空格,和用戶名一樣的規則" + public: "允許用戶自由加入/離開群組(需要群組是可見)" + empty: + posts: "群組成員沒有發佈帖子。" + members: "這個團隊裡面沒有成員" + mentions: "群組從未被提及過。" + messages: "群組從未發送過消息。" + topics: "群組的成員從未發表主題。" + logs: "這個團隊裡面沒有日誌" add: "新增" + join: "加入團隊" + leave: "離開團隊" + request: "請求加入團隊" + automatic_group: 自動群組 + closed_group: 關閉群組 + is_group_user: "你是團隊裡面的成員" + allow_membership_requests: "允許用戶向群組擁有者發送加入小組請求(群組需要能讓所有人提及)" + membership: "會員資格" + name: "名字" + user_count: "成員數量" + bio: "關於群組" selector_placeholder: "新增成員" owner: "擁有者" visible: "群組可被所有用戶看到" + index: + title: "群組" + empty: "沒有可看見的群組。" title: other: "群組" + activity: "活動" members: "成員" topics: "主題" posts: "文章" + mentions: "提及" messages: "訊息" alias_levels: title: "誰可以在這個群組發送訊息和使用@提到" @@ -304,8 +369,28 @@ zh_TW: notifications: watching: title: "關注" + description: "你將會在該消息中的每個新帖子發佈後收到通知,並且會顯示新回覆數量。" + watching_first_post: + title: "關注第一則帖子" + description: "你只會收到此組中每個新主題的第一帖的通知。" + tracking: + title: "追蹤" + description: "只有當有人 @您 或者回覆您的文章時您才會收到通知,並且會顯示新回覆的數目。" regular: title: "一般" + description: "只有當有人 @您 或者回覆您的文章時您才會收到通知。" + muted: + title: "靜音" + description: "您將不會再收到任何關於此群組新討論話題的通知。" + flair_url: "頭像圖片" + flair_url_placeholder: "(可選)圖片 URL 或 Font Awesome class" + flair_bg_color: "頭像背景顏色" + flair_bg_color_placeholder: "(可選)十六進制色彩值" + flair_color: "頭像顏色" + flair_color_placeholder: "(可選)十六進制色彩值" + flair_preview_icon: "預覽圖示" + flair_preview_image: "預覽圖片" + flair_note: "注意:標示將只在用戶的主要群組顯示" user_action_groups: '1': "已按讚" '2': "已收到的讚" @@ -324,12 +409,14 @@ zh_TW: all_subcategories: "所有" no_subcategory: "無" category: "分類" + category_list: "顯示分類列表" reorder: title: "重新排序分類" title_long: "重新排序分類列表" fix_order: "固定位置" fix_order_tooltip: "並非所有的分類皆有唯一的位置參數, 可能會有出乎意料之外的結果." save: "儲存順序" + apply_all: "申請" position: "位置" posts: "貼文" topics: "標題" @@ -337,6 +424,8 @@ zh_TW: latest_by: "最近由" toggle_ordering: "顯示/隱藏排序控制" subcategories: "次分類" + topic_sentence: + other: "%{count} 話題" topic_stat_sentence: other: "在過去一%{unit}內有 %{count} 個新討論話題。" ip_lookup: @@ -361,6 +450,11 @@ zh_TW: profile: "基本資料" mute: "靜音" edit: "編輯喜好設定" + download_archive: + button_text: "下載我的文章" + confirm: "你確定要下載你的文章嗎?" + success: "開始下載,處理完畢後將以私人訊息通知您。" + rate_limit_error: "帖子只能每天下載一次,請明天再重試。" new_private_message: "新訊息" private_message: "訊息" private_messages: "訊息" @@ -372,14 +466,19 @@ zh_TW: invited_by: "邀請人" trust_level: "信任等級" notifications: "通知" + statistics: "統計" desktop_notifications: label: "桌面通知" not_supported: "非常遺憾,你的瀏覽器不支持桌面通知。" perm_default: "啟用桌面通知" perm_denied_btn: "權限被拒絕" + perm_denied_expl: "你拒絶了通知提醒的權限。設置瀏覽器以啟用通知提醒。" disable: "停用通知" enable: "啟用通知" + each_browser_note: "注意:你必須在你使用的所用瀏覽器中更改這項設置。" + dismiss_notifications: "設定全部為已讀" dismiss_notifications_tooltip: "標記所有未讀通知為已讀" + first_notification: "你的頭一個通知!選中它開始。" disable_jump_reply: "不要在回覆之後直接跳到我的文章" dynamic_favicon: "在瀏覽器小圖示上顯示新主題/更新的主題數" external_links_in_new_tab: "以新分頁開啟所有外部連結" @@ -393,9 +492,35 @@ zh_TW: suspended_notice: "此用戶已被停權至 {{date}}。" suspended_reason: "原因: " github_profile: "Github" + email_activity_summary: "活動摘要" + mailing_list_mode: + label: "郵件列表模式" + enabled: "啟用郵件列表模式" + instructions: | + 此設置將覆蓋活動摘要。
    + 靜音主題和分類不包含在這些郵件中。 + daily: "發送每日更新" + individual: "每當有新文章時,寄給我郵件通知" + individual_no_echo: "每當有新文章時,寄給我郵件通知(除了我自己的文章)" + many_per_day: "每當有新文章時,寄給我郵件通知(每天約有 {{dailyEmailEstimate}} 封)。" + few_per_day: "每當有新文章時,寄給我郵件通知(每天約有 2 封)。" + tag_settings: "添加" + watched_tags: "已觀看" + watched_tags_instructions: "您將會自動監視所有這些添加的主題。您會收到新文章或新主題的通知,新文章數量將出現在每個主題後。" + tracked_tags: "已追蹤" + tracked_tags_instructions: "您將會自動監視所有這些添加的主題。新文章數量將出現在每個主題後。" + muted_tags: "靜音" + muted_tags_instructions: "你將不會收到有這些標籤的新主題任何通知,它們也不會出現在“最新”主題列表。" watched_categories: "關注" + watched_categories_instructions: "你將自動監看這些分類中的所有主題。所有新帖子和新主題會通知你,新帖數量也將顯示在主題旁邊。" tracked_categories: "追蹤" + tracked_categories_instructions: "你將自動跟蹤這些分類中的所有主題。新帖數量將會顯示在主題旁邊。" + watched_first_post_categories: "關注第一則帖子" + watched_first_post_categories_instructions: "在這些分類裡面,每一個新主題的第一帖會通知你。" + watched_first_post_tags: "關注第一則帖子" + watched_first_post_tags_instructions: "在有了這些標籤的每一個新主題,第一帖會通知你。" muted_categories: "靜音" + muted_categories_instructions: "在這些分類裡面,你將不會收到新主題任何通知,它們也不會出現在“最新”主題列表。" delete_account: "刪除我的帳號" delete_account_confirm: "你真的要刪除帳號嗎?此動作不能被還原!" deleted_yourself: "你的帳號已成功刪除" @@ -405,6 +530,13 @@ zh_TW: users: "用戶" muted_users: "靜音" muted_users_instructions: "禁止來自這些用戶的所有通知。" + muted_topics_link: "顯示已靜音的主題" + watched_topics_link: "顯示已觀看的討論話題" + automatically_unpin_topics: "當我完整閲讀了主題時自動解除置頂。" + apps: "應用" + revoke_access: "撤銷許可" + undo_revoke_access: "解除撤銷許可" + api_approved: "已批准:" staff_counters: flags_given: "有幫助的投訴" flagged_posts: "已投訴的文章" @@ -413,9 +545,15 @@ zh_TW: warnings_received: "警告" messages: all: "全部" + inbox: "收件匣" + sent: "送出" archive: "封存" groups: "我的群組" + bulk_select: "選擇訊息" + move_to_inbox: "移動到收件匣" move_to_archive: "封存" + failed_to_move: "移動到所選郵件失敗(也許你的網絡沒有開啟)" + select_all: "選擇全部" change_password: success: "( 寄出的郵件 )" in_progress: "( 正在傳送郵件 )" @@ -424,8 +562,10 @@ zh_TW: set_password: "設定密碼" change_about: title: "修改關於我" + error: "修改設定值時發生錯誤" change_username: title: "修改用戶名稱" + confirm: "確定更換用戶名?你的帖子和@提及你的引用將失效。" taken: "抱歉,此用戶名稱已經有人使用。" error: "修改你的用戶名稱時發生錯誤。" invalid: "此用戶名稱無效,只能使用數字與英文字母。" @@ -445,6 +585,7 @@ zh_TW: upload_title: "上傳你的圖片" upload_picture: "上傳圖片" image_is_not_a_square: "警告:我們裁切了你的圖片,因為該圖片不是正方形的。" + cache_notice: "更改了頭像成功,但是鑒於瀏覽器緩存可能需要一段時間後才會生效。" change_profile_background: title: "基本資料背景圖案" instructions: "個人資料背景會被置中,且默認寬度為850px。" @@ -457,6 +598,9 @@ zh_TW: ok: "我們將寄一封確認郵件給您。" invalid: "請輸入有效的電子郵件地址。" authenticated: "你的 Email 已由 {{provider}} 驗證完成。" + frequency_immediately: "如果您沒有閱讀過重要通知,我們會立即發送電子郵件給您。" + frequency: + other: "我們只會在您 {{count}} 分鐘內沒有活動時,才會寄送電郵通知給您。" name: title: "名稱" instructions: "您的全名 (選填)。" @@ -480,6 +624,7 @@ zh_TW: title: "界面語言" instructions: "使用者介面的語言,當頁面重新整理的時候會更換成你的設定。" default: "(default)" + any: "任何" password_confirmation: title: "再次輸入密碼" last_posted: "最近發表" @@ -492,13 +637,30 @@ zh_TW: title: "用戶卡徽章" website: "網站" email_settings: "電子郵件" + like_notification_frequency: + title: "用戶被讚時通知提醒" + always: "總是" + first_time_and_daily: "每天首個被讚" + first_time: "歷史首個被讚" + never: "永不" + email_previous_replies: + title: "郵件底部包含歷史回覆" + unless_emailed: "首次" + always: "總是" + never: "永不" email_digests: + title: "長期未訪問時發送熱門主題和回覆的摘要郵件" + every_30_minutes: "每 30 分鐘" + every_hour: "每小時" daily: "每天" every_three_days: "每三天" weekly: "每週" every_two_weeks: "每兩星期" + include_tl0_in_digests: "摘要郵件中包含新用戶的內容" + email_in_reply_to: "郵件中包含回覆你的內容節選" email_direct: "當有人引用、回覆我的發文,或以 @用戶名稱 提到我時,請以電子郵件通知我。" email_private_messages: "當有人寄給我私人訊息時,以電子郵件通知我。" + email_always: "即使我在論壇中活躍時也發送郵件提醒" other_settings: "其它" categories_settings: "分類" new_topic_duration: @@ -520,32 +682,43 @@ zh_TW: after_4_minutes: "四分鐘後" after_5_minutes: "五分鐘後" after_10_minutes: "十分鐘後" + notification_level_when_replying: "當我在主題中回覆後,將主題設置至" invited: search: "輸入要搜尋邀請的文字..." title: "邀請" user: "受邀請的用戶" sent: "送出" + none: "沒有未接受狀態的邀請。" + truncated: + other: "只顯示前 {{count}} 個邀請。" redeemed: "已接受的邀請" + redeemed_tab: "接受日期" + redeemed_tab_with_count: "接受日期 ({{count}})" redeemed_at: "接受日期" pending: "尚未接受的邀請" + pending_tab: "等待中" + pending_tab_with_count: "等待中 ({{count}})" topics_entered: "參與的討論話題" posts_read_count: "已讀的文章" expired: "此邀請已過期" rescind: "移除" rescinded: "邀請已刪除" reinvite: "重送邀請" + reinvite_all: "重送所有邀請" reinvited: "邀請已經重送" + reinvited_all: "所有邀請已經重送" time_read: "閱讀時間" days_visited: "到訪天數" account_age_days: "帳號已建立 (天)" create: "送出邀請" generate_link: "拷貝邀請連結" + link_generated: "邀請連結生成成功!" + valid_for: "邀請連結只對這個郵件地址有效:%{email}" bulk_invite: - none: "你尚未邀請任何人。你可以發送個別邀請,或者透過上傳邀請名單一次邀請一群人。" + none: "你還沒有邀請過任何人。你可以邀請一個人,或者上傳 CSV 檔案邀請一批人。" text: "從檔案大量邀請" - uploading: "正在上傳..." success: "檔案已上傳成功,處理完畢後將以私人訊息通知你。" - error: "上傳 '{{filename}}' 時發生問題:{{message}}" + error: "抱歉,檔案應該要用 CSV 格式。" password: title: "密碼" too_short: "你的密碼太短。" @@ -554,6 +727,39 @@ zh_TW: same_as_email: "你的密碼與電郵相同。" ok: "你的密碼符合要求。" instructions: "至少 %{count} 個字。" + summary: + title: "摘要" + stats: "統計" + time_read: "閱讀時間" + topic_count: + other: "討論話題已建立" + post_count: + other: "帖子已建立" + likes_given: + other: " 送出的" + likes_received: + other: " 收到的" + days_visited: + other: "到訪天數" + posts_read: + other: "讀過的文章" + bookmark_count: + other: "書籤" + top_replies: "最佳回覆" + no_replies: "暫無回覆。" + more_replies: "更多回覆" + top_topics: "熱門話題" + no_topics: "暫無主題。" + more_topics: "更多主題" + top_badges: "熱門徽章" + no_badges: "還沒有徽章。" + more_badges: "更多徽章" + top_links: "最佳連結" + no_links: "暫無連結" + most_liked_by: "誰得到最多讚" + most_liked_users: "讚誰最多" + most_replied_to_users: "最多回覆至" + no_likes: "暫無讚" associated_accounts: "登入" ip_address: title: "最近的 IP 位址" @@ -561,8 +767,9 @@ zh_TW: title: "註冊之 IP 位址" avatar: title: "個人資料圖片" + header_title: "個人頁面、消息、書籤和設置" title: - title: "標題" + title: "用戶標題" filters: all: "全部" stream: @@ -584,6 +791,7 @@ zh_TW: network_fixed: "似乎沒有問題了" server: "錯誤代碼:{{status}}" forbidden: "你不允許瀏覽此處。" + not_found: "沒有這個頁面" unknown: "發生錯誤。" buttons: back: "返回" @@ -594,8 +802,20 @@ zh_TW: logout: "已登出" refresh: "重新整理" read_only_mode: + enabled: "站點正處於只讀模式。你可以繼續瀏覽,但是回覆、讚和其他操作暫時被禁用。" login_disabled: "在唯讀模式下不能登入" + logout_disabled: "站點在只讀模式下無法登出。" + too_few_topics_and_posts_notice: "讓我們開始討論!目前有 %{currentTopics} / %{requiredTopics} 個主題和 %{currentPosts} / %{requiredPosts} 個帖子。新訪客需要能夠閲讀和回覆一些討論。" + too_few_topics_notice: "讓我們開始討論!目前有 %{currentTopics} / %{requiredTopics} 個主題。新訪客需要能夠閲讀和回覆一些討論。" + too_few_posts_notice: "讓我們開始討論!目前有 %{currentPosts} / %{requiredPosts} 個帖子。新訪客需要能夠閲讀和回覆一些討論。" + logs_error_rate_notice: + reached: "%{relativeAge}%{rate} 達到了站點設置中的 %{siteSettingRate}。" + exceeded: "[%{relativeAge}] 目前的錯誤率 %{rate} 已超出了站點設置中的 %{siteSettingRate}。" + rate: + other: "%{count} 錯誤/%{duration}" learn_more: "進一步了解..." + all_time: '總數' + all_time_desc: '創建的主題總量' year: '年' year_desc: '最近 365 天內建立的討論話題' month: '月' @@ -612,8 +832,15 @@ zh_TW: other: 回覆 signup_cta: sign_up: "註冊" + hide_session: "明天提醒我" + hide_forever: "不了" + hidden_for_session: "好的,我會在明天提醒你。不過你隨時都可以使用“登錄”來創建賬戶。" + intro: "你好!:heart_eyes: 看起來你挺喜歡這樣的討論,可是你還沒有註冊賬戶。" + value_prop: "當你創建賬戶後,我們可以準確地記錄你的閲讀進度,這樣你能夠在下一次訪問時回到你上次閲讀到的地方。你也可以選擇接受新帖子的網頁和郵件通知。並且你可以讚任何帖子來分享你的感謝。:heartbeat:" summary: enabled_description: "你正在檢視此討論話題的摘要:在這個社群裡最熱門的文章。" + description: "有 {{replyCount}} 個回覆。" + description_time: "有 {{replyCount}} 個回覆,大約要花 {{readingTime}} 分鐘閲讀。" enable: '以摘要檢視此討論話題' disable: '顯示所有文章' deleted_filter: @@ -624,6 +851,8 @@ zh_TW: private_message_info: title: "訊息" invite: "邀請其他人..." + remove_allowed_user: "確定將 {{name}} 從本條消息中移除?" + remove_allowed_group: "確定將 {{name}} 從本條消息中移除?" email: '電子郵件' username: '用戶名稱' last_seen: '出現時間' @@ -632,6 +861,7 @@ zh_TW: trust_level: '信任等級' search_hint: '使用者名稱、電子郵件、或是IP位址' create_account: + disclaimer: "註冊即表示你同意隱私策略服務條款。" title: "建立新帳號" failed: "發生了某些錯誤,可能此電子郵件地址已經註冊過,請試試看忘記密碼連結" forgot_password: @@ -667,6 +897,8 @@ zh_TW: resend_activation_email: "按這裡重新寄出啟用帳號的電子郵件。" sent_activation_email_again: "我們已經將啟用帳號的電子郵件寄至 {{currentEmail}},你可能幾分鐘後才會收到,如果一直沒收到,請檢查垃圾郵件資料夾。" to_continue: "請登入" + preferences: "需要登入後更改設置" + forgot: "我記不清賬號詳情了" google: title: "使用 Google 帳號" message: "使用 Google 帳號認証 (請確定你的網頁瀏覽器未阻擋彈出視窗)" @@ -676,6 +908,9 @@ zh_TW: twitter: title: "使用 Twitter" message: "使用 Twitter 認証 (請確定你的網頁瀏覽器未阻擋彈出視窗)" + instagram: + title: "用 Instagram 登錄" + message: "正在通過 Instagram 帳號驗證登錄(請確保瀏覽器沒有禁止彈出窗口)" facebook: title: "使用 Facebook" message: "使用 Facebook 認証 (請確定你的網頁瀏覽器未阻擋彈出視窗)" @@ -685,28 +920,48 @@ zh_TW: github: title: "使用 GitHub" message: "使用 GitHub 認証 (請確定你的網頁瀏覽器未阻擋彈出視窗)" + emoji_set: + apple_international: "Apple/國際化" + google: "Google" + twitter: "Twitter" + emoji_one: " Emoji One " + win10: "Win10" + category_page_style: + categories_only: "僅分類" + categories_with_featured_topics: "有推薦主題的分類" + categories_and_latest_topics: "分類和最新主題" shortcut_modifier_key: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' composer: + emoji: "表情符號 :)" more_emoji: "更多..." options: "選項" whisper: "密談" + unlist: "不公開" add_warning: "這是正式警告。" toggle_whisper: "切換密談" + toggle_unlisted: "切換 不公開" posting_not_on_topic: "你想要回覆哪個討論話題?" saving_draft_tip: "正在儲存..." saved_draft_tip: "儲存完畢" saved_local_draft_tip: "本地儲存完畢" similar_topics: "與你的討論話題類似的討論..." drafts_offline: "離線草稿" + group_mentioned: + other: "提及 {{group}} 時,你將通知 {{count}} 人 - 確定嗎?" + cannot_see_mention: + category: "你提到了{{userrname}},然而他們不能訪問該分類,所以他們不會被通知。你需要把他們加入到能訪問該分類的群組中。" + private: "你提到了{{userrname}},然而他們不能訪問該私信,所以他們不會被通知。你需要邀請他們至私信中。" + duplicate_link: "似乎你的連結 {{domain}}{{ago}}已經由@{{username}}回覆了 - 確定再次提交嗎?" error: title_missing: "標題為必填欄位" title_too_short: "標題必須至少 {{min}} 個字" title_too_long: "標題不能超過 {{max}} 個字" post_missing: "文章不可空白" post_length: "文章必須至少 {{min}} 個字。" + try_like: '試試 按鈕?' category_missing: "你必須選擇一個分類。" save_edit: "儲存編輯" reply_original: "回覆至原始的討論話題" @@ -718,8 +973,11 @@ zh_TW: title: "或者按 Ctrl+Enter" users_placeholder: "新增用戶" title_placeholder: "用一個簡短的句子來描述想討論的內容。" + title_or_link_placeholder: "鍵入標題,或貼上一個連結在這裡" edit_reason_placeholder: "你為什麼做編輯?" show_edit_reason: "(請加入編輯原因)" + topic_featured_link_placeholder: "在標題裡輸入連結" + reply_placeholder: "在這裡輸入內文,可以使用 Markdown, BBCode 或 HTML 來格式化文字,也可以拖曳或貼上圖片。" view_new_post: "檢視你的新文章。" saving: "正在儲存" saved: "儲存完畢!" @@ -728,23 +986,28 @@ zh_TW: show_preview: '顯示預覽 »' hide_preview: '« 隱藏預覽' quote_post_title: "引用完整文章" + bold_label: "B" bold_title: "粗體" bold_text: "粗體字" + italic_label: "I" italic_title: "斜體" italic_text: "斜體字" link_title: "超連結" link_description: "在此輸入超連結的描述" link_dialog_title: "插入超連結" link_optional_text: "標題 (可選填)" + link_url_placeholder: "http://example.com" quote_title: "引用" quote_text: "引用" code_title: "預先格式化文字" code_text: "以 4 格空白將預先格式的化文字縮排" + paste_code_text: "輸入或粘貼代碼" upload_title: "上傳" upload_description: "在此輸入上傳的描述" olist_title: "編號清單" ulist_title: "符號清單" list_item: "清單項目" + heading_label: "H" heading_title: "標頭" heading_text: "標頭" hr_title: "分隔線" @@ -753,6 +1016,9 @@ zh_TW: modal_ok: "確定" modal_cancel: "取消" cant_send_pm: "抱歉,你不能向 %{username} 發送訊息。" + yourself_confirm: + title: "你忘記添加收信人了嗎?" + body: "目前該私信只發給了你自己!" admin_options_title: "此討論話題可選用之工作人員設定選項" auto_close: label: "自動關閉主題時間:" @@ -766,34 +1032,77 @@ zh_TW: notifications: title: "當有人以「@用戶名稱」提及您、回覆您的貼文、或是傳送訊息給您的時候通知您的設定。" none: "目前無法載入通知訊息。" + empty: "未找到任何通知。" more: "檢視較舊的通知" total_flagged: "所有被投訴的文章" mentioned: "

    {{username}} {{description}}

    " + group_mentioned: "

    {{username}} {{description}}

    " quoted: "

    {{username}} {{description}}

    " replied: "

    {{username}} {{description}}

    " + posted: "

    {{username}} {{description}}

    " edited: "

    {{username}} {{description}}

    " liked: "

    {{username}} {{description}}

    " + liked_2: "

    {{username}}、{{username2}} {{description}}

    " + liked_many: + other: "

    {{username}}、{{username2}}和其他 {{count}} 人{{description}}

    " private_message: "

    {{username}} {{description}}

    " invited_to_private_message: "

    {{username}} {{description}}

    " + invited_to_topic: "

    {{username}}{{description}}

    " invitee_accepted: "

    {{username}}已接受你的邀請

    " moved_post: "

    {{username}} 移動了 {{description}}

    " + linked: "

    {{username}}{{description}}

    " granted_badge: "

    獲得徽章「{{description}}」

    " + watching_first_post: "

    近期主題{{description}}

    " + group_message_summary: + other: "

    {{count}} 條消息在{{group_name}}組的收件箱中

    " alt: + mentioned: "被提及" + quoted: "引用者" + replied: "回覆" + posted: "發自" + edited: "編輯你的帖子" + liked: "讚了你的帖子" + private_message: "私信來自" + invited_to_private_message: "私信邀請自" + invited_to_topic: "主題邀請自" + invitee_accepted: "介紹邀請自" + moved_post: "你的帖子被移動自" linked: "連結到你的討論" + granted_badge: "勛章授予" + group_message_summary: "在群組收件箱中的消息" + popup: + mentioned: '{{username}}在“{{topic}}”提到了你 - {{site_title}}' + group_mentioned: '{{username}}在“{{topic}}”提到了你 - {{site_title}}' + quoted: '{{username}}在“{{topic}}”引用了你的帖子 - {{site_title}}' + replied: '{{username}}在“{{topic}}”回覆了你 - {{site_title}}' + posted: '{{username}}在“{{topic}}”中發佈了帖子 - {{site_title}}' + private_message: '{{username}}在“{{topic}}”中給你發送了一個私信 - {{site_title}}' + linked: '{{username}}在“{{topic}}”中連結了你的帖子 - {{site_title}}' upload_selector: title: "加入一張圖片" title_with_attachments: "加入一張圖片或一個檔案" from_my_computer: "從我的電腦" from_the_web: "從網站" remote_tip: "圖片連結" + remote_tip_with_attachments: "連結到圖片或檔案 {{authorized_extensions}}" + local_tip: "從你的設備中選擇圖片" + local_tip_with_attachments: "從裝置選取圖片或檔案: ({{authorized_extensions}})" hint: "(你也可以將檔案拖放至編輯器直接上傳)" + hint_for_supported_browsers: "可以拖放或複製粘帖至編輯器以上傳" uploading: "正在上傳" select_file: "選取檔案" image_link: "連結你的圖片將指向" search: sort_by: "排序" + relevance: "最相關" + latest_post: "最新發帖" + most_viewed: "最多閲讀" + most_liked: "最多讚" select_all: "選擇全部" clear_all: "清除全部" + too_short: "你的搜索詞太短。" + result_count: + other: "搜索“{{term}}”有 {{count}} 條相關結果" title: "搜尋討論話題、文章、用戶或分類" no_results: "未找到任何結果。" no_more_results: "沒有找到更多的結果。" @@ -801,16 +1110,65 @@ zh_TW: post_format: "#{{post_number}} {{username}}" context: user: "搜尋 @{{username}} 的文章" + category: "搜索 #{{category}} 分類" topic: "搜尋此討論話題" private_messages: "搜尋訊息" + advanced: + title: 高級搜索 + posted_by: + label: 發帖人 + in_category: + label: 在該分類中 + in_group: + label: 在該群組中 + with_badge: + label: 有該徽章 + with_tags: + label: 有該標籤 + filters: + label: 只返回主題/帖子符合... + likes: 我給了讚的 + posted: 我參與發帖 + watching: 我正在監看 + tracking: 我正在追蹤 + private: 在我的私信中 + bookmarks: 我已經收藏了 + first: 是第一帖 + pinned: 是置頂的 + unpinned: 不是置頂的 + wiki: 公共編輯 + statuses: + label: 當主題 + open: 是開放的 + closed: 是關閉的 + archived: 已經存檔的 + noreplies: 沒有回覆 + single_user: 只有一個用戶參與 + post: + count: + label: 最小帖子數 + time: + label: 發表於 + before: 之前 + after: 之後 + hamburger_menu: "轉到另一個主題列表或分類" new_item: "新增" go_back: '返回' not_logged_in_user: '用戶頁面包含目前活動及喜好的總結' current_user: '到你的用戶頁面' topics: + new_messages_marker: "上次訪問" bulk: + select_all: "選擇全部" + clear_all: "清除全部" + unlist_topics: "未在列表的主題" reset_read: "重設閱讀" delete: "刪除討論話題" + dismiss: "忽略" + dismiss_read: "忽略所有未讀主題" + dismiss_button: "忽略..." + dismiss_tooltip: "僅忽略新帖子或停止跟蹤主題" + also_dismiss_topics: "停止追蹤這些主題,這樣這些主題就不再顯示為未讀了" dismiss_new: "設定新文章為已讀" toggle: "批量切換選擇討論話題" actions: "批量操作" @@ -821,6 +1179,9 @@ zh_TW: choose_new_category: "為主題選擇新類別:" selected: other: "你已選擇了 {{count}} 個討論話題。" + change_tags: "修改標籤" + choose_new_tags: "為主題選擇新標籤" + changed_tags: "主題的標籤被修改" none: unread: "沒有未讀的討論話題。" new: "沒有新的討論話題。" @@ -831,6 +1192,10 @@ zh_TW: bookmarks: "您目前沒有加入書籤的討論話題。" category: "沒有 {{category}} 的討論話題。" top: "沒有精選討論話題。" + search: "沒有搜索結果。" + educate: + new: '

    這裡顯示了近期主題列表。

    預設情況下,以下主題將顯示在近期列表。如果是最近 2 天內創建的,還會顯示一個近期標誌。

    你可以在用戶設置中更改要顯示哪些內容。

    ' + unread: '

    這裡顯示你的未讀主題。

    預設情況下,下述主題會被放在未讀中。並且會在旁邊顯示未讀的數量1。如果你:

    • 創建了該主題
    • 回覆了該主題
    • 閲讀該主題超過 4 分鐘

    或者你在主題底部的通知控制中選擇了跟隨或關注。

    你可以在用戶設置中修改未讀設置。

    ' bottom: latest: "已經沒有其它最近的討論話題了。" hot: "已經沒有其它熱門的討論話題了。" @@ -841,12 +1206,22 @@ zh_TW: category: "{{category}} 分類已經沒有其它討論話題了。" top: "沒有更多精選討論話題。" bookmarks: "書籤裡沒有更多的討論話題了。" + search: "沒有更多搜索結果了。" topic: + unsubscribe: + stop_notifications: "你將收到更少的關於{{title}}的通知" + change_notification_state: "你現在的通知狀態是" + filter_to: + other: "本主題中的 {{count}} 帖" create: '新討論話題' create_long: '建立新討論話題' private_message: '發送訊息' archive_message: + help: '移動消息到存檔' title: '封存' + move_to_inbox: + title: '移動到收件箱' + help: '移動消息到收件箱' list: '討論話題' new: '新討論話題' unread: '未讀' @@ -891,17 +1266,29 @@ zh_TW: auto_close_title: '自動關閉設定' auto_close_save: "儲存" auto_close_remove: "不要自動關閉此討論話題" + auto_close_immediate: + other: "主題中的最後一帖是 %{hours} 小時前發出的,所以主題將會立即關閉。" + timeline: + back: "返回" + back_description: "回到最後一個未讀帖子" + replies_short: "%{current} / %{total}" progress: title: topic progress go_top: "頂部" go_bottom: "底部" go: "前往" jump_bottom: "跳至最後一則帖子" + jump_prompt: "跳到..." + jump_prompt_of: "%{count} 帖子" + jump_prompt_long: "你想跳轉至哪一貼?" jump_bottom_with_number: "跳至第 %{post_number} 篇文章" total: 所有文章 current: 目前的文章 notifications: + title: 改變你收到該主題通知的頻率 reasons: + mailing_list_mode: "郵件列表模式已啟用,將以郵件通知你關於該主題的回覆。" + '3_10': '因為你正監看該主題上的標籤,你將會收到通知。' '3_6': '你將會收到通知,因為你正在關注此分類。' '3_5': '你將會收到通知,因為你在觀看此討論話題。' '3_2': '你將收到關於此討論話題的通知,因為你正在關注此討論話題。' @@ -911,26 +1298,35 @@ zh_TW: '2_4': '你將收到關於此討論話題的通知,因為你回覆了此討論話題。' '2_2': '你將收到關於此討論話題的通知,因為你正在追蹤此討論話題。' '2': '你將收到關於此討論話題的通知,因為你看過此討論話題。' + '1_2': '如果有人@你或回覆你,將通知你。' + '1': '如果有人@你或回覆你,將通知你。' '0_7': '你正忽略此分類中的所有通知。' '0_2': '你正忽略此討論話題的所有通知。' '0': '你正忽略此討論話題的所有通知。' watching_pm: title: "關注中" + description: "消息有新回覆時提醒我,並顯示新回覆數量。" watching: title: "關注" + description: "在此主題裡,每一個新回覆將通知你,還將顯示新回覆的數量。" tracking_pm: title: "追蹤" + description: "在消息標題後顯示新回覆數量。你只會在別人@你或回覆你的帖子時才會收到通知。" tracking: title: "追蹤" + description: "將為該主題顯示新回覆的數量。如果有人@你或回覆你,將通知你。" regular: title: "一般" + description: "如果有人@你或回覆你,將通知你。" regular_pm: title: "一般" + description: "如果有人@你或回覆你,將通知你。" muted_pm: title: "靜音" description: "你將不會再收到關於此訊息的通知。" muted: title: "靜音" + description: "你不會收到此主題的任何通知,它也不會出現在“最新”主題列表。" actions: recover: "復原已刪除的討論話題" delete: "刪除討論話題" @@ -945,6 +1341,8 @@ zh_TW: invisible: "不出現在列表上" visible: "出現在列表上" reset_read: "重置讀取資料" + make_public: "設置為公共主題" + make_private: "設置為私信" feature: pin: "置頂主題" unpin: "取消置頂主題" @@ -960,30 +1358,64 @@ zh_TW: share: title: '分享' help: '分享此討論話題的連結' + print: + title: '打印' + help: '打開該主題對打印友好的版本' flag_topic: title: '投訴' help: '投訴此討論話題,或以私訊通知管理員' success_message: '已投訴此討論話題。' feature_topic: title: "擁有這個話題" + pin: "將該主題置於{{categoryLink}}分類最上方至" + confirm_pin: "已有{{count}}個置頂主題。太多的置頂主題可能會困擾新用戶和訪客。確定想在該分類再置頂一個主題?" unpin: "取消此主題在{{categoryLink}}類別的置頂狀態" + unpin_until: "從{{categoryLink}}分類最上方移除主題或者移除於%{until}。" + pin_note: "允許用戶取消置頂。" + pin_validation: "置頂該主題需要一個日期。" not_pinned: "沒有主題被釘選在 {{categoryLink}} ." + already_pinned: + other: "{{categoryLink}}分類的置頂主題數:{{count}}" + pin_globally: "將主題置於所有主題列表最上方至" + confirm_pin_globally: "已有{{count}}個全局置頂主題。太多的置頂主題可能會困擾新用戶和訪客。確定想再全局置頂一個主題?" + unpin_globally: "將主題從所有主題列表的最上方移除。" + unpin_globally_until: "從所有主題列表最上方移除主題或者移除於%{until}。" + global_pin_note: "允許用戶取消全局置頂。" + not_pinned_globally: "沒有全局置頂的主題。" + already_pinned_globally: + other: "全局置頂的主題數:{{count}}" + make_banner: "將主題設置為出現在所有頁面頂端的橫幅主題。" + remove_banner: "移除所有頁面頂端的橫幅主題。" + banner_note: "用戶能點擊關閉隱藏橫幅。且只能設置一個橫幅主題。" + no_banner_exists: "沒有橫幅主題。" + banner_exists: "當前設置了橫幅主題。" inviting: "正在邀請..." + automatically_add_to_groups: "邀請將把用戶加入群組:" invite_private: title: '邀請訊息交流' email_or_username: "受邀請者的電子郵件地址或用戶名稱" email_or_username_placeholder: "電子郵件地址或用戶名稱" action: "邀請" + success: "成功邀請了用戶至該消息。" + success_group: "成功邀請了群組至該消息。" error: "抱歉,向此用戶發出邀請時發生錯誤。" group_name: "群組名稱" + controls: "主題控件" invite_reply: title: '邀請' username_placeholder: "用戶名稱" action: '送出邀請' + help: '通過電子郵件或通知邀請其他人到該主題' to_forum: "我們將向你的朋友發出一封電子郵件,他不必登入,他只要按電子郵件裡的連結就可以加入此論壇。" + sso_enabled: "輸入其用戶名,邀請其人到本主題。" to_topic_blank: "輸入你想邀請的用戶的用戶名稱或電子郵件地址到該討論主題" + to_topic_email: "你輸入了郵箱地址。我們將發送一封郵件邀請,讓你的朋友可直接回覆該主題。" + to_topic_username: "你輸入了用戶名。我們將發送一個至該主題連結的邀請通知。" + to_username: "輸入你想邀請的人的用戶名。我們將發送一個至該主題連結的邀請通知。" email_placeholder: '電子郵件地址' + success_email: "我們發了一封郵件邀請{{emailOrUsername}}。邀請被接受後你會收到通知。檢查用戶頁中的邀請標籤頁來追蹤你的邀請。" success_username: "我們已經邀請該使用者加入此主題討論" + error: "抱歉,我們不能邀請這個人。可能他已經被邀請了?(邀請有頻率限制)" login_reply: '登入以發表回應' filters: n_posts: @@ -1002,6 +1434,10 @@ zh_TW: error: "將討論話題移至已存在的討論話題時發生錯誤。" instructions: other: "請選擇你想將那 {{count}} 篇文章移至哪一個討論話題。" + merge_posts: + title: "合併選擇的帖子" + action: "合併選擇的帖子" + error: "合併選擇的帖子試出錯。" change_owner: title: "更改文章的擁有者" action: "變更擁有者" @@ -1015,6 +1451,8 @@ zh_TW: title: "變更時間戳記" action: "變更時間戳記" invalid_timestamp: "時間戳記不能為將來的時刻。" + error: "更改主題時間時發生錯誤。" + instructions: "請為主題選擇新的時間。主題中的所有帖子將按照相同的時間差更新。" multi_select: select: '選取' selected: '選取了 ({{count}})' @@ -1026,6 +1464,9 @@ zh_TW: description: other: 你已選擇了 {{count}} 篇文章。 post: + reply: " {{replyAvatar}} {{usernameLink}}" + reply_topic: " {{link}}" + quote_reply: "引用" edit: "編輯 {{replyAvatar}} {{username}} 發表的 {{link}}" edit_reason: "原因: " post_number: "文章 {{number}}" @@ -1048,12 +1489,16 @@ zh_TW: has_likes_title: other: "{{count}} 個使用者對此文章讚好" has_likes_title_only_you: "你已按讚" + has_likes_title_you: + other: "你和其他 {{count}} 人讚了該貼" errors: create: "抱歉,建立你的文章時發生錯誤,請再試一次。" edit: "抱歉,編輯你的文章時發生錯誤,請再試一次。" upload: "抱歉,上傳你的檔案時發生錯誤,請再試一次。" + file_too_large: "檔案過大(最大 {{max_size_kb}}KB)。為什麼不就大檔案上傳至雲存儲服務後再分享連結呢?" too_many_uploads: "抱歉,一次只能上傳一個檔案。" - upload_not_authorized: "抱歉,你想上傳的是不允許的檔案 (允許的副檔名: {{authorized_extensions}})." + too_many_dragged_and_dropped_files: "抱歉,一次只能上傳 10 個檔案。" + upload_not_authorized: "抱歉,你沒有上傳檔案的權限 (驗證擴展:{{authorized_extensions}})。" image_upload_not_allowed_for_new_user: "抱歉,新用戶不可上傳圖片。" attachment_upload_not_allowed_for_new_user: "抱歉,新用戶不可上傳附件。" attachment_download_requires_login: "抱歉,您必須登入以下載附件。" @@ -1062,9 +1507,13 @@ zh_TW: no_value: "否" yes_value: "是" via_email: "本文章透過電子郵件送達" + via_auto_generated_email: "通過自動生成郵件發表的帖子" whisper: "這文章是版主私人密談" + wiki: + about: "此帖允許被公共編輯" archetypes: save: '儲存選項' + few_likes_left: "謝謝你的熱情!你今天的讚快用完了。" controls: reply: "開始編寫對此文章的回覆" like: "給此文章按讚" @@ -1089,6 +1538,7 @@ zh_TW: revert_to_regular: "移除工作人員顏色" rebake: "重建 HTML" unhide: "取消隱藏" + change_owner: "更改作者" actions: flag: '投訴' defer_flags: @@ -1106,6 +1556,9 @@ zh_TW: inappropriate: "投訴為不當內容" notify_moderators: "已通知的版主" notify_user: "已送出一則訊息" + bookmark: "收藏" + like: "讚了它" + vote: "已投票" by_you: off_topic: "你已投訴此文章偏離討論話題" spam: "你已投訴此文章為垃圾" @@ -1152,6 +1605,9 @@ zh_TW: delete: confirm: other: "你確定要刪除這些文章?" + merge: + confirm: + other: "確定要合併這 {{count}} 個帖子嗎?" revisions: controls: first: "第一版" @@ -1160,6 +1616,7 @@ zh_TW: last: "最新版" hide: "隱藏修訂紀錄" show: "顯示修訂紀錄" + revert: "還原至該版本" comparing_previous_to_current_out_of_total: "{{previous}} {{current}} / {{total}}" displays: inline: @@ -1182,6 +1639,12 @@ zh_TW: general: '一般' settings: '設定' topic_template: "主題範本" + tags: "標籤" + tags_allowed_tags: "僅在該分類內可以使用的標籤" + tags_allowed_tag_groups: "僅在該分類內可以使用的標籤組" + tags_placeholder: "(可選)允許使用的標籤列表" + tag_groups_placeholder: "(可選)允許使用的標籤組列表" + topic_featured_link_allowed: "運行在該分類中發佈特色連結" delete: '刪除分類' create: '新分類' create_long: '建立新的分類' @@ -1207,6 +1670,7 @@ zh_TW: change_in_category_topic: "編輯描述" already_used: '此顏色已經用於其它分類' security: "安全性" + special_warning: "警告:這個分類是已經自動建立好的分類,它的安全設置不能被更改。如果你不想要使用這個分類,直接刪除它,而不是另作他用。" images: "圖片" auto_close_label: "自動關閉討論話題的期限:" auto_close_units: "小時" @@ -1215,6 +1679,8 @@ zh_TW: email_in_disabled: "\"用電子郵件張貼新的討論話題\"功能已被關閉。若要使用此功能," email_in_disabled_click: '請啟用"email in"功能' suppress_from_homepage: "不在首頁上顯示此分類。" + all_topics_wiki: "新的主題預設為共筆。" + sort_order: "預設排序:" allow_badges_label: "允許授予本分類的徽章" edit_permissions: "編輯權限" add_permission: "新增權限" @@ -1227,30 +1693,59 @@ zh_TW: notifications: watching: title: "關注" + description: "你將自動監看這些分類中的所有主題。每一個主題的每一個新帖,將通知你,還將顯示新回覆的數量。" + watching_first_post: + title: "監看頭一帖" + description: "在這些分類裡面,只是每一個新主題的第一帖,才會通知你。" tracking: title: "追蹤" + description: "你將自動跟蹤這些分類中的所有主題。如果有人@你或回覆你,將通知你,還將顯示新回覆的數量。" regular: title: "一般" + description: "如果有人@你或回覆你,將通知你。" muted: title: "靜音" + description: "在這些分類裡面,你將不會收到新主題任何通知,它們也不會出現在“最新”主題列表。 " + sort_options: + default: "預設" + likes: "讚" + op_likes: "原始帖子讚" + views: "瀏覽" + posts: "帖子" + activity: "活動" + posters: "發表人" + category: "分類" + created: "創建" + sort_ascending: '升序' + sort_descending: '降序' flagging: title: '感謝幫助社群遠離邪惡!' action: '投訴文章' take_action: "執行動作" notify_action: '訊息' + official_warning: '正式警告' delete_spammer: "刪除垃圾文章發送者" + delete_confirm_MF: "你將刪除該用戶的{POSTS, plural, one {1個帖子} other {#個帖子}} and {TOPICS, plural, one {1個主題} other {#個主題}}、該賬戶,並阻止其IP地址 %{ip_address} 再次註冊,並將其郵件地址 %{email} 加入黑名單。你確定這用戶是廣告散佈者嗎?" yes_delete_spammer: "是的,刪除垃圾文章發送者" ip_address_missing: "(N/A)" hidden_email_address: "( 隱藏) " submit_tooltip: "送出私人投訴" take_action_tooltip: "使其立刻達到投訴門檻,不用等待更多社群投訴" cant: "抱歉,你目前無法投訴此文章。" + notify_staff: '私下通知管理人員' formatted_name: off_topic: "離題內容" inappropriate: "不當內容" spam: "垃圾內容" custom_placeholder_notify_user: "請具體說明出有建設性且溫和的意見。" custom_placeholder_notify_moderators: "讓我們知道您的意見,並請盡可能地提供相關連結和例子。" + custom_message: + at_least: + other: "輸入至少 {{count}} 個字元" + more: + other: "還差 {{count}} 個..." + left: + other: "剩餘 {{count}}" flagging_topic: title: "感謝幫助社群遠離邪惡!" action: "投訴討論話題" @@ -1259,8 +1754,13 @@ zh_TW: title: "討論話題摘要" participants_title: "頻繁發文者" links_title: "熱門連結" + links_shown: "顯示更多連結..." clicks: other: "%{count} 點擊" + post_links: + about: "為本帖展開更多連結" + title: + other: "%{count} 更多" topic_statuses: warning: help: "這是正式警告。" @@ -1270,11 +1770,14 @@ zh_TW: help: "此討論話題已關閉,不再接受回覆" archived: help: "此討論話題已封存,已被凍結無法再修改" + locked_and_archived: + help: "這個主題被關閉並存檔;不再允許新的回覆,並不能改變" unpinned: title: "取消釘選" help: "此討論話題已取消置頂,將會以預設順序顯示。" pinned_globally: title: "全區置頂" + help: "本主題已全局置頂;它始終會在最新列表以及它所屬的分類中置頂" pinned: title: "已釘選" help: "此討論話題已置頂,將顯示在它所屬分類話題列表的最上方" @@ -1293,7 +1796,8 @@ zh_TW: views_lowercase: other: "觀看" replies: "回覆" - views_long: "此討論話題已被看過 {{number}} 次" + views_long: + other: "這個討論話題已經被檢視過 {{number}} 次" activity: "活動" likes: "讚" likes_lowercase: @@ -1338,7 +1842,12 @@ zh_TW: lower_title_with_count: other: "{{count}} 個未讀" new: + lower_title_with_count: + other: "{{count}} 近期" lower_title: "新話題" + title: "新的" + title_with_count: + other: "近期 ({{count}})" help: "最近幾天建立的主題" posted: title: "我的文章" @@ -1378,6 +1887,175 @@ zh_TW: full: "建立 / 回覆 / 觀看" create_post: "回覆 / 觀看" readonly: "觀看" + lightbox: + download: "下載" + keyboard_shortcuts_help: + title: '快捷鍵' + jump_to: + title: '轉至' + home: 'g, h 首頁' + latest: 'g, l 最新' + new: 'g, n 近期' + unread: 'g, u 未讀' + categories: 'g, c 分類' + top: 'g, t 熱門' + bookmarks: 'g, b 書籤' + profile: 'g 然後 p 個人頁面' + messages: 'g, m 私信' + navigation: + title: '導航' + jump: '# 前往帖子 #' + back: 'u 返回' + up_down: 'kj 移動選擇焦點 ↑ ↓' + open: 'o 然後 回車 打開選擇的主題' + next_prev: 'shift+jshift+k 下一個/前一個段落' + application: + title: '應用' + create: 'c 創建新主題' + notifications: 'n Open notifications' + hamburger_menu: '= 打開漢堡菜單' + user_profile_menu: 'p 打開用戶菜單' + show_incoming_updated_topics: '. 顯示更新主題' + search: '/ 搜索' + help: ' ? 打開按鍵說明' + dismiss_new_posts: 'x 然後 r 解除新/帖子提示' + dismiss_topics: 'x 然後 t 解除主題提示' + log_out: 'shift+z shift+z 退出' + actions: + title: '動作' + bookmark_topic: 'f 切換主題收藏狀態' + pin_unpin_topic: 'shift+p 置頂/截至置頂主題' + share_topic: 'shift+s 分享主題' + share_post: 's 分享帖子' + reply_as_new_topic: 't 回覆為聯結主題' + reply_topic: 'shift+r 回覆主題' + reply_post: 'r 回覆帖子' + quote_post: 'q 引用帖子' + like: 'l 讚帖子' + flag: '! 標記帖子' + bookmark: 'b 收藏帖子' + edit: 'e 編輯帖子' + delete: 'd 刪除帖子' + mark_muted: 'm, m 忽略主題' + mark_regular: 'm, r 常規 (預設) 主題' + mark_tracking: 'm, t 追蹤主題' + mark_watching: 'm, w 看主題' + print: 'ctrl+p 打印主題' + badges: + earned_n_times: + other: "授予徽章 %{count} 次" + granted_on: "授予於%{date}" + others_count: "其他有該徽章的人(%{count})" + title: 徽章 + allow_title: "能用作頭銜" + multiple_grant: "能被授予多次" + badge_count: + other: "%{count} 徽章" + more_badges: + other: "+%{count} 更多" + granted: + other: "%{count} 授予" + select_badge_for_title: 選擇一個徽章作為你的頭銜使用 + none: "" + badge_grouping: + getting_started: + name: 開始 + community: + name: 社區 + trust_level: + name: 信任等級 + other: + name: 其它 + posting: + name: 發帖 + google_search: | +

    用 Google 搜索

    +

    +

    +

    + tagging: + all_tags: "所有標籤" + selector_all_tags: "所有標籤" + selector_no_tags: "無標籤" + changed: "標籤被修改:" + tags: "標籤" + choose_for_topic: "為此主題選擇可選標籤" + delete_tag: "刪除標籤" + delete_confirm: "確定要刪除這個標籤嗎?" + rename_tag: "重命名標籤" + rename_instructions: "標籤的新名稱:" + sort_by: "排序方式:" + sort_by_count: "總數" + sort_by_name: "名稱" + manage_groups: "管理標籤組" + manage_groups_description: "管理標籤的群組" + filters: + without_category: "%{tag}的%{filter}主題" + with_category: "%{filter} %{tag}主題在%{category}" + untagged_without_category: "無標籤的%{filter}主題" + untagged_with_category: "%{category}無標籤的%{filter}主題" + notifications: + watching: + title: "監看" + description: "你將自動監看該標籤中的所有主題。新帖子和新主題會通知你,再者未讀和新帖的數量也將顯示在主題旁邊。" + watching_first_post: + title: "監看頭一帖" + description: "在這個標籤中,只是每一個新主題的第一帖,才會通知你。" + tracking: + title: "跟蹤" + description: "你將自動跟蹤這個標籤裡的所有主題。未讀和新帖的數量將顯示在主題旁邊。" + regular: + title: "普通" + description: "如果有人@你或回覆你的帖子,將通知你。" + muted: + title: "靜音" + description: "在這個標籤中,你將不會收到新主題任何通知,它們也不會出現在你的未讀列表上面。" + groups: + title: "標籤組" + about: "將標籤分組以便管理。" + new: "新標籤組" + tags_label: "標籤組內標籤:" + parent_tag_label: "上級標籤:" + parent_tag_placeholder: "可選" + parent_tag_description: "未設置上級標籤前群組內標籤無法使用。" + one_per_topic_label: "只可給主題設置一個該組內的標籤" + new_name: "新標籤組名" + save: "保存" + delete: "刪除" + confirm_delete: "確定要刪除此標籤組嗎?" + topics: + none: + unread: "你沒有未讀主題。" + new: "你沒有新的討論話題。" + read: "你尚未閲讀任何主題。" + posted: "你尚未在任何主題中發帖。" + latest: "沒有最新主題。" + hot: "沒有熱門主題。" + bookmarks: "你還沒有收藏主題。" + top: "沒有最佳主題。" + search: "沒有搜索結果。" + bottom: + latest: "沒有更多的最新主題。" + hot: "沒有更多的熱門話題。" + posted: "沒有更多的發佈主題。" + read: "沒有更多已閲主題可看了。" + new: "已經沒有其他新討論話題了。" + unread: "沒有更多未讀主題了。" + top: "沒有更多最佳主題了。" + bookmarks: "沒有更多收藏的主題了。" + search: "沒有更多搜索結果了。" + invite: + custom_message: "讓你的邀請稍稍個人化一些吧,寫個" + custom_message_link: "留言" + custom_message_placeholder: "輸入留言" + custom_message_template_forum: "你好,你應該來我們這個論壇!" + custom_message_template_topic: "你好,我覺得你可能會喜歡這個主題!" + safe_mode: + enabled: "安全模式已經開啟,關閉該瀏覽器窗口以退出安全模式" admin_js: type_to_filter: "輸入要搜尋的文字..." admin: @@ -1412,8 +2090,8 @@ zh_TW: backups: "備份檔" traffic_short: "流量" traffic: "網頁應用程式請求數" - page_views: "API 請求數量" - page_views_short: "API 請求數量" + page_views: "瀏覽數" + page_views_short: "瀏覽數" show_traffic_report: "顯示詳細的流量報表" reports: today: "今天" @@ -1425,9 +2103,11 @@ zh_TW: 30_days_ago: "30 天前" all: "全部" view_table: "表格" + view_graph: "圖表" refresh_report: "重新整理報告" start_date: "開始日期" end_date: "結束日期" + groups: "所有群組" commits: latest_changes: "最近的變更:請經常更新!" by: "由" @@ -1496,22 +2176,28 @@ zh_TW: refresh: "重新整理" new: "建立" selector_placeholder: "輸入用戶名稱" - name_placeholder: "群組名稱,不可含有空白字元,使用戶名稱的規則相同" about: "請在此編輯你的群組成員與名稱" group_members: "群組成員" delete: "刪除" delete_confirm: "刪除此群組?" delete_failed: "無法刪除群組,自動建立的群組無法刪除。" - delete_member_confirm: "從 '%{group}' 群組刪除 '%{username}' ?" - name: "名稱" + delete_owner_confirm: "移除“%{username}”的權限?" add: "加入" add_members: "新增成員" custom: "客製" + bulk_complete: "用戶已被添加到群組。" + bulk: "批量添加到群組" + bulk_paste: "粘貼用戶名郵件列表,一行一個:" + bulk_select: "( 選擇一個群組 )" automatic: "自動建立" automatic_membership_email_domains: "註冊的用戶的電子郵件地址網域,完全符合列表裡某項時,會自動加進這個群組裡:" automatic_membership_retroactive: "套用相同的電子郵件網域規則到已經註冊的用戶上:" default_title: "群組內所有成員的預設頭銜" primary_group: "自動設定為主要群組" + group_owners: 所有者 + add_owners: 添加所有者 + incoming_email: "自定義進站電子郵件地址" + incoming_email_placeholder: "輸入郵箱地址" api: generate_master: "產生主 API 金鑰" none: "目前沒有啟用中的 API 金鑰。" @@ -1526,6 +2212,73 @@ zh_TW: info_html: "你可以使用 API 金鑰呼叫 JSON 建立與更新討論話題。" all_users: "所有用戶" note_html: "請安全地保管密鑰,任何擁有該密鑰的使用者,都可以使用它以任何的使用者的名義發文。" + web_hooks: + title: "Webhooks" + none: "當前沒有 Webhooks。" + instruction: "Webhooks 讓 Discourse 可以在特定事件發生時通知外部服務。當 webhook 事件觸發時,一個 POST 請求將發向指定地址。" + detailed_instruction: "一個 POST 請求將在選定事件發生時發至指定 URL。" + new: "新建 Webhook" + create: "創建" + save: "保存" + destroy: "刪除" + description: "描述" + controls: "控制" + go_back: "返回列表" + payload_url: "Payload URL" + payload_url_placeholder: "https://example.com/postreceive" + warn_local_payload_url: "你好像將 webhook 指向了一個本地地址。把相關事件發送到本地可能產生副作用或未預期的行為。繼續嗎?" + secret_invalid: "密鑰不能包含空白字元。" + secret_too_short: "密鑰必須至少有 12 個字元。" + event_type_missing: "你必須設置一個事件類型。" + content_type: "內容格式" + secret: "密鑰" + event_chooser: "你想要 webhook 發送哪些事件?" + wildcard_event: "發送任何事件。" + individual_event: "選擇各個事件。" + verify_certificate: "檢查 Payload URL 的 TLS 證書" + active: "啟用" + active_notice: "我們將在事件發生時分發事件詳情。" + categories_filter_instructions: "相關 Webhook 事件將在滿足特定分類的情況下才發送。留空忽略分類限制。" + categories_filter: "觸發的分類" + groups_filter_instructions: "相關 Webhook 事件將在滿足特定群組的情況下才發送。留空忽略群組限制。" + groups_filter: "觸發的群組" + delete_confirm: "刪除這個 webhook?" + topic_event: + name: "主題事件" + details: "當有新主題、主題被修訂、修改或者刪除時。" + post_event: + name: "帖子事件" + details: "當有新回覆、編輯、帖子被刪除或者恢復時。" + user_event: + name: "用戶事件" + details: "當用戶被創建、審核通過或更新時。" + delivery_status: + title: "分髮狀態" + inactive: "不活躍" + failed: "失敗" + successful: "成功" + events: + none: "沒有相關事件。" + redeliver: "重新發送" + incoming: + other: "有 {{count}} 個新事件。" + completed_in: + other: "在 {{count}} 秒內完成。" + request: "請求" + response: "回應" + redeliver_confirm: "你確定要再次發送一樣的內容嗎?" + headers: "頭部" + payload: "內容" + body: "內容" + go_list: "前往列表" + go_details: "編輯 Webhook" + go_events: "前往事件列表" + ping: "Ping" + status: "狀態碼" + event_id: "ID" + timestamp: "創建時間" + completion: "完成時間" + actions: "操作" plugins: title: "外掛" installed: "已安裝外掛" @@ -1544,6 +2297,14 @@ zh_TW: backups: "備份" logs: "紀錄" none: "沒有可用的備份。" + read_only: + enable: + title: "開啟只讀模式" + label: "開啟只讀模式" + confirm: "你確定要開啟只讀模式麼?" + disable: + title: "關閉只讀模式" + label: "關閉只讀模式" logs: none: "尚無紀錄..." columns: @@ -1577,9 +2338,11 @@ zh_TW: is_disabled: "此站設定已關閉復原" label: "還原" title: "復原備份" + confirm: "你確定要從該備份中恢復嗎?" rollback: label: "回溯" title: "回溯資料庫到以前的工作階段" + confirm: "你確定要將資料庫回滾到之前的工作狀態嗎?" export_csv: success: "開始匯出,處理完畢後將以私人訊息通知你。" failed: "匯出失敗。請觀看紀錄。" @@ -1683,12 +2446,16 @@ zh_TW: email: title: "電子郵件" settings: "設定" + templates: "模板" preview_digest: "預覽文摘" sending_test: "傳送測試郵件" error: "錯誤 - %{server_error}" test_error: "發送測試電子郵件時遇到錯誤。請檢查你輸入的電子郵件地址,並確認網路提供者沒有封鎖郵件的發送,然後再試一次。" sent: "送出" skipped: "跳過" + bounced: "退回" + received: "收到" + rejected: "拒絶" sent_at: "送出時間" time: "時間" user: "用戶" @@ -1698,18 +2465,37 @@ zh_TW: send_test: "送出測試Email" sent_test: "已送出!" delivery_method: "傳送方式" + preview_digest_desc: "預覽發送給不活躍用戶的摘要郵件內容。" refresh: "重新整理" + send_digest_label: "發送結果至:" + send_digest: "發送" + sending_email: "發送郵件..." format: "格式" html: "html" text: "純文字" last_seen_user: "最近出現的用戶:" + no_result: "沒有找到摘要信息。" reply_key: "回覆金鑰" skipped_reason: "跳過原因" incoming_emails: + from_address: "來自" + to_addresses: "發至" + cc_addresses: "抄送" + subject: "主題" error: "錯誤" + none: "沒有找到進站郵件。" modal: + title: "進站郵件詳情" error: "錯誤" + headers: "頭部" + subject: "主題" + body: "內容" + rejection_message: "拒絶郵件" filters: + from_placeholder: "from@example.com" + to_placeholder: "to@example.com" + cc_placeholder: "cc@example.com" + subject_placeholder: "主題..." error_placeholder: "錯誤" logs: none: "找不到記錄。" @@ -1760,6 +2546,7 @@ zh_TW: change_site_setting: "修改網站設定" change_site_customization: "修改網站客製化" delete_site_customization: "刪除網站客製化" + change_site_text: "更改站點文字" suspend_user: "將用戶停權" unsuspend_user: "恢復用戶權限" grant_badge: "升級徽章" @@ -1769,6 +2556,7 @@ zh_TW: delete_post: "刪除文章" impersonate: "檢視" anonymize_user: "匿名用戶" + roll_up: "回退 IP 封禁" change_category_settings: "變更分類設定" delete_category: "刪除分類" create_category: "建立分類" @@ -1778,6 +2566,15 @@ zh_TW: revoke_admin: "撤銷管理員權限" grant_moderation: "授予板主權限" revoke_moderation: "撤銷板主權限" + backup_operation: "備份操作" + deleted_tag: "刪除的標籤" + renamed_tag: "重命名的標籤" + revoke_email: "撤銷郵件" + lock_trust_level: "鎖定信任等級" + unlock_trust_level: "解除信任等級鎖定" + activate_user: "啟動使用者" + deactivate_user: "撤銷使用者" + change_readonly_mode: "變更唯讀模式" screened_emails: title: "過濾的電子郵件地址" description: "以下的電子郵件地址將無法用來建立新用戶。" @@ -1814,6 +2611,7 @@ zh_TW: title: "檢視角度" help: "使用此工具以用戶的檢視角度進行除錯。完成後將需登出。" not_found: "找不到那位使用者。" + invalid: "抱歉,你不能以此用戶角度檢視。" users: title: '用戶' create: '新增管理員' @@ -1841,6 +2639,9 @@ zh_TW: pending: '等待審核的用戶' newuser: '信任等級 0 的用戶 ( 新用戶 )' basic: '信任等級 1 的用戶 ( 初級用戶 )' + member: '信任等級為2的用戶(成員)' + regular: '信任等級為3的用戶(活躍)' + leader: '信任等級為4的用戶(資深)' staff: "管理員" admins: '管理員' moderators: '板主' @@ -1864,12 +2665,14 @@ zh_TW: suspend_reason: "原因" suspended_by: "將其停權者" delete_all_posts: "刪除所有文章" + delete_all_posts_confirm_MF: "你將要刪除 {POSTS, plural, one {1 個帖子} other {# 個帖子}}和 {TOPICS, plural, one {1 個主題} other {# 個主題}}。確定嗎?" suspend: "停權" unsuspend: "恢復權限" suspended: "已停權?" moderator: "板主?" admin: "管理員?" blocked: "已封鎖?" + staged: "暫存?" show_admin_profile: "管理員" edit_title: "編輯標題" save_title: "儲存標題" @@ -1931,9 +2734,20 @@ zh_TW: deactivate_failed: "取消此帳號的啟用狀態時發生錯誤。" unblock_failed: '解除此用戶的封鎖狀態時發生錯誤。' block_failed: '封鎖此用戶時發生錯誤。' + block_confirm: '你確定要封禁用戶嗎?他們將沒有辦法創建任何主題或者帖子。' + block_accept: '是的,封禁用戶' + bounce_score: "累計退信分值" + reset_bounce_score: + label: "重置" + title: "重置累計退信分值為 0" deactivate_explanation: "帳號的啟用狀態被取消的用戶必需重新啟用帳號。" suspended_explanation: "被停權的用戶無法登入。" block_explanation: "被封鎖的用戶無法發表文章或建立討論話題。" + staged_explanation: "暫存用戶只能通過郵件回覆指定主題。" + bounce_score_explanation: + none: "近期該郵箱沒有退信。" + some: "近期該郵箱有少量退信。" + threshold_reached: "近期該郵箱有過多退信。" trust_level_change_failed: "修改用戶的信任等級時發生錯誤。" suspend_modal_title: "將用戶停權" trust_level_2_users: "信任等級 2 用戶" @@ -1944,6 +2758,8 @@ zh_TW: unlock_trust_level: "解鎖信任等級" tl3_requirements: title: "信任等級 3 之條件" + table_title: + other: "這最近 %{count} 天:" value_heading: "價值" requirement_heading: "要求" visits: "訪問" @@ -1999,16 +2815,23 @@ zh_TW: title: "顯示在公開的基本資料裡?" enabled: "在基本資料裡顯示" disabled: "不在基本資料裡顯示" + show_on_user_card: + title: "在用戶卡片上顯示?" + enabled: "在用戶卡片上顯示" + disabled: "在用戶卡片上隱藏" field_types: text: '文字區域' confirm: '確認' dropdown: "下拉" site_text: + description: "你可以自定義論壇的任意文本。請按以下搜索:" + search: "搜索你想要編輯的文本" title: '文字內容' edit: '編輯' revert: "恢復變更" revert_confirm: "你確定要撤回這個改動?" go_back: "回到搜尋" + recommended: "我們建議自定義以下文本以符合你的需求:" show_overriden: '只顯示修改過的項目' site_settings: show_overriden: '只顯示修改過的項目' @@ -2036,11 +2859,15 @@ zh_TW: developer: '開發人員' embedding: "嵌入" legal: "法律" + user_api: '用戶 API' uncategorized: '其他' backups: "備份" login: "登入" plugins: "延伸套件" user_preferences: "偏好設定" + tags: "標籤" + search: "搜索" + groups: "群組" badges: title: 徽章 new_badge: 新徽章 @@ -2049,6 +2876,7 @@ zh_TW: badge: 徽章 display_name: 顯示名稱 description: 簡述 + long_description: 詳情 badge_type: 徽章類型 badge_grouping: 群組 badge_groupings: @@ -2088,6 +2916,7 @@ zh_TW: post_revision: "當用戶新增或是編輯一個文章" trust_level_change: "當用戶信任等級有改變" user_change: "當用戶被新增或是編輯" + post_processed: "在帖子被處理之後" preview: link_text: "預覽獲得的徽章" plan_text: "預覽 SQL 查詢語法" @@ -2097,6 +2926,9 @@ zh_TW: bad_count_warning: header: "警告 !" text: "查詢結果沒有授予徽章的樣本;當查詢結果回傳的使用者 ID 或文章 ID 不存在時此問題有可能發生。如此可能會發生未預期的結果 ―― 請再次檢查您的 SQL 語法。" + no_grant_count: "沒有指定徽章。" + grant_count: + other: "指定了 %{count} 個徽章。" sample: "樣本:" grant: with: %{username} @@ -2111,15 +2943,30 @@ zh_TW: image: "圖片" delete_confirm: "你確定要刪除 :%{name}: emoji ?" embedding: + get_started: "如果你想要將 Discourse 嵌入至其他網站,添加他們的主機地址。" confirm_delete: "你確定要刪除此主機?" + sample: "使用下列 HTML 代碼至你的站點創建和嵌入 Discourse 主題。把REPLACE_ME 替換成你將嵌入至的網址。" title: "嵌入" host: "允許的主機" + path_whitelist: "路徑白名單" edit: "編輯" category: "張貼到分類" add_host: "新增主機" settings: "嵌入設定" + feed_settings: "源設置" + feed_description: "為你的站點提供一份 RSS/ATOM 源能改善 Discourse 導入你的內容的能力" crawling_settings: "爬蟲設定" + crawling_description: "當 Discourse 為你的帖子創建了主題時,如果沒有 RSS/ATOM 流存在,它將嘗試從 HTML 中解析內容。有時分離其中的內容時可能是很有挑戰性的,所以我們提供了指定 CSS 規則的能力來幫助分離過程。" + embed_by_username: "主題創建者的用戶名" + embed_post_limit: "嵌入的最大帖子數量。" + embed_username_key_from_feed: "從流中拉取 Discourse 用戶名的 Key " + embed_title_scrubber: "從帖子中提取標題的正則表達式 \"regular expression\"" + embed_truncate: "截斷嵌入的帖子" + embed_whitelist_selector: "使用 CSS 選擇器選擇允許的嵌入元素" + embed_blacklist_selector: "使用 CSS 選擇器移除嵌入元素" + embed_classname_whitelist: "允許 CSS class 名稱" feed_polling_enabled: "匯入帖子藉由 RSS/ATOM" + feed_polling_url: "用於抓取的 RSS/ATOM 流的 URL" save: "儲存崁入設定" permalink: title: "固定連結" @@ -2136,3 +2983,21 @@ zh_TW: label: "新增:" add: "新增" filter: "搜尋 (網址或外部網址)" + wizard_js: + wizard: + done: "完成" + back: "上一步" + next: "下一步" + step: "%{current} / %{total}" + upload: "上傳" + uploading: "上傳中..." + quit: "以後再說" + staff_count: + other: "你的社群中有 %{count} 位工作人員。" + invites: + add_user: "添加" + none_added: "你還沒有邀請任何工作人員。你確定要繼續嗎?" + roles: + admin: "管理員" + moderator: "版主" + regular: "普通用戶" diff --git a/config/locales/plurals.rb b/config/locales/plurals.rb index 6ab9d3dc5a4..9e6ea0b56e9 100644 --- a/config/locales/plurals.rb +++ b/config/locales/plurals.rb @@ -103,7 +103,8 @@ :tl => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :to => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :tr_TR => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, - :uk => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other } } } }, + # TODO put this back when translations are correct: :uk => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other } } } }, + :uk => { :i18n => { :plural => { :keys => [:one, :few, :other], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :other : :other } } } }, :ur => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :vi => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :wa => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, diff --git a/config/locales/server.ar.yml b/config/locales/server.ar.yml index b772eb260b3..2910360b499 100644 --- a/config/locales/server.ar.yml +++ b/config/locales/server.ar.yml @@ -120,8 +120,6 @@ ar: max_username_length_range: "لا يمكن أن تكون القيمة العليا أصغر من الدنيا." default_categories_already_selected: "لا يمكنك تحديد فئة تستخدم في قائمة أخرى." s3_upload_bucket_is_required: "لا يمكنك تفعيل الرفع إلى S3 حتّى توفّر 's3_upload_bucket'." - bulk_invite: - file_should_be_csv: "على نسق الملف الملف المرفوع أن يكون إمّا csv أو txt." backup: operation_already_running: "ثمّة عملية تجري حاليا. لا يمكنك بدء مهمة جديدة الآن." backup_file_should_be_tar_gz: "على الملف الاحتياطي أن يكون أرشيف \"‎.tar.gz\"." @@ -1006,9 +1004,7 @@ ar: top_page_default_timeframe: "الوقت المثبت علي الصفحة الأكثر مشاهدة." show_email_on_profile: "إظهار بريدك المستخدم على صفحته الشخصية (مرئية فقط لأنفسهم والموظفين)" email_token_valid_hours: "نسيت كلمه السر/ تنشيط رموز الحساب صالحه ل(n) ساعات" - email_token_grace_period_hours: "نسيت كلمه السر/ تنشيط رموز الحساب لا تزال صالحة لفترة سماح بالـ(n) ساعات بعد استبدالها." enable_badges: "تفعيل نظام الأوسمة." - enable_whispers: "السماح للموظفين الخصوصين التواصل ضمن موضوع.(تجريبي)" allow_index_in_robots_txt: "تحديد في ملف robots.txt أن يسمح هذا الموقع ليتم فهرستها من قبل محركات البحث على شبكة الإنترنت." email_domains_blacklist: "قائمة pipe-delimited المجالات البريد الإلكتروني الذي لا يسمح للمستخدمين تسجيل حسابات مع. مثال: mailinator.com | trashmail.net" email_domains_whitelist: "قائمة pipe-delimited من مجالات البريد الإلكتروني التي يجب على المستخدمين تسجيل حسابات مع. تحذير: لن يسمح للمستخدمين مع مجالات البريد الإلكتروني الأخرى غير المذكورة هنا!" @@ -1250,7 +1246,6 @@ ar: embed_whitelist_selector: "منتقي CSS للعناصر التي تسمح في التضمينات." embed_blacklist_selector: "منتقي CSS للعناصر التي حذفت من التضمينات." notify_about_flags_after: "اذا كانت هناك علامه انه لم يتم تاتعامل معه بعد هذه الساعات, ارسال رساله الي جهه الاتصال_بريده الالكتروني. اضبط 0 للتعطيل" - enable_cdn_js_debugging: "السماح/logs لعرض أخطاء المناسبة عن طريق إضافة تتضمن تحليل عرض كل شبيبة." show_create_topics_notice: "إذا كان الموقع يحتوي على أقل من 5 مواضيع عامة , إظهار إشعار مطالبة المسؤولين إنشاء بعض المواضيع." delete_drafts_older_than_n_days: حذف المسودات مضى عليها أكثر من (ن) يوما. prevent_anons_from_downloading_files: "امنع المستخدمين المجهولين من تحميل المرفقات. تحذير:سوف تمنع اي شخص ليس لديه صوره موقع اصول نشره كمرفقات من العمل." @@ -1501,26 +1496,6 @@ ar: (أذا كنت بحاجة للتواصل مع [الموظفين](%{base_url}/about) كمستخدم جديد, فقط مجرد الرد على هذه الرسالة.) welcome_invite: subject_template: "مرحبا بك في %{site_name}!" - text_body_template: | - شكرًا لقبولك الدعوة إلى موقع %{site_name} أهلا بك . - - انشأنا حساب جديد لك **%{username}** وستقوم بتسجيل الدخول، وستتمكن من تغيير اسمك من [your user profile][prefs]. - - لتسجيل الدخول لاحقا: - - 1.دائما **استخدم نفس البريد الالكتروني الذي استقبلت فيه الدعوة** عند تسجيل الدخول، وإلا فإننا لن نستطيع معرفة أنه أنت ! - - 2. أنشأ كلمة مرور فريدة [your user profile][prefs] واستخدمها لتسجيل الدخول . - - %{new_user_tips} - - ونحن نتبع [civilized community behavior](%{base_url}/guidelines)دائما.. - - استمتع بوجودك بيننا ! - - (إذا كنت تريد التواصل مع [staff members](%{base_url}/about) كمستخدم جديد، رد على هذه الرسالة فقط لتتواصل معهم) - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "اكتملت عملية النسخ الإحتياطي بنجاح" backup_failed: diff --git a/config/locales/server.bs_BA.yml b/config/locales/server.bs_BA.yml index 4140cfd933f..8e1da3c6a4c 100644 --- a/config/locales/server.bs_BA.yml +++ b/config/locales/server.bs_BA.yml @@ -43,8 +43,6 @@ bs_BA: taken: "has already been taken" embed: load_from_remote: "There was an error loading that post." - bulk_invite: - file_should_be_csv: "The uploaded file should be of csv or txt format." backup: operation_already_running: "An operation is currently running. Can't start a new job right now." backup_file_should_be_tar_gz: "The backup file should be a .tar.gz archive." @@ -460,7 +458,6 @@ bs_BA: redirect_users_to_top_page: "Automatically redirect new and long absent users to the top page." show_email_on_profile: "Show a user's email on their profile (only visible to themselves and staff)" email_token_valid_hours: "Forgot password / activate account tokens are valid for (n) hours." - email_token_grace_period_hours: "Forgot password / activate account tokens are still valid for a grace period of (n) hours after being redeemed." enable_badges: "Enable the badge system" allow_index_in_robots_txt: "Specify in robots.txt that this site is allowed to be indexed by web search engines." email_domains_blacklist: "A list of email domains that users are not allowed to register accounts with. Example: mailinator.com trashmail.net" @@ -622,7 +619,6 @@ bs_BA: embed_whitelist_selector: "CSS selector for elements that are allowed in embeds." embed_blacklist_selector: "CSS selector for elements that are removed from embeds." notify_about_flags_after: "If there are flags that haven't been handled after this many hours, send an email to the contact_email. Set to 0 to disable." - enable_cdn_js_debugging: "Allow /logs to display proper errors by adding crossorigin permissions on all js includes." show_create_topics_notice: "If the site has fewer than 5 public topics, show a notice asking admins to create some topics." prevent_anons_from_downloading_files: "Prevent anonymous users from downloading files. WARNING: this will prevent any site assets posted as attachments from working." errors: @@ -747,24 +743,6 @@ bs_BA: (Ako trebate razgovarati s nekim od [članova osoblja](%{base_url}/about) kao novi korisnik, samo odgovorite na ovu poruku.) welcome_invite: subject_template: "Dobrodošli na %{site_name}!" - text_body_template: | - Hvala vam što ste primili pozivnicu na %{site_name} -- dobrodošli! - - Mi smo automatski kreirali vaše korisničko ime: **%{username}**, ali možete ga promjeniti preko [tvoj profil][postavke]. - - Da se opet ulogujete: - - 1. Log in using any method you like -- but it must resolve to the **same email address** that you received your original invitation email at. Otherwise we won't be able to tell it is you! - - 2. Create a unique password for [your user profile][prefs], and use it to log in. - - %{new_user_tips} - - We believe in [civilized community behavior](%{base_url}/guidelines) at all times. - - Enjoy your stay! - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "Backup completed successfully" backup_failed: diff --git a/config/locales/server.cs.yml b/config/locales/server.cs.yml index ba9bb6a729c..e441ff8c96e 100644 --- a/config/locales/server.cs.yml +++ b/config/locales/server.cs.yml @@ -89,8 +89,6 @@ cs: max_username_length_exists: "Nemůžeš nastavit délku maximální uživatelského jména kratší než je nejdelší uživatelské jméno. " max_username_length_range: "Nemůžeš nastavit maximum pod minimum." default_categories_already_selected: "Nemůžeš vybrat kategorii používanou v jiném seznamu." - bulk_invite: - file_should_be_csv: "Nahraný soubrou by měl být ve formátu csv nebo txt." backup: operation_already_running: "Právě probíhá operace %{operation}. V tuto chvíli nelze zahájit novou operaci %{operation}." backup_file_should_be_tar_gz: "Záloha by měla být archiv s příponou .tar.gz." @@ -785,6 +783,9 @@ cs: title: "Podmínky používání" privacy_topic: title: "Ochrana soukromí" + badges: + admired: + name: Obdivovaný admin_login: success: "E-mail odeslán" error: "Chyba!" diff --git a/config/locales/server.da.yml b/config/locales/server.da.yml index 5c9e71a6b1d..e1eec0ecab7 100644 --- a/config/locales/server.da.yml +++ b/config/locales/server.da.yml @@ -102,8 +102,6 @@ da: max_username_length_range: "Du kan ikke sætte maksimum til mindre end minimum." default_categories_already_selected: "Du kan ikke vælge en kategori der er brugt i en anden liste." s3_upload_bucket_is_required: "Du kan ikke oploade til S3 med mindre du har angivet 's3_upload_bucket'." - bulk_invite: - file_should_be_csv: "Den uploadede fil skal være i .csv eller .txt format." backup: operation_already_running: "Der kører allerede en %{operation}. Kan ikke starte et nyt %{operation} job lige nu." backup_file_should_be_tar_gz: "Backup filen skal være et .tar.gz arkiv." @@ -835,7 +833,6 @@ da: topics_per_period_in_top_page: "Antallet af top emner der vises når 'Vis Mere' er aktiveret." show_email_on_profile: "Vis en brugers email på deres profil (kun synligt for brugerne selv - samt admin)" email_token_valid_hours: "Glemte password / konto aktiverings muligheder er gyldige i (n) timer." - email_token_grace_period_hours: "Glemt password / konto aktiverings muligheder er fortsat gyldige i (n) timer efter at være blevet indløst." enable_badges: "Aktiver badge systemet" log_out_strict: "Når brugeren logger af, log da ud af alle sessioner, på alle enheder" new_version_emails: "Send en email til contact_email adressen når der er en ny version af Discourse tilgængelig." @@ -1038,10 +1035,16 @@ da: subject_template: "[%{site_name}] [PM] %{topic_title}" digest: why: "Et kort resumé af %{site_link} siden dit sidste besøg %{last_seen_at}" + since_last_visit: "Siden dit sidste besøg" + unread_messages: "Ulæste beskeder" + new_posts: "Nye indlæg" + popular_topics: "Populære emner" + join_the_discussion: "Læs mere" subject_template: "[%{site_name}] Resumé" unsubscribe: "Dette resumé sendes fra %{site_link} når vi ikke har set dig i et stykke tid. For at afmelde %{unsubscribe_link}." click_here: "klik her" from: "%{site_name} resumé" + preheader: "Et kort resume siden de sidste besøg %{last_seen_at}" mailing_list: subject_template: "[%{site_name}] Resumé for %{date}" forgot_password: diff --git a/config/locales/server.de.yml b/config/locales/server.de.yml index 01ee15be885..88a3653a42c 100644 --- a/config/locales/server.de.yml +++ b/config/locales/server.de.yml @@ -32,6 +32,7 @@ de: purge_reason: "Verlassenes, deaktiviertes Konto automatisch gelöscht" disable_remote_images_download_reason: "Der Download von Bildern wurde deaktiviert, weil nicht mehr genug Plattenplatz vorhanden war." anonymous: "Anonym" + remove_posts_deleted_by_author: "Gelöscht vom Verfasser" emails: incoming: default_subject: "Eingehende E-Mail von %{email}" @@ -71,6 +72,9 @@ de: has_already_been_used: "wird bereits verwendet" inclusion: ist nicht in der Liste enthalten invalid: ist ungültig + is_invalid: "scheint unklar, ist das ein ganzer Satz?" + contains_censored_words: "Beinhaltet ein oder mehrere verbotene Wörter: %{censored_words}" + matches_censored_pattern: "stimmt mit dem folgenden verbotenen regulären Ausdruck überein: %{censored_pattern}" less_than: muss weniger als %{count} sein less_than_or_equal_to: muss weniger oder gleich %{count} sein not_a_number: ist keine Zahl @@ -105,7 +109,8 @@ de: default_categories_already_selected: "Du kannst keine Kategorie auswählen, welche bereits in einer anderen Liste benutzt wird. " s3_upload_bucket_is_required: "Uploads auf Amazon S3 können nicht aktiviert werden, bevor der 's3_upload_bucket' eingetragen wurde." bulk_invite: - file_should_be_csv: "Die hochgeladene Datei sollte im CSV oder TXT Format vorliegen." + file_should_be_csv: "Die hochzuladende Datei sollte im CSV-Format vorliegen." + error: "Es gab einen Fehler beim Hochladen dieser Datei. Bitte versuche es später noch einmal." backup: operation_already_running: "Eine Arbeitsschritt wird momentan bearbeitet. Im Moment kann kein neuer Vorgang gestartet werden." backup_file_should_be_tar_gz: "Die Sicherungsdatei sollte ein .tar.gz-Archiv sein." @@ -123,6 +128,11 @@ de: embed: start_discussion: "Diskussion beginnen" continue: "Diskussion fortsetzen" + error: "Fehler bei der Einbettung" + referer: "Referrer:" + mismatch: "Der Referrer entsprach keiner der folgenden Hostnamen:" + no_hosts: "Es wurden keine Hostnamen für die Einbettung konfiguriert." + configure: "Einbettung konfigurieren" more_replies: one: "1 weitere Antwort" other: "%{count} weitere Antworten" @@ -156,8 +166,10 @@ de: spamming_host: "Entschuldigung, du kannst keine Links zu diesem Webserver posten." user_is_suspended: "Gesperrte Benutzer dürfen keine Beiträge schreiben." topic_not_found: "Etwas ist schief gelaufen. Wurde das Thema eventuell geschlossen oder gelöscht, während du es angeschaut hast?" + not_accepting_pms: "Entschuldige, %{username} akzeptiert gerade keine Nachrichten." just_posted_that: "ist einer einer vor Kurzem von dir geschriebenen Nachricht zu ähnlich" invalid_characters: "enthält ungültige Zeichen" + is_invalid: "scheint unklar, ist das ein ganzer Satz?" next_page: "nächste Seite →" prev_page: "← vorherige Seite" page_num: "Seite %{num}" @@ -198,7 +210,7 @@ de: everyone: "jeder" admins: "admins" moderators: "moderatoren" - staff: "mitarbeiter" + staff: "team" trust_level_0: "vertrauensstufe_0" trust_level_1: "vertrauensstufe_1" trust_level_2: "vertrauensstufe_2" @@ -268,6 +280,7 @@ de: name: "Name der Kategorie" topic: title: 'Titel' + featured_link: 'Hervorgehobener Link' post: raw: "Hauptteil" user_profile: @@ -281,6 +294,9 @@ de: too_many_users: "Du kannst eine Warnung nur an einen Benutzer zugleich anhängen." cant_send_pm: "Entschuldigung, du kannst diesem Benutzer keine Direktnachricht schicken." no_user_selected: "Du musst einen gültigen Benutzer auswählen." + featured_link: + invalid: "ist ungültig. URL sollte http:// oder https:// enthalten." + invalid_category: "kann in dieser Kategorie nicht bearbeitet werden." user: attributes: password: @@ -309,9 +325,26 @@ de: vip_category_description: "Eine Kategorie exklusiv für Mitglieder mit Vertrauensstufe 3 oder höher." meta_category_name: "Feedback" meta_category_description: "Diskussionen über dieses Forum, seine Organisation, wie es funktioniert und wie wir es verbessern können." - staff_category_name: "Mitarbeiter" - staff_category_description: "Geschützte Kategorie für Mitarbeiter. Themen sind nur für Administratoren und Moderatoren sichtbar." - assets_topic_body: "Dies ist ein fester Beitrag, der nur für Mitarbeiter sichtbar ist, um Bilder und Dateien, die im Forum benutzt werden zu speichern. Lösche diese nicht!\n\n\nAnleitung:\n\n\n1. Antworte auf dieses Thema.\n2. Lade alle Bilder, die du für Logos, Favicons und usw. nutzen willst, hier hoch. (Nutze dazu das Symbol für Lade-Symbolleiste im Beitrags-Editor oder ziehe und lasse die Bilder hier fallen oder füge sie eins.)\n3. Sende deine Antwort. \n4. Klicke mit der rechten Maustaste auf die Bilder in deinem neuen Beitrag, um die den Pfad zu bekommen oder klicke das Editier-Symbol, um deinen Beitrag zu editieren und dadurch den Pfad zu den Bildern zu bekommen. Kopiere die Bild-Pfade.\n5. Füge die Bild-Pfade in [basic settings](/admin/site_settings/category/required) ein.\n\n\nWenn du andere Dateityp-Uploads aktivieren willst, editiere `authorized_extensions` in [file settings](/admin/site_settings/category/files)." + staff_category_name: "Team" + staff_category_description: "Geschützte Kategorie für das Team-Diskussionen. Themen sind nur für Administratoren und Moderatoren sichtbar." + assets_topic_title: "Mediendateien für das Seitendesign" + assets_topic_body: "Dies ist ein fester Beitrag, der nur für das Team sichtbar ist, um Bilder und Dateien, die im Forum benutzt werden zu speichern. Lösche diese nicht!\n\n\nAnleitung:\n\n\n1. Antworte auf dieses Thema.\n2. Lade alle Bilder, die du für Logos, Favicons und usw. nutzen willst, hier hoch. (Nutze dazu das Symbol für Lade-Symbolleiste im Beitrags-Editor oder ziehe und lasse die Bilder hier fallen oder füge sie eins.)\n3. Sende deine Antwort. \n4. Klicke mit der rechten Maustaste auf die Bilder in deinem neuen Beitrag, um die den Pfad zu bekommen oder klicke das Editier-Symbol, um deinen Beitrag zu editieren und dadurch den Pfad zu den Bildern zu bekommen. Kopiere die Bild-Pfade.\n5. Füge die Bild-Pfade in [basic settings](/admin/site_settings/category/required) ein.\n\n\nWenn du andere Dateityp-Uploads aktivieren willst, editiere `authorized_extensions` in [file settings](/admin/site_settings/category/files)." + discourse_welcome_topic: + title: "Willkommen bei Discourse" + body: |2 + + Der erste Absatz dieses angehefteten Themas wird allen neuen Besuchern deiner Webseite als Willkommensnachricht angezeigt. Er ist wichtig! + + **Bearbeite dies** und erstelle eine kurze Beschreibung deiner Community: + + - Für wen ist sie? + - Was findet man hier? + - Warum sollte man hier vorbeischauen? + - Wo kann man mehr erfahren (Links, Dokumente, usw.)? + + + + Du solltest dieses Thema eventuell schließen über die Administration :wrench: (oben rechts oder unten), damit sich an einer Ankündigung wie dieser nicht die Antworten aufstapeln. lounge_welcome: title: "Willkommen in der Lounge" body: |2 @@ -375,9 +408,10 @@ de: create_topic: "Du erstellst zu schnell zu viele Themen hintereinander. Bitte warte %{time_left}, bis Du es wieder versuchst." create_post: "Du antwortest zu schnell. Bitte warte %{time_left}, bis Du es wieder versuchst." delete_post: "Du löschst zu schnell Beiträge. Bitte warte %{time_left}, bis Du es wieder versuchst." + public_group_membership: "Du wechselst die Gruppenzugehörigkeit zu häufig. Bitte warte %{time_left}, bevor du es erneut versuchst." topics_per_day: "Du hast die maximale Anzahl an neuen Themen für heute erreicht. Bitte warte %{time_left}, bis Du es wieder versuchst." pms_per_day: "Du hast die maximale Anzahl an Nachrichten für heute erreicht. Bitte warte %{time_left}, bis Du es wieder versuchst." - create_like: "Du hast die maximale Anzahl „Gefällt mir“ für heute erreicht. Bitte warte %{time_left}, bis Du es wieder versuchst." + create_like: "Du hast die maximale Anzahl an Likes für heute erreicht. Bitte warte %{time_left}, bevor du es wieder versuchst." create_bookmark: "Du hast die maximale Anzahl an Lesezeichen für heute erreicht. Bitte warte %{time_left}, bis Du es wieder versuchst." edit_post: "Du hast die maximale Anzahl an Änderungen für heute erreicht. Bitte warte %{time_left}, bis Du es wieder versuchst." live_post_counts: "Du forderst die Live-Anzahl der Antworten zu schnell neu an. Bitte warte %{time_left}, bis du es wieder versuchst." @@ -529,6 +563,13 @@ de: title: 'Abstimmung' description: 'Stimme für diesen Beitrag' long_form: 'für diesen Beitrag gestimmt' + user_activity: + no_bookmarks: + self: "Du hast keine Beiträge mit Lesezeichen, Lesezeichen ermöglichen es dir, diese später einfach zu finden." + others: "Keine Lesezeichen." + no_likes_given: + self: "Du hast noch keine Beiträge mit einem „Like“ markiert." + others: "Keine Beiträge mit „Like“." topic_flag_types: spam: title: 'Spam' @@ -540,7 +581,7 @@ de: long_form: 'als unangemessen gemeldet' notify_moderators: title: "Irgendetwas anderes" - description: 'Dieser Beitrag muss von einem Mitarbeiter begutachtet werden, da er entweder nicht mit den Richtlinien oder den Nutzungsbedingungen in Einklang zu bringen ist, oder aus sonstigen oben nicht genannten Gründen.' + description: 'Dieser Beitrag erfordert die allgemeine Aufmerksamkeit des Teams, da er entweder nicht mit den Richtlinien oder den Nutzungsbedingungen in Einklang zu bringen ist, oder aus anderen Gründen.' long_form: ' hast dies den Moderatoren gemeldet' email_title: 'Das Thema "%{title}" benötigt die Aufmerksamkeit eines Moderators' email_body: "%{link}\n\n%{message}" @@ -575,8 +616,16 @@ de: authorize: "Genehmigen" read: "Lesen" read_write: "Lesen/Schreiben" + description: "\"%{application_name}\" fordert den folgenden Zugriff auf dein Konto:" no_trust_level: "Entschuldige, du hast nicht die erforderliche Vertrauensstufe, um die Benutzer API zu nutzen." generic_error: "Entschuldige, wir können keinen Benutzer API Schlüssel erstellen. Dieses Feature ist möglicherweise vom Site Administrator deaktiviert worden." + scopes: + message_bus: "Live-Aktualisierungen" + notifications: "Benachrichtigungen lesen und leeren" + push: "Push-Benachrichtigungen an externe Dienste" + session_info: "Informationen zur Benutzersitzung lesen" + read: "Alles lesen" + write: "Alles schreiben" reports: visits: title: "Nutzerbesuche" @@ -599,9 +648,9 @@ de: xaxis: "Tag" yaxis: "Anzahl neuer Beiträge" likes: - title: "„Gefällt mir“" + title: "Likes" xaxis: "Tag" - yaxis: "Anzahl neuer „Gefällt mir“" + yaxis: "Anzahl neuer Likes" flags: title: "Meldungen" xaxis: "Tag" @@ -742,14 +791,17 @@ de: poll_pop3_auth_error: "Die Verbindung zum POP3-Server schlägt mit einem Authentisierungsfehler fehl. Überprüfe deine POP3-Einstellungen." site_settings: censored_words: "Wörter, die automatisch durch ■■■■ ersetzt werden" + censored_pattern: "Regex-Muster das automatisch ersetzt wird mit ■■■■" delete_old_hidden_posts: "Automatisch alle Beiträge löschen, die länger als 30 Tage versteckt bleiben." default_locale: "Die Standardsprache dieser Discourse-Instanz (kodiert in ISO 639-1)." - allow_user_locale: "Erlaube Benutzern, ihre eigene Interfacesprache zu wählen" + allow_user_locale: "Erlaube Benutzern, ihre eigene Oberflächensprache zu wählen" set_locale_from_accept_language_header: "Sprache der Benutzeroberfläche für anonyme Benutzer an Hand der Spracheinstellung ihres Browsers wählen (EXPERIMENTELL, funktioniert nicht mit Caches für anonyme Benutzer)" min_post_length: "Minimal zulässige Beitragslänge in Zeichen." min_first_post_length: "Minimal zulässige Länge des ersten Beitrags (eines Themas) in Zeichen" min_private_message_post_length: "Minimale zulässige Beitragslänge in Zeichen für Nachrichten" max_post_length: "Maximale zulässige Beitragslänge in Zeichen." + topic_featured_link_enabled: "Beitrag mit Link zu hervorgehobenen Themen erlauben" + show_topic_featured_link_in_digest: "Zeige den Hervorgehobene Themen Link in der E-Mail-Zusammenfassung." min_topic_title_length: "Minimale zulässige Titellänge von Themen in Zeichen." max_topic_title_length: "Maximale zulässige Titellänge von Themen in Zeichen." min_private_message_title_length: "Minimale zulässige Titellänge von Nachrichten in Zeichen." @@ -773,7 +825,7 @@ de: disabled_image_download_domains: "Liste von Domänen, von denen verlinkte Bilder niemals heruntergeladen werden sollen." editing_grace_period: "Für (n) Sekunden wird nach dem Bearbeiten keine neue Revision im Beitragsverlauf angelegt." post_edit_time_limit: "Der Verfasser eines Beitrags kann diesen nur für (n) Minuten nach Absenden des Beitrags bearbeiten. 0 deaktiviert diese Beschränkung." - edit_history_visible_to_public: "Erlaube jedem, vorherige Versionen eines bearbeiteten Beitrags zu sehen. Wenn deaktiviert sind diese nur für Mitarbeiter sichtbar." + edit_history_visible_to_public: "Erlaube jedem, vorherige Versionen eines bearbeiteten Beitrags zu sehen. Wenn deaktiviert sind diese nur für Team-Mitglieder sichtbar." delete_removed_posts_after: "Beiträge, die deren Verfasser selbst entfernt hat, werden nach (n) Stunden automatisch gelöscht. Die Beiträge werden sofort gelöscht, wenn dieser Wert auf 0 gesetzt wird." max_image_width: "Maximale Breite von Thumbnails von Bildern in einem Beitrag." max_image_height: "Maximale Höhe von Vorschaubildern in einer Nachricht" @@ -784,9 +836,11 @@ de: add_rel_nofollow_to_user_content: "Füge mit Ausnahme interner Links (schließt übergeordnete Domains ein) allen benutzergenerierten Inhalten 'rel nofollow' hinzu. Die Änderung dieser Einstellung erfordert, dass du sämtliche Markdown-Beiträge aktualisierst: \"rake posts:rebake\"" exclude_rel_nofollow_domains: "Eine Liste von Domains auf welchen das Attribut nofollow nicht auf Links gesetzt werden sollte (tld.com erlaubt auch sub.tld.com). Du solltest mindestens die Top-Level Domain dieser Site hinzufügen, damit die Crawler der Suchmaschinen all deinen Content indexieren können. Wenn weitere Teile deiner Website unter anderen Domains zu finden sind, kannst du diese hier ebenfalls hinzufügen." post_excerpt_maxlength: "Maximale Länge eines Beitrags-Auszuges bzw. -Zusammfassung." - show_pinned_excerpt_mobile: "Zeige einen Auszug hervorgehobener Beiträge in der mobilen Ansicht." - show_pinned_excerpt_desktop: "Zeige einen Auszug hervorgehobener Beiträge in der Desktop-Ansicht." + show_pinned_excerpt_mobile: "Zeige einen Auszug angehefteter Themen in der mobilen Ansicht." + show_pinned_excerpt_desktop: "Zeige einen Auszug angehefteter Themen in der Desktop-Ansicht." post_onebox_maxlength: "Maximale Länge eines Onebox-Discourse-Beitrags in Zeichen." + onebox_domains_blacklist: "Eine Liste von Domains, die nie in eine Onebox umgewandelt wird." + max_oneboxes_per_post: "Maximale Anzahl von Oneboxes in einem Beitrag." logo_url: "Das Logo oben links auf deiner Site sollte eine breite, rechteckige Form haben. Wenn du kein Logo auswählst, wird stattdessen `title` angezeigt." digest_logo_url: "Das alternative Logo oben in den E-Mail-Zusammenfassungen deiner Site. Sollte eine breite, rechteckige Form haben. Sollte kein SVG-Bild sein. Wenn leer, wird `logo_url` verwendet." logo_small_url: "Dein Logo in klein für die obere linke Seite deiner Site, in Form eines rechteckigen Quadrates. Es wird angezeigt, wenn der Benutzer scrollt. Wenn du dieses Feld frei lässt, wird stattdessen ein Haus-Symbol angezeigt." @@ -799,10 +853,10 @@ de: force_https: "Erzwinge HTTPS für deine Site. ACHTUNG: Aktiviere dies nicht, bevor HTTPS nicht vollständig eingerichtet ist und auf jeden Fall überall funktioniert! Hast du alle CDN-Netzwerke, alle Logins über Soziale Netzwerke, alle externe Logos / Abhängigkeiten geprüft, um sicherzustellen, dass sie auch alle HTTPS-kompatibel sind?" summary_score_threshold: "Mindestpunktzahl, die ein Beitrag benötigt, um in der \"Thema zusammenfassen\"-Ansicht zu erscheinen." summary_posts_required: "Mindestanzahl an Beiträgen in einem Thema, bevor die \"Thema zusammenfassen\"-Funktion aktiviert wird." - summary_likes_required: "Mindestanzahl an \"Gefällt mir\" Wertungen in einem Thema, bevor die \"Thema zusammenfassen\" Funktion aktiviert wird." + summary_likes_required: "Mindestanzahl an Likes in einem Thema, bevor die \"Thema zusammenfassen\" Funktion aktiviert wird." summary_percent_filter: "Zeige die besten (n)% der Beiträge eines Themas in der \"Thema zusammenfassen\"-Ansicht." summary_max_results: "Maximale Anzahl der sichtbaren Beiträge beim Zusammenfassen von Themen" - enable_private_messages: "Erlaube Benutzer mit der Vertrauensstufe 1 (konfigurierbar über die minimale Vertrauensstufe zum Senden von Nachrichten), Nachrichten zu erstellen und auf Nachrichten zu antworten. Beachte, dass Mitarbeiter immer Nachrichten und Antworten senden können." + enable_private_messages: "Erlaube Benutzer mit der Vertrauensstufe 1 (konfigurierbar über die minimale Vertrauensstufe zum Senden von Nachrichten), Nachrichten zu erstellen und auf Nachrichten zu antworten. Beachte, dass das Team immer Nachrichten und Antworten senden können." enable_long_polling: "Nachrichtenbus für Benachrichtigungen kann Long-Polling nutzen." long_polling_base_url: "Basis-URL für Long Polling (wenn zum Ausliefern von dynamischen Inhalten ein CDN verwendet wird, setze es auf Origin Pull), z. B. http://origin.site.com" long_polling_interval: "Wartezeit, bevor der Server auf Clients reagiert, wenn keine Daten gesendet werden müssen (nur für angemeldete Benutzer)" @@ -825,7 +879,7 @@ de: traditional_markdown_linebreaks: "Traditionelle Zeilenumbrüche in Markdown, die zwei nachfolgende Leerzeichen für einen Zeilenumbruch benötigen." allow_html_tables: "Erlaube es, Tabellen in Markdown mit HTML-Tags einzugeben. TABLE, THEAD, TD, TR, TH werden erlaubt (alle Beiträge mit Tabellen müssen ihr HTML erneuern)" post_undo_action_window_mins: "Minuten, die ein Benutzer hat, um Aktionen auf einen Beitrag rückgängig zu machen (Gefällt mir, Meldung, usw.)." - must_approve_users: "Mitarbeiter müssen alle neuen Benutzerkonten freischalten, bevor diese Zugriff auf die Website erhalten. ACHTUNG: Das Aktivieren dieser Option für eine Live-Site entfernt den Zugriff auch für alle existierenden Benutzer ausser Mitarbeiter!" + must_approve_users: "Team-Mitglieder müssen alle neuen Benutzerkonten freischalten, bevor diese Zugriff auf die Website erhalten. ACHTUNG: Das Aktivieren dieser Option für eine Live-Site entfernt den Zugriff auch für alle existierenden Benutzer außer für Team-Mitglieder!" pending_users_reminder_delay: "Benachrichtige die Moderatoren, falls neue Benutzer mehr als so viele Stunden auf ihre Genehmigung gewartet haben. Stelle -1 ein, um diese Benachrichtigungen zu deaktivieren." maximum_session_age: "Benutzer bleiben (n) Stunden nach ihrem letzten Besuch angemeldet" ga_tracking_code: "VERALTET: Google Analytics (analytics.js) tracking code code, z.B.: UA-12345678-9; siehe http://google.com/analytics" @@ -843,7 +897,7 @@ de: post_menu_hidden_items: "Die Einträge im Menü eines Beitrags, die standardmäßig hinter einer erweiterbaren Ellipse versteckt werden sollen." share_links: "Legt fest, welche Dienste in welcher Reihenfolge im Teilen-Dialog auftauchen." track_external_right_clicks: "Verfolge, welche externen Links per Rechtsklick geöffnet werden (zum Beispiel in einem neuen Browser-Tab). Standardmäßig deaktiviert, da dies URL-Rewrites erfordert." - site_contact_username: "Gültiger Benutzername eines Mitarbeiters, in dessen Name alle automatisch erzeugten Direktnachrichten versendet werden sollen. Falls leer wird das Standardkonto \"system\" verwendet." + site_contact_username: "Gültiger Benutzername eines Team-Mitglieds, in dessen Name alle automatisch erzeugten Direktnachrichten versendet werden sollen. Falls leer wird das Standardkonto \"system\" verwendet." send_welcome_message: "Sende allen neuen Benutzern eine Willkommensnachricht mit Hinweisen zur Benutzung des Forums." suppress_reply_directly_below: "Zeige die erweiterbare Anzahl der Antworten auf einen Beitrag nicht, falls die einzige Antwort direkt darunter folgt." suppress_reply_directly_above: "Verstecke das erweiterbare „Antwort auf“-Feld in einem Beitrag, wenn der beantwortete Beitrag direkt darüber angezeigt wird." @@ -853,12 +907,11 @@ de: topics_per_period_in_top_page: "Anzahl der Themen, die in der mit \"Mehr zeigen\" erweiterten Top-Themenübersicht angezeigt werden." redirect_users_to_top_page: "Verweise neue und länger abwesende Benutzer automatisch zur Angesagt-Seite" top_page_default_timeframe: "Standardzeitfenster für die oberste, angezeigte Seite." - show_email_on_profile: "Im Profil die E-Mail-Adresse des Benutzers anzeigen (ist nur für den Benutzer selbst und Mitarbeiter sichtbar)." + show_email_on_profile: "Im Profil die E-Mail-Adresse des Benutzers anzeigen (ist nur für den Benutzer selbst und das Team sichtbar)." prioritize_username_in_ux: "Zeige den Benutzernamen auf der Benutzerseite, der Benutzerkarte und in Beiträgen an erster Stelle (wenn deaktiviert, wird der Name an erster Stelle angezeigt)" email_token_valid_hours: "Tokens zur Passwort-Wiederherstellung / Aktivierung eines Kontos sind für (n) Stunden gültig." - email_token_grace_period_hours: "Tokens zur Passwort-Wiederherstellung / Aktivierung eines Kontos sind auch nach ihrer Verwendung noch für eine Frist von (n) Stunden gültig." enable_badges: "Abzeichen aktivieren" - enable_whispers: "Erlaube Moderatoren und Administratoren in Beiträgen privat zu kommunizieren (experimentell)" + enable_whispers: "Erlaube dem Team private Kommunikation innerhalb von Themen." allow_index_in_robots_txt: "Suchmaschinen mittels der robots.txt Datei erlauben, die Site zu indizieren." email_domains_blacklist: "Eine durch senkrechte Striche getrennte Liste von E-Mail-Domains, die für die Registrierung neuer Konten nicht verwendet werden dürfen. Beispiel: mailinator.com|trashmail.net" email_domains_whitelist: "Eine durch senkrechte Striche getrennte Liste von E-Mail-Domains, die für die Registrierung neuer Konten verwendet werden können. ACHTUNG: Benutzer mit E-Mail-Adressen anderer Domains werden nicht zugelassen!" @@ -870,7 +923,7 @@ de: force_hostname: "NUR FÜR ENTWICKLER! ACHTUNG! Spezifiziere einen Hostnamen in der URL. Dieses Feld leer lassen heißt 'keinen'. Dient hauptsächlich Entwicklungszwecken." invite_expiry_days: "Tage, die Benutzereinladungen gültig bleiben." invite_passthrough_hours: "Wie viele Stunden ein Benutzer einen bereits eingelösten Einladungsschlüssel zum Anmelden verwenden kann" - invite_only: "Deaktiviere die öffentliche Registrierung, neue Benutzer können nur durch eine Einladung von existierenden Mitgliedern oder Mitarbeitern beitreten." + invite_only: "Deaktiviere die öffentliche Registrierung, neue Benutzer können nur durch eine Einladung von anderen Mitgliedern oder dem Team beitreten." login_required: "Nur angemeldete Benutzer dürfen Inhalte der Site lesen, anonyme Zugriffe sind verboten." min_username_length: "Minimale Benutzernamenlänge in Zeichen." max_username_length: "Maximale Benutzernamenlänge in Zeichen." @@ -889,6 +942,7 @@ de: sso_overrides_name: "Überschreibt den vollen Namen des Benutzers mit den Daten von der externen Site aus dem SSO-Payload bei jedem Login. Außerdem werden lokale Änderungen verhindert." sso_overrides_avatar: "Überschreibt das Profilbild des Benutzers mit dem Profilbild aus dem SSO-Payload. Wenn aktiv, dann sollte allow_uploaded_avatars deaktiviert werden." sso_not_approved_url: "Nicht genehmigte SSO-Konten zu dieser URL weiterleiten" + sso_allows_all_return_paths: "Beschränke die Domain für SSO-Return-Paths (standardmäßig muss der Return Path auf der aktuellen Seite sein)" enable_local_logins: "Aktiviere Login mit lokal gespeicherten Benutzernamen und Passwörtern. (Anmerkung: muss aktiviert sein, damit Einladungen funktionieren)" allow_new_registrations: "Erlaube das Registrieren neuer Benutzerkonten. Wird dies deaktiviert, so kann niemand mehr ein neues Konto erstellen." enable_signup_cta: "Zeige wiederkehrenden Gästen einen Hinweis, dass diese sich Anmelden oder Registrieren sollen." @@ -930,7 +984,7 @@ de: rate_limit_create_post: "Nach Schreiben eines Beitrags muss ein Benutzer (n) Sekunden warten, bevor ein weiterer Beitrag erstellt werden kann." rate_limit_new_user_create_topic: "Nach Erstellen eines Themas muss ein neuer Benutzer (n) Sekunden warten, bevor ein weiteres Thema erstellt werden kann." rate_limit_new_user_create_post: "Nach Schreiben eines Beitrags muss ein neuer Benutzer (n) Sekunden warten, bevor ein weiterer Beitrag erstellt werden kann." - max_likes_per_day: "Maximale Anzahl der „Gefällt mir“-Angaben pro Benutzer und Tag." + max_likes_per_day: "Maximale Anzahl der Likes pro Benutzer und Tag." max_flags_per_day: "Maximale Anzahl der Meldungen pro Benutzer und Tag." max_bookmarks_per_day: "Maximale Anzahl der Lesezeichen pro Benutzer und Tag." max_edits_per_day: "Maximale Anzahl der Bearbeitungen pro Benutzer und Tag." @@ -987,8 +1041,8 @@ de: tl3_requires_posts_read_all_time: "Mindestanzahl Beiträge, die ein Benutzer gelesen haben muss, um die Vertrauensstufe Anführer (3) erreichen zu können." tl3_requires_max_flagged: "Um die Vertrauensstufe 3 erhalten zu können, dürfen in den letzten (tl3 time period) Tagen höchstens X Beiträge eines Benutzer von X verschiedenen anderen Benutzer gemeldet worden sein, wobei X diesem Wert entspricht. (0 oder mehr)" tl3_promotion_min_duration: "Mindestanzahl an Tagen, die ein Benutzer auf Vertrauensstufe 3 beförderter Benutzer auf dieser Stufe verbleibt, bevor er automatisch wieder auf Vertrauensstufe 2 heruntergestuft werden kann." - tl3_requires_likes_given: "Mindestanzahl an „Gefällt mir“-Angaben, die ein Benutzer innerhalb der letzten (tl3 time period) gegeben haben muss, um Vertrauensstufe 3 erreichen zu können." - tl3_requires_likes_received: "Mindestanzahl an „Gefällt mir“-Angaben die ein Benutzer innerhalb der letzten (tl3 time period) bekommen haben muss, um Vertrauensstufe 3 erreichen zu können." + tl3_requires_likes_given: "Mindestanzahl an Likes, die ein Benutzer innerhalb der letzten (tl3 time period) gegeben haben muss, um Vertrauensstufe 3 erreichen zu können." + tl3_requires_likes_received: "Mindestanzahl an Likes die ein Benutzer innerhalb der letzten (tl3 time period) bekommen haben muss, um Vertrauensstufe 3 erreichen zu können." tl3_links_no_follow: "rel=nofollow nicht von Links entfernen, die von Benutzern mit Vertrauensstufe 3 erstellt wurden." min_trust_to_create_topic: "Die minimale Vertrauensstufe wird benötigt um eine neues Thema zu erstellen." min_trust_to_edit_wiki_post: "Die minimal benötigte Vertrauensstufe, um als Wiki markierte Beiträge bearbeiten zu können." @@ -1021,6 +1075,7 @@ de: max_attachment_size_kb: "Maximale Größe hochgeladener Dateianhänge in kB. Dieser Wert muss auch in Nginx (client_max_body_size), Apache oder anderen Proxies entsprechend konfiguriert werden." authorized_extensions: "Liste von erlaubten Dateiendungen für hochgeladene Dateien ('*' um alle Dateiendungen zu erlauben)" max_similar_results: "Anzahl ähnlicher Themen, die beim Erstellen eines neuen Themas über dem Editor angezeigt werden. Ähnlichkeit wird an Hand des Titels und Inhalts bestimmt." + max_image_megapixels: "Maximale erlaubte Auflösung für Bilder (in Megapixeln)." title_prettify: "Verhindert gängige Fehler im Titel, wie reine Grossschreibung, Kleinbuchstaben am Anfang, mehrere ! und ?, überflüssiger . am Ende, etc." topic_views_heat_low: "Aufrufe-Feld leicht hervorheben, sobald das Thema so oft gelesen wurde." topic_views_heat_medium: "Aufrufe-Feld mäßig hervorheben, sobald das Thema so oft gelesen wurde." @@ -1031,19 +1086,19 @@ de: history_hours_low: "Bearbeitungs-Symbol leicht hervorheben, wenn der Beitrag innerhalb so vieler Stunden nach Erstellen bearbeitet wird." history_hours_medium: "Bearbeitungs-Symbol mäßig hervorheben, wenn der Beitrag innerhalb so vieler Stunden nach Erstellen bearbeitet wird." history_hours_high: "Bearbeitungs-Symbol stark hervorheben, wenn der Beitrag innerhalb so vieler Stunden nach Erstellen bearbeitet wird." - topic_post_like_heat_low: "Feld für Anzahl der Antworten leicht hervorheben, wenn das Verhältnis von „Gefällt mir“-Angaben zu Antworten diesen Wert übersteigt." - topic_post_like_heat_medium: "Feld für Anzahl der Antworten mäßig hervorheben, wenn das Verhältnis von „Gefällt mir“-Angaben zu Antworten diesen Wert übersteigt." - topic_post_like_heat_high: "Feld für Anzahl der Antworten stark hervorheben, wenn das Verhältnis von „Gefällt mir“-Angaben zu Antworten diesen Wert übersteigt." + topic_post_like_heat_low: "Feld für Anzahl der Antworten leicht hervorheben, wenn das Verhältnis von Likes zu Antworten diesen Wert übersteigt." + topic_post_like_heat_medium: "Feld für Anzahl der Antworten mäßig hervorheben, wenn das Verhältnis von Likes zu Antworten diesen Wert übersteigt." + topic_post_like_heat_high: "Feld für Anzahl der Antworten stark hervorheben, wenn das Verhältnis von Likes zu Antworten diesen Wert übersteigt." faq_url: "Vollständige URL zu einer externen FAQ, welche du gerne verwenden möchtest." tos_url: "Die vollständige URL zu deinen extern gehosteten Nutzungsbedingungen, sofern vorhanden." privacy_policy_url: "Die vollständige URL zu deinen extern gehosteten Datenschutzrichtlinien, sofern vorhanden." newuser_spam_host_threshold: "Wie häufig kann ein neuer Benutzer Links der gleichen Domain innerhalb ihrer `newuser_spam_host_threshold` Beiträge schreiben, ohne als Spam eingeordnet zu werden." white_listed_spam_host_domains: "Liste von Domänen, die keinem Spam-Host Test unterzogen werden. Neue Benutzer werden niemals daran gehindert, Beiträge mit Links zu diesen Domains zu erstellen." - staff_like_weight: "Zusätzlicher Gewichtungsfaktor für \"Gefällt mir\" Wertungen von Mitarbeitern." + staff_like_weight: "Zusätzlicher Gewichtungsfaktor für Likes vom Team." topic_view_duration_hours: "Alle (n) Stunden einen neuen Themenaufruf pro IP/Benutzer zählen." user_profile_view_duration_hours: "Alle (n) Stunden einen neuen Profilaufruf pro IP/Benutzer zählen." levenshtein_distance_spammer_emails: "E-Mail-Adressen, die sich um so viele Zeichen unterscheiden, werden beim Abgleich mit Adressen der Spammer dennoch als identisch betrachtet." - max_new_accounts_per_registration_ip: "Keine neuen Registrierungen von einer IP-Adresse annehmen, zu der bereits (n) Benutzerkonten mit Vertrauensstufe 0 (und keine davon sind Mitarbeiter oder mit Vertrauensstufe 2 oder höher) gehören." + max_new_accounts_per_registration_ip: "Keine neuen Registrierungen von einer IP-Adresse annehmen, wenn bereits (n) Benutzerkonten mit Vertrauensstufe 0 zugeordnet sind (und keines davon ein Team-Mitglied ist oder eine Vertrauensstufe 2 oder höher hat)." min_ban_entries_for_roll_up: "Ein Klick auf den \"Zusammenfassen\" Knopf führt (N) oder mehr Sperren zu einer einzelnen Subnetz-Sperre zusammen." max_age_unmatched_emails: "Gefilterte E-Mail-Adressen nach (N) Tagen ohne Treffer löschen." max_age_unmatched_ips: "Gefilterte IP-Adressen nach (N) Tagen ohne Treffer löschen." @@ -1079,9 +1134,12 @@ de: reset_bounce_score_after_days: "Bounce-Score automatisch nach X Tagen zurücksetzen." attachment_content_type_blacklist: "Liste der Schlüsselwörter für die Ablehnung von Anhängen basierend auf Inhaltstypen." attachment_filename_blacklist: "Liste der Schlüsselwörter für die Ablehnung von Anhängen basierend auf dem Dateinamen." + enable_forwarded_emails: "[Beta] Erlaube Benutzern, ein Thema zu erstellen, indem sie eine E-Mail weiterleiten." + always_show_trimmed_content: "Immer den gekürzten Teil von eingehenden E-Mails anzeigen. WARNUNG: lässt möglicherweise E-Mail-Adressen erkennen." manual_polling_enabled: "Eingehende E-Mails über die API für E-Mail-Antworten annehmen." pop3_polling_enabled: "E-Mail-Antworten über POP3 abholen." pop3_polling_ssl: "SSL für die Verbindung zum POP3-Server verwenden. (Empfohlen)" + pop3_polling_openssl_verify: "Überprüfe TLS-Server-Zertifikat (Standard: aktiviert)" pop3_polling_period_mins: "Intervall in Minuten zum Abholen neuer E-Mails vom POP3-Konto. HINWEIS: benötigt Neustart." pop3_polling_port: "Port für die POP3-Abfrage." pop3_polling_host: "Hostname für die POP3-Abfrage." @@ -1104,19 +1162,27 @@ de: allow_animated_thumbnails: "Generiert animierte Vorschaubilder aus animierten GIFs." default_avatars: "URLs zu Bildern, die als Standard-Profilbilder verwendet werden sollen, bis neue Benutzer ihr Profilbild geändert haben." automatically_download_gravatars: "Profilbilder von Gravatar herunterladen, wenn ein Benutzer sich registriert oder seine E-Mail-Adresse ändert." + digest_topics: "Die maximale Anzahl von Top-Beiträgen, die in der E-Mail-Zusammenfassung angezeigt werden sollen." + digest_posts: "Die maximale Anzahl von beliebten Beiträgen, die in der E-Mail-Zusammenfassung angezeigt werden sollen." + digest_other_topics: "Die maximale Anzahl von Themen, die in dem Bereich 'Neues in Themen und Kategorien, denen du folgst' in der E-Mail-Zusammenfassung angezeigt werden sollen." digest_min_excerpt_length: "Minimale Zeichenlänge für Auszüge von Beiträgen in der E-Mail-Zusammenfassung." delete_digest_email_after_days: "Unterdrücke E-Mail-Zusammenfassungen für Benutzer, die länger als (n) Tage nicht auf der Site gesehen wurden." digest_suppress_categories: "Unterdrücke diese Kategorien in E-Mail-Zusammenfassungen." disable_digest_emails: "Deaktiviere E-Mail-Zusammenfassungen für alle Benutzer." + email_accent_bg_color: "Die Hervorhebungsfarbe, die als Hintergrund mancher Elemente in HTML-E-Mails verwendet wird. Gib’ einen Namen ('red') oder einen Hex-Wert ('#FF000') der Farbe an." + email_accent_fg_color: "Gib’ einen Namen ('white') oder einen Hex-Wert ('#FFFFFF') der Farbe an." + email_link_color: "Die Farbe von Links in HTML-Mails. Gib’ einen Namen ('blue') oder einen Hex-Wert ('#0000FF') der Farbe an." detect_custom_avatars: "Aktiviere diese Option, um zu überprüfen, ob Benutzer eigene Profilbilder hochgeladen haben." max_daily_gravatar_crawls: "Wie oft pro Tag Discourse höchstens auf Gravatar nach benuterdefinierten Avataren suchen soll." public_user_custom_fields: "Liste selbst definierter Profil-Felder, die öffentlich angezeigt werden dürfen." - staff_user_custom_fields: "Liste selbst definierter Profil-Felder, die Mitarbeitern angezeigt werden dürfen." + staff_user_custom_fields: "Eine Liste von benutzerdefinierten Benutzerfeldern, die vom Team eingesehen werden können." enable_user_directory: "Aktiviert ein durchsuchbares Benutzerverzeichnis" + enable_group_directory: "Aktiviert ein durchsuchbares Gruppenverzeichnis" allow_anonymous_posting: "Benutzern erlauben, in den anonymen Modus zu wechseln" anonymous_posting_min_trust_level: "Vertrauensstufe, ab der das Schreiben anonymer Beiträge erlaubt ist" anonymous_account_duration_minutes: "Erzeuge alle (n) Minuten ein neues anonymes Konto je Benutzer, um die Anonymität der virtuellen anonymen Benutzer zu gewährleisten. Beispiel: Ein Wert von 600 sorgt dafür, dass ein neues anonymes Konto erzeugt wird, wenn ein Benutzer in den anonymen Modus wechselt UND mindestens 600 Minuten seit der letzten anonymen Nachricht dieses Benutzers vergangen sind." hide_user_profiles_from_public: "Deaktiviert Benutzerkarten, Benutzerprofile und das Benutzerverzeichnis für anonyme Benutzer." + user_website_domains_whitelist: "Benutzer-Webseiten werden mit diesen Domains abgeglichen. Mehrere Domains können mit einem Pipe-Symbol „|“ getrennt angegeben werden." allow_profile_backgrounds: "Erlaubt es Benutzern, Profilhintergründe hochzuladen." sequential_replies_threshold: "Anzahl an Beiträgen die ein Benutzer machen muss, um benachrichtigt zu werden, dass er zu viele aufeinanderfolgende Antworten schreibt." enable_mobile_theme: "Mobilgeräte verwenden eine mobile Darstellung mit der Möglichkeit zur vollständigen Site zu wechseln. Deaktiviere diese Option, wenn du ein eigenes Full-Responsive-Stylesheet verwenden möchtest." @@ -1129,6 +1195,7 @@ de: automatically_unpin_topics: "Themen automatisch loslösen, wenn ein Benutzer das Ende erreicht." read_time_word_count: "Wörter pro Minute für die Berechnung der geschätzten Lesezeit." topic_page_title_includes_category: "Name des Themas enthält den Namen der Kategorie." + native_app_install_banner: "Wiederkehrende Benutzer dazu einladen, die native Discourse-App herunterzuladen." max_prints_per_hour_per_user: "Maximale Anzahl von Aufrufen der Druckansicht pro Nutzer pro Stunde (0 zum deaktivieren)" full_name_required: "Der voller Name wird für das Benutzerprofil benötigt." enable_names: "Zeigt den vollen Namen eines Benutzers auf dem Profil, der Benutzerkarte und in E-Mails an. Wenn deaktiviert wird der volle Name überall ausgeblendet." @@ -1146,15 +1213,15 @@ de: embed_username_key_from_feed: "Schlüssel, um Discourse-Benutzernamen aus Feed zu ermitteln." embed_title_scrubber: "Regulärer Ausdruck (Regex) um eingebettete Titel zu bereinigen" embed_truncate: "Kürze die eingebetteten Beiträge" + allowed_href_schemes: "URI-Schemas, die in Links zusätzlich zu http und https erlaubt sind." embed_post_limit: "Maximale Anzahl der Beiträge die eingebettet werden." embed_username_required: "Der Benutzername ist für die Themenerstellung notwendig" embed_whitelist_selector: "CSS-Selektor für Elemente, die in Einbettungen erlaubt sind." embed_blacklist_selector: "CSS-Selektor für Elemente, die in Einbettungen entfernt werden." notify_about_flags_after: "Wenn es Meldungen gibt, die nicht nach dieser Anzahl von Stunden behandelt wurden, sende eine E-Mail an contact_email. Setze dies auf 0 um es zu deaktivieren." - enable_cdn_js_debugging: "Ermöglicht die Anzeige vollständiger Fehler auf /logs, indem alle eingebetteten JavaScripts Cross-Origin Zugriffsberechtigungen erhalten." show_create_topics_notice: "Administratoren eine Warnmeldung anzeigen, wenn im Forum weniger als 5 öffentlich sichtbare Themen existieren." delete_drafts_older_than_n_days: Lösche Entwürfe, die mehr als (n) Tage alt sind. - bootstrap_mode_min_users: "Erforderliche Benutzeranzahl, um den Bootstrapping-Modus zu deaktivieren (0 = ausgeschaltet)" + bootstrap_mode_min_users: "Erforderliche Benutzeranzahl, um den Starthilfe-Modus zu deaktivieren (0 = ausgeschaltet)" vacuum_db_days: "Führe VACUUM ANALYZE aus, um Datenbankspeicher nach Migrationen zurückzuerhalten (0 um zu deaktivieren)" prevent_anons_from_downloading_files: "Nichtangemeldeten Benutzern das Herunterladen von Anhängen verbieten. WARNUNG: dies verhindert auch das Herunterladen jeglicher Ressourcen für Website-Anpassungen, die als Anhänge gespeichert wurden." slug_generation_method: "Gib eine Methode an, wie Kürzel in URLs generiert werden sollen. 'encoded' verwendet einen Prozent-Encodierten String, bei 'none' wird kein Kürzel verwendet." @@ -1180,17 +1247,21 @@ de: default_email_in_reply_to: "Standardmäßig einen Anriss des Beitrags, auf den geantwortet wurde, in E-Mails einfügen." default_other_new_topic_duration_minutes: "Zeit wie lange ein Thema als \"Neu\" markiert werden soll. " default_other_auto_track_topics_after_msecs: "Zeit bevor ein Thema automatisch verfolg wird. " + default_other_notification_level_when_replying: "Globales Standard-Benachrichtigungslevel, wenn ein Benutzer auf ein Thema antwortet." default_other_external_links_in_new_tab: "Öffne externe Links standardmäßig in einem neuen Tab." default_other_enable_quoting: "Aktiviere standardmäßig die Zitat-Antwort Funktion für hervorgehobenen Text." default_other_dynamic_favicon: "Zeige standardmäßig die Anzahl von neuen und geänderten Beiträgen im Browser-Symbol an." default_other_disable_jump_reply: "Springe standardmäßig nicht zum neusten Beitrag des Users, wenn dieser geantwortet hat." - default_other_like_notification_frequency: "Benutzer standardmäßig bei „Gefällt mir“-Angaben benachrichtigen." + default_other_like_notification_frequency: "Benutzer standardmäßig bei erhaltenen Likes benachrichtigen." default_topics_automatic_unpin: "Standardmäßig Themen automatisch loslösen, wenn ein Benutzer das Ende erreicht." default_categories_watching: "Liste der standardmäßig beobachteten Kategorien." default_categories_tracking: "Liste der standardmäßig gefolgten Kategorien." default_categories_muted: "Liste der standardmäßig stummgeschalteten Kategorien." + default_categories_watching_first_post: "Liste von Kategorien, in denen der erste Beiträge in jedem neuen Thema automatisch beobachtet wird." max_user_api_reqs_per_day: "Maximale Zahl der Benutzer API Anfragen pro Schlüssel pro Tag" max_user_api_reqs_per_minute: "Maximale Zahl der Benutzer API Anfragen pro Schlüssel pro Minute" + allow_user_api_keys: "Erlaube das Generieren von Benutzer-API-Schlüsseln" + allow_user_api_key_scopes: "Liste erlaubter Scopes für Benutzer-API-Schlüssel" max_api_keys_per_user: "Maximale Zahl der Benutzer API Anfragen pro Benutzer" min_trust_level_for_user_api_key: "Erforderliche Vertrauensstufe für die Generierung von Benutzer API Schlüsseln" allowed_user_api_auth_redirects: "Erlaubte URL für die Authentifizierungs-Umleitung von Benutzer API Schlüsseln" @@ -1204,12 +1275,13 @@ de: max_tags_in_filter_list: "Maximale Anzahl von Schlagwörtern, die in einer Dropdown-Liste angezeigt werden. Es werden die am häufigsten verwendeten Schlagwörter angezeigt." tags_sort_alphabetically: "Zeige Schlagwörter in alphabetischer Reihenfolge. Standardmäßig werden sie nach Beliebtheit sortiert." tag_style: "Visueller Stil für Schlagwort-Abzeichen." - staff_tags: "Eine Liste von Schlagwörtern, die nur von Mitarbeitern angewendet werden können." + staff_tags: "Eine Liste von Schlagwörtern, die nur von Team-Mitgliedern angewendet werden können." min_trust_level_to_tag_topics: "Minimale Vertrauensstufe, um Schlagwörter zu Themen hinzuzufügen." suppress_overlapping_tags_in_list: "Schlagwort nicht zeigen, wenn es genau so im Thementitel vorkommt" - remove_muted_tags_from_latest: "Zeige in der Liste der neusten Beiträge keine Themen mit stummgeschalteten Schlagwörtern." + remove_muted_tags_from_latest: "Zeige in der Liste der neuesten Beiträge keine Themen mit stummgeschalteten Schlagwörtern." company_short_name: "Firmenname (kurz)" company_full_name: "Firmenname (komplett)" + company_domain: "Firmendomain" errors: invalid_email: "Ungültige E-Mail-Ad­res­se" invalid_username: "Es gibt keinen Benutzer mit diesem Benutzernamen." @@ -1232,6 +1304,7 @@ de: reply_by_email_address_is_empty: "Du musst 'reply by email address' definieren, bevor per E-Mail antworten aktiviert wird" email_polling_disabled: "Du musst entweder manuelles oder POP3 polling aktivieren, bevor per E-Mail antworten aktiviert wird" user_locale_not_enabled: "Du musst zuerst 'allow user locale' aktivieren bevor du dies aktivierst" + invalid_regex: "Regulärer Ausdruck ist ungültig oder nicht erlaubt." search: within_post: "#%{post_number} von %{username}" types: @@ -1302,10 +1375,10 @@ de: other: "Dieses Thema wurde automatisch %{count} Minuten nach der letzten Antwort geschlossen. Es sind keine neuen Nachrichten mehr erlaubt." autoclosed_disabled: "Dieses Thema ist nun offen. Neue Beiträge werden angenommen." autoclosed_disabled_lastpost: "Dieses Thema ist jetzt geöffnet. Neue Antworten sind erlaubt." - pinned_enabled: "Dieses Thema ist nun angepinnt. In seiner Kategorie wird es nun oben aufgelistet, solange der Pin nicht von einem Mitarbeiter gelöst wird, oder nicht jeder Benutzer selbst den Pin löst." - pinned_disabled: "Dieses Thema ist nun nicht mehr angepinnt. In seiner Kategorie wird es nicht länger oben aufgelistet." - pinned_globally_enabled: "Dieses Thema ist nun global angepinnt. Es wird sowohl in seiner Kategorie als auch in allen anderen Themenlisten oben aufgelistet, solange der Pin nicht von einem Mitarbeiter gelöst wird, oder nicht jeder Benutzer selbst den Pin löst." - pinned_globally_disabled: "Dieses Thema ist nun nicht mehr angepinnt. In seiner Kategorie wird es nicht länger oben aufgelistet." + pinned_enabled: "Dieses Thema ist nun angeheftet. In seiner Kategorie wird es nun oben erscheinen, bis es vom Team oder von einzelnen Benutzer losgelöst wird." + pinned_disabled: "Dieses Thema ist nun nicht mehr angeheftet. In seiner Kategorie erscheint es nicht länger oben." + pinned_globally_enabled: "Dieses Thema ist nun global angeheftet. Es wird in seiner Kategorie und in allen Themenlisten oben erscheinen, bis es vom Team oder von einzelnen Benutzer losgelöst wird." + pinned_globally_disabled: "Dieses Thema ist nicht mehr angeheftet. In seiner Kategorie wird es nicht länger oben erscheinen." visible_enabled: "Das Thema ist jetzt gelistet. Es wird in der Themenliste angezeigt." visible_disabled: "Das Thema ist jetzt ungelistet. Es wird nicht mehr in der Themenliste angezeigt. Dieses Thema kann nur mit einem direkten Link erreicht werden." login: @@ -1324,6 +1397,7 @@ de: something_already_taken: "Etwas ist schief gelaufen. Möglicherweise ist der Benutzername bereits registriert. Probiere den 'Passwort vergessen'-Link." omniauth_error: "Entschuldigung, bei der Autorisierung deines Kontos ist ein Fehler aufgetreten. Hast du die Autorisierung möglicherweise abgelehnt?" omniauth_error_unknown: "Während des Anmeldens ist etwas schief gelaufen, bitte versuche es noch einmal." + authenticator_error_no_valid_email: "E-Mail-Adressen mit %{account} sind nicht erlaubt. Du musst möglicherweise dein Konto mit einer anderen E-Mail-Adresse einrichten." new_registrations_disabled: "Leider können derzeit keine neuen Konten registriert werden." password_too_long: "Passwörter sind beschränkt auf 200 Zeichen." email_too_long: "Die von dir eingegebene E-Mail-Adresse ist zu lang. Der Teil vor dem @ darf maximal 254 Zeichen lang sein und Domain-Namen maximal 253 Zeichen." @@ -1334,6 +1408,8 @@ de: user: no_accounts_associated: "Es sind keine Konten zugeordnet" deactivated: "Deaktiviert wegen zu vielen unzustellbaren E-Mails an '%{email}'." + deactivated_by_staff: "Deaktiviert vom Team" + activated_by_staff: "Aktiviert vom Team" username: short: "muss mindestens %{min} Zeichen lang sein" long: "darf nicht länger als %{max} Zeichen sein" @@ -1351,6 +1427,8 @@ de: ip_address: blocked: "Neue Registrierungen sind von deiner IP-Adresse aus nicht erlaubt." max_new_accounts_per_registration_ip: "Weitere Registrierungen sind von deiner IP-Adresse aus nicht gestattet (limit erreicht). Kontaktiere einen Administrator mit dem Problem damit er dir helfen kann." + website: + domain_not_allowed: "Webseite ist ungültig. Erlaubte Domains sind: %{domains}" flags_reminder: flags_were_submitted: one: "Vor über einer Stunde wurden Meldungen gesendet. Bitte überprüfe sie." @@ -1359,6 +1437,7 @@ de: one: "Eine Markierung wartet auf Bearbeitung" other: "%{count} Markierungen warten auf Bearbeitung" unsubscribe_mailer: + title: "Abbestellung von E-Mail-Updates" subject_template: "Bitte bestätige, dass du keine E-Mail-Updates mehr von %{site_title} erhalten möchtest." text_body_template: | Jemand (wahrscheinlich du?) hat angefragt, keine E-Mail-Updates mehr von %{site_domain_name} auf dieser Adresse zu erhalten. @@ -1369,6 +1448,7 @@ de: Wenn du weiterhin E-Mail-Updates erhalten möchtest, dann kannst du diese E-Mail ignorieren. invite_mailer: + title: "Einladung zu einem Thema" subject_template: "%{invitee_name} hat dich zum Thema '%{topic_title}' auf %{site_domain_name} eingeladen" text_body_template: | %{invitee_name} hat dich dazu eingeladen, an einer Diskussion teilzunehmen: @@ -1385,6 +1465,7 @@ de: Dies ist eine Einladung von einem vertrauenswürdigen Benutzer. Du kannst deshalb sofort auf die Diskussion antworten. custom_invite_mailer: + title: "Einladung zu einem Thema (mit Nachricht)" subject_template: "%{invitee_name} hat dich eingeladen zu '%{topic_title}' auf %{site_domain_name}" text_body_template: | %{invitee_name} hat dich zu einer Diskussion eingeladen @@ -1407,38 +1488,45 @@ de: Diese Einladung stammt von einem vertrauenswürdigen Benutzer, daher kannst du direkt auf die Diskussion antworten. invite_forum_mailer: + title: "Einladung zur Teilnahme" subject_template: "%{invitee_name} hat dich eingeladen %{site_domain_name} beizutreten" text_body_template: | - %{invitee_name} hat dich zur Teilnahme eingeladen + %{invitee_name} hat dich eingeladen, > **%{site_title}** > > %{site_description} - Wenn du Interesse hast, klicke auf den nachfolgenden Link: + beizutreten. + + Wenn du interessiert bist, folge dem folgenden Link: %{invite_link} - Diese Einladung stammt von einem vertrauenswürdigen Benutzer. Daher wird für dich automatisch ein Konto erstellt. + Die Einladung kommt von einem vertrauenswürdigen Benutzer. Daher wird für dich beim Betreten automatisch ein Benutzerkonto mit dieser E-Mail-Adresse erstellt. custom_invite_forum_mailer: + title: "Einladung zur Teilnahme" subject_template: "%{invitee_name} hat dich eingeladen %{site_domain_name} beizutreten" text_body_template: | - %{invitee_name} hat dich zur Teilnahme eingeladen + %{invitee_name} hat dich eingeladen, > **%{site_title}** > > %{site_description} + beizutreten. + Nachricht von %{invitee_name}: %{user_custom_message} - Wenn du Interesse hast, klicke auf den nachfolgenden Link: + Wenn du interessiert bist, folge einfach diesem Link: %{invite_link} - Diese Einladung stammt von einem vertrauenswürdigen Benutzer. Daher wird für dich automatisch ein Konto erstellt. + Diese Einladung kommt von einem vertrauenswürdigen Benutzer. Daher wird für dich beim Betreten automatisch ein Benutzerkonto mit dieser E-Mail-Adresse erstellt. invite_password_instructions: + title: "Passwort festlegen" subject_template: "Lege ein Passwort für dein %{site_name}-Konto fest" text_body_template: | Schön, dass du die Einladung zu %{site_name} angenommen hast -- Willkommen! @@ -1448,6 +1536,7 @@ de: (Wenn der Link abgelaufen ist, wähle "Passwort vergessen" aus, wenn du dich mit deiner E-Mail-Adresse einloggen möchtest.) test_mailer: + title: "Test-E-Mail" subject_template: "[%{site_name}] Test der E-Mail-Zustellbarkeit" text_body_template: | Dies ist eine Test-E-Mail von @@ -1491,6 +1580,7 @@ de: [mj]: https://www.mailjet.com/pricing [mt]: http://www.mail-tester.com/ new_version_mailer: + title: "Neue Version" subject_template: "[%{site_name}] Neue Discourse Version, Update verfügbar" text_body_template: | Hurra, eine neue Version von [Discourse](http://www.discourse.org) ist verfügbar! @@ -1504,6 +1594,7 @@ de: - Besuche [meta.discourse.org](https://meta.discourse.org) für Neuigkeiten, Diskussionen und Support für Discourse new_version_mailer_with_notes: + title: "Neue Version mit Versionshinweisen" subject_template: "[%{site_name}] Update verfügbar" text_body_template: | Hurra, eine neue Version von [Discourse](http://www.discourse.org) ist verfügbar! @@ -1521,6 +1612,7 @@ de: %{notes} queued_posts_reminder: + title: "Erinnerung an Freischaltung wartender Beiträge" subject_template: one: "[%{site_name}] %{count} auf Freischaltung wartender Beitrag." other: "[%{site_name}] %{count} auf Freischaltung wartende Beiträge." @@ -1542,6 +1634,7 @@ de: temporarily_closed_due_to_flags: "Dieses Thema ist vorrübergehend geschlossen. Mehrere User haben dieses Thema gemeldet. " system_messages: post_hidden: + title: "Benachrichtigung: Beitrag versteckt" subject_template: "Beitrag versteckt wegen Community-Meldungen" text_body_template: | Hallo, @@ -1554,82 +1647,16 @@ de: Mehrere Community-Mitglieder haben diesen Beitrag gemeldet, bevor er ausgeblendet wurde, daher prüfe bitte, wie du deinen Beitrag möglicherweise anpassen kannst, um ihr Feedback zu berücksichtigen. **Du kannst deinen Beitrag nach %{edit_delay} Minuten bearbeiten und er wird automatisch wieder sichtbar.** - Wenn der Beitrag jedoch von der Community erneut ausgeblendet wurde, wird er ausgeblendet bleiben, bis sich ein Mitarbeiter darum kümmert – und möglicherweise gibt es weitere Maßnahmen, einschließlich einer möglichen Sperrung deines Kontos. + Wenn der Beitrag jedoch von der Community erneut ausgeblendet wurde, wird er ausgeblendet bleiben, bis sich das Team darum kümmert – und möglicherweise gibt es weitere Maßnahmen, einschließlich einer möglichen Sperrung deines Kontos. Weitre Hinweise findest du in unseren [Community-Richtlinien](%{base_url}/guidelines). usage_tips: text_body_template: | - In dieser Nachricht findest du einige Tipps um dir den Einstieg zu erleichtern. + Ein paar Tipps für die ersten Schritte als neuer Benutzer [findest du in diesem Blog-Eintrag](http://blog.discourse.org/2016/12/discourse-new-user-tips-and-tricks/). - ## Einfach weiterscrollen - - Es gibt keine Knöpfe um auf die nächste Seite zu gelangen oder Seitenzahlen – um mehr zu lesen, **scrolle einfach weiter nach unten!** - - Wenn neue Beiträge eingebracht werden, erscheinen diese automatisch - ohne dass die Seite neu geladen werden muss. - - ## Wo bin ich? - - - Um die Suche, das Menü oder deine Profilseite aufzurufen, benutze die **Schaltflächen oben rechts**. - - - Das Klicken auf den Titel eines Themas bringt dich zu **deinem nächsten ungelesenen Beitrag** in diesem Thema. Um stattdessen ganz oben oder ganz unten einzusteigen, klicke die Beitragszahl oder das Datum der letzten Antwort. - - - - - Während des Lesens eines Themas kannst du mit Hilfe dessen Titels zum ↑ Anfang springen. Die grüne Fortschrittsanzeige unten rechts erlaubt weitere Navigation. - - - - Du kannst auch ? auf der Tastatur drücken, für eine Liste super-schneller Tastaturkürzel. - - ## Wie antworte ich? - - - Um auf das gesamte Thema zu antworten, benutze den Antwortknopf ganz unten auf der Seite. - - - Um auf einen bestimmten Beitrag zu antworten kannst du die Schaltfläche direkt unter diesem Beitrag verwenden. - - Das Zitieren eines Beitrags ist mit dem Auswählen des gewünschten Texts gefolgt von einem beliebigen Antwortknopf möglich. - - - - Um jemanden in auf deinen Beitrag aufmerksam zu machen, erwähne ihn durch das Eingeben von `@` gefolgt von seinem Benutzernamen. - - - - - Um die Diskussion in eine andere Richtung zu lenken, die beiden Themen aber zu verknüpfen, benutze bitte Mit verknüpftem Thema antworten` rechts des passenden Beitrags. - - - ## Was kann ich sonst noch machen? - - Unter jedem Beitrag befinden sich Aktionsbuttons: - - - - Um zu Zeigen, dass dir der Beitrag gefallen hat, drücke den **❤**-Knopf. Wenn du ein Problem mit einem Beitrag feststellst, mach den Autor oder die Moderatoren durch **Melden** darauf aufmerksam. - - Du kannst außerdem einen Link zu einem Beitrag **teilen**, oder ihn zum Merken mit einem [**Lesezeichen**](/my/activity/bookmarks) versehen. - - ## Wer schreibt mir? - - Wenn jemand auf deinen Beitrag antwortet, deinen Beitrag zitiert, oder deinen `@Benutzernamen` erwähnt, zeigt sich sofort eine Zahl oben rechts auf der Seite. Dort kannst du auch deine **Benachrichtigungen** abrufen. - - - - Um das Verpassen von Antworten (und Nachrichten) musst du dir keine Sorgen machen – diese werden dir 3 Minuten nach ihrer Erstellung automatisch per E-Mail zugeschickt, für den Fall dass du nicht online sein solltest wenn sie ankommen. - - ## Wann sind Themen neu? - - Standardmäßig gelten alle Themen die weniger als zwei Tage alt sind als neu. Alle Themen an denen du teilgenommen hast (durch Antwort, eigene Erstellung, oder längeres Lesen) werden automatisch verfolgt. - - Neben diesen Themen wirst du blaue Indikatoren finden, die dich über die Aktualität informieren: - - - - Du kannst den Informationsmodus eines Themas mit dem Menü am Ende anpassen (auch für ganze Kategorien möglich). Du kannst damit Stummstellen, Verfolgen oder Benachrichtigungen über alles Neue erhalten. Um diese Funktion zu konfigurieren, gehe in [deine Einstellungen](/my/preferences). - - ## Warum kann ich manche Sachen nicht machen? - - Aus Sicherheitsgründen sind neue Benutzer etwas eingeschränkt in ihren Befugnissen. Mit dem Teilnehmen hier und dem Gewinnen von Vertrauen werden diese Einschränkungen automatisch aufgehoben. Wenn du eine höhere Vertrauensstufe erlangst, kannst du außerdem ein wenig beim Moderieren helfen. + Während du hier teilnimmst, werden wir dich kennenlernen und die vorübergehenden Einschränkungen für neue Benutzer werden aufgehoben. Über die Zeit, erreichst du [Vertrauensstufen](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924), die spezielle Fähigkeiten beinhalten, um die Community gemeinsam zu verwalten. welcome_user: + title: "Willkommen: Benutzer" subject_template: "Willkommen bei %{site_name}!" text_body_template: | Danke fürs Anmelden bei %{site_name}, sei willkommen! @@ -1640,30 +1667,28 @@ de: Viel Spaß! - (Wenn du als neuer Benutzer unter vier Augen mit einem unserer [Mitarbeiter](%{base_url}/about) reden möchtest, antworte einfach auf diese Nachricht.) + (Wenn du als neuer Benutzer unter vier Augen mit einem unserer [Team-Mitglieder](%{base_url}/about) reden möchtest, antworte einfach auf diese Nachricht.) welcome_invite: + title: "Willkommen: Einladung" subject_template: "Willkommen bei %{site_name}!" text_body_template: | - Danke, dass du der Einladung zu %{site_name} gefolgt bist -- herzlich willkommen! + Danke, dass du die Einladung zu %{site_name} angenommen hast -- und willkommen! - Wir haben automatisch das Konto **%{username}** für dich angelegt und du bist bereits angemeldet, aber du kannst deinen Benutzernamen in [deinem Profil][prefs] noch ändern. + - Wir haben dieses neue Konto **%{username}** für dich erstellt. Ändere deinen Namen oder dein Passwort, indem du [dein Benutzerprofil][prefs] aufrufst. - Um dich später wieder anzumelden: - - 1. Verwende bitte **dieselbe E-Mail-Adresse, unter der du die ursprüngliche Einladung erhalten hast**. Ansonsten können wir nicht erkennen, dass du es bist! - - 2. Wähle ein eindeutiges Passwort in [deinem Profil][prefs] und verwende dieses, um dich anzumelden. + - Wenn du dich anmeldest, **verwende immer die gleiche E-Mail-Adresse wie von deiner ursprünglichen Einladung** – sonst wissen wir nicht, ob du es wirklich bist! %{new_user_tips} - Wir wünschen uns ein stets [zivilisiertes Verhalten in unserer Community](%{base_url}/guidelines). + Wir glauben an [zivilisiertes Verhalten in unserer Community(%{base_url}/guidelines) zu jeder Zeit. - Viel Spaß! + Genieße deinen Aufenthalt! - (Wenn du als neuer Benutzer unter vier Augen mit einem unserer [Mitarbeiter](%{base_url}/about) reden möchtest, antworte einfach auf diese Nachricht.) + (Wenn du als neuer Benutzer mit [Team-mitgliedern](%{base_url}/about) kommunizieren möchtest, antworte einfach auf diese Nachricht.) [prefs]: %{user_preferences_url} backup_succeeded: + title: "Backup erfolgreich" subject_template: "Sicherung erfolgreich abgeschlossen" text_body_template: | Backup erfolgreich erstellt. @@ -1676,6 +1701,7 @@ de: %{logs} ``` backup_failed: + title: "Backup fehlgeschlagen" subject_template: "Sicherung fehlgeschlagen" text_body_template: | Die Sicherung ist fehlgeschlagen. @@ -1686,6 +1712,7 @@ de: %{logs} ``` restore_succeeded: + title: "Wiederherstellung erfolgreich" subject_template: "Wiederherstellung erfolgreich abgeschlossen" text_body_template: | Die Wiederherstellung war erfolgreich. @@ -1696,6 +1723,7 @@ de: %{logs} ``` restore_failed: + title: "Wiederherstellung fehlgeschlagen" subject_template: "Wiederherstellung fehlgeschlagen" text_body_template: | Die Wiederherstellung ist fehlgeschlagen. @@ -1706,9 +1734,11 @@ de: %{logs} ``` bulk_invite_succeeded: + title: "Masseneinladung erfolgreich" subject_template: "Masseneinladung von Benutzern erfolgreich verarbeitet" text_body_template: "Deine Masseneinladung von Benutzern wurde erfolgreich verarbeitet, insgesamt wurden %{sent} Einladungen per E-Mail verschickt." bulk_invite_failed: + title: "Masseneinladung fehlgeschlagen" subject_template: "Bei der Verarbeitung der Masseneinladung von Benutzern sind Fehler aufgetreten" text_body_template: | Deine Masseneinladungs-Datei wurde verarbeitet, insgesamt wurden %{sent} Einladungen verschickt und dabei traten %{failed} Fehler auf. @@ -1719,6 +1749,7 @@ de: %{logs} ``` csv_export_succeeded: + title: "CSV-Export erfolgreich" subject_template: "Datenexport abgeschlossen" text_body_template: | Deine Daten wurden erfolgreich exportiert! :dvd: @@ -1727,51 +1758,60 @@ de: Dieser Download-Link ist für die nächsten 48 Stunden gültig. csv_export_failed: + title: "CSV-Export fehlgeschlagen" subject_template: "Datenexport fehlgeschlagen" - text_body_template: "Entschuldigung, beim Exportieren deiner Daten trat ein Fehler auf. Bitte kontaktiere einen Mitarbeiter oder sieh in die Logs." + text_body_template: "Entschuldigung, beim Exportieren deiner Daten trat ein Fehler auf. Bitte kontaktiere ein Team-Mitglied oder überprüfe die Logdateien." email_reject_insufficient_trust_level: + title: "E-Mail abgelehnt weil Vertrauensstufe unzureichend" subject_template: "[%{site_name}] E-Mail-Problem -- Unzureichende Vertrauensstufe" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (Titel: %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (Titel: %{former_title}) konnte nicht zugestellt werden. - Du hast nicht die notwendige Vertrauensstufe, um neue Themen über diese E-Mail-Adresse zu erstellen. Wenn du glaubst, dass das ein Irrtum ist, dann kontaktiere einen Mitarbeiter. + Du hast nicht die notwendige Vertrauensstufe, um neue Themen über diese E-Mail-Adresse zu erstellen. Wenn du glaubst, dass das ein Irrtum ist, dann kontaktiere ein Team-Mitglied. email_reject_user_not_found: + title: "E-Mail abgelehnt weil Benutzer nicht gefunden" subject_template: "[%{site_name}] E-Mail-Problem -- Benutzer nicht gefunden" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) konnte nicht zugestellt werden. - Deine Antwort wurde von einer unbekannten E-Mail-Adresse gesendet. Probiere eine andere Absende-Adresse oder wende dich an einen Mitarbeiter. + Deine Antwort wurde von einer unbekannten E-Mail-Adresse gesendet. Probiere eine andere Absende-Adresse oder wende dich an ein Team-Mitglied. email_reject_screened_email: + title: "E-Mail abgelehnt weil E-Mail-Adresse gesperrt" subject_template: "[%{site_name}] E-Mail-Problem -- Blockiertee E-Mail-Adresse" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) konnte nicht zugestellt werden. - Deine Antwort wurde von einer blockierten E-Mail-Adresse gesendet. Probiere eine andere Absende-Adresse oder wende dich an einen Mitarbeiter. + Deine Antwort wurde von einer blockierten E-Mail-Adresse gesendet. Probiere eine andere Absende-Adresse oder wende dich an ein Team-Mitglied. email_reject_inactive_user: + title: "E-Mail abgelehnt weil Benutzer inaktiv" subject_template: "[%{site_name}] E-Mail-Problem -- Inaktiver Benutzer" text_body_template: | Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. Dein mit dieser E-Mail-Adresse verbundenes Benutzerkonto ist nicht aktiviert. Bitte aktiviere dein Konto bevor du E-Mails sendest. email_reject_blocked_user: + title: "E-Mail abgelehnt weil Benutzer gesperrt" subject_template: "[%{site_name}] E-Mail-Problem -- Blockierter Benutzer" text_body_template: | Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. Dein mit dieser E-Mail-Adresse verbundenes Konto wurde blockiert. email_reject_reply_user_not_matching: + title: "E-Mail abgelehnt weil E-Mail-Adresse abweichend" subject_template: "[%{site_name}] E-Mail-Problem -- Unerwartete Antwort-Adresse" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) konnte nicht zugestellt werden. - Deine Antwort wurde von einer anderen E-Mail-Adresse versandt als wir erwartet haben, weshalb wir nicht sicher wissen ob das die gleiche Person ist. Probiere eine andere Absende-Adresse oder wende dich an einen Mitarbeiter. + Deine Antwort wurde von einer anderen E-Mail-Adresse versandt als wir erwartet haben, weshalb wir nicht sicher wissen ob das die gleiche Person ist. Probiere eine andere Absende-Adresse oder wende dich an ein Team-Mitglied. email_reject_no_account: + title: "E-Mail abgelehnt weil unbekanntes Konto" subject_template: "[%{site_name}] E-Mail-Problem -- Unbekanntes Konto" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) konnte nicht zugestellt werden. - Wir konnten kein Konto finden, das zu deiner E-Mail-Adresse passt. Probiere eine andere Absende-Adresse oder wende dich an einen Mitarbeiter. + Wir konnten kein Konto finden, das zu deiner E-Mail-Adresse passt. Probiere eine andere Absende-Adresse oder wende dich an ein Team-Mitglied. email_reject_empty: + title: "E-Mail abgelehnt weil kein Inhalt" subject_template: "[%{site_name}] E-Mail-Problem -- Kein Inhalt" text_body_template: | Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. @@ -1780,30 +1820,35 @@ de: Wenn du diese E-Mail bekommst, obwohl deine E-Mail Inhalt enthalten hat, versuche es erneut mit weniger Formatierung. email_reject_parsing: + title: "E-Mail abgelehnt weil Inhalt nicht erkannt" subject_template: "[%{site_name}] E-Mail-Problem -- Inhalt nicht erkannt" text_body_template: | Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. Wir konnten keinen Inhalt in deiner E-Mail feststellen. **Versichere dich, dass du den Inhalt oberhalb der erhaltenen E-Mail eingegeben hast** -- Eingebettete Antworten können wir nicht verarbeiten. email_reject_invalid_access: + title: "E-Mail abgelehnt weil nicht erlaubt" subject_template: "[%{site_name}] E-Mail-Problem -- Nicht erlaubt" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (Titel: %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) konnte nicht zugestellt werden. - Du hast nicht die notwendigen Zugriffsrechte, um neue Themen in dieser Kategorie zu erstellen. Wenn du glaubst, dass das ein Irrtum ist, dann kontaktiere einen Mitarbeiter. + Du hast nicht die notwendigen Zugriffsrechte, um neue Themen in dieser Kategorie zu erstellen. Wenn du glaubst, dass das ein Irrtum ist, dann kontaktiere ein Team-Mitglied. email_reject_strangers_not_allowed: + title: "E-Mail abgelehnt weil Zugriff nicht erlaubt" subject_template: "[%{site_name}] E-Mail-Problem -- Zugriff nicht erlaubt" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (Titel: %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) konnte nicht zugestellt werden. - Die Kategorie, an die du die E-Mail geschickt hast, erlaubt nur Antworten von Benutzern mit gültigem Konto und von bekannten E-Mail-Adressen. Wenn du glaubst, dass das ein Irrtum ist, dann kontaktiere einen Mitarbeiter. + Die Kategorie, an die du die E-Mail geschickt hast, erlaubt nur Antworten von Benutzern mit gültigem Konto und von bekannten E-Mail-Adressen. Wenn du glaubst, dass das ein Irrtum ist, dann kontaktiere ein Team-Mitglied. email_reject_invalid_post: + title: "E-Mail abgelehnt weil ungültiger Beitrag" subject_template: "[%{site_name}] E-Mail-Problem -- Ungültiger Beitrag" text_body_template: | Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. Mögliche Gründe sind komplizierte Formatierung und zu lange oder kurze Nachrichten. Bitte versuche es erneut oder schreibe deinen Beitrag über die Website. email_reject_invalid_post_specified: + title: "E-Mail abgelehnt weil ungültiger Beitrag" subject_template: "[%{site_name}] E-Mail-Problem -- Ungültiger Beitrag" text_body_template: | Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. @@ -1814,42 +1859,49 @@ de: Bitte versuch es erneut, wenn du das Problem beheben kannst. email_reject_invalid_post_action: + title: "E-Mail abgelehnt weil fehlerhafte Beitragsaktion" subject_template: "[%{site_name}] E-Mail-Problem -- Fehlerhafte Beitragsaktion" text_body_template: | Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. Die Beitragsaktion wurde nicht erkannt. Bitte versuche es erneut oder erstelle deinen Beitrag auf der Website, wenn der Fehler weiterhin auftritt. email_reject_reply_key: + title: "E-Mail abgelehnt weil unbekannter Antwort-Schlüssel" subject_template: "[%{site_name}] E-Mail-Problem -- Unbekannter Antwort-Schlüssel" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) konnte nicht zugestellt werden. - Der angegebene Antwort-Schlüssel ist ungültig oder unbekannt. Wir wissen daher nicht auf welchen Beitrag diese E-Mail antwortet. Bitte kontaktiere einen Mitarbeiter. + Der angegebene Antwort-Schlüssel ist ungültig oder unbekannt. Wir wissen daher nicht auf welchen Beitrag diese E-Mail antwortet. Bitte kontaktiere ein Team-Mitglied. email_reject_bad_destination_address: + title: "E-Mail abgelehnt weil unbekannte Empfänger-Adresse" subject_template: "[%{site_name}] E-Mail Problem -- Unbekannte An:-Adresse" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) konnte nicht zugestellt werden. - Keine der Ziel-E-Mail-Adressen wurde erkannt. Bitte stell sicher, dass du die E-Mail an die richtige Adresse schickst, die dir von unseren Mitarbeitern genannt wurde. + Keine der Ziel-E-Mail-Adressen wurde erkannt. Bitte stelle sicher, dass du die E-Mail an die richtige Adresse schickst, die dir von unserem Team genannt wurde. email_reject_topic_not_found: + title: "E-Mail abgelehnt weil Thema nicht gefunden" subject_template: "[%{site_name}] E-Mail-Problem -- Thema nicht gefunden" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) konnte nicht zugestellt werden. - Das Thema, auf das du geantwortet hast, existiert nicht mehr -- vielleicht wurde es gelöscht? Wenn du glaubst, dass dies ein Irrtum ist, nimm Bitte Kontakt mit einem Mitarbeiter auf. + Das Thema, auf das du geantwortet hast, existiert nicht mehr -- vielleicht wurde es gelöscht? Wenn du glaubst, dass dies ein Irrtum ist, nimm Bitte Kontakt mit einem Team-Mitglied auf. email_reject_topic_closed: + title: "E-Mail abgelehnt weil Thema geschlossen" subject_template: "[%{site_name}] E-Mail-Problem -- Thema geschlossen" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) konnte nicht zugestellt werden. - Das Thema, auf das du geantwortet hast, ist derzeit geschlossen und akzeptiert keine Antworten mehr. Wenn du glaubst, dass dies ein Irrtum ist, nimm bitte Kontakt mit einem Mitarbeiter auf. + Das Thema, auf das du geantwortet hast, ist derzeit geschlossen und akzeptiert keine Antworten mehr. Wenn du glaubst, dass dies ein Irrtum ist, nimm bitte Kontakt mit einem Team-Mitglied auf. email_reject_auto_generated: + title: "E-Mail abgelehnt weil automatisch generierte Antwort" subject_template: "[%{site_name}] E-Mail-Problem -- Automatisch erzeugte Antwort" text_body_template: | - Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) hat nicht funktioniert. + Entschuldige, aber deine E-Mail-Nachricht an %{destination} (betitelt mit %{former_title}) konnte nicht zugestellt werden. - Deine E-Mail wurde als „automatisch generiert“ markiert, was bedeutet, dass sie automatisch von einem Computer erstellt wurde statt von einem Menschen getippt; wir können diese Arten von E-Mails nicht akzeptieren. Wenn du glaubst, dass dies ein Irrtum ist, nimm bitte Kontakt mit einem Mitarbeiter auf. + Deine E-Mail wurde als „automatisch generiert“ markiert, was bedeutet, dass sie automatisch von einem Computer erstellt wurde statt von einem Menschen getippt; wir können diese Arten von E-Mails nicht akzeptieren. Wenn du glaubst, dass dies ein Irrtum ist, nimm bitte Kontakt mit einem Team-Mitglied auf. email_error_notification: + title: "Benachrichtigung zu E-Mail-POP-Authentifizierungsfehler" subject_template: "[%{site_name}] E-Mail-Problem -- POP-Authentifizierungsfehler" text_body_template: | Leider gab es einen Authentifizierungsfehler beim Abrufen von E-Mails vom POP-Server. @@ -1858,36 +1910,40 @@ de: Wenn es eine Weboberfläche für das POP-E-Mail-Postfach gibt, möchtest du dich eventuell dort anmelden und die Einstellungen überprüfen. too_many_spam_flags: + title: "Neues Konto gesperrt wegen zu viel Spam" subject_template: "Neues Konto gesperrt" text_body_template: | Hallo, dies ist eine automatisch erzeugte Nachricht von %{site_name}, um dich darüber zu informieren, dass deine Beitrage vorübergehend ausgeblendet wurden, weil sie von der Community gemeldet wurden. - Als Vorsichtsmaßnahme wurde dein neues Konto für das Erstellen neuer Antworten und Themen gesperrt, bis ein Mitarbeiter dein Konto überprüfen kann. Wir bitten um Entschuldigung für die Unannehmlichkeiten. + Als Vorsichtsmaßnahme wurde dein neues Konto für das Erstellen neuer Antworten und Themen gesperrt, bis ein Team-Mitglied dein Konto überprüfen kann. Wir bitten um Entschuldigung für die Unannehmlichkeiten. Weitere Hinweise findest du in unseren [Community-Richtlinien](%{base_url}/guidelines). too_many_tl3_flags: + title: "E-Mail abgelehnt wegen Meldungen durch Vertrauensstufe 3" subject_template: "Neues Konto gesperrt" text_body_template: | Hallo, dies ist eine automatisch erzeugte Nachricht von %{site_name}, um dich darüber zu informieren, dass dein Konto aufgrund einer großen Anzahl von Community-Meldungen vorübergehend gesperrt wurde. - Als Vorsichtsmaßnahme wurde dein neues Konto für das Erstellen neuer Antworten und Themen gesperrt, bis ein Mitarbeiter dein Konto überprüfen kann. Wir bitten um Entschuldigung für die Unannehmlichkeiten. + Als Vorsichtsmaßnahme wurde dein neues Konto für das Erstellen neuer Antworten und Themen gesperrt, bis ein Team-Mitglied dein Konto überprüfen kann. Wir bitten um Entschuldigung für die Unannehmlichkeiten. Weitere Hinweise findest du in unseren [Community-Richtlinien](%{base_url}/guidelines). blocked_by_staff: + title: "Gesperrt vom Team" subject_template: "Konto vorübergehend gesperrt" text_body_template: | Hallo, dies ist eine automatisch erzeugte Nachricht von %{site_name}, um dich darüber zu informieren, dass als Vorsichtsmaßnahme vorübergehend gesperrt wurde. - Bitte schaue dir weiter Inhalte an, aber du kannst zunächst keine Antworten oder Themen erstellen, [Mitarbeiter](%{base_url}/about) deine aktuellesten Beiträge überprüft hat. Wir bitten um Entschuldigung für die Unannemlichkeiten. + Bitte schaue dir weiter Inhalte an, aber du kannst zunächst keine Antworten oder Themen erstellen, bis ein [Team-Mitglied](%{base_url}/about) deine aktuellesten Beiträge überprüft hat. Wir bitten um Entschuldigung für die Unannemlichkeiten. Weitere Hinweise findest du in unseren [Community-Richtlinien](%{base_url}/guidelines). user_automatically_blocked: + title: "Benutzer automatisch gesperrt" subject_template: "Neuer Benutzer %{username} gesperrt wegen Community-Meldungen" text_body_template: | Dies ist eine automatisierte Nachricht. @@ -1898,6 +1954,7 @@ de: Der Schwellenwert kann über die Einstellung `block_new_user` geändert werden. spam_post_blocked: + title: "Spam-Beitrag gesperrt" subject_template: "Beiträge des neuen Benutzers ${username} wegen mehrfacher Verlinkung blockiert" text_body_template: | Dies ist eine automatisierte Nachricht. @@ -1908,14 +1965,16 @@ de: Dies kann über die Einstellungen `newuser_spam_host_threshold` und `white_listed_spam_host_domains` geändert werden. unblocked: + title: "Entsperrt" subject_template: "Konto nicht mehr gesperrt" text_body_template: | Hallo, - dies ist eine automatische Nachricht von %{site_name}, um dich darüber zu informieren, dass dein Benutzerkonto nach der Überprüfung durch einen Mitarbeiter nicht mehr länger gesperrt ist. + dies ist eine automatische Nachricht von %{site_name}, um dich darüber zu informieren, dass dein Benutzerkonto nach der Überprüfung durch ein Team-Mitglied nicht mehr länger gesperrt ist. Du kannst nun wieder neue Antworten und Themen erstellen. Vielen Dank für deine Geduld. pending_users_reminder: + title: "Benachrichtigung: Benutzer warten auf Freigabe" subject_template: one: "Es gibt einen nicht freigegebenen Benutzer" other: "Es gibt %{count} nicht freigegebene Benutzer" @@ -1924,9 +1983,11 @@ de: [Bitte bewerte diese im Administrationsbereich](/admin/users/list/pending). download_remote_images_disabled: + title: "Download von externen Bildern deaktiviert" subject_template: "Download von externen Bildern deaktiviert" text_body_template: "Die `download_remote_images_to_local` Einstellung wurde deaktiviert, da das Speicherplatz Limit von `download_remote_images_threshold` erreicht wurde." dashboard_problems: + title: "Dashboard-Probleme" subject_template: "Probleme wurden festgestellt" text_body_template: | Es wurden Probleme in deinem Admin-Dashboard gemeldet. @@ -1978,6 +2039,7 @@ de: > %{site_title} -- %{site_description} user_invited_to_private_message_pm: + title: "Benutzer zu Nachricht eingeladen" subject_template: "[%{site_name}] %{username} hat dich zur Unterhaltung '%{topic_title}' eingeladen" text_body_template: | %{header_instructions} @@ -1986,6 +2048,7 @@ de: %{respond_instructions} user_invited_to_private_message_pm_staged: + title: "Benutzer zu Nachricht eingeladen (automatisch)" subject_template: "[%{site_name}] %{username} hat dich zur Unterhaltung '%{topic_title}' eingeladen" text_body_template: | %{header_instructions} @@ -1994,6 +2057,7 @@ de: %{respond_instructions} user_invited_to_topic: + title: "Benutzer zu Thema eingeladen" subject_template: "[%{site_name}] %{username} hat dich zum Thema '%{topic_title}' eingeladen" text_body_template: | %{header_instructions} @@ -2002,6 +2066,7 @@ de: %{respond_instructions} user_replied: + title: "Benutzer hat auf Beitrag geantwortet" subject_template: "[%{site_name}] %{username} hat auf deinen Beitrag '%{topic_title}' geantwortet" text_body_template: | %{header_instructions} @@ -2012,6 +2077,7 @@ de: %{respond_instructions} user_replied_pm: + title: "Benutzer hat auf Nachricht geantwortet" subject_template: "[%{site_name}] [PN] %{topic_title}" text_body_template: | %{header_instructions} @@ -2022,6 +2088,7 @@ de: %{respond_instructions} user_quoted: + title: "Benutzer wurde zitiert" subject_template: "[%{site_name}] %{username} hat Dich in '%{topic_title}' zitiert" text_body_template: | %{header_instructions} @@ -2032,6 +2099,7 @@ de: %{respond_instructions} user_linked: + title: "Benutzer wurde verlinkt" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2042,6 +2110,7 @@ de: %{respond_instructions} user_mentioned: + title: "Benutzer wurde erwähnt" subject_template: "[%{site_name}] %{username} hat Dich in '%{topic_title}' erwähnt" text_body_template: | %{header_instructions} @@ -2052,6 +2121,7 @@ de: %{respond_instructions} user_group_mentioned: + title: "Gruppe wurde erwähnt" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2062,6 +2132,7 @@ de: %{respond_instructions} user_posted: + title: "Benutzer hat in Thema geantwortet" subject_template: "[%{site_name}] %{subject_prefix}%{username} hat auf '%{topic_title}' geantwortet" text_body_template: | %{header_instructions} @@ -2072,6 +2143,7 @@ de: %{respond_instructions} user_watching_first_post: + title: "Benutzer folgt erstem Beitrag" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2082,6 +2154,7 @@ de: %{respond_instructions} user_posted_pm: + title: "Benutzer hat Nachricht geschrieben" subject_template: "[%{site_name}] [PN] %{topic_title}" text_body_template: | %{header_instructions} @@ -2092,16 +2165,31 @@ de: %{respond_instructions} user_posted_pm_staged: + title: "Benutzer hat Nachricht geschrieben (automatisch)" subject_template: "%{optional_re}%{topic_title}" text_body_template: |2 %{message} digest: why: "Eine kurze Zusammenfassung von %{site_link} seit deinem letzten Besuch am %{last_seen_at}" + since_last_visit: "Seit deinem letzten Besuch" + new_topics: "Neue Themen" + unread_messages: "Ungelesene Nachrichten" + unread_notifications: "Ungelesene Benachrichtigungen" + liked_received: "Erhaltene Likes" + new_posts: "Neue Beiträge" + new_users: "Neue Benutzer" + popular_topics: "Beliebte Themen" + follow_topic: "Diesem Thema folgen" + join_the_discussion: "Mehr lesen" + popular_posts: "Beliebte Beiträge" + from_topic_label: "Von" + more_new: "Neu für dich" subject_template: "Zusammenfassung für [%{site_name}]" unsubscribe: "Diese Zusammenfassung wird von %{site_link} gesendet, wenn wir dich einige Zeit lang nicht gesehen haben. Abbestellen unter %{unsubscribe_link}." click_here: "klicke hier" from: "Zusammenfassung für %{site_name}" + preheader: "Eine kurze Zusammenfassung seit deinem letzten Besuch am %{last_seen_at}" mailing_list: why: "Alle Aktivitäten auf %{site_link} am %{date}" subject_template: "[%{site_name}] Zusammenfassung für den %{date}" @@ -2112,6 +2200,7 @@ de: view_this_topic: "Thema anzeigen" back_to_top: "Zurück nach oben" forgot_password: + title: "Passwort vergessen" subject_template: "[%{site_name}] Passwort zurückgesetzt" text_body_template: | Jemand hat darum gebeten, dein Passwort auf [%{site_name}](%{base_url}) zurückzusetzen. @@ -2121,6 +2210,7 @@ de: Andernfalls besuche den folgenden Link, um ein neues Passwort zu wählen: %{base_url}/users/password-reset/%{email_token} set_password: + title: "Passwort setzen" subject_template: "[%{site_name}] Setze Passwort" text_body_template: | Jemand hat ein Passwort für dein Konto auf [%{site_name}](%{base_url}) beantragt. Alternativ kannst du dich mit einem unterstützen Online-Service (Google, Facebook, etc), der mit dieser validierten E-Mail-Adresse verknüpft ist, anmelden. @@ -2130,6 +2220,7 @@ de: Klicke auf den folgenden Link, um ein Passwort auszuwählen: %{base_url}/users/password-reset/%{email_token} admin_login: + title: "Administrator-Anmeldung" subject_template: "[%{site_name}] Anmeldung" text_body_template: | Jemand hat versucht sich in dein Konto auf [%{site_name}](%{base_url}) anzumelden. @@ -2139,6 +2230,7 @@ de: Klicke den folgenden Link, um dich anzumelden: %{base_url}/users/admin-login/%{email_token} account_created: + title: "Konto erstellt" subject_template: "[%{site_name}] Dein neues Konto" text_body_template: | Ein neues Konto wurde für dich auf %{site_name} erstellt. @@ -2146,12 +2238,14 @@ de: Klicke auf den folgenden Link, um ein Passwort für dein neues Konto festzulegen: %{base_url}/users/password-reset/%{email_token} confirm_new_email: + title: "E-Mail-Adresse bestätigen (an neue)" subject_template: "[%{site_name}] Bestätige deine neue E-Mail-Adresse" text_body_template: | Um deine E-Mail-Adresse für %{site_name} zu bestätigen, klicke auf den folgenden Link: %{base_url}/users/authorize-email/%{email_token} confirm_old_email: + title: "E-Mail-Adresse bestätigen (an alte)" subject_template: "[%{site_name}] Bestätige deine aktuelle E-Mail-Adresse" text_body_template: | Bevor wir deine E-Mail-Adresse ändern können, müssen wir dich bitten zu bestätigen, dass du das E-Mail-Konto kontrollierst. Nach diesem Schritt, werden wir dich bitten die neue E-Mail-Adresse zu bestätigen. @@ -2160,19 +2254,21 @@ de: %{base_url}/users/authorize-email/%{email_token} notify_old_email: + title: "Benachrichtigung an alte E-Mail-Adresse" subject_template: "[%{site_name}] Deine E-Mail-Adresse wurde geändert" text_body_template: | - Dies ist eine automatisierte Nachricht, um eine Änderung deiner E-Mail-Adresse für %{site_name} mitzuteilen. Bitte kontaktiere einen Mitarbeiter, wenn du von einem Fehler ausgehst. + Dies ist eine automatisierte Nachricht, um eine Änderung deiner E-Mail-Adresse für %{site_name} mitzuteilen. Bitte kontaktiere ein Team-Mitglied, wenn du von einem Fehler ausgehst. Deine E-Mail-Adresse wurde geändert zu: %{new_email} signup_after_approval: + title: "Konto bestätigen nach Genehmigung" subject_template: "You've been approved on %{site_name}!" text_body_template: | Willkommen bei %{site_name}! - Einer unserer Mitarbeiter hat dein Benutzerkonto bei %{site_name} genehmigt. + Einer unserer Team-Mitglieder hat dein Benutzerkonto bei %{site_name} genehmigt. Klicke auf den folgenden Link, um dein neues Konto zu bestätigen und zu aktivieren: %{base_url}/users/activate-account/%{email_token} @@ -2185,8 +2281,9 @@ de: Viel Spaß! - (Wenn du als neuer Benutzer unter vier Augen mit einem unserer [Mitarbeiter](%{base_url}/about) reden möchtest, antworte einfach auf diese Nachricht.) + (Wenn du als neuer Benutzer unter vier Augen mit einem unserer [Team-Mitglieder](%{base_url}/about) reden möchtest, antworte einfach auf diese Nachricht.) signup: + title: "Konto bestätigen nach Anmeldung" subject_template: "[%{site_name}] Bestätige deinen neuen Account" text_body_template: | Willkommen bei %{site_name}! @@ -2220,6 +2317,7 @@ de: too_large: "Entschuldigung, die Datei die du hochladen möchtest, ist zu groß (maximale Dateigröße ist %{max_size_kb}KB)." images: too_large: "Entschuldigung, das Bild das du hochladen möchtest, ist zu groß (maximale Dateigröße ist %{max_size_kb}KB). Bitte verkleinere es und versuche es erneut." + larger_than_x_megapixels: "Entschuldige, das Bild, das du versucht hast hochzuladen, ist zu groß (maximale Auflösung beträgt %{max_image_megapixels} Megapixel), bitte verkleinere es und versuche es erneut." size_not_found: "Entschuldige, aber wir konnten die Größe des Bildes nicht bestimmen. Vielleicht ist das Bild defekt?" avatar: missing: "Hoppla, wir können kein Profilbild für diese E-Mail-Adresse finden. Kannst du versuchen es erneut hochzuladen?" @@ -2244,6 +2342,7 @@ de: message_to_blank: "message.to ist leer" text_part_body_blank: "text_part.body ist leer" body_blank: "body ist leer" + no_echo_mailing_list_mode: "Mailinglisten-Benachrichtigung für eigene Beiträge deaktivieren" color_schemes: base_theme_name: "Basis" about: "Über uns" @@ -2348,7 +2447,7 @@ de: ## [Betrieben von Euch](#power) - Diese Site wird von euren [freundlichen Mitarbeitern](/about) und *euch* betrieben, der Community. Wenn du irgendwelche weiteren Fragen dazu hast, wie Dinge hier funktionieren sollten, öffne ein neues Thema in der Kategorie [Feedback zur Site](/c/site-feedback) und lass es uns diskutieren! Wenn es ein kritisches oder dringendes Problem gibt, dass nicht mit einem Meta-Thema oder einer Meldung behandelt werden kann, kontaktiere uns über die [Mitarbeiter-Seite](/about). + Diese Site wird von eurem [freundlichen Team](/about) und *euch* betrieben, der Community. Wenn du irgendwelche weiteren Fragen dazu hast, wie Dinge hier funktionieren sollten, öffne ein neues Thema in der Kategorie [Feedback zur Site](/c/site-feedback) und lass es uns diskutieren! Wenn es ein kritisches oder dringendes Problem gibt, dass nicht mit einem Meta-Thema oder einer Meldung behandelt werden kann, kontaktiere uns über die [Team-Seite](/about). @@ -2483,7 +2582,7 @@ de: ## [17. Schadloshaltung](#17) - Du stimmst zu, %{company_name}, Vertragspartnern und Lizenznehmern, und jeweiligen Vorstandsmitglieder, Amtsträger, Mitarbeiter und Vertreter gegen jegliche Haftungsfälle, Ansprüche und Ausgaben schadlos zu halten, einschließlich angemessener Anwaltskosten, die den schadlos gehaltenen Parteien im Zusammenhang mit jeglichen Ansprüchen entstehen, die sich aus jeglicher Verletzung dieser Vereinbarung ergeben. + Du stimmst zu, %{company_name}, Vertragspartnern und Lizenznehmern, und jeweiligen Vorstandsmitglieder, Amtsträger, Team-Mitglieder und Vertreter gegen jegliche Haftungsfälle, Ansprüche und Ausgaben schadlos zu halten, einschließlich angemessener Anwaltskosten, die den schadlos gehaltenen Parteien im Zusammenhang mit jeglichen Ansprüchen entstehen, die sich aus jeglicher Verletzung dieser Vereinbarung ergeben. @@ -2591,24 +2690,24 @@ de: Das Abzeichen wird verliehen, wenn du Vertrauensstufe 1 erreichst. Danke, dass du eine Weile dageblieben bist und ein paar Themen gelesen hast um zu lernen, worum es in unserer Community geht. Für dich gelten die Einschränkungen für neue Nutzer nicht mehr und du hast nun Zugriff auf alle wichtigen Funktionen, beispielsweise persönliche Nachrichten, die Melden-Funktion, das Bearbeiten von Wiki-Beiträgen und die Fähigkeit, mehrere Bilder und Links in Beiträgen zu verwenden. member: name: Mitglied - description: Ermöglicht das Versenden von Einladungen, Gruppen-Nachrichten, mehr „Gefällt mir“-Angaben + description: Ermöglicht das Versenden von Einladungen, Gruppen-Nachrichten, mehr Likes long_description: | - Das Abzeichen wird verliehen, wenn du Vertrauensstufe 2 erreichst. Danke, dass du einige Wochen mitgemacht hast, um unserer Community richtig beizutreten. Du kannst nun von deiner Benutzerseite und einzelnen Themen-Seiten aus Einladungen versenden, Gruppennachrichten erstellen und ein paar mehr „Gefällt mir“-Angaben pro Tag vergeben. + Das Abzeichen wird verliehen, wenn du Vertrauensstufe 2 erreichst. Danke, dass du einige Wochen mitgemacht hast, um unserer Community richtig beizutreten. Du kannst nun von deiner Benutzerseite und einzelnen Themen-Seiten aus Einladungen versenden, Gruppennachrichten erstellen und ein paar mehr Likes pro Tag vergeben. regular: name: Stammgast - description: Ermöglicht verschieben und umbenennen von Themen, veröffentlichen verfolgbarer Links, Aktivierung der Wiki-Funktion, mehr „Gefällt mir“-Angaben + description: Ermöglicht verschieben und umbenennen von Themen, veröffentlichen verfolgbarer Links, Aktivierung der Wiki-Funktion, mehr Likes long_description: | - Das Abzeichen wird verliehen, wenn du Vertrauensstufe 3 erreichst. Danke, dass du in unserer Community über mehrere Monate ein Stammgast gewesen bist. Du bist nun einer unserer aktivsten Leser und ein zuverlässiges Mitglied, das diese Community großartig macht. Du kannst nun Themen neu kategorisieren und umbenennen, mächtigere Spam-Meldungen nutzen, eine private Lounge nutzen und kannst viel mehr „Gefällt mir“-Angaben pro Tag erhalten. + Das Abzeichen wird verliehen, wenn du Vertrauensstufe 3 erreichst. Danke, dass du in unserer Community über mehrere Monate ein Stammgast gewesen bist. Du bist nun einer unserer aktivsten Leser und ein zuverlässiges Mitglied, das diese Community großartig macht. Du kannst nun Themen neu kategorisieren und umbenennen, mächtigere Spam-Meldungen nutzen, eine private Lounge nutzen und kannst viel mehr Likes pro Tag erhalten. leader: name: Anführer - description: Ermöglicht bearbeiten aller Beiträge, anheften, schließen, archivieren, aufteilen und zusammenfügen von Themen, mehr „Gefällt mir“-Angaben + description: Ermöglicht bearbeiten aller Beiträge, anheften, schließen, archivieren, aufteilen und zusammenfügen von Themen, mehr Likes long_description: | - Das Abzeichen wird verliehen, wenn du Vertrauensstufe 4 erreichst. Du bist ein von den Mitarbeitern ausgezeichneter Anführer und hast durch deine Aktivität und Worte ein positives Beispiel für die übrige Community abgegeben. Du kannst alle Beiträge bearbeiten, Moderator-Aktionen wie das Anpinnen, Schließen, Unsichtbar machen, Archivieren, Teilen und Zusammenführen von Themen durchführen und viel mehr „Gefällt mir“-Angaben pro Tag vergeben. + Das Abzeichen wird verliehen, wenn du Vertrauensstufe 4 erreichst. Du bist ein vom Team ausgezeichneter Anführer und hast durch deine Aktivität und Worte ein positives Beispiel für die übrige Community abgegeben. Du kannst alle Beiträge bearbeiten, Moderator-Aktionen wie das Anheften, Schließen, Unsichtbar machen, Archivieren, Teilen und Zusammenführen von Themen durchführen und viel mehr Likes pro Tag vergeben. welcome: name: Willkommen - description: Hat eine „Gefällt mir“-Angabe erhalten + description: Hat ein Like erhalten long_description: | - Das Abzeichen wird verliehen, wenn du die erster „Gefällt mir“-Angabe auf einen Beitrag erhältst. Glückwunsch, du hast einen Beitrag geschrieben, den deine Mitbenutzer interessant, cool oder nützlich finden! + Das Abzeichen wird verliehen, wenn du den ersten Like auf einen Beitrag erhältst. Glückwunsch, du hast einen Beitrag geschrieben, den deine Mitbenutzer interessant, cool oder nützlich finden! autobiographer: name: Autobiograf description: Hat Benutzerprofil ausgefüllt @@ -2621,34 +2720,34 @@ de: Das Abzeichen wird verliehen, wenn du ein Jahr lang Mitglied warst und in diesem Jahr mindestens einen Beitrag geschrieben hast. Danke, dass du hier geblieben bist und zu unserer Community beiträgst. Ohne dich könnten wir dies nicht tun. nice_post: name: Schöne Antwort - description: Hat 10 „Gefällt mir“-Angaben für eine Antwort erhalten + description: Hat 10 Likes für eine Antwort erhalten long_description: | - Das Abzeichen wird verliehen, wenn eine deiner Antworten 10 „Gefällt mir“-Angaben erhält. Deine Antwort hat die Community wirklich beeindruckt und dabei geholfen, den Dialog voranzubringen! + Das Abzeichen wird verliehen, wenn eine deiner Antworten 10 Likes erhält. Deine Antwort hat die Community wirklich beeindruckt und dabei geholfen, den Dialog voranzubringen! good_post: name: Gute Antwort - description: Hat 25 „Gefällt mir“-Angaben für eine Antwort erhalten + description: Hat 25 Likes für eine Antwort erhalten long_description: | - Das Abzeichen wird verliehen, wenn eine deiner Antworten 25 „Gefällt mir“-Angaben erhält. Deine Antwort war außergewöhnlich und hat den Dialog sehr viel besser für alle gemacht! + Das Abzeichen wird verliehen, wenn eine deiner Antworten 25 Likes erhält. Deine Antwort war außergewöhnlich und hat den Dialog sehr viel besser für alle gemacht! great_post: name: Großartige Antwort - description: Hat 50 „Gefällt mir“-Angaben für eine Antwort erhalten + description: Hat 50 Likes für eine Antwort erhalten long_description: | - Das Abzeichen wird verliehen, wenn eine deiner Antworten 50 „Gefällt mir“-Angaben erhält. Wow! Deine Antwort war inspierend, faszinierend, wahnsinnig komisch oder aufschlussreich und die Community hat sie geliebt. + Das Abzeichen wird verliehen, wenn eine deiner Antworten 50 Likes erhält. Wow! Deine Antwort war inspirierend, faszinierend, wahnsinnig komisch oder aufschlussreich und die Community hat sie geliebt. nice_topic: name: Schönes Thema - description: Hat 10 „Gefällt mir“-Angaben für ein Thema erhalten + description: Hat 10 Likes für ein Thema erhalten long_description: | - Das Abzeichen wird verliehen, wenn eines deiner Themen 10 „Gefällt mir“-Angaben erhält. Hey, du hast einen interessanten Dialog begonnen, den die Community genossen hat! + Das Abzeichen wird verliehen, wenn eines deiner Themen 10 Likes erhält. Hey, du hast einen interessanten Dialog begonnen, den die Community genossen hat! good_topic: name: Gutes Thema - description: Hat 25 „Gefällt mir“-Angaben für ein Thema erhalten + description: Hat 25 Likes für ein Thema erhalten long_description: | - Das Abzeichen wird verliehen, wenn eines deiner Themen 25 „Gefällt mir“-Angaben erhält. Du hast einen lebendigen Dialog gestartet, die die Community versammelt hat und von dieser geliebt wurde! + Das Abzeichen wird verliehen, wenn eines deiner Themen 25 Likes erhält. Du hast einen lebendigen Dialog gestartet, die die Community versammelt hat und von dieser geliebt wurde! great_topic: name: Großartiges Thema - description: Hat 50 „Gefällt mir“-Angaben für ein Thema erhalten + description: Hat 50 Likes für ein Thema erhalten long_description: | - Das Abzeichen wird verliehen, wenn eines deiner Themen 50 „Gefällt mir“-angaben erhält. Du hast einen faszinierenden Dialog losgetreten und die Community hat die daraus enstandene, dynamische Diskussion genossen! + Das Abzeichen wird verliehen, wenn eines deiner Themen 50 Likes erhält. Du hast einen faszinierenden Dialog losgetreten und die Community hat die daraus entstandene, dynamische Diskussion genossen! nice_share: name: Schön geteilt description: Hat einen Beitrag mit 25 Besuchern geteilt @@ -2665,7 +2764,7 @@ de: long_description: | Das Abzeichen wird verliehen, wenn du einen Link teilst, der von 1000 Besuchern angeklickt wurde. Wow! Du hast eine interessante Diskussion einer riesigen Leserschaft näher gebracht und unserer Community sehr geholfen zu wachsen! first_like: - name: Erste „Gefällt mir“-Angabe + name: Erster Like description: Hat einen Beitrag mit „Gefällt mir“ markiert long_description: | Das Abzeichen wird verliehen, wenn du das erste Mal auf die :heart:-Schaltfläche unter einem Beitrag klickst. Beiträge mit „Gefällt mir“ zu markieren, ist eine tolle Art, den Community-Kollegen wissen zu lassen, dass sein Beitrag interessant, nützlich, cool oder witzig war. Teile die Liebe! @@ -2731,49 +2830,49 @@ de: Das Abzeichen wird verliehen, wenn ein von dir geteilter Link 1000 Klicks erhält. Wow! Du hast einen Link geteilt, der den Dialog signifikant verbessert hat, indem es ein wesentliches Detail, Kontext und Information geliefert hat. Großartige Arbeit! appreciated: name: Geschätzt - description: Hat je eine „Gefällt mir“-Angabe auf 20 Beiträge erhalten. + description: Hat je ein Like auf 20 Beiträge erhalten long_description: | - Das Abzeichen wird verliehen, wenn du mindestens eine „Gefällt mir“-Angabe an 20 verschiedenen Beiträgen erhältst. Die Community genießt deine Beiträge zu den Dialogen! + Das Abzeichen wird verliehen, wenn du mindestens ein Like auf 20 verschiedenen Beiträgen erhältst. Die Community genießt deine Beiträge zu den Dialogen! respected: name: Respektiert - description: Hat je zwei „Gefällt mir“-Angaben auf 100 Beiträge erhalten. + description: Hat je zwei Likes auf 100 Beiträge erhalten long_description: | - Das Abzeichen wird verliehen, wenn 100 deiner Beiträge mindestens 2 „Gefällt mir“-Angaben erhalten. Die Community wächst und respektiert deine zahlreichen Beiträge zu den Dialogen! + Das Abzeichen wird verliehen, wenn 100 deiner Beiträge mindestens 2 Likes erhalten. Die Community wächst und respektiert deine zahlreichen Beiträge zu den Dialogen! admired: name: Bewundert - description: Hat je fünf „Gefällt mir“-Angaben auf 300 Beiträge erhalten. + description: Hat je fünf Likes auf 300 Beiträge erhalten long_description: | - Das Abzeichen wird verliehen, wenn 300 deiner Beiträge mindestens 5 „Gefällt mir“-Angaben erhalten. Wow! Die Community bewundert deine regelmäßigen, hochwertigen Beiträge zu den Dialogen! + Das Abzeichen wird verliehen, wenn 300 deiner Beiträge mindestens 5 Likes erhalten. Wow! Die Community bewundert deine regelmäßigen, hochwertigen Beiträge zu den Dialogen! out_of_love: name: Out of Love - description: Hat 50 „Gefällt mir“-Angaben an einem Tag vergeben + description: Hat 50 Likes an einem Tag vergeben long_description: | - Das Abzeichen wird verliehen, wenn du alle deiner 50 täglichen „Gefällt mir“-Angaben nutzt. Daran zu denken, sich einen Moment zu nehmen und die Beiträge mit „Gefällt mir“ zu markieren, die du genießt und schätzt, ermuntert deine Community-Kollegen, in der Zukunft noch großartigere Diskussionen zu erstellen. + Das Abzeichen wird verliehen, wenn du alle deiner 50 täglichen Likes nutzt. Daran zu denken, sich einen Moment zu nehmen und die Beiträge mit „Gefällt mir“ zu markieren, die du genießt und schätzt, ermuntert deine Community-Kollegen, in der Zukunft noch großartigere Diskussionen zu erstellen. higher_love: name: Higher Love - description: Hat fünfmal je 50 „Gefällt mir“-Angaben an einem Tag vergeben + description: Hat fünfmal je 50 Likes an einem Tag vergeben long_description: | - Das Abzeichen wird verliehen, wenn du fünf Tage lang alle deiner 50 täglichen „Gefällt mir“-Angaben nutzt. Danke, dass du dir die Zeit nimmst, die besten Dialoge täglich zu fördern! + Das Abzeichen wird verliehen, wenn du fünf Tage lang alle deiner 50 täglichen Likes nutzt. Danke, dass du dir die Zeit nimmst, die besten Dialoge täglich zu fördern! crazy_in_love: name: Crazy in Love - description: Hat 20-mal je 50 „Gefällt mir“-Angaben an einem Tag vergeben + description: Hat 20-mal je 50 Likes an einem Tag vergeben long_description: | - Das Abzeichen wird verliehen, wenn du 20 Tage lang alle deiner 50 täglichen „Gefällt mir“-Angaben nutzt. Wow! Du bist ein Vorbild für die regelmäßige Ermunterung deiner Community-Kollegen! + Das Abzeichen wird verliehen, wenn du 20 Tage lang alle deiner 50 täglichen Likes nutzt. Wow! Du bist ein Vorbild für die regelmäßige Ermunterung deiner Community-Kollegen! thank_you: name: Dankeschön - description: Hat 20 „Gefällt mir“-Angaben für Beiträge erhalten und 10 „Gefällt mir“-Angaben vergeben + description: Hat 20 Likes für Beiträge erhalten und 10 Likes vergeben long_description: | - Das Abzeichen wird verliehen, wenn du 20 Beiträge mit „Gefällt mir“-Angaben hast und im Gegenzug mindestens 10 „Gefällt mir“-Angaben vergeben hast. Wenn jemand deine Beiträge mit „Gefällt mir“ markiert, findest du auch die Zeit, mit „Gefällt mir“ zu markieren, was andere schreiben. + Das Abzeichen wird verliehen, wenn du 20 Beiträge mit Likes hast und im Gegenzug mindestens 10 Likes vergeben hast. Wenn jemand deine Beiträge mit „Gefällt mir“ markiert, findest du auch die Zeit, mit „Gefällt mir“ zu markieren, was andere schreiben. gives_back: name: Geben & Nehmen - description: Hat 100 „Gefällt mir“-Angaben für Beiträge erhalten und 100 „Gefällt mir“-Angaben vergeben + description: Hat 100 Likes für Beiträge erhalten und 100 Likes vergeben long_description: | - Das Abzeichen wird verliehen, wenn du 100 Beiträge mit „Gefällt mir“-Angaben hast und im Gegenzug mindestens 100 „Gefällt mir“-Angaben vergeben hast. Danke, dass du vorab bezahlst! + Das Abzeichen wird verliehen, wenn du bei 100 Beiträgen Likes erhalten und im Gegenzug mindestens 100 Likes vergeben hast. Danke, dass du vorab bezahlst! empathetic: name: Empathisch - description: Hat 500 „Gefällt mir“-Angaben für Beiträge erhalten und 1000 „Gefällt mir“-Angaben vergeben + description: Hat 500 Likes für Beiträge erhalten und 1000 Likes vergeben long_description: | - Das Abzeichen wird verliehen, wenn du 500 Beiträge mit „Gefällt mir“-Angaben hast und im Gegenzug mindestens 1000 „Gefällt mir“-Angaben vergeben hast. Wow! Du bist ein Vorbild von Großzügigkeit und gegenseitige Wertschätzung :two_hearts:. + Das Abzeichen wird verliehen, wenn du bei 500 Beiträgen Likes erhalten und im Gegenzug mindestens 1000 Likes vergeben hast. Wow! Du bist ein Vorbild von Großzügigkeit und gegenseitige Wertschätzung :two_hearts:. first_emoji: name: Erstes Emoji description: Hat ein Emoji in einem Beitrag verwendet @@ -2806,39 +2905,142 @@ de: user_exists: "Entschuldige, dieser Benutzer ist bereits eingeladen worden. Du kannst einen Benutzer nur einmal zu einem Thema einladen." tags: title: "Schlagwörter" - staff_tag_disallowed: "Das Schlagwort \"%{tag}\" kann nur von Mitarbeitern angewendet werden." - staff_tag_remove_disallowed: "Das Schlagwort \"%{tag}\" kann nur von Mitarbeitern entfernt werden." + staff_tag_disallowed: "Das Schlagwort \"%{tag}\" darf nur vom Team verwendet werden." + staff_tag_remove_disallowed: "Das Schlagwort \"%{tag}\" darf nur vom Team entfernt werden." rss_by_tag: "Themen mit dem Schlagwort %{tag}" + finish_installation: + congratulations: "Glückwunsch, du hast Discourse installiert!" + register: + button: "Registrieren" + title: "Administrator-Konto registrieren" + help: "registriere ein neues Konto, um loszulegen" + no_emails: "Leider wurden bei der Einrichtung keine Administrator-Mails festgelegt, sodass es schwer sein dürfte, die Konfiguration abzuschließen." + confirm_email: + title: "Bestätige deine E-Mail-Adresse" + message: "

    Wir haben eine Aktivierungsmail an %{email} gesendet. Bitte folge den Anweisungen in der E-Mail, um dein Konto zu aktivieren.

    Wenn diese nicht ankommst, stelle sicher, dass du E-Mail für dein Discourse richtig eingestellt hast und prüfe deinen Spamordner.

    " + resend_email: + title: "Aktivierungsmail erneut senden" + message: "

    Wir haben die Aktivierungsmail noch einmal an %{email} gesendet" + safe_mode: + title: "Abgesicherten Modus betreten" + description: "Der abgesicherte Modus ermöglicht es dir, deine Seite zu testen, ohne Plugins oder Seiten-Anpassungen zu laden." + no_customizations: "Alle Seiten-Anpassungen deaktivieren" + only_official: "Inoffizielle Plugins deaktivieren" + no_plugins: "Alle Plugins deaktivieren" + enter: "Abgesicherten Modus betreten" wizard: + title: "Discourse einrichten" step: + locale: + title: "Willkommen zu Discourse!" + fields: + default_locale: + description: "Was ist die Standardsprache für deine Community?" forum_title: title: "Name" + description: "Der Name ist ein Zeichen, das aus der Ferne sichtbar ist, wahrscheinlich die erste Sache, die mögliche Besucher über deine Community bemerken werden Was sagt dein Name und Titel über deine Community aus?" + fields: + title: + label: "Name deiner Community" + placeholder: "Erikas Stammtisch" + site_description: + label: "Beschreibe deine Community in einem kurzen Satz" + placeholder: "Ein Ort für Erika und ihre Bekannten, um coole Sachen zu besprechen" introduction: title: "Einführung" + fields: + welcome: + label: "Willkommen-Thema" + description: "

    Wie würdest du deine Community einem Fremden im Fahrstuhl in etwa 1 Minute beschreiben?

    • An wen richten sich die Diskussionen?
    • Was kann ich hier finden?
    • Warum lohnt es sich, vorbeizuschauen?

    Dein Willkommen-Thema ist die erste Sache, die neue Besucher sehen werden. Betrachte es als dein 'Fahrstuhl-Vorstellungsgespräch' oder als 'Leitbild'.

    " + one_paragraph: "Bitte begrenze deine Willkommensnachricht auf einen Absatz." privacy: title: "Zugriff" + description: "

    Ist deine Community offen für alle oder beschränkt durch Mitgliedschaft, Einladung oder Genehmigung? Wenn du dies bevorzugst, kannst du alles zunächst privat einrichten und dann später auf öffentlich umschalten.

    Bitte denke daran, dass du Einladungen auch immer aus Themen oder von deiner Benutzerprofil-Seite aus schicken kannst.

    " fields: privacy: choices: open: label: "Öffentlich" + description: "Jeder kann auf diese Community zugreifen, der ein Konto registriert." restricted: label: "Privat" + description: "Nur Personen, die ich eingeladen oder genehmigt habe, können auf diese Community zugreifen." contact: title: "Kontakt" fields: contact_email: label: "Mail" placeholder: "name@example.com" + description: "E-Mail-Adresse der verantwortlichen Person oder Gruppe für diese Community. Wird verwendet für kritische Benachrichtigungen wie unbehandelte Meldungen, Sicherheitsaktualisierungen sowie auf eurer „Über uns“-Seite für dringenden Community-Kontakt." + contact_url: + label: "Webseite" + placeholder: "http://www.example.com/kontaktiere-uns" + description: "Allgemeines Kontaktformular für euch oder eure Organisation. Wird angezeigt auf eurer „Über uns“-Seite." + site_contact: + label: "Automatische Nachrichten" + description: "Alle automatischen, persönlichen Discourse-Nachrichten werden von diesem Benutzer versandt. Insbesondere wird dieser Benutzer der ausgewiesene Absender jeder Willkommensnachricht sein, die automatisch an neue Benutzer geschickt werden." corporate: title: "Organisation" + description: "Diese Namen werden in eure Datenschutzerklärung und Nutzungsbedingungen eingefügt, die du jederzeit in der Team-Kategorie ändern kannst Wenn du keine Firma hast, kannst du diesen Schritt auch überspringen." fields: company_short_name: label: "Firmenname (kurz)" + placeholder: "Musterfirma" company_full_name: label: "Firmenname (komplett)" + placeholder: "Musterfirma GmbH" + company_domain: + label: "Firmen-Domainname" + placeholder: "musterfirma.com" + colors: + title: "Design" + fields: + theme_id: + description: "Bevorzugst du ein helles oder dunkles Farbschema? Du kannst das Erscheinungsbild deiner Seite jederzeit weiter anpassen unter Administration, Anpassen." + choices: + default: + label: "Simple Light (Hell)" + dark: + label: "Simple Dark (Dunkel)" + logos: + title: "Logos" + fields: + logo_url: + label: "Hauptlogo" + description: "Das Logobild für den linken, oberen Bereich deiner Seite. Verwende eine weite, rechteckige Form." + logo_small_url: + label: "Kompaktes Logo" + description: "Eine kompakte Version deines Logos, das auf deiner Seite oben links angezeigt wird, wenn man herunterscollt. Verwende eine quadratische Form." + icons: + title: "Icons" + fields: + favicon_url: + label: "Kleines Icon" + description: "Icon-Bild, das in Webbrowsern mit kleineren Dimensionen gut aussieht. Die empfohlene Größe beträgt 32x32 Pixel." + apple_touch_icon_url: + label: "Großes Icon" + description: "Icon-Bild, das auf modernen Geräten mit größeren Dimensionen gut aussieht. Die empfohlene Größe beträgt mindestens 144x144 Pixel." + homepage: + description: "Wir empfehlen, die aktuellen Themen auf deiner Startseite anzuzeigen, aber du kannst dich auch dafür entscheiden, Kategorien (Gruppen von Themen) auf der Startseite anzuzeigen, wenn dir das lieber ist." + title: "Homepage" + fields: + homepage_style: + choices: + latest: + label: "Neueste Beiträge" + categories: + label: "Kategorien" emoji: title: "Emoji" + description: "Welches Emoji-Design bevorzugst du für deine Community? Du kannst später jederzeit mehr benutzerdefinierte Emoji einfügen unter Administration, Anpassen, Emoji." + invites: + title: "Team einladen" + description: "Du hast es fast geschafft! Lass uns ein paar Team-Mitglieder einladen, um eure Diskussionen in Gang zu bringen mit interessanten Themen und Antworten und deine Community zu beginnen." + finished: + title: "Dein Discourse ist bereit!" + description: | +

    Wenn du diese Einstellungen jemals ändern möchtest, besuche deinen Administrationsbereich; finde ihn neben dem Schraubenschüssel-Symbol im Seitenmenü..

    +

    Viel Spaß, und viel Glück beim Aufbauen deiner neuen Community!

    activemodel: errors: <<: *errors diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 81580737a2f..eb2e54eed1d 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -53,10 +53,11 @@ en: purge_reason: "Automatically deleted as abandoned, deactivated account" disable_remote_images_download_reason: "Remote images download was disabled because there wasn't enough disk space available." anonymous: "Anonymous" + remove_posts_deleted_by_author: "Deleted by author" emails: incoming: - default_subject: "Incoming email from %{email}" + default_subject: "This topic needs a title" show_trimmed_content: "Show trimmed content" maximum_staged_user_per_email_reached: "Reached maximum number of staged users created per email." errors: @@ -95,6 +96,8 @@ en: inclusion: is not included in the list invalid: is invalid is_invalid: "seems unclear, is it a complete sentence?" + contains_censored_words: "contains the following censored words: %{censored_words}" + matches_censored_pattern: "contains the following words that matches the site's censored regexp: %{censored_words}" less_than: must be less than %{count} less_than_or_equal_to: must be less than or equal to %{count} not_a_number: is not a number @@ -133,10 +136,17 @@ en: errors: <<: *errors + invite: + accept_invite: "Accept Invitation" + not_found: "Your invite token is invalid. Please contact the site's administrator." + bulk_invite: file_should_be_csv: "The uploaded file should be of csv format." error: "There was an error uploading that file. Please try again later." + topic_invite: + user_exists: "Sorry, that user has already been invited. You may only invite a user to a topic once." + backup: operation_already_running: "An operation is currently running. Can't start a new job right now." backup_file_should_be_tar_gz: "The backup file should be a .tar.gz archive." @@ -158,6 +168,11 @@ en: embed: start_discussion: "Start Discussion" continue: "Continue Discussion" + error: "Error Embedding" + referer: "Referer:" + mismatch: "The referer did not match any of the following hosts:" + no_hosts: "No hosts were set up for embedding." + configure: "Configure Embedding" more_replies: one: "1 more reply" other: "%{count} more replies" @@ -194,6 +209,7 @@ en: spamming_host: "Sorry you cannot post a link to that host." user_is_suspended: "Suspended users are not allowed to post." topic_not_found: "Something has gone wrong. Perhaps this topic was closed or deleted while you were looking at it?" + not_accepting_pms: "Sorry, %{username} is not accepting messages at the moment." just_posted_that: "is too similar to what you recently posted" invalid_characters: "contains invalid characters" @@ -374,8 +390,27 @@ en: staff_category_name: "Staff" staff_category_description: "Private category for staff discussions. Topics are only visible to admins and moderators." + assets_topic_title: "Assets for the site design" assets_topic_body: "This is a permanent topic, visible only to staff, for storing images and files used in the site design. Don't delete it!\n\n\nHere's how:\n\n\n1. Reply to this topic.\n2. Upload all the images you wish to use for logos, favicons, and so forth here. (Use the upload toolbar icon in the post editor, or drag-and-drop or paste images.)\n3. Submit your reply to post it.\n4. Right click the images in your new post to get the path to the uploaded images, or click the edit icon to edit your post and retrieve the path to the images. Copy the image paths.\n5. Paste those image paths into [basic settings](/admin/site_settings/category/required).\n\n\nIf you need to enable different file type uploads, edit `authorized_extensions` in the [file settings](/admin/site_settings/category/files)." + discourse_welcome_topic: + title: "Welcome to Discourse" + body: | + + The first paragraph of this pinned topic will be visible as a welcome message to all new visitors on your homepage. It's important! + + **Edit this** into a brief description of your community: + + - Who is it for? + - What can they find here? + - Why should they come here? + - Where can they read more (links, resources, etc)? + + + + You may want to close this topic via the admin :wrench: (at the upper right and bottom), so that replies don't pile up on an announcement. + + lounge_welcome: title: "Welcome to the Lounge" body: | @@ -538,8 +573,8 @@ en: password_reset: no_token: "Sorry, that password change link is too old. Select the Log In button and use 'I forgot my password' to get a new link." - choose_new: "Please choose a new password" - choose: "Please choose a password" + choose_new: "Choose a new password" + choose: "Choose a password" update: 'Update Password' save: 'Set Password' title: 'Reset Password' @@ -972,7 +1007,6 @@ en: prioritize_username_in_ux: "Show username first on user page, user card and posts (when disabled name is shown first)" email_token_valid_hours: "Forgot password / activate account tokens are valid for (n) hours." - email_token_grace_period_hours: "Forgot password / activate account tokens are still valid for a grace period of (n) hours after being redeemed." enable_badges: "Enable the badge system" enable_whispers: "Allow staff private communication within topics." @@ -1015,6 +1049,7 @@ en: sso_overrides_name: "Overrides local full name with external site full name from SSO payload on every login, and prevent local changes." sso_overrides_avatar: "Overrides user avatar with external site avatar from SSO payload. If enabled, disabling allow_uploaded_avatars is highly recommended" sso_not_approved_url: "Redirect unapproved SSO accounts to this URL" + sso_allows_all_return_paths: "Do not restrict the domain for return_paths provided by SSO (by default return path must be on current site)" enable_local_logins: "Enable local username and password login based accounts. (Note: this must be enabled for invites to work)" allow_new_registrations: "Allow new user registrations. Uncheck this to prevent anyone from creating a new account." @@ -1185,6 +1220,8 @@ en: authorized_extensions: "A list of file extensions allowed for upload (use '*' to enable all file types)" max_similar_results: "How many similar topics to show above the editor when composing a new topic. Comparison is based on title and body." + max_image_megapixels: "Maximum number of megapixels allowed for an image." + title_prettify: "Prevent common title typos and errors, including all caps, lowercase first character, multiple ! and ?, extra . at end, etc." topic_views_heat_low: "After this many views, the views field is slightly highlighted." @@ -1301,18 +1338,24 @@ en: delete_digest_email_after_days: "Suppress summary emails for users not seen on the site for more than (n) days." digest_suppress_categories: "Suppress these categories from summary emails." disable_digest_emails: "Disable summary emails for all users." + email_accent_bg_color: "The accent color to be used as the background of some elements in HTML emails. Enter a color name ('red') or hex value ('#FF000')." + email_accent_fg_color: "The color of text rendered on the email bg color in HTML emails. Enter a color name ('white') or hex value ('#FFFFFF')." + email_link_color: "The color of links in HTML emails. Enter a color name ('blue') or hex value ('#0000FF')." detect_custom_avatars: "Whether or not to check that users have uploaded custom profile pictures." max_daily_gravatar_crawls: "Maximum number of times Discourse will check Gravatar for custom avatars in a day" public_user_custom_fields: "A whitelist of custom fields for a user that can be shown publicly." staff_user_custom_fields: "A whitelist of custom fields for a user that can be shown to staff." enable_user_directory: "Provide a directory of users for browsing" + enable_group_directory: "Provide a directory of groups for browsing" allow_anonymous_posting: "Allow users to switch to anonymous mode" anonymous_posting_min_trust_level: "Minimum trust level required to enable anonymous posting" anonymous_account_duration_minutes: "To protect anonymity create a new anonymous account every N minutes for each user. Example: if set to 600, as soon as 600 minutes elapse from last post AND user switches to anon, a new anonymous account is created." hide_user_profiles_from_public: "Disable user cards, user profiles and user directory for anonymous users." + user_website_domains_whitelist: "User website will be verified against these domains. Pipe-delimited list." + allow_profile_backgrounds: "Allow users to upload profile backgrounds." sequential_replies_threshold: "Number of posts a user has to make in a row in a topic before being reminded about too many sequential replies." @@ -1337,6 +1380,8 @@ en: topic_page_title_includes_category: "Topic page title includes the category name." + native_app_install_banner: "Asks recurring visitors to install Discourse native app." + max_prints_per_hour_per_user: "Maximum number of /print page impressions (set to 0 to disable)" full_name_required: "Full name is a required field of a user's profile." @@ -1580,6 +1625,8 @@ en: user: no_accounts_associated: "No accounts associated" deactivated: "Was deactivated due to too many bounced emails to '%{email}'." + deactivated_by_staff: "Deactivated by staff" + activated_by_staff: "Activated by staff" username: short: "must be at least %{min} characters" long: "must be no more than %{max} characters" @@ -1597,6 +1644,8 @@ en: ip_address: blocked: "New registrations are not allowed from your IP address." max_new_accounts_per_registration_ip: "New registrations are not allowed from your IP address (maximum limit reached). Contact a staff member." + website: + domain_not_allowed: "Website is invalid. Allowed domains are: %{domains}" flags_reminder: flags_were_submitted: @@ -1607,6 +1656,7 @@ en: other: "%{count} flags waiting to be handled" unsubscribe_mailer: + title: "Unsubscribe Mailer" subject_template: "Confirm you no longer want to receive email updates from %{site_title}" text_body_template: | Someone (possibly you?) requested to no longer send email updates from %{site_domain_name} to this address. @@ -1618,6 +1668,7 @@ en: If you want to continue receiving email updates, you may ignore this email. invite_mailer: + title: "Invite Mailer" subject_template: "%{invitee_name} invited you to '%{topic_title}' on %{site_domain_name}" text_body_template: | %{invitee_name} invited you to a discussion @@ -1637,6 +1688,7 @@ en: This invitation is from a trusted user, so you can reply to the discussion immediately. custom_invite_mailer: + title: "Custom Invite Mailer" subject_template: "%{invitee_name} invited you to '%{topic_title}' on %{site_domain_name}" text_body_template: | %{invitee_name} invited you to a discussion @@ -1649,9 +1701,9 @@ en: > %{site_title} -- %{site_description} - Message from %{invitee_name}: + With this note - %{user_custom_message} + > %{user_custom_message} If you're interested, click the link below: @@ -1660,6 +1712,7 @@ en: This invitation is from a trusted user, so you can reply to the discussion immediately. invite_forum_mailer: + title: "Invite Forum Mailer" subject_template: "%{invitee_name} invited you to join %{site_domain_name}" text_body_template: | %{invitee_name} invited you to join @@ -1672,9 +1725,10 @@ en: %{invite_link} - This invitation is from a trusted user, so an account will be created for you automatically. + This invitation is from a trusted user, so an account will be created for you automatically using this email address. custom_invite_forum_mailer: + title: "Invite Forum Mailer" subject_template: "%{invitee_name} invited you to join %{site_domain_name}" text_body_template: | %{invitee_name} invited you to join @@ -1683,17 +1737,18 @@ en: > > %{site_description} - Message from %{invitee_name}: + With this note - %{user_custom_message} + > %{user_custom_message} If you're interested, click the link below: %{invite_link} - This invitation is from a trusted user, so an account will be created for you automatically. + This invitation is from a trusted user, so an account will be created for you automatically using this email address. invite_password_instructions: + title: "Invite Password Instructions" subject_template: "Set password for your %{site_name} account" text_body_template: | Thanks for accepting your invitation to %{site_name} -- welcome! @@ -1704,6 +1759,7 @@ en: (If the link above has expired, choose "I forgot my password" when logging in with your email address.) test_mailer: + title: "Test Mailer" subject_template: "[%{site_name}] Email Deliverability Test" text_body_template: | This is a test email from @@ -1748,6 +1804,7 @@ en: [mt]: http://www.mail-tester.com/ new_version_mailer: + title: "New Version Mailer" subject_template: "[%{site_name}] New Discourse version, update available" text_body_template: | Hooray, a new version of [Discourse](http://www.discourse.org) is available! @@ -1762,6 +1819,7 @@ en: - Visit [meta.discourse.org](https://meta.discourse.org) for news, discussion, and support for Discourse new_version_mailer_with_notes: + title: "New Version Mailer with Notes" subject_template: "[%{site_name}] update available" text_body_template: | Hooray, a new version of [Discourse](http://www.discourse.org) is available! @@ -1780,6 +1838,7 @@ en: %{notes} queued_posts_reminder: + title: "Queued Posts Reminder" subject_template: one: "[%{site_name}] 1 post waiting to be reviewed" other: "[%{site_name}] %{count} posts waiting to be reviewed" @@ -1805,6 +1864,7 @@ en: system_messages: post_hidden: + title: "Post Hidden" subject_template: "Post hidden by community flags" text_body_template: | Hello, @@ -1823,99 +1883,12 @@ en: usage_tips: text_body_template: | - Here are a few quick tips to get you started: + For a few quick tips on getting started as a new user, [check out this blog post](http://blog.discourse.org/2016/12/discourse-new-user-tips-and-tricks/). - ## Reading - - To read more, **just keep scrolling down!** - - As new replies or new topics arrive, they will appear automatically – no need to refresh the page. - - ## Navigation - - - For search, your user page, or the menu, use the **icon buttons at upper right**. - - - Selecting a topic title will always take you to your **next unread reply** in the topic. To enter at the top or bottom instead, select the reply count or last reply date. - - - - - While reading a topic, use the timeline on the right to jump to the top, bottom, or your last read position. On smaller screens, select the progress bar at bottom right to expand it: - - - - You can also press ? on your keyboard for a list of super-speedy keyboard shortcuts. - - ## Replying - - To insert a quote, select the text you wish to quote, then press any Reply button to open the editor. Repeat for multiple quotes. - - - - You can always continue reading while you compose your reply, and we automatically save drafts as you write. - - To notify someone about your reply, mention their name. Type `@` to begin selecting a username. - - - - To use [standard Emoji](http://www.emoji.codes/), just type `:` to match by name, or use the traditional smileys `;)` - - - - To generate a summary for a link, paste it on a line by itself: - - - - Your reply can be formatted using simple HTML, BBCode, or [Markdown](http://commonmark.org/help/): - - This is bold. - This is [b]bold[/b]. - This is **bold**. - - For more formatting tips, [try our fun 10 minute interactive tutorial!](http://commonmark.org/help/tutorial/) - - ## Actions - - There are action buttons at the bottom of each post: - - - - - To let someone know that you enjoyed and appreciated their post, use the **like** button. Share the love! - - - Grab a copy-pasteable link to any reply or topic via the **link** button. - - - Use the show more button to reveal more actions. **Flag** to privately let the author, or [our staff](%{base_url}/about), know about a problem. **Bookmark** to find this post later on your profile page. - - ## Notifications - - When someone replies to you, quotes your post, mentions your `@username`, or even links to your post, a number will immediately appear at the top right of the page. Select it to access your **notifications**. - - - - Don't worry about missing a reply – you'll be emailed any notifications that arrive when you are away. - - ## Preferences - - - All topics less than **two days old** are considered new. - - - Any topic you've **actively participated in** (by creating it, replying to it, or reading it for an extended period) will be automatically tracked on your behalf. - - You will see the new and unread number indicators next to these topics: - - - - You can change your notifications for any topic via the notification control at the bottom, and right hand side, of each topic. - - - - You can also set notification state per category, if you want to watch or mute every new topic in a specific category. - - To change any of these settings, see [your user preferences](%{base_url}/my/preferences). - - ## Community Trust - - It's great to meet you! As you participate here, over time we'll get to know you, and your temporary new user limitations will be lifted. Keep participating, and over time you'll gain new [trust levels](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924) that include special abilities to help us manage our community together. + As you participate here, we’ll get to know you, and temporary new user limitations will be lifted. Over time you’ll gain [trust levels](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924) that include special abilities to help us manage our community together. welcome_user: + title: "Welcome User" subject_template: "Welcome to %{site_name}!" text_body_template: | Thanks for joining %{site_name}, and welcome! @@ -1929,17 +1902,14 @@ en: (If you need to communicate with [staff members](%{base_url}/about) as a new user, just reply to this message.) welcome_invite: + title: "Welcome Invite" subject_template: "Welcome to %{site_name}!" text_body_template: | Thanks for accepting your invitation to %{site_name} -- welcome! - We've created a new account **%{username}** for you, and you are logged in. You can change your name by visiting [your user profile][prefs]. + - We've created this new account **%{username}** for you. Change your name or password by visiting [your user profile][prefs]. - To log in again later: - - 1. Always **use the same email address from your original invitation** when logging in. Otherwise we won't be able to tell it's you! - - 2. Create a unique password for [your user profile][prefs], and use it to log in. + - When you log in, please **use the same email address from your original invitation** — otherwise we won't be able to tell it's you! %{new_user_tips} @@ -1952,6 +1922,7 @@ en: [prefs]: %{user_preferences_url} backup_succeeded: + title: "Backup Succeeded" subject_template: "Backup completed successfully" text_body_template: | The backup was successful. @@ -1965,6 +1936,7 @@ en: ``` backup_failed: + title: "Backup Failed" subject_template: "Backup failed" text_body_template: | The backup has failed. @@ -1976,6 +1948,7 @@ en: ``` restore_succeeded: + title: "Restore Succeeded" subject_template: "Restore completed successfully" text_body_template: | The restore was successful. @@ -1987,6 +1960,7 @@ en: ``` restore_failed: + title: "Restore Failed" subject_template: "Restore failed" text_body_template: | The restore has failed. @@ -1998,10 +1972,12 @@ en: ``` bulk_invite_succeeded: + title: "Bulk Invite Succeeded" subject_template: "Bulk user invite processed successfully" text_body_template: "Your bulk user invite file was processed, %{sent} invites mailed." bulk_invite_failed: + title: "Bulk Invite Failed" subject_template: "Bulk user invite processed with errors" text_body_template: | Your bulk user invite file was processed, %{sent} invites mailed with %{failed} error(s). @@ -2013,6 +1989,7 @@ en: ``` csv_export_succeeded: + title: "CSV Export Succeeded" subject_template: "Data export complete" text_body_template: | Your data export was successful! :dvd: @@ -2021,11 +1998,15 @@ en: The above download link will be valid for 48 hours. + The data is compressed as a gzip archive. If the archive does not extract itself when you open it, use the tools recommended here: http://www.gzip.org/#faq4 + csv_export_failed: + title: "CSV Export Failed" subject_template: "Data export failed" text_body_template: "We're sorry, but your data export failed. Please check the logs or contact a staff member." email_reject_insufficient_trust_level: + title: "Email Reject insufficient Trust Level" subject_template: "[%{site_name}] Email issue -- Insufficient Trust Level" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2033,6 +2014,7 @@ en: Your account does not have the required trust level to post new topics to this email address. If you believe this is an error, contact a staff member. email_reject_user_not_found: + title: "Email Reject User Not Found" subject_template: "[%{site_name}] Email issue -- User Not Found" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2040,6 +2022,7 @@ en: Your reply was sent from an unknown email address. Try sending from another email address, or contact a staff member. email_reject_screened_email: + title: "Email Reject Screened Email" subject_template: "[%{site_name}] Email issue -- Blocked Email" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2047,6 +2030,7 @@ en: Your reply was sent from a blocked email address. Try sending from another email address, or contact a staff member. email_reject_inactive_user: + title: "Email Reject Inactive User" subject_template: "[%{site_name}] Email issue -- Inactive User" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2054,6 +2038,7 @@ en: Your account associated with this email address is not activated. Please activate your account before sending emails in. email_reject_blocked_user: + title: "Email Reject Blocked User" subject_template: "[%{site_name}] Email issue -- Blocked User" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2061,6 +2046,7 @@ en: Your account associated with this email address has been blocked. email_reject_reply_user_not_matching: + title: "Email Reject User Not Matching" subject_template: "[%{site_name}] Email issue -- Unexpected Reply Address" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2068,6 +2054,7 @@ en: Your reply was sent from a different email address than the one we expected, so we're not sure if this is the same person. Try sending from another email address, or contact a staff member. email_reject_no_account: + title: "Email Reject No Account" subject_template: "[%{site_name}] Email issue -- Unknown Account" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2075,6 +2062,7 @@ en: We can't find any accounts that match your email address. Try sending from a different email address, or contact a staff member. email_reject_empty: + title: "Email Reject Empty" subject_template: "[%{site_name}] Email issue -- No Content" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2084,6 +2072,7 @@ en: If you're getting this and you _did_ include a reply, try again with simpler formatting. email_reject_parsing: + title: "Email Reject Parsing" subject_template: "[%{site_name}] Email issue -- Content Unrecognized" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2091,6 +2080,7 @@ en: We couldn't find your reply in the email. **Make sure your reply is at the top of the email** -- we can't process inline replies. email_reject_invalid_access: + title: "Email Reject Invalid Access" subject_template: "[%{site_name}] Email issue -- Invalid Access" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2098,6 +2088,7 @@ en: Your account does not have the privileges to post new topics in that category. If you believe this is an error, contact a staff member. email_reject_strangers_not_allowed: + title: "Email Reject Strangers Not Allowed" subject_template: "[%{site_name}] Email issue -- Invalid Access" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2105,6 +2096,7 @@ en: The category you sent this email to only allows replies from users with valid accounts and known email addresses. If you believe this is an error, contact a staff member. email_reject_invalid_post: + title: "Email Reject Invalid Post" subject_template: "[%{site_name}] Email issue -- Posting error" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2112,6 +2104,7 @@ en: Some possible causes are: complex formatting, message too large, message too small. Please try again, or post via the website if this continues. email_reject_invalid_post_specified: + title: "Email Reject Invalid Post Specified" subject_template: "[%{site_name}] Email issue -- Posting error" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2123,6 +2116,7 @@ en: If you can correct the problem, please try again. email_reject_invalid_post_action: + title: "Email Reject Invalid Post Action" subject_template: "[%{site_name}] Email issue -- Invalid Post Action" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2131,6 +2125,7 @@ en: email_reject_reply_key: + title: "Email Reject Reply Key" subject_template: "[%{site_name}] Email issue -- Unknown Reply Key" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2138,6 +2133,7 @@ en: The reply key in the email is invalid or unknown, so we can't figure out what this email is in reply to. Contact a staff member. email_reject_bad_destination_address: + title: "Email Reject Bad Destination Address" subject_template: "[%{site_name}] Email issue -- Unknown To: Address" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2145,6 +2141,7 @@ en: None of the destination email addresses are recognized. Please make sure that you are sending to the correct email address provided by staff. email_reject_topic_not_found: + title: "Email Reject Topic Not Found" subject_template: "[%{site_name}] Email issue -- Topic Not Found" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2152,6 +2149,7 @@ en: The topic you are replying to no longer exists -- perhaps it was deleted? If you believe this is an error, contact a staff member. email_reject_topic_closed: + title: "Email Reject Topic Closed" subject_template: "[%{site_name}] Email issue -- Topic Closed" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2159,6 +2157,7 @@ en: The topic you are replying to is currently closed and no longer accepting replies. If you believe this is an error, contact a staff member. email_reject_auto_generated: + title: "Email Reject Auto Generated" subject_template: "[%{site_name}] Email issue -- Auto Generated Reply" text_body_template: | We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. @@ -2166,6 +2165,7 @@ en: Your email was marked as "auto generated", which means it was automatically created by a computer instead of being typed by a human; we can't accept those kinds of emails. If you believe this is an error, contact a staff member. email_error_notification: + title: "Email Error Notification" subject_template: "[%{site_name}] Email issue -- POP authentication error" text_body_template: | Unfortunately, there was an authentication error while polling mails from the POP server. @@ -2174,6 +2174,7 @@ en: If there is a web UI for the POP email account, you may need to log in on the web and check your settings there. too_many_spam_flags: + title: "Too Many Spam Flags" subject_template: "New account on hold" text_body_template: | Hello, @@ -2184,6 +2185,7 @@ en: For additional guidance, please refer to our [community guidelines](%{base_url}/guidelines). too_many_tl3_flags: + title: "Too Many TL3 Flags" subject_template: "New account on hold" text_body_template: | Hello, @@ -2194,6 +2196,7 @@ en: For additional guidance, please refer to our [community guidelines](%{base_url}/guidelines). blocked_by_staff: + title: "Blocked by Staff" subject_template: "Account temporarily on hold" text_body_template: | Hello, @@ -2205,6 +2208,7 @@ en: For additional guidance, refer to our [community guidelines](%{base_url}/guidelines). user_automatically_blocked: + title: "User Automatically Blocked" subject_template: "New user %{username} blocked by community flags" text_body_template: | This is an automated message. @@ -2216,6 +2220,7 @@ en: This threshold can be changed via the `block_new_user` site settings. spam_post_blocked: + title: "Spam Post Blocked" subject_template: "New user %{username} posts blocked due to repeated links" text_body_template: | This is an automated message. @@ -2227,6 +2232,7 @@ en: This can be modified via the `newuser_spam_host_threshold` and `white_listed_spam_host_domains` site settings. unblocked: + title: "Unblocked" subject_template: "Account no longer on hold" text_body_template: | Hello, @@ -2236,6 +2242,7 @@ en: You can now create new replies and topics again. Thank you for your patience. pending_users_reminder: + title: "Pending Users Reminder" subject_template: one: "1 user waiting for approval" other: "%{count} users waiting for approval" @@ -2245,10 +2252,12 @@ en: [Please review them in the admin section](%{base_url}/admin/users/list/pending). download_remote_images_disabled: + title: "Download Remote Images Disabled" subject_template: "Downloading remote images disabled" text_body_template: "The `download_remote_images_to_local` setting was disabled because the disk space limit at `download_remote_images_threshold` was reached." dashboard_problems: + title: "Dashboard Problems" subject_template: "Problems have been found" text_body_template: | Some problems are being reported on your admin dashboard. @@ -2311,6 +2320,7 @@ en: > %{site_title} -- %{site_description} user_invited_to_private_message_pm: + title: "User Invited to PM" subject_template: "[%{site_name}] %{username} invited you to a message '%{topic_title}'" text_body_template: | %{header_instructions} @@ -2320,6 +2330,7 @@ en: %{respond_instructions} user_invited_to_private_message_pm_staged: + title: "User Invited to PM Staged" subject_template: "[%{site_name}] %{username} invited you to a message '%{topic_title}'" text_body_template: | %{header_instructions} @@ -2329,6 +2340,7 @@ en: %{respond_instructions} user_invited_to_topic: + title: "User Invited to Topic" subject_template: "[%{site_name}] %{username} invited you to '%{topic_title}'" text_body_template: | %{header_instructions} @@ -2338,6 +2350,7 @@ en: %{respond_instructions} user_replied: + title: "User Replied" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2349,6 +2362,7 @@ en: %{respond_instructions} user_replied_pm: + title: "User Replied PM" subject_template: "[%{site_name}] [PM] %{topic_title}" text_body_template: | %{header_instructions} @@ -2360,6 +2374,7 @@ en: %{respond_instructions} user_quoted: + title: "User Quoted" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2371,6 +2386,7 @@ en: %{respond_instructions} user_linked: + title: "User Linked" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2382,6 +2398,7 @@ en: %{respond_instructions} user_mentioned: + title: "User Mentioned" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2393,6 +2410,7 @@ en: %{respond_instructions} user_group_mentioned: + title: "User Group Mentioned" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2404,6 +2422,7 @@ en: %{respond_instructions} user_posted: + title: "User Posted" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2415,6 +2434,7 @@ en: %{respond_instructions} user_watching_first_post: + title: "User Watching First Post" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2426,6 +2446,7 @@ en: %{respond_instructions} user_posted_pm: + title: "User Posted PM" subject_template: "[%{site_name}] [PM] %{topic_title}" text_body_template: | %{header_instructions} @@ -2437,6 +2458,7 @@ en: %{respond_instructions} user_posted_pm_staged: + title: "User Posted PM Staged" subject_template: "%{optional_re}%{topic_title}" text_body_template: | @@ -2456,7 +2478,7 @@ en: join_the_discussion: "Read More" popular_posts: "Popular Posts" from_topic_label: "From" - more_new: "New in topics and categories you follow" + more_new: "New for you" subject_template: "[%{site_name}] Summary" unsubscribe: "This summary is sent from %{site_link} when we haven't seen you in a while. To unsubscribe %{unsubscribe_link}." click_here: "click here" @@ -2495,6 +2517,7 @@ en: view_this_topic: "View this topic" back_to_top: "Back to top" forgot_password: + title: "Forgot Password" subject_template: "[%{site_name}] Password reset" text_body_template: | Somebody asked to reset your password on [%{site_name}](%{base_url}). @@ -2505,6 +2528,7 @@ en: %{base_url}/users/password-reset/%{email_token} set_password: + title: "Set Password" subject_template: "[%{site_name}] Set Password" text_body_template: | Somebody asked to add a password to your account on [%{site_name}](%{base_url}). Alternatively, you can log in using any supported online service (Google, Facebook, etc) that is associated with this validated email address. @@ -2515,6 +2539,7 @@ en: %{base_url}/users/password-reset/%{email_token} admin_login: + title: "Admin Login" subject_template: "[%{site_name}] Login" text_body_template: | Somebody asked to login to your account on [%{site_name}](%{base_url}). @@ -2525,6 +2550,7 @@ en: %{base_url}/users/admin-login/%{email_token} account_created: + title: "Account Created" subject_template: "[%{site_name}] Your New Account" text_body_template: | A new account was created for you at %{site_name} @@ -2533,6 +2559,7 @@ en: %{base_url}/users/password-reset/%{email_token} confirm_new_email: + title: "Confirm New Email" subject_template: "[%{site_name}] Confirm your new email address" text_body_template: | Confirm your new email address for %{site_name} by clicking on the following link: @@ -2540,6 +2567,7 @@ en: %{base_url}/users/authorize-email/%{email_token} confirm_old_email: + title: "Confirm Old Email" subject_template: "[%{site_name}] Confirm your current email address" text_body_template: | Before we can change your email address, we need you to confirm that you control @@ -2551,6 +2579,7 @@ en: %{base_url}/users/authorize-email/%{email_token} notify_old_email: + title: "Notify Old Email" subject_template: "[%{site_name}] Your email address has been changed" text_body_template: | This is an automated message to let you know that your email address for @@ -2562,6 +2591,7 @@ en: %{new_email} signup_after_approval: + title: "Signup After Approval" subject_template: "You've been approved on %{site_name}!" text_body_template: | Welcome to %{site_name}! @@ -2582,6 +2612,7 @@ en: (If you need to communicate with [staff members](%{base_url}/about) as a new user, just reply to this message.) signup: + title: "Signup" subject_template: "[%{site_name}] Confirm your new account" text_body_template: | Welcome to %{site_name}! @@ -2620,6 +2651,7 @@ en: too_large: "Sorry, the file you are trying to upload is too big (maximum size is %{max_size_kb}KB)." images: too_large: "Sorry, the image you are trying to upload is too big (maximum size is %{max_size_kb}KB), please resize it and try again." + larger_than_x_megapixels: "Sorry, the image you are trying to upload is too large (maximum dimension is %{max_image_megapixels}-megapixels), please resize it and try again." size_not_found: "Sorry, but we couldn't determine the size of the image. Maybe your image is corrupted?" avatar: @@ -3218,9 +3250,6 @@ en: initial_post_raw: This topic includes daily performance reports for your site. initial_topic_title: Website performance reports - topic_invite: - user_exists: "Sorry, that user has already been invited. You may only invite a user to a topic once." - tags: title: "Tags" staff_tag_disallowed: "The tag \"%{tag}\" may only be applied by staff." @@ -3281,13 +3310,13 @@ en:
  • What can I find here?
  • Why should I visit?
  • -

    Your welcome topic is the first thing new visitors will see. Think of it as your one paragraph 'elevator pitch' or 'mission statement'.

    " +

    Your welcome topic is the first thing new arrivals will read. Think of it as your one paragraph 'elevator pitch' or 'mission statement'.

    " one_paragraph: "Please restrict your welcome message to one paragraph." privacy: title: "Access" description: "

    Is your community open to everyone, or is it restricted by membership, invitation, or approval? If you prefer, you can set things up privately, then switch over to public later.

    -

    Remember you can always send invites from topics, or from your user profile page, too.

    " +

    You can always send invites from topics, or from your user profile page, too.

    " fields: privacy: @@ -3316,7 +3345,7 @@ en: corporate: title: "Organization" - description: "These names will be entered in your Privacy Policy and Terms of Service, which you can edit any time in the Staff category. If you don’t have a company, feel free to skip this step for now." + description: "These names will be entered in your Privacy Policy and Terms of Service, which are topics you can edit in the Staff category. If you don’t have a company, feel free to skip this step for now." fields: company_short_name: @@ -3333,7 +3362,7 @@ en: title: "Theme" fields: theme_id: - description: "Do you prefer a light or dark color scheme to start with? You can always further customize the look and feel of your site via Admin, Customize." + description: "Do you prefer a light or dark color scheme to start with? You can further customize the look and feel of your site via Admin, Customize." choices: default: label: "Simple Light" @@ -3361,7 +3390,7 @@ en: description: "Icon image used to represent your site on modern devices that looks good at larger sizes. Recommended size is at least 144px by 144px." homepage: - description: "We recommend showing the latest topics on your homepage, but you can choose to show categories (groups of topics) on the homepage if you prefer." + description: "We recommend showing the latest topics on your homepage, but you can also show categories (groups of topics) on the homepage if you prefer." title: "Homepage" fields: @@ -3374,7 +3403,7 @@ en: emoji: title: "Emoji" - description: "Which Emoji style do you prefer for your community? You can always add more custom Emoji later via Admin, Customize, Emoji." + description: "Which Emoji style do you prefer for your community? You can add more custom Emoji later via Admin, Customize, Emoji." invites: title: "Invite Staff" diff --git a/config/locales/server.es.yml b/config/locales/server.es.yml index 8a38dea7436..e3cef5ecd77 100644 --- a/config/locales/server.es.yml +++ b/config/locales/server.es.yml @@ -32,6 +32,7 @@ es: purge_reason: "Cuenta eliminada automáticamente al detectarse como abandonada, desactivada" disable_remote_images_download_reason: "La descarga de imágenes remotas se desactivó porque no había suficiente espacio disponible en disco." anonymous: "Anónimos" + remove_posts_deleted_by_author: "Eliminado por su autor" emails: incoming: default_subject: "Email entrante desde %{email}" @@ -71,6 +72,9 @@ es: has_already_been_used: "ya se está utilizando" inclusion: no está incluido en la lista invalid: no es válido + is_invalid: "parece poco claro, es una oración completa?" + contains_censored_words: "incluye una o más palabras censuradas: %{censored_words}" + matches_censored_pattern: "coincide con la siguiente expresión regular censurada: %{censored_pattern}" less_than: debe ser menor que %{count} less_than_or_equal_to: debe ser menor o igual que %{count} not_a_number: no es un número @@ -105,7 +109,8 @@ es: default_categories_already_selected: "No se puede seleccionar una categoría ya utilizada en otra lista." s3_upload_bucket_is_required: "No se pueden activar las subidas a S3 a menos que se haya proporcionado un valor a 's3_upload_bucket'." bulk_invite: - file_should_be_csv: "El archivo a subir debe tener formato csv o txt." + file_should_be_csv: "El archivo subido debería ser de formato csv." + error: "Ha ocurrido un error al subir ese archivo. Por favor, inténtalo más tarde de nuevo." backup: operation_already_running: "Actualmente se está ejecutando una operación. No se puede iniciar un nuevo trabajo en este momento." backup_file_should_be_tar_gz: "El archivo de la copia de seguridad debería ser del tipo .tar.gz" @@ -123,6 +128,11 @@ es: embed: start_discussion: "Empezar discusión" continue: "Continuar discusión" + error: "Error al insertar" + referer: "Referente:" + mismatch: "El referente no ha coincidido con ninguno de los siguientes hosts:" + no_hosts: "No se han definido hosts para el insertado" + configure: "Configurar insertado" more_replies: one: "otra respuesta" other: "otras %{count} respuestas" @@ -156,8 +166,10 @@ es: spamming_host: "Lo sentimos, no puedes publicar un enlace a esa web." user_is_suspended: "A los usuarios suspendidos no se les permite publicar." topic_not_found: "Algo ha salido mal. ¿Tal vez este tema ha sido cerrado o eliminado mientras estabas lo estabas mirando?" + not_accepting_pms: "Lo sentimos, %{username} no acepta mensajes en este momento." just_posted_that: "es demasiado parecido a lo que has publicado recientemente" invalid_characters: "contiene caracteres no válidos" + is_invalid: "parece poco claro, es una oración completa?" next_page: "siguiente página →" prev_page: "← página anterior" page_num: "Página %{num}" @@ -268,6 +280,7 @@ es: name: "Nombre de la categoría" topic: title: 'Título' + featured_link: 'Enlace destacado' post: raw: "Body" user_profile: @@ -281,6 +294,9 @@ es: too_many_users: "Solamente puedes enviar advertencias a un usuario a la vez." cant_send_pm: "Lo sentimos, no puedes enviar un mensaje privado a este usuario." no_user_selected: "Debes seleccionar un usuario válido." + featured_link: + invalid: "es inválido. La dirección debería incluir http:// o https://." + invalid_category: "no puede ser editado en esta categoría." user: attributes: password: @@ -311,7 +327,24 @@ es: meta_category_description: "Debate sobre este sitio, su gestión, cómo funciona y cómo podríamos mejorarlo." staff_category_name: "Staff" staff_category_description: "Categoría privada para debates entre moderadores y administradores. Los temas solo serán visibles para miembros del staff." + assets_topic_title: "Recursos para el diseño del sitio" assets_topic_body: "Este es un tema permanente, visible únicamente para miembros del staff, con el fin de almacenar las imágenes y archivos utilizados en el diseño del sitio. ¡No lo elimines!\n\n\nCómo hacerlo:\n\n\n1. Responde a este tema.\n2. Sube todas las imágenes que desees para los logos, favicons y demás aquí. (Usa el icono de la barra de herramientas en el editor o arrastra y suelta las imágenes o pégalas). \n3. Publica tu respuesta.\n4. Haz clic con el botón derecho en las imágenes de tu nuevo post para obtener la ruta donde están subidas, o haz clic en el icono de editar para ver estas rutas en el panel de edición. Copia las rutas.\n5. Pega las rutas a las imágenes en [ajustes básicos](/admin/site_settings/category/required).\n\n\nSi necesitas habilitar la subida de diferentes tipos de archivo, edita `authorized_extensions` en las opciones de [archivos](/admin/site_settings/category/files)." + discourse_welcome_topic: + title: "Bienvenido a Discourse" + body: |2 + + El primer párrafo de este tema destacado (tema fijo) será visible para todos los usuarios como mensaje de bienvenida en tu página principal. Es importante! + + **Estia esto** con un resumen de lo que es tu comunidad: + + - ¿Para quiénes es? + - ¿Qué pueden encontrar aquí? + - ¿Por qué deben venir aquí? + - ¿Dónde pueden leer más sobre la comunidad (enlaces, recursos, etc)? + + + + Quizás quieras "cerrar" este tema :wrench: (en la parte superior derecha o en la parte de abajo), para que las nuevas respuestas no se sumen en el anuncio. lounge_welcome: title: "Bienvenido a la Sala VIP" body: |2 @@ -375,6 +408,7 @@ es: create_topic: "Estás creando temas demasiado rápido. Por favor, espera %{time_left} antes de intentarlo de nuevo." create_post: "Estás respondiendo demasiado rápido. Por favor, espera %{time_left} antes de intentarlo de nuevo." delete_post: "Estás eliminando posts demasiado rápido. Por favor espera %{time_left} antes de intentarlo de nuevo." + public_group_membership: "Estás uniéndote o saliendo de grupos con mucha frecuencia. Por favor, espera %{time_left} antes de volver a intentarlo." topics_per_day: "Has llegado al límite de nuevos temas de hoy. Por favor, espera %{time_left} antes de intentarlo de nuevo." pms_per_day: "Has llegado al límite de mensajes de hoy. Por favor, espera %{time_left} antes de intentarlo de nuevo." create_like: "Has llegado al límite de Me gusta de hoy. Por favor, espera %{time_left} antes de intentarlo de nuevo." @@ -529,6 +563,13 @@ es: title: 'Vota' description: 'Vota por este post' long_form: 'Votado para este post' + user_activity: + no_bookmarks: + self: "No tienes temas en marcadores, añadir temas a marcadores te permite acceder a ellos más tarde fácilmente." + others: "Sin marcadores." + no_likes_given: + self: "No le has dado a \"Me gusta\" en ningún tema." + others: "No te gusta ningún tema." topic_flag_types: spam: title: 'Spam' @@ -750,6 +791,7 @@ es: poll_pop3_auth_error: "La conexión al servidor POP3 está fallando debido a un error de autenticación. Por favor revisa los ajustes POP3." site_settings: censored_words: "Las palabras serán reemplazadas con ■■■■" + censored_pattern: "Patrones de Regex serán automáticamente reemplazados con ■■■■" delete_old_hidden_posts: "Auto-borrar cualquier post que se quede oculto por mas de 30 días." default_locale: "El idioma por defecto de Discourse (ISO 639-1 Code)" allow_user_locale: "Permitir que los usuarios escojan su propio idioma para la interfaz" @@ -758,6 +800,8 @@ es: min_first_post_length: "Extensión mínima permitida en el primer mensaje (cuerpo del tema) en caracteres" min_private_message_post_length: "Extensión mínima de los posts en los mensajes, en número de caracteres" max_post_length: "Extensión máxima de los posts, en número de caracteres" + topic_featured_link_enabled: "Activar publicar temas a partir de un enlace." + show_topic_featured_link_in_digest: "Mostrar el enlace destacado por el tema en el email de resumen." min_topic_title_length: "Extensión mínima del título de los temas, en número de caracteres" max_topic_title_length: "Extensión máxima del título de los temas, en número de caracteres" min_private_message_title_length: "Extensión mínima del título de los temas en mensajes, en número de caracteres" @@ -795,6 +839,8 @@ es: show_pinned_excerpt_mobile: "Mostrar extracto de temas destacados en la vista móvil." show_pinned_excerpt_desktop: "Mostrar extracto de temas destacados en la vista de escritorio." post_onebox_maxlength: "Extensión máxima en caracteres de un post de Discourse en formato Onebox." + onebox_domains_blacklist: "Una lista de dominios que nunca se mostrarán en un obenox." + max_oneboxes_per_post: "Número máximo de oneboxes en un tema." logo_url: "El logo situado en la esquina superior izquierda de tu sitio, debería encajar en las dimensiones de un rectángulo. Si se deja en blanco, se mostrará un texto con el título del sitio." digest_logo_url: "La imagen de logo alterno utilizado en la parte superior del resumen del sitio enviado por email. Debería encajar en las dimensiones de un rectángulo. No debería ser una imagen SVG. Si se deja en blanco, se utilizará `logo_url`." logo_small_url: "El logo pequeño situado en la esquina superior izquierda del sitio, debería encajar en las dimensiones de un cuadrado y se muestra cuando se hace scroll hacia abajo. Si se deja en blanco, se mostrará un glifo de una casita." @@ -864,9 +910,8 @@ es: show_email_on_profile: "Mostrar el e-mail los usuarios en su perfil (solamente visibles para ellos mismos y el staff)" prioritize_username_in_ux: "Mostrar username primero en la página de usuario, tarjeta de usuario y mensajes (cuando el nombre ha sido desactivado se muestra primero)" email_token_valid_hours: "Los tokens para restablecer contraseña olvidada / activar cuenta son válidos durante (n) horas." - email_token_grace_period_hours: "Los tokens para restablecer contraseña olvidada / activar cuenta son válidos durante (n) horas de periodo de gracia, después de ser redimidos." enable_badges: "Activar el sistema de distintivos" - enable_whispers: "Permitir al staff comunicarse privadamente en los temas. (experimental)" + enable_whispers: "Permitir a los miembros del staff comunicarse privadamente entre ellos en temas públicos." allow_index_in_robots_txt: "Especificar en robots.txt que este sitio puede ser indexado por los motores de búsqueda web." email_domains_blacklist: "Una lista de dominios de correo electrónico con los que los usuarios no se podrán registrar. Ejemplo: mailinator.com|trashmail.net" email_domains_whitelist: "Una lista de dominios de email con los que los usuarios DEBERÁN registrar sus cuentas. AVISO: ¡los usuarios con un email con diferente dominio a los listados no estarán permitidos!" @@ -897,6 +942,7 @@ es: sso_overrides_name: "Sobreescribe el nombre completo con el que provee el payload del SSO en cada registro, y previene cambios locales." sso_overrides_avatar: "Sustituye el avatar de usuario con el avatar proveniente del sitio externo configurado para el SSO. Si se activa esta opción, se recomienda encarecidamente deshabilitar allow_uploaded_avatars" sso_not_approved_url: "Redireccionar cuentas SSO sin aprobar a esta URL" + sso_allows_all_return_paths: "No restringe el dominio para return_paths provisto por SSO (por defecto, el return_paths debe ser sobre el sitio actual)." enable_local_logins: "Habilitar las cuentas con nombre de usuario y contraseña de forma local. (Nota: esto debe estar habilitado para que funcionen las invitaciones)" allow_new_registrations: "Permitir el registro de nuevos usuarios. Desactiva esta opción para prevenir que nadie pueda crear una nueva cuenta." enable_signup_cta: "Mostrar un aviso a los usuarios anónimos que vuelvan a visitar el sitio animándoles a registrarse." @@ -1029,6 +1075,7 @@ es: max_attachment_size_kb: "El tamaño máximo, en kB, para adjuntar archivos. Debe ser configurado también en nginx (client_max_body_size) / apache o proxy." authorized_extensions: "Una lista de las extensiones de archivo permitidas para subir (usa \"*\" para habilitar todos los tipos de archivo)" max_similar_results: "Cuántos temas similares se mostrarán encima del editor cuando estés creando un nuevo tema. La comparación se basa en el título y el cuerpo del tema." + max_image_megapixels: "Máximo de megapíxeles permitidos por una imagen." title_prettify: "Prevenir errores comunes en el título, incluyendo \"todo mayúsculas\", primera letra minúscula, multiples signos ! o ?, . extra al final, etc." topic_views_heat_low: "Después de este número de vistas, el campo vistas será ligeramente resaltado." topic_views_heat_medium: "Después de este número de visitas, el campo visitas será moderadamente resaltado." @@ -1087,9 +1134,12 @@ es: reset_bounce_score_after_days: "Restablecer la puntuación de reobte automáticamente pasados X días." attachment_content_type_blacklist: "Lista de palabras clave utilizadas para bloquear adjuntos basados en el tipo de contenido." attachment_filename_blacklist: "Lista de palabras clave utilizadas para bloquear adjuntos basados en el nombre de archivo." + enable_forwarded_emails: "[BETA] Permitir a los usuarios crear temas enviándolos por email." + always_show_trimmed_content: "Mostrar siempre la parte recortada de los emails entrantes. AVISO: podría revelar direcciones de correo." manual_polling_enabled: "Lanza emails usando la API para las respuestas por email." pop3_polling_enabled: "Poll vía POP3 para respuestas de e-mail." pop3_polling_ssl: "Usar SSL mientras se conecta al servidor POP3. (Recomendado)" + pop3_polling_openssl_verify: "Verificar certificado TLS sel servidor (activado por defecto)" pop3_polling_period_mins: "El período en minutos entre revisiones de correo de la cuenta POP3. NOTA: requiere reiniciar." pop3_polling_port: "El puerto utilizado para hacer polling a la cuenta POP3." pop3_polling_host: "El host utilizado para hacer polling de e-mails vía POP3." @@ -1112,19 +1162,27 @@ es: allow_animated_thumbnails: "Generar miniaturas en movimiento de los gifs animados." default_avatars: "URLs de avatares que se utilizarán por defecto para nuevos usuarios." automatically_download_gravatars: "Descargar Gravatars para usuarios cuando se creen una cuenta o cambien el email." + digest_topics: "El número máximo de temas populares que se muestran en el email de resumen." + digest_posts: "El número máximo de temas populares que se mostrarán en el email de resumen." + digest_other_topics: "El número máximo de temas que se mostrarán en la sección del email de resumen 'Nuevo en temas y categorías'." digest_min_excerpt_length: "Mínimo de caracteres del extracto de posts en el resumen por email." delete_digest_email_after_days: "Suprimir los emails de resumen para aquellos usuarios que no han visto el sitio desde más de (n) días." digest_suppress_categories: "Suprimir estas categorías de los emails de resumen." disable_digest_emails: "Desactivar emails de resumen para todos los usuarios." + email_accent_bg_color: "El color de realce utilizado como fondo en algunos elementos del HTML en los emails. Introduce un nombre de color ('red') o un valor hexadecimal ('#FF000')." + email_accent_fg_color: "El color de texto renderizado que irá con el color de fondo en el HTML de los emails. Introduce un nombre de color ('white') o un valor hexadecimal ('#FFFFFF')." + email_link_color: "El color de los enlaces en el HTML de los emails. Introduce un nombre de color ('blue') o un valor hexadecimal ('#0000FF')." detect_custom_avatars: "Verificar o no que los usuarios han subido una imagen de perfil." max_daily_gravatar_crawls: "Máximo número de veces que Discourse comprobará Gravatar en busca de avatares personalizados en un día" public_user_custom_fields: "Una lista con campos personalizados para el usuario que pueden ser mostrados públicamente." staff_user_custom_fields: "Una lista con campos personalizados para el usuario que pueden ser mostrados a los moderadores o admin." enable_user_directory: "Proporcionar un directorio de usuarios" + enable_group_directory: "Activa un directorio de grupos para explorar" allow_anonymous_posting: "Permitir a los usuarios cambiar a modo anónimo" anonymous_posting_min_trust_level: "Nivel de confianza mínimo requerido para activar el modo anónimo" anonymous_account_duration_minutes: "Para proteger el anonimato, crear una nueva cuenta anónima cada N minutos para cada usuario. Ejemplo: si se establece en 600, tan pronto como pasen 600 minutos desde el último post Y el usuario cambie a anónimo, se creará una nueva cuenta anónima." hide_user_profiles_from_public: "Desactiva las tarjetas de usuario, los perfiles y el directorio de usuarios para usuarios anónimos." + user_website_domains_whitelist: "El sitio web del usuario será automáticamente verificado con estos dominios. Lista delimitada por barras |" allow_profile_backgrounds: "Permitir a los usuarios subir sus propios fondos de perfil personalizados." sequential_replies_threshold: "Número de mensajes que un usuario tiene que publicar seguidos antes de que se le recuerde sobre demasiadas respuestas consecutivas." enable_mobile_theme: "Los dispositivos móviles utilizan un tema adaptado, con la habilidad de cambiar al estilo de sitio completo. Deshabilita esta opción si quieres utilizar una plantilla personalizada que sea completamente adaptable." @@ -1137,6 +1195,7 @@ es: automatically_unpin_topics: "Quitar destacado automáticamente cuando el usuario llega al final del tema." read_time_word_count: "Número de palabras por minuto para calcular el tiempo de lectura estimado." topic_page_title_includes_category: "El título de la página del tema incluye el nombre de la categoría." + native_app_install_banner: "Preguntar a visitantes recurrentes si quieren instalar la app nativa de Discourse" max_prints_per_hour_per_user: "Número máximo de impresiones de página /print (pon un 0 para desactivar esta opción)" full_name_required: "El nombre completo es un campo obligatorio del perfil de usuario." enable_names: "Mostrar el nombre completo del usuario en su perfil, tarjeta de usuario y emails. Desactiva esta opción para ocultar el nombre completo en todas partes." @@ -1154,12 +1213,12 @@ es: embed_username_key_from_feed: "Clave para extraer el nombre de usuario en Discourse desde el feed." embed_title_scrubber: "Expresión regular para depurar títulos embebibles." embed_truncate: "Truncar los posts embebidos." + allowed_href_schemes: "Esquemas permitidos en enlaces además de http y https." embed_post_limit: "Número máximo de posts a embeber." embed_username_required: "Se requiere el nombre de usuario para la creación de temas." embed_whitelist_selector: "Selector CSS para los elementos que están permitidos en los embebidos." embed_blacklist_selector: "Selector CSS para los elementos que están eliminados desde los embebidos." notify_about_flags_after: "Si hay reportes que no han sido revisados después de este número de horas, enviar un correo electrónico al contact_email. Deshabilita esta opción introduciendo el valor 0." - enable_cdn_js_debugging: "Permitir /logs mostrar los errores correctamente, añadiendo permisos crossorigin en todas las inclusiones de js" show_create_topics_notice: "Si el sitio tiene menos de 5 temas abiertos al público, mostrar un aviso pidiendo a los administradores crear más temas." delete_drafts_older_than_n_days: Eliminar borradores de más de (n) días de antigüedad. bootstrap_mode_min_users: "Mínimo número de usuarios requerido para desactivar el modo bootstrap (pon 0 para desactivar esta opción)" @@ -1177,6 +1236,7 @@ es: auto_close_topics_post_count: "Máximo número de publicaciones permitidas en un tema antes de que sea cerrado automáticamente (0 para desactivar)" code_formatting_style: "El botón de código en el editor se establecerá por defecto a este estilo de formato de código" default_email_digest_frequency: "Cuán a menudo recibirán los usuarios emails de resumen por defecto." + default_include_tl0_in_digests: "Incluir temas de usuarios nuevos en los emails de resumen por defecto. Los usuarios pueden cambiar esto en sus preferencias." default_email_private_messages: "Enviar un email cuando alguien envíe un mensaje al usuario por defecto." default_email_direct: "Enviar un email cuando alguien cite/responda/mencione o invite al usuario por defecto." default_email_mailing_list_mode: "Enviar un email por cada nuevo post por defecto." @@ -1187,6 +1247,7 @@ es: default_email_in_reply_to: "Incluir por defecto un extracto del post al que se ha respondido en los emails." default_other_new_topic_duration_minutes: "Condición por defecto para que un tema sea considerado nuevo" default_other_auto_track_topics_after_msecs: "Tiempo por defecto hasta que un tema sea seguido automáticamente." + default_other_notification_level_when_replying: "Nivel global de notificación cuando el usuario responde a un tema." default_other_external_links_in_new_tab: "Abrir enlaces externos en una nueva pestaña por defecto." default_other_enable_quoting: "Activar respuesta citando texto seleccionado por defecto." default_other_dynamic_favicon: "Mostrar temas nuevos/actualizados en el icono del navegador por defecto" @@ -1196,17 +1257,28 @@ es: default_categories_watching: "Lista de categorías que están vigiladas por defecto." default_categories_tracking: "Lista de categorías que están seguidas por defecto" default_categories_muted: "Lista de categorías que están silenciadas por defecto." + default_categories_watching_first_post: "Lista de categorías en las que el mensaje de cada nuevo tema será vigilado por defecto." + max_user_api_reqs_per_day: "Número máximo de peticiones de API de usuario por clave y por día" + max_user_api_reqs_per_minute: "Número máximo de peticiones de API de usuario por clave y por minuto" + allow_user_api_keys: "Permitir que se generen claves de API de usuario" + max_api_keys_per_user: "Número máximo de claves de usuario por usuario" + min_trust_level_for_user_api_key: "Nivel de confianza necesario para generar claves de API de usuario" tagging_enabled: "¿Activar etiquetas para los temas?" min_trust_to_create_tag: "El mínimo nivel de confianza requerido para crear una etiqueta." max_tags_per_topic: "El máximo número de etiquetas que se pueden añadir a un tema." max_tag_length: "Máximo número de caracteres que puede tener una etiqueta." + max_tag_search_results: "Al buscar etiquetas, el número máximo de resultados que mostrar." show_filter_by_tag: "Mostrar un desplegable para filtrar una lista de temas por etiqueta." max_tags_in_filter_list: "Máximo número de etiquetas en el desplegable. Se mostrarán primero aquellas más utilizadas." tags_sort_alphabetically: "Mostrar etiquetas en orden alfabético. Por defecto se mostrarán por popularidad." tag_style: "Estilo visual de las etiquetas." staff_tags: "Una lista de etiquetas que sólo pueden ser aplicadas por administradores o moderadores" min_trust_level_to_tag_topics: "Nivel mínimo requerido para etiquetar temas" + suppress_overlapping_tags_in_list: "Si alguna etiqueta coinciden con palabras en el título de los temas, ocultarla." remove_muted_tags_from_latest: "No mostrar temas con etiquetas silenciadas en la lista de temas recientes." + company_short_name: "Nombre de la empresa (corto)" + company_full_name: "Nombre de la empresa (largo)" + company_domain: "Dominio de la empresa" errors: invalid_email: "Dirección de correo electrónico inválida. " invalid_username: "No existe ningún usuario con ese nombre de usuario. " @@ -1221,6 +1293,7 @@ es: invalid_string_min: "Debe contener como mínimo %{min} caracteres. " invalid_string_max: "No debe exceder los %{max} caracteres. " invalid_reply_by_email_address: "El valor debe contener '%{reply_key}' y debe ser diferente del email de notificación." + invalid_alternative_reply_by_email_addresses: "Todas los valores deben contener '%{reply_key}' y deben ser diferentes del email de notificación." pop3_polling_host_is_empty: "Debes establecer un host de 'pop3 polling' antes de activar el polling POP3." pop3_polling_username_is_empty: "Debes establecer un usuario de 'pop3 polling' antes de activar el polling POP3." pop3_polling_password_is_empty: "Debes establecer una contraseña de 'pop3 polling' antes de activar el polling POP3." @@ -1228,6 +1301,7 @@ es: reply_by_email_address_is_empty: "Debes establecer el campo 'reply by email address' antes de activar respuesta por email." email_polling_disabled: "Debes activar el polling POP3 o bien el manual antes de activar la respuesta por email." user_locale_not_enabled: "Debes activar primero 'allow user locale' antes de activar esta opción." + invalid_regex: "El código Regex es inválido o no está permitido." search: within_post: "#%{post_number} por %{username}" types: @@ -1246,6 +1320,13 @@ es: redirected_to_top_reasons: new_user: "¡Bienvenido a nuestra comunidad! Estos son los temas recientes mas populares." not_seen_in_a_month: "¡Bienvenido de vuelta! No te habíamos visto en un tiempo. Estos son los temas mas populares desde que no has estado." + merge_posts: + edit_reason: + one: "Un tema fue juntado por %{username}" + other: "%{count} mensaje fueron juntados por %{username}" + errors: + different_topics: "Mensajes que pertenecen a temas diferentes no pueden ser juntados." + different_users: "Mensajes que pertenecen a diferentes usuarios no pueden ser juntados." move_posts: new_topic_moderator_post: one: "un post fue trasladado a un nuevo tema: %{topic_link}" @@ -1313,6 +1394,7 @@ es: something_already_taken: "Algo ha salido mal, quizá el nombre de usuario o el email ya han sido registrados. Prueba con el enlace de olvidé mi contraseña." omniauth_error: "Lo sentimos, hubo un error al autorizar tu cuenta. ¿Quizás no has aprobado la autorización?" omniauth_error_unknown: "Algo ha salido mal procesando tu inicio de sesión, por favor, vuelve a intentarlo." + authenticator_error_no_valid_email: "Ninguna dirección de email asociada con %{account} está permitida. Puede que necesites configurar tu cuenta con una dirección de email diferente." new_registrations_disabled: "El registro de nuevas cuentas no está permitido en este momento." password_too_long: "Las contraseñas están limitadas a 200 caracteres" email_too_long: "El email que has proporcionado es demasiado largo. Las direcciones de correo no deben tener más de 254 caracteres y los nombres de dominio no más de 253." @@ -1322,6 +1404,7 @@ es: already_logged_in: "Ups, parece que estás intentando aceptar una invitación dirigida a otro usuariol. Si no eres %{current_user}, por favor cierra sesión e inténtalo de nuevo." user: no_accounts_associated: "No hay cuentas relacionadas." + deactivated: "Ha sido desactivado a causa de muchos rebotes al email '%{email}'." username: short: "debe contener al menos %{min} caracteres" long: "debe contener no más de %{max} caracteres" @@ -1335,9 +1418,12 @@ es: email: not_allowed: "este proveedor de email no está permitido. Por favor, utiliza otra dirección de email." blocked: "no está permitido." + revoked: "No se enviarán más emails a '%{email}' hasta %{date}." ip_address: blocked: "No se permiten nuevos registros desde tu dirección IP." max_new_accounts_per_registration_ip: "No se permiten nuevos registros desde tu dirección IP (alcanzado el límite máximo). Contacta un miembro del staff." + website: + domain_not_allowed: "El sitio web no es válido. Los dominios permitidos son: %{domains}" flags_reminder: flags_were_submitted: one: "Hay reportes enviados hace 1 hora. Por favor, revísalos." @@ -1373,8 +1459,32 @@ es: %{invite_link} Esta invitación proviene de un usuario de confianza, por lo que puedes comentar en el tema inmediatamente. + custom_invite_mailer: + subject_template: "%{invitee_name} te ha invitado a '%{topic_title}' en %{site_domain_name}" + text_body_template: | + %{invitee_name} te ha invitado a un debate + + > **%{topic_title}** + > + > %{topic_excerpt} + + en + + > %{site_title} -- %{site_description} + + Mensaje de %{invitee_name}: + + %{user_custom_message} + + Si estás interesado en participar, haz clic en el enlace debajo: + + %{invite_link} + + Esta invitación viene de un usuario en el que confiamos, por lo que podrás responder inmediatamente. invite_forum_mailer: subject_template: "%{invitee_name} te invitó a unirte a %{site_domain_name}" + custom_invite_forum_mailer: + subject_template: "%{invitee_name} te ha invitado a %{site_domain_name}" invite_password_instructions: subject_template: "Asigna una contraseña para tu cuenta en %{site_name}" text_body_template: | @@ -1388,12 +1498,43 @@ es: subject_template: "[%{site_name}] Prueba de envío de email" new_version_mailer: subject_template: "[%{site_name}] Nueva versión de Discourse, actualización disponible" + text_body_template: | + ¡Genial, una nueva versión de [Discourse](http://www.discourse.org) está disponible! + + Tu versión: %{installed_version} + Nueva versión: **%{new_version}** + + - Actualiza usando nuestro sencillo **[sistema de un clic para actualizar](%{base_url}/admin/upgrade)** + + - Echa un vistazo a los cambios en el [changelog de GitHub](https://github.com/discourse/discourse/commits/master) + + - Visita [meta.discourse.org](https://meta.discourse.org) para noticias, debates y ayuda para Discourse. new_version_mailer_with_notes: subject_template: "[%{site_name}] actualización disponible" + text_body_template: |+ + ¡Genial, una nueva versión de [Discourse](http://www.discourse.org) está disponible! + + Tu versión: %{installed_version} + Nueva versión: **%{new_version}** + + - Actualiza usando nuestro sencillo **[sistema de un clic para actualizar](%{base_url}/admin/upgrade)** + + - Echa un vistazo a los cambios en el [changelog de GitHub](https://github.com/discourse/discourse/commits/master) + + - Visita [meta.discourse.org](https://meta.discourse.org) para noticias, debates y ayuda para Discourse. + + ### Detalles de la versión + + %{notes} + queued_posts_reminder: subject_template: one: "[%{site_name}] 1 post esperando ser revisado" other: "[%{site_name}] %{count} posts esperando ser revisados" + text_body_template: | + Hola, + + Algunos mensajes de usuarios nuevos han sido retenidos para moderar y están esperando ser revisados. [Apruébalos o recházalos aquí](%{base_url}/queued-posts). flag_reasons: off_topic: "Tu post fue reportado como **off-topic**: la comunidad piensa que no se ajusta debidamente al tema, definido por el título o el primer post." inappropriate: "Tu post fue reportado como **inapropiado**: la comunidad piensa que es ofensivo, abusivo o que vulnera alguna de [nuestros consejos de uso](/guidelines)." @@ -1407,6 +1548,22 @@ es: deferred_and_deleted: "Gracias por hacérnoslo saber. Hemos eliminado el post." temporarily_closed_due_to_flags: "Este tema está temporalmente cerrado debido a un gran número de reportes de la comunidad." system_messages: + post_hidden: + subject_template: "Mensaje ocultado debido a varios reportes de la comnuidad" + text_body_template: | + Hola, + + Esto es un mensaje automático de %{site_name} para hacerte saber que tu mensaje ha sido ocultado. + + %{base_url}%{url} + + %{flag_reason} + + Varios miembros de la comunidad han reportado el mensaje antes de que fuera ocultado, por lo que te recomendamos que revises tu mensaje para reflejar su opinión. **Puedes editar tu mensaje en %{edit_delay} minutos, y será automáticamente mostrado de nuevo.** + + Sin embargo, si el mensaje es ocultado por la comunidad una segunda vez, seguirá ocultado hasta que el staff lo revise – y se podrían tomar medidas incluida la posible suspensión de tu cuenta. + + Para más información sobre lo que consideramos adecuado, lee las [directrices de la comunidad](%{base_url}/guidelines). welcome_user: subject_template: "¡Bienvenido a %{site_name}!" text_body_template: | @@ -1421,34 +1578,49 @@ es: (Si necesitas comunicarte con [algún miembro del staff](%{base_url}/about) como nuevo usuario, puedes responder a este mensaje.) welcome_invite: subject_template: "¡Bienvenido a %{site_name}!" - text_body_template: | - Gracias por aceptar tu invitación a %{site_name} -- ¡Te damos la bienvenida! - - Hemos creado automáticamente una nueva cuenta para ti: **%{username}**. Puedes cambiar tu nombre de usuario en cualquier momento visitando [tu perfil][prefs]. - - Para iniciar sesión en adelante: - - 1. Usa siempre la **misma dirección de correo** en la que recibiste tu invitación original. ¡De otra manera no seremos capaces de reconocer que eres tú! - - 2. Crea una contraseña unica para [tu perfil de usuario][prefs], y úsala para iniciar sesión. - - %{new_user_tips} - - Creemos en una comunidad con un [comportamiento civilizado](%{base_url}/guidelines). - - ¡Disfruta de tu estancia! - - (Si necesitas comunicarte por privado con [algún miembro del staff](%{base_url}/about) como nuevo usuario, puedes responder a este mensaje.) - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "La copia de seguridad se completo exitosamente" + text_body_template: |+ + Copia de seguridad realizada con éxito. + + Visita la sección [admin > copias de seguridad](%{base_url}/admin/backups) para descargarla. + + Aquí está el registro: + + ```text + %{logs} + ``` + backup_failed: subject_template: "La copia de seguridad falló" + text_body_template: | + La copia de seguridad ha fallado. + + Aquí está el registro: + + ```text + %{logs} + ``` restore_succeeded: subject_template: "Restauración completada exitosamente." + text_body_template: | + La restauración se ha completado con éxito. + + Aquí está el registro: + + ```text + %{logs} + ``` restore_failed: subject_template: "La restauración falló." + text_body_template: | + La restauración ha fallado. + + Aquí está el registro: + + ```text + %{logs} + ``` bulk_invite_succeeded: subject_template: "Invitación masiva procesada con éxito" text_body_template: "Tu archivo de invitación masiva ha sido procesado, se han enviado %{sent} invitaciones." @@ -1475,12 +1647,32 @@ es: text_body_template: "Lo sentimos, pero la exportación de datos falló. Por favor, verifica los registros o contacta a un miembro del staff." email_reject_insufficient_trust_level: subject_template: "[%{site_name}] Problema relacionado con el email -- Insuficiente nivel de confianza" + text_body_template: | + Lo sentimos, pero tu mensaje de email a %{destination} (con título %{former_title}) no ha funcionado. + + Tu cuenta no tiene el nivel de confianza necesario para publicar nuevos temas a esta dirección de email. Si crees que se trata de un error, contacta a un miembro del staff. + email_reject_user_not_found: + subject_template: "[%{site_name}] Problema de email -- Usuario no encontrado" + email_reject_screened_email: + subject_template: "[%{site_name}] Problema con el correo electrónico -- Correo bloqueado" + text_body_template: | + Lo sentimos, pero tu email para %{destination} (titulado %{former_title}) se ha rechazado. + + No hay una cuenta asociada con esta dirección de email. Intenta enviarlo con otra dirección de email o contacta con algún miembro del Staff. email_reject_inactive_user: subject_template: "[%{site_name}] Problema relacionado con el email -- Usuario inactivo" text_body_template: | Lo sentimos, pero tu email para %{destination} (titulado %{former_title}) no se entregó. La cuenta asociada a esta dirección de email no ha sido activada. Por favor activa tu cuenta antes de enviar emails. + email_reject_blocked_user: + subject_template: "[%{site_name}] Problema con el correo electrónico -- Usuario bloqueado" + text_body_template: | + Lo sentimos, pero tu email para %{destination} (titulado %{former_title}) no se entregó. + + La cuenta asociada a esta dirección de email ha sido bloqueada. + email_reject_reply_user_not_matching: + subject_template: "[%{site_name}] Problema con el correo electrónico -- Email de respuesta no esperado" email_reject_no_account: subject_template: "[%{site_name}] Problema con el correo electrónico -- Cuenta Desconocida" email_reject_empty: @@ -1492,12 +1684,15 @@ es: Si estás teniendo este problema y _sí_ incluiste contenido, inténtalo de nuevo con un formato más simple. email_reject_parsing: + subject_template: "[%{site_name}] Problema con el correo electrónico -- Contenido erróneo" text_body_template: | Lo sentimos, pero tu email para %{destination} (titulado %{former_title}) no funcionó. No hemos encontrado tu respuesta en el email. **Asegúrate de escribir tu entera respuesta al principio del email** - no podemos analizar respuestas entre líneas. email_reject_invalid_access: subject_template: "[%{site_name}] Error de email -- Acceso no válido" + email_reject_strangers_not_allowed: + subject_template: "[%{site_name}] Error de email -- Acceso no válido" email_reject_reply_key: subject_template: "[%{site_name}] Problema con el correo electrónico -- Clave de Respuesta Desconocida" email_reject_topic_not_found: @@ -1508,6 +1703,37 @@ es: subject_template: "[%{site_name}] Problema con el correo electrónico -- Respuesta Auto Generada" email_error_notification: subject_template: "[%{site_name}] Problema con el correo electrónico -- Error de autenticación POP" + too_many_spam_flags: + subject_template: "Nueva cuenta retenida" + text_body_template: | + Hola, + + Esto es un mensaje automático de %{site_name} para hacerte saber que tus mensajes han sido ocultados temporalmente porque han sido reportados por la comunidad. + + Como medida cautelar, tu cuenta nueva ha sido bloqueada y no puede crear nuevas respuestas o temas hasta que un miembro del staff la revise. Sentimos las molestias ocasionadas. + + Para más información sobre lo que consideramos adecuado, lee las [directrices de la comunidad](%{base_url}/guidelines). + too_many_tl3_flags: + subject_template: "Nueva cuenta retenida" + text_body_template: | + Hola, + + Esto es un mensaje automático de %{site_name} para hacerte saber que tus mensajes han sido ocultados temporalmente porque han sido reportados muchas veces por la comunidad. + + Como medida cautelar, tu cuenta nueva ha sido bloqueada y no puede crear nuevas respuestas o temas hasta que un miembro del staff la revise. Sentimos las molestias ocasionadas. + + Para más información sobre lo que consideramos adecuado, lee las [directrices de la comunidad](%{base_url}/guidelines). + blocked_by_staff: + subject_template: "Cuenta temporalmente retenida" + text_body_template: | + Hola, + + Esto es un mensaje automático de %{site_name} para hacerte saber que tu cuenta ha sido temporalmente retenida como medida cautelar. + + Por favor, sigue leyendo, pero no podrás responder o crear temas hasta que un [miembro del staff](%{base_url}/about) revise tus últimos temas. Sentimos las molestias ocasionadas. + + + Para más información sobre lo que consideramos adecuado, lee las [directrices de la comunidad](%{base_url}/guidelines). user_automatically_blocked: subject_template: "Nuevo usuario %{username} bloqueado por las \"banderas\" de la comunidad." text_body_template: | @@ -1599,6 +1825,7 @@ es: > %{site_title} -- %{site_description} user_invited_to_private_message_pm: + title: "Usuario invitado a MP" subject_template: "[%{site_name}] %{username} te ha invitado a un hilo de mensajes '%{topic_title}'" text_body_template: | %{header_instructions} @@ -1607,6 +1834,7 @@ es: %{respond_instructions} user_invited_to_private_message_pm_staged: + title: "Usuario invitado a MP provisional" subject_template: "[%{site_name}] %{username} te ha invitado a un mensaje '%{topic_title}'" text_body_template: | %{header_instructions} @@ -1615,6 +1843,7 @@ es: %{respond_instructions} user_invited_to_topic: + title: "Usuario invitado a tema" subject_template: "[%{site_name}] %{username} te invitó a '%{topic_title}'" text_body_template: | %{header_instructions} @@ -1623,6 +1852,7 @@ es: %{respond_instructions} user_replied: + title: "Usuario respondió" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -1633,6 +1863,7 @@ es: %{respond_instructions} user_replied_pm: + title: "Usuario respondió por MP" subject_template: "[%{site_name}] [MP] %{topic_title}" text_body_template: | %{header_instructions} @@ -1643,6 +1874,7 @@ es: %{respond_instructions} user_quoted: + title: "Usuario citado" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -1653,6 +1885,7 @@ es: %{respond_instructions} user_linked: + title: "Usuario enlazado" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -1663,6 +1896,7 @@ es: %{respond_instructions} user_mentioned: + title: "Usuario mencionado" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -1673,6 +1907,7 @@ es: %{respond_instructions} user_group_mentioned: + title: "Grupo del usuario mencionado" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -1683,6 +1918,7 @@ es: %{respond_instructions} user_posted: + title: "Usuario publicó" subject_template: "[%{site_name}] %{subject_prefix}%{username} publicó en '%{topic_title}'" text_body_template: | %{header_instructions} @@ -1719,10 +1955,23 @@ es: %{message} digest: why: "Un breve resumen de %{site_link} desde tu última visita el %{last_seen_at}" + since_last_visit: "Desde tu última visita" + new_topics: "Temas nuevos" + unread_messages: "Mensajes no leídos" + unread_notifications: "Notificaciones no leídas" + liked_received: "Me gusta recibidos" + new_posts: "Nuevos temas" + new_users: "Nuevos usuarios" + popular_topics: "Temas populares" + follow_topic: "Seguir este tema" + join_the_discussion: "Leer más" + popular_posts: "Temas populares" + from_topic_label: "Formulario" subject_template: "Resumen de [%{site_name}]" unsubscribe: "Este resumen se envía desde %{site_link} cuando pasa un tiempo desde tu última visita. Para cancelar tu suscripción %{unsubscribe_link}." click_here: "clic aquí" from: "resumen de %{site_name}" + preheader: "Un corto resumen desde tu última visita el %{last_seen_at}" mailing_list: why: "Actividad en %{site_link} a %{date}" subject_template: "[%{site_name}] Resumen del %{date}" @@ -1865,6 +2114,7 @@ es: message_to_blank: "message.to está en blanco" text_part_body_blank: "text_part.body está en blanco" body_blank: "el cuerpo está en blanco" + no_echo_mailing_list_mode: "Modo lista de correo desactivado para los post del usuario" color_schemes: base_theme_name: "Base" about: "Acerca de" @@ -2432,6 +2682,131 @@ es: staff_tag_disallowed: "La etiqueta \"%{tag}\" solo puede ser insertada por moderadores." staff_tag_remove_disallowed: "La etiqueta \"%{tag}\" solo puede ser eliminada por moderadores." rss_by_tag: "Temas con la etiqueta %{tag}" + finish_installation: + congratulations: "Enhorabuena, ¡has instalado Discourse!" + register: + button: "Registrarse" + title: "Registrar cuenta de administrador" + help: "registra una nueva cuenta para empezar" + no_emails: "Desgraciadamente, no se han definido emails de administrador durante la instalación, por lo que finalizar la configuración podría ser difícil." + confirm_email: + title: "Confirmar tu email" + message: "

    Hemos enviado un email de activación a %{email}. Por favor, sigue las intrucciones en el email para activar tu cuenta.

    Si no llega, asegúrate que el email esté configurado correctamente en Discourse y comprueba tu carpeta de spam

    " + resend_email: + title: "Volver a enviar email de activación" + message: "

    Hemos reenviado el correo de activación a %{email}" + safe_mode: + title: "Activar modo seguro" + description: "El modo seguro permite probar tu página sin cargar plugins o customizaciones." + no_customizations: "Desactivar todas las customizaciones" + only_official: "Desactivar plugins no oficiale" + no_plugins: "Desactivar todos los plugins" + enter: "Activar modo seguro" + wizard: + title: "Instalación de Discourse" + step: + locale: + title: "¡Bienvenido a tu foro de discourse!" + fields: + default_locale: + description: "¿Cuál es el idioma por defecto para tu comunidad?" + forum_title: + title: "Nombre" + description: "El nombre es un cartel que se vé desde lejos, la primera cosa que los visitantes en potencia verán sobre tu comunidad. ¿Qué dice el nombre de yu comunidad?" + fields: + title: + label: "El nombre de la comunidad" + site_description: + label: "Describe tu comunidad en una frase corta" + introduction: + title: "Introducción" + fields: + welcome: + label: "Tema de bienvenida" + one_paragraph: "El mensaje de bienvenida no debería ser más de un párrafo." + privacy: + title: "Acceso" + fields: + privacy: + choices: + open: + label: "Pública" + description: "Todo el mundo puede acceder a la comunidad y registrar una cuenta" + restricted: + label: "Privada" + description: "Solo gente invitada o con aprobación tiene acceso a esta comunidad" + contact: + title: "Contacto" + fields: + contact_email: + label: "Correo" + placeholder: "nombre@ejemplo.com" + description: "Dirección de email de la persona o grupo responsable de esta comunidad. Usado para notificaciones críticas como reportes sin atender, actualizaciones de seguridad y estará en la página Acerca de para cosas urgentes." + contact_url: + label: "Página web" + placeholder: "http://ejemplo.com/contacto" + description: "Tu página de contacto o la de tu organización. Será mostrada en la página de acerca de." + site_contact: + label: "Mensajes automáticos" + description: "Todos los mensajes privados automáticos de Discourse serán mandados desde este usuarios. Más importante, este usuario será el que envíe el mensaje de bienvenida que se manda automáticamente a todos los usuarios." + corporate: + title: "Organización" + fields: + company_short_name: + label: "Nombre de la empresa (corto)" + placeholder: "Initech" + company_full_name: + label: "Nombre de la empresa (completo)" + placeholder: "Initech S.L." + company_domain: + label: "Dominio de la empresa " + placeholder: "initech.com" + colors: + title: "Tema" + fields: + theme_id: + choices: + default: + label: "Simple y claro" + dark: + label: "Simple y oscuro" + logos: + title: "Logos" + fields: + logo_url: + label: "Logo principal" + description: "La imágen que estará arriba a la izquierda en tu página. Usar un rectángulo ancho." + logo_small_url: + label: "Logo compacto" + description: "Una versión compacta del logo que estará arriba a la izquierda cuando los usuarios bajen. Usar un cuadrado." + icons: + title: "Iconos" + fields: + favicon_url: + label: "Icono pequeño" + description: "Imagen usada para representar tu página en los navegadores que se vea bien en tamaños pequelos como 32px por 32px." + apple_touch_icon_url: + label: "Icono grande" + description: "Icono usado para representar tu página en dispositivos modernos y que se ve bien para tamaños grandes. El tamaño recomendado es al menos de 144px por 144px." + homepage: + title: "Página de inicio" + fields: + homepage_style: + choices: + latest: + label: "Temas recientes" + categories: + label: "Categorías" + emoji: + title: "Emoji" + invites: + title: "Invitar staff" + description: "¡Ya casi está! Invita algunos miembros del staff para ayudar a iniciar conversaciones con temas interesantes y respuestas para dar tu comunidad por empezadas." + finished: + title: "Tu foro de Discourse está listo!" + description: | +

    Si alguna vez quieres cambiar alguno de estos ajustes, visita tu sección de administrador; la puedes encontrar el lado del icono de una llave inglesa en el menú de la página..

    +

    Diviértete, y ¡buena suerte construyendo tu nueva comunidad!

    activemodel: errors: <<: *errors diff --git a/config/locales/server.et.yml b/config/locales/server.et.yml index 4b6459c0c50..a6959baca64 100644 --- a/config/locales/server.et.yml +++ b/config/locales/server.et.yml @@ -71,6 +71,7 @@ et: has_already_been_used: "on juba kasutusel" inclusion: puudub nimekirjas invalid: pole korrektne + is_invalid: "tundub segane. kas see on terve lause?" less_than: peab olema väiksem kui %{count} less_than_or_equal_to: peab olema väiksem või võrdne kui %{count} not_a_number: ei ole number @@ -105,11 +106,13 @@ et: default_categories_already_selected: "Sa ei saa valida teises nimekirjas valitud liiki." s3_upload_bucket_is_required: "Ei saa aktiveerida S3 üleslaadimist, kui 's3_upload_bucket' ei ole määratud." bulk_invite: - file_should_be_csv: "Üles laetud fail peab olema kas csv või txt formaadis." + file_should_be_csv: "Üles laetav fail peab olema CSV vormingus." + error: "Selle faili üleslaadimisel tekkis viga. Palun proovi hiljem uuesti." backup: operation_already_running: "Praegu on üks protsess pooleli. Uut tegevust ei saa hetkel käivitada." backup_file_should_be_tar_gz: "Varukoopia peab olema .tar.gz arhiivifail." not_enough_space_on_disk: "Varukoopia üleslaadimiseks pole piisavalt kettaruumi." + invalid_filename: "Varundusfaili nimi sisaldab keelatud sümboleid. Lubatud sümbolid on a-z 0-9 . - _." not_logged_in: "Selleks peate olema sisse logitud." not_found: "Päritud URLi või ressurssi ei leitud." invalid_access: "Päritud ressursi vaatamiseks puuduvad õigused." @@ -122,6 +125,11 @@ et: embed: start_discussion: "Alusta vestlust" continue: "Jätka arutelu" + error: "Sängitamine ebaõnnestus" + referer: "Sissetulev link:" + mismatch: "Sissetulev link ei kattu ühegagi järgmistest hostidest:" + no_hosts: "Sängitamiseks pole ühtegi hosti seadistatud." + configure: "Sängitamise seadistamine" more_replies: one: "veel 1 vastus" other: "veel %{count} vastust" @@ -155,8 +163,10 @@ et: spamming_host: "Vabandust, sa ei tohi sellele domeenile viidata." user_is_suspended: "Peatatud kasutajatel pole lubatud postitada." topic_not_found: "Midagi on valesti. Kas on võimalik, et antud teema suleti või kustutati samal ajal, kui te seda vaatasite?" + not_accepting_pms: "Kahjuks ei aktsepteeri %{username} hetkel sõnumeid." just_posted_that: "on liiga sarnane sellele, mida sa hiljuti postitasid" invalid_characters: "sisaldab ebasobivaid tähemärke" + is_invalid: "tundub segane. kas see on terve lause?" next_page: "järgmine leht →" prev_page: "← eelmine leht" page_num: "Leht %{num}" @@ -249,12 +259,25 @@ et: See teema on Sulle kindlasti väga tähtis – enam kui %{percent}% vastustest siin on Sinu postitatud. Kas oled kindel, et jätad ka teistele piisavalt aega ja võimalust oma arvamuse avaldamiseks? + too_many_replies: | + ### Oled selle teema vastuste limiidi saavutanud + + Vabandame, kuid uutele kasutajatele on ajutiselt seatud limiit %{newuser_max_replies_per_topic} vastust teema kohta. + + Uue vastuse lisamise asemel kaalu oma varasema vastuse muutmist või teiste teemade külastust. + reviving_old_topic: | + ### Vana teema taaselustamine? + + Viimane vastus sellele teemale on rohkem kui %{days} päeva vana. Sinu vastus tõstab selle teema nimekirja ette ning teavitab kõiki, kes selle teemaga seotud olid. + + Oled sa kindel, et soovid seda vana arutelu jätkata? activerecord: attributes: category: name: "Liigi nimetus" topic: title: 'Pealkiri' + featured_link: 'Põhiloo viide' post: raw: "Sisu" user_profile: @@ -268,12 +291,16 @@ et: too_many_users: "Saad hoiatusi saata vaid ühele kasutajale korraga." cant_send_pm: "Vabanda, sa ei saa sellele kasutajale privaatsõnumit saata." no_user_selected: "Pead valima sobiva kasutaja." + featured_link: + invalid: "on vigane. URL peab sisaldama http:// või https://." + invalid_category: "ei saa selles foorumis redigeerida." user: attributes: password: common: "on üks 10000 enim kasutatud salasõnast. Palun kasuta turvalisemat parooli." same_as_username: "on sama mis su kasutajanimi. Palun kasuta turvalisemat parooli." same_as_email: "on sama mis su meiliaadress. Palun kasuta turvalisemat parooli." + same_as_current: "ühtib sinu hetkel kehtiva parooliga." ip_address: signup_not_allowed: "Sellelt kontolt pole liitumine lubatud." color_scheme_color: @@ -283,6 +310,10 @@ et: post_reply: base: different_topic: "Postitus ja vastus peavad kuuluma samasse teemasse." + web_hook: + attributes: + payload_url: + invalid: "URL on vigane. URL peab sisaldama http:// või https://. Ning tühikud ei ole lubatud." <<: *errors user_profile: no_info_me: "
    Sinu profiili väli 'Minust' on hetkel tühi, kas sooviksid selle ära täita?
    " @@ -293,7 +324,24 @@ et: meta_category_description: "Arutelu selle saidi, tema korralduse, töömeetodite ja arenguvõimaluste kohta." staff_category_name: "Meeskond" staff_category_description: "Privaatfoorum meeskonnasisesteks aruteludeks. Teemad on nähtavad vaid adminnidele ja moderaatoritele." + assets_topic_title: "Saidi kujunduse vahendid" assets_topic_body: "See on püsiteema, nähtav vaid meeskonnale, selle saidi kujunduses kasutatavate piltide ja failide talletamiseks. Ära seda kustuta!\n\n\nTee nii:\n\n\n1. Vasta siia teemasse.\n2. Lae üles kõik pildid, mida soovida kasutada logodena, ikoonidena, vms. (Kasuta üleslaadimise ikooni postituse redaktori tööriistaribal, võid pildid siia ka lohistada või kleepida.)\n3. Postita oma vastus.\n4. Tee üleslaetud pildifailini leiad kas oma uues postituses oleval pildil paremklikates, või postituse muutmise ikooni klikkides ja kopeerides postitusest redaktoris. Kopeeri teed pildifailideni.\n5. Kleebi need teed sättesse [basic settings](/admin/site_settings/category/required).\n\n\nKui soovid lubada einevate failitüüpide üleslaadimist, muuda `authorized_extensions` sättes [file settings](/admin/site_settings/category/files)." + discourse_welcome_topic: + title: "Teretulemast Discourse'i" + body: |2 + + Selle märgistatud teema esimene lõik saab olema kõikidele uutele külastajatele nähtav kui tervitustekst sinu avalehel. See on oluline! + + **Muuda see** enda kommuuni lühitutvustuseks: + + - Kellele see on? + - Mida siit leiab? + - Miks peaks keegi siia tulema? + - Kust saab rohkem infot (lingid, ressursid jne)? + + + + Ilmselt peaksid sa selle teema administreerimise alt sulgema :wrench: (üleval paremal ja allääres), et teadandele vastuseid ei kuhjuks. lounge_welcome: title: "Teretulemast Lounge'i" body: |2 @@ -319,6 +367,8 @@ et: [trust]: https://meta.discourse.org/t/what-do-user-trust-levels-do/4924 category: topic_prefix: "Liigist %{category}" + replace_paragraph: "(Asenda see paragrahv oma uues kategoorias kategooria lühitutvustusega. See juhis ilmub siis kategooriate vaates. Seega, katsu hoida kirjeldus alla 200 tähemärgi. **Kuniks sa pole muutnud seda kirjeldust või kuni sa pole loonud teemasid, ei ole seda kategooriat kategooriate lehel näha.**)" + post_template: "%{replace_paragraph}\n\nKasuta järgnevaid lõikusid pikema kirjelduse jaoks või foorumi juhendi või reeglite jaoks:\n\n- Miks peaksid inimesed seda foorumit kasutama? Mille jaoks see on?\n\n- Mille poolest erineb see meie teistest foorumitest?\n\n- Mis infot peaksid selle foorumi teemad sisaldama?\n\n- Kas meil on seda foorumit vaja? Kas me saame seda foorumit ühendada teise foorumiga või alamfoorumiga?\n" errors: uncategorized_parent: "'Liigitamata' ei saa omada vanem-liiki" self_parent: "Alamliigi vanemaks ei tohi olla alamliik ise" @@ -345,6 +395,7 @@ et: title: "tavaline" leader: title: "juht" + change_failed_explanation: "Üritasid alandada %{user_name} tasemele '%{new_trust_level}'. Samas on tal juba tase'%{current_trust_level}'. %{user_name} jääb tasemele '%{current_trust_level}' - kui soovid alandada kasutaja taset, siis lukusta kõigepealt usaldustase." rate_limiter: slow_down: "Oled antud seda toimingut liiga palju proovinud. Proovi hiljem uuesti." too_many_requests: "Antud tegevuse jaoks on meil päevane kordade limiit. Palun oota %{time_left} enne kui uuesti proovid." @@ -354,6 +405,7 @@ et: create_topic: "Lisad teemasid liiga kiiresti. Palun oota %{time_left} enne kui uuesti proovid." create_post: "Vastad liiga kiiresti. Palun oota %{time_left} enne kui uuesti proovid." delete_post: "Kustutad postitusi liiga kiiresti. Palun oota %{time_left} enne kui uuesti proovid." + public_group_membership: "Liitud gruppidega/lahkud neist liiga sageli. Palun oota %{time_left} enne kui uuesti proovid." topics_per_day: "Oled ületanud tänaseks lubatud uute teemade lisamise limiidi. Palun oota %{time_left} enne kui uuesti proovid." pms_per_day: "Oled ületanud tänaseks lubatud sõnumite limiidi. Palun oota %{time_left} enne kui uuesti proovid." create_like: "Oled ületanud tänaseks lubatud meeldimiste lisamise limiidi. Palun oota %{time_left} enne kui uuesti proovid." @@ -443,36 +495,50 @@ et: one: "peaaegu 1 aasta tagasi" other: "peaaegu %{count} aastat tagasi" password_reset: + no_token: "Vabandust, see parooli uuendamise link on liiga vana. Vajuta sisselogimise nuppu ja kasuta värske lingi saamiseks 'Unustasin parooli'." choose_new: "Palun vali uus parool" choose: "Palun vali parool" update: 'Uuenda parooli' save: 'Määra Parool' title: 'Uuenda Parool' + success: "Sinu parooli muutmine õnnestus ja oled nüüd sisse logitud." success_unapproved: "Sinu parooli muutmine õnnestus." continue: "Edasi saidile %{site_name}" change_email: confirmed: "Sinu meiliaadress on uuendatud." please_continue: "Edasi saidile %{site_name}" + error: "Sinu meiliaadressi muutmisel esines tõrge. Äkki on see juba kasutuses?" + error_staged: "Sinu meiliaadressi muutmisel esines tõrge. Ettevalmistamisel olev kasutaja juba kasutab seda." + already_done: "Vabandust, see kinnitamise link ei kehti enam. Äkki on teie meiliaadress juba muudetud?" authorizing_old: title: "Täname, et oma kehtiva meiliaadressi kinnitasid" + description: "Saadame nüüd kinnituse Teie uuele meiliaadressile." activation: action: "Oma konto aktiveerimiseks kliki siia" + already_done: "Vabandust, see konto kinnitamise link ei kehti enam. Äkki on Teie konto juba aktiveeritud?" + please_continue: "Teie uus konto on kinnitatud; Teid suunatakse nüüd avalehele." continue_button: "Edasi saidile %{site_name}" welcome_to: "Tere tulemast %{site_name}!" + approval_required: "Enne, kui saate foorumit kasutada, peab moderaator Teie uue konto käsitsi kinnitama. Konto kinnitamise kohta tuleb teade meilile." + missing_session: "Me ei saa kontrollida kas Teie konto on loodud, palun kontrolli et brauseris oleks küpsised lubatud." post_action_types: off_topic: title: 'Teemaväline' + description: 'Arvestades postituse pealkirja ja sisu, ei ole see postitus käesoleva vestlusega seotud ning see tuleks tõenäoliselt mujale liigutada.' long_form: 'tähistasin selle kui teemavälise' spam: title: 'Spämm' + description: 'See postitus on reklaam. Käesoleva vestlusega seoses ei ole see ei kasulik ega asjakohane vaid pigem millegi reklaamimine.' long_form: 'tähistasin selle kui spämmi' email_title: '"%{title}" tähistati spämmina' email_body: "%{link}\n\n%{message}" inappropriate: title: 'Ebasünnis' + description: 'Selle postituse sisu on iga mõistliku inimese hinnangul solvav, ahistav või rikub meie kommuuni reegleid.' long_form: 'tähistasin selle kui sobimatu' notify_user: title: 'Saada kasutajale @{{username}} sõnum' + description: 'Soovin selle isikuga tema postituse osas otse ja privaatselt suhelda.' long_form: 'saatsin kasutajale sõnumi' email_title: 'Sinu postitus teemas "%{title}"' email_body: "%{link}\n\n%{message}" @@ -494,17 +560,36 @@ et: title: 'Hääleta' description: 'Hääleta selle postituse poolt' long_form: 'hääletas selle postituse poolt' + user_activity: + no_bookmarks: + self: "Te ei ole postitustele järjehoidjaid lisanud. Postitustele järjehoidjate lisamine lubab nende juurde hiljem hõlpsasti tagasi pöörduda." + others: "Järjehoidjad puuduvad." + no_likes_given: + self: "Sa pole oma meeldimist ühelegi postitusele andnud." + others: "Meeldimisega postitusi veel pole." topic_flag_types: spam: title: 'Spämm' + description: 'See teema on reklaam. See ei ole ei kasulik ega teemakohane.' long_form: 'tähistasin selle kui spämmi' inappropriate: title: 'Ebasobiv' long_form: 'tähistasin selle kui sobimatu' + notify_moderators: + title: "Miski muu" + long_form: 'tähistasin selle kui moderaatori tähelepanu vajava' + email_title: 'Teema "%{title}" nõuab moderaatori tähelepanu' + email_body: "%{link}\n\n%{message}" archetypes: + regular: + title: "Tavaline teema" banner: title: "Teema Bänneriks" + unsubscribed: + title: "Tellimus tühistatud!" unsubscribe: + title: "Tühista tellimus" + mailing_list_mode: "Lülita postiloendi režiim välja" log_out: "Logi välja" user_api_key: read: "lugemine" @@ -623,12 +708,41 @@ et: mobile_visits: xaxis: "Päev" yaxis: "Külastuste arv" + dashboard: + host_names_warning: "Sinu config/database.yml fail kasutab vaikimisi hostinime localhost. Kirjuta sinna oma saidi hostinimi." site_settings: min_post_length: "Lühim lubatud postituse pikkus" max_post_length: "Maksimaalne lubatud postituse pikkus tähemärkides" min_topic_title_length: "Lühim lubatud teema pealkirja pikkus tähemärkides" max_topic_title_length: "Maksimaalne lubatud teema pealkirja pikkus tähemärkides" min_private_message_title_length: "Minimaalne lubatud teema pealkirja pikkus tähemärkides" + enable_instagram_logins: "Luba autentimine Instagrami abil, nõuab instagram_consumer_key ja instagram_consumer_secret" + instagram_consumer_key: "Teenusekasutaja avalik võti Instagrami abil autentimiseks" + instagram_consumer_secret: "Teenusekasutaja salajane võti Instagrami abil autentimiseks" + enable_staged_users: "Sissetulevate meilide töötlemisel loo kasutajad ettevalmistamiseks automaatselt." + maximum_staged_users_per_email: "Ettevalmistamisel olevate kasutajate maksimaalne arv sai sissetuleva meili töötlemisel täis." + dominating_topic_minimum_percent: "Mitu protsenti teema postitustest peab kasutaja tegema, et talle saadetaks meeldetuletus teema liigse domineerimise kohta." + feed_polling_enabled: "VAID SÄNGITAMISEL: Kas sängitada RSS/ATOM voog postitusena." + feed_polling_url: "VAID SÄNGITAMISEL: URL või RSS/ATOM voog, mida sängitada." + embed_by_username: "Sängitatud teemasid lisava kasutaja Discourse kasutajanimi." + embed_title_scrubber: "Regex sängitatavate päiste puhastamiseks." + embed_truncate: "Lühenda sängitatud postitused." + embed_post_limit: "Maksimaalne postituste arv, mida sängitada." + embed_whitelist_selector: "CSS valik elementidele, mida lubada sängitamistes." + embed_blacklist_selector: "CSS valik elementidele, mida eemaldada sängitamistes." + tagging_enabled: "Luba silte teemadel?" + min_trust_to_create_tag: "Sildi lisamiseks nõutav minimaalne usaldustase." + max_tags_per_topic: "Teemale liidetavate siltide maksimaalne arv." + max_tag_length: "Sildis kasutatavate tähemärkide maksimaalne arv." + max_tag_search_results: "Siltide otsimisel maksimaalselt kuvatavate tulemuste arv." + show_filter_by_tag: "Näita rippmenüüd teemade loetelu filtreerimiseks siltide alusel." + max_tags_in_filter_list: "Filtri rippmenüüs kuvatavate siltide maksimaalne arv. Kuvatakse enimkasutatud sildid." + tags_sort_alphabetically: "Kuva sildid tähestikulises järjekorras. Vaikimisi kuvatakse need populaarsuse järjekorras." + tag_style: "Siltide vimplite visuaalne stiil." + staff_tags: "Siltide loetelu, mida võib lisada ainult meeskonna liige" + min_trust_level_to_tag_topics: "Teemade sildistamiseks on nõutav minimaalne usaldustase" + suppress_overlapping_tags_in_list: "Ära näita silti, kui see ühtib täpselt sõnaga teema päses" + remove_muted_tags_from_latest: "Ära näita värskete teemade nimistus teemasid, millel on vaigistatud silt." search: types: category: 'Liigid' @@ -639,6 +753,7 @@ et: frequent_poster: "Tihedam postitaja" login: admin_not_allowed_from_ip_address: "Sellelt IP-aadressilt ei saa adminnina sisse logida." + already_logged_in: "Oih, näib, et üritad vastu võtta võõra kasutaja kutset. Kui Sa ei ole kasutaja %{current_user}, logi palun välja ja proovi uuesti." system_messages: backup_failed: subject_template: "Varundamine ebaõnnestus" @@ -649,12 +764,39 @@ et: csv_export_failed: subject_template: "Andmete eksportimine ebaõnnestus" user_notifications: + unsubscribe: + title: "Tühista tellimus" + user_posted_pm_staged: + subject_template: "%{optional_re}%{topic_title}" + text_body_template: |2 + + %{message} mailing_list: + why: "Saidi %{site_link} kõik toimingud päeval %{date}" + subject_template: "[%{site_name}] Kokkuvõte päeval %{date}" + from: "%{site_name} kokkuvõte" new_topics: "Uued teemad" topic_updates: "eemade uuendused" view_this_topic: "Vaata seda teemat" back_to_top: "Tagasi üles" + forgot_password: + subject_template: "[%{site_name}] Parooli uuendamine" + set_password: + subject_template: "[%{site_name}] Määra parool" + admin_login: + subject_template: "[%{site_name}] Logi sisse" + account_created: + subject_template: "[%{site_name}] Sinu uus konto" + confirm_old_email: + subject_template: "[%{site_name}] Kinnita oma kehtiv meiliaadress" + notify_old_email: + subject_template: "[%{site_name}] Sinu meiliaadress on muudetud" + signup_after_approval: + subject_template: "Oled saidil %{site_name} heaks kiidetud!" + signup: + subject_template: "[%{site_name}] Kinnita oma uus konto" page_not_found: + title: "Oih! Soovitud lehte ei ole või on see privaatne." popular_topics: "Populaarsed" recent_topics: "Viimased" see_more: "Veel" @@ -666,7 +808,10 @@ et: email_log: anonymous_user: "Kasutaja on anonüümne" seen_recently: "Kasutajat nähti hiljuti" + topic_nil: "post.topic tühi hulk" message_blank: "sõnum on tühi" + message_to_blank: "message.to on tühi" + text_part_body_blank: "text_part.body on tühi" body_blank: "sisu on tühi" about: "Teave" guidelines: "Juhendid" @@ -692,39 +837,52 @@ et: name: Vedaja welcome: name: Teretulemast + description: Sai like'i autobiographer: name: Autobiograaf anniversary: name: Tähtpäev + description: Olnud aktiivne kasutaja vähemalt aasta, postitanud vähemalt ühe korra nice_post: name: Mõnus vastus good_post: name: Hea vastus + description: Kogus vastusele 25 like'i great_post: name: Suurepärane vastus + description: Kogus vastusele 50 like'i nice_topic: name: Mõnus teema + description: Kogus teemale 10 like'i good_topic: name: Hea teema + description: Kogus teemale 25 like'i great_topic: name: Suurepärane teema + description: Kogus teemale 50 like'i nice_share: name: Mõnus jagamine + description: Jagas postitust 25 unikaalse kasutajaga good_share: name: Hea jagamine + description: Jagas postitust 300 unikaalse külastajaga great_share: name: Suurepärane jagamine first_like: name: Esimene meeldimine + description: Laikis postitust first_flag: name: Esimene tähis description: Teatas lipuga postitusest promoter: name: Promootor + description: Kutsus kasutaja campaigner: name: Aktiivne promootor + description: Kutsus 3 tavakasutajat champion: name: Tšempion + description: Kutsus 5 liiget first_share: name: Esimene jagamine description: Jagas postitust @@ -740,10 +898,13 @@ et: name: Lugeja popular_link: name: Populaarne viide + description: Postitas välise lingi, millel 50 klikki hot_link: name: Kuum viide + description: Postitas välise lingi, millel 300 klikki famous_link: name: Kuulus viide + description: Postitas välise lingi, millel 1000 klikki appreciated: name: Hinnatud respected: @@ -758,16 +919,24 @@ et: name: Hullult armunud thank_you: name: Tänud + description: Omab 20 laigitud postitust ja laikis 10 postitust gives_back: name: Annab tagasi + description: Omab 100 laigitud postitust ja laikis 100 postitust empathetic: name: Empaatiline + description: Omab 500 laigitud postitust ja laikis 1000 postitust + long_description: | + Saad selle märgise, kui sul on 500 laigitud postitust ning oled ise laikunud 1000 või enam postitust. Oled tõeline lahkuse ja vastastikuse lugupidamise eeskuju :two_hearts: first_emoji: name: Esimene emotikon + description: Kasutasid postituses emotikoni first_mention: name: Esimene mainimine + description: Mainisid postituses kasutajat first_reply_by_email: name: Esimene vastamine meiliga + description: Vastasid postitusele läbi e-maili admin_login: success: "Kiri saadetud" error: "Viga!" @@ -775,6 +944,121 @@ et: submit_button: "Saada kiri" tags: title: "Sildid" + staff_tag_disallowed: "Sildi \"%{tag}\" võib lisada ainult meeskonna liige." + staff_tag_remove_disallowed: "Sildi \"%{tag}\" võib eemaldada ainult meeskonna liige." + rss_by_tag: "%{tag}-ga sildistatud teemad" + finish_installation: + congratulations: "Palju õnne, Discourse on paigaldatud!" + register: + button: "Registreeru" + title: "Registreeri adminni konto" + help: "alustamiseks registreeri uus konto" + resend_email: + title: "Saada aktiveerimismeil uuesti" + safe_mode: + title: "Sisene turvalisse režiimi" + no_customizations: "Keela kõik saidi kohandused" + only_official: "Keela kõik mitteametlikud pluginad" + no_plugins: "Keela kõik pluginad" + enter: "Sisene turvalisse režiimi" + wizard: + title: "Discourse sätted" + step: + locale: + title: "Tere tulemast oma Discourse'i!" + fields: + default_locale: + description: "Mis on Sinu kogukonna vaikekeel?" + forum_title: + title: "Nimi" + fields: + title: + label: "Sinu kogukonna nimi" + placeholder: "Jane ajaviitenurgake" + site_description: + label: "Kirjelda oma kogukonda ühe lühikese lausega" + placeholder: "Koht Janele ja tema sõpradele lahedate arutelude jaoks" + introduction: + title: "Sissejuhatus" + fields: + welcome: + label: "Tervitusteema" + one_paragraph: "Palun koonda oma tervitustekst ühte lõiku." + privacy: + title: "Juurdepääs" + fields: + privacy: + choices: + open: + label: "Avalik" + description: "Kogukonnale pääseb ligi igaüks ning võib liituda" + restricted: + label: "Privaatne" + description: "Kogukonnaga saavad liituda ainult minu poolt kutsutud või heakskiidetud inimesed" + contact: + title: "Kontakt" + fields: + contact_email: + label: "Meil" + placeholder: "nimi@kuskil.ee" + contact_url: + label: "Veebileht" + placeholder: "http://www.example.com/contact-us" + site_contact: + label: "Automaatsed sõnumid" + corporate: + title: "Organisatsioon" + fields: + company_short_name: + label: "Ettevõtte nimi (lühike)" + placeholder: "Juurutajad" + company_full_name: + label: "Ettevõtte nimi (täielik)" + placeholder: "Juurutajad OÜ" + company_domain: + label: "Ettevõtte domeeni nimi" + placeholder: "juurutajad.ee" + colors: + title: "Kujundusteema" + fields: + theme_id: + choices: + default: + label: "Lihtne hele" + dark: + label: "Lihtne tume" + logos: + title: "Logod" + fields: + logo_url: + label: "Peamine logo" + description: "Logo kujutis Sinu saidi vasakul ülanurgas. Kasuta laia ristküliku kujulist pilti." + logo_small_url: + label: "Kompaktne logo" + description: "Sinu logo kompaktne versioon, kuvatakse alla kerimisel Sinu saidi vasakul ülanurgas. Kasuta ruudu kujulist pilti." + icons: + title: "Ikoonid" + fields: + favicon_url: + label: "Väike ikoon" + apple_touch_icon_url: + label: "Suur ikoon" + description: "Soovitame kasutada ikooni, et kuvada oma saiti uuematel seadmetel, mille pilt on suurem. Soovitatud ikooni suurus on vähemalt 144px x 144px" + homepage: + title: "Avaleht" + fields: + homepage_style: + choices: + latest: + label: "Viimased teemad" + categories: + label: "Foorumid" + emoji: + title: "Emotikon" + invites: + title: "Kutsu meeskonda" + finished: + title: "Sinu Discourse on valmis!" activemodel: errors: <<: *errors diff --git a/config/locales/server.fa_IR.yml b/config/locales/server.fa_IR.yml index 678d7ba238a..5456009bf6a 100644 --- a/config/locales/server.fa_IR.yml +++ b/config/locales/server.fa_IR.yml @@ -15,6 +15,14 @@ fa_IR: short: "%m-%d-%Y" short_no_year: "%B %-d" date_only: "%B %-d, %Y" + long: "%B %-d, %Y, %l:%M%P" + date: + month_names: [null, ژانویه, فوریه, مارچ, آپریل, می, جون, جولای, آگوست, سپتامبر, اکتبر, نوامبر, دسامبر] + <<: *datetime_formats + time: + am: "ق.ظ" + pm: "ب.ظ" + <<: *datetime_formats title: "گفتمان" topics: "موضوعات" posts: "نوشته ها" @@ -31,11 +39,13 @@ fa_IR: maximum_staged_user_per_email_reached: "تکمیل ظرفیت تعداد حساب های کاربری با هر ایمیل." errors: empty_email_error: "رخ دادن در هنگامی که ایمیل خام دریافتی خالی باشد." + no_message_id_error: "این اتفاق زمانی رخ می دهد که شناسه پیغام در سربرگ ایمیل وجود ندارد." inactive_user_error: "رخ دادن در هنگامی که ارسال کننده فعال نباشد." blocked_user_error: "رخ دادن در هنگامی که که ارسال کننده مسدود شده باشد." strangers_not_allowed_error: "رخ دادن در هنگامی که که کاربر سعی در ایجاد مبحث در دسته بندی می کند که در آن عضو نیست." reply_user_not_matching_error: "رخ دادن در هنگامی که پاسخ از ایمیل متفاوتی از آنچه که ما اطلاع رسانی را به آن ارسال کرده ایم، دریافت شده باشد." topic_not_found_error: "رخ دادن در هنگامی که پاسخ دریافت شده باشد، اما مبحث مربوطه حذف شده باشد." + topic_closed_error: "این اتفاق زمانی رخ می دهد که تاپیک مربوطه از سمت مدیران بسته شده باشد." errors: &errors format: '%{attribute} %{message}' messages: @@ -55,6 +65,7 @@ fa_IR: has_already_been_used: "قبلا استفاده شده" inclusion: در لیست وجود ندارد invalid: صحیح نیست + is_invalid: "واضح نیست. آیا این جمله کامل است؟" less_than: باید کمتر از %{count} باشد less_than_or_equal_to: باید کمتر و یا مساوی %{count} باشد not_a_number: یک عدد نمی باشد @@ -85,20 +96,26 @@ fa_IR: default_categories_already_selected: "شما نمیتوانید یک دسته بندی که در یک فهرست دیگر استفاده شده را انتخاب کنید." s3_upload_bucket_is_required: "شما نمیتوانید بارگذاری به S3 را فعال کنید مگر اینکه 's3_upload_bucket' ارائه بدهید." bulk_invite: - file_should_be_csv: "قالب پرونده‌ی بارگذاری شده باید csv و یا txt باشد." + file_should_be_csv: "فرمت فایل آپلود شده می بایست csv باشد." + error: "خطایی هنگام آپلود فایل مربوطه رخ داده است. لطفا بعدا/مجددا امتحان کنید." backup: operation_already_running: "یک عملیات در حال اجراست. کار جدیدی نمی توان شروع کرد." backup_file_should_be_tar_gz: "پرونده‌ی پشتیبان باید یک فایل فشرده با پسوند tar.gz. باشد." not_enough_space_on_disk: "فضای کافی برای بارگذاری این پشتیبان وجود ندارد." + invalid_filename: "نام فایل پشتیبان شامل حروف ممنوعه می باشد. کاراکترهای قابل استفاده a-z و 0-9 می باشد." not_logged_in: "برای اینکار شما باید وارد شوید." not_found: "URL یا منبع درخواست شده یافت نشد." invalid_access: "شما اجازه مشاهده منبع درخواست شده را ندارید." read_only_mode_enabled: "سایت در حالت فقط خواندنی است. تداخلات غیرفعال هستند." + reading_time: "زمان مطالعه" + likes: "لایک ها" too_many_replies: other: "متأسفیم، ولی کاربران جدید موقتا محدود به {count}% پاسخ در برخی از تاپیک ها هستند." embed: start_discussion: "مبحث جدید" continue: "ادامه این بحث" + error: "خطایی در جاسازی رخ داده است" + referer: "ارجاع دهنده:" more_replies: other: "%{count} پاسخ دیگر" loading: "بارگزاری مبحث ..." @@ -127,6 +144,7 @@ fa_IR: topic_not_found: "یک مشکلی وجود دارد. شاید این جستار بسته شده یا پاک شده همزمان که داشتی نگاهش می کردی ؟" just_posted_that: "به آن‌چه که به‌تازگی فرستادید بسیار نزدیک است" invalid_characters: "نویسه‌های نامعتبر در بر دارد." + is_invalid: "نامعتبر است. تلاش کنید که کمی بیش‌ترتوضیح بگذارید." next_page: "صفحه بعد ←" prev_page: "→ صفحه قبل" page_num: "صفحه %{num}" @@ -681,7 +699,6 @@ fa_IR: top_page_default_timeframe: "دعوتنامه های معمولی در صفحه کاربر نشان داده می شوند. " show_email_on_profile: "به کاربران ایمیلشان را در نمایه نشان بده (فقط برای خودشان و مدیران)" email_token_valid_hours: "رمز عبور فراموش شده/ حساب کاربری فعال اعتبار دارد برای (n) ساعت." - email_token_grace_period_hours: "رمز عبور فراموش شده/ نشانه حساب کاربری فعال هنوز قابل اعتبار است برای مهلت (n) ساعت بعد از اینکه بخشوده شد." enable_badges: "فعال سازی سیستم مدال دهی" allow_index_in_robots_txt: "مشخص کردن در robots.txt که به این سایت اجازه می دهد به نمایه شدن برای موتورهای جستجوی وب." email_domains_blacklist: "لیست pipe-delimit دامنه های ایمیل که کاربران اجازه ندارند با آن حساب کاربری ثبت نام کنند. برای مثال: mailinator.com|trashmail.net" @@ -877,7 +894,6 @@ fa_IR: embed_whitelist_selector: "CSS انتخاب کننده برای المان های که اجازه دارند جاسازی شوند." embed_blacklist_selector: "CSS انتخاب کننده برای المان های که از جاسازی پاک شده اند. " notify_about_flags_after: "اگر پرچم هایی هست که به آنها بعد از چند ساعت رسیدگی نشده٬ ایمیلی ارسال کن به contact_email. برای از کار انداختن 0 را تنظیم کن." - enable_cdn_js_debugging: "اجازه بده / logs به نمایش خطاهای مناسب با اضافه کردن مجوز crossorigin به همه آنها دارای js ." show_create_topics_notice: "اگر سایت کمتر از 5 جستار عمومی دارد٬ اطلاع بده به مدیران تا جستارهای بیشتری بسازند." delete_drafts_older_than_n_days: پیش‌نویس‌های قدیمی‌تر از (n) روز را حذف کن prevent_anons_from_downloading_files: "جلوگیری از دانلود کردن فایل پیوست توسط افراد ناشناس. اخطار: این جلوگیری می کنه از هر سایت دارای بدون عکسی. " @@ -1048,33 +1064,6 @@ fa_IR: (اگر نیاز به تماس با یکی از مدیران[staff members] را دارید(%{base_url}/about) به عنوان یک کاربر جدید٬ فقط به این پیام پاسخ دهید.) welcome_invite: subject_template: "به %{site_name} خوش آمدید!" - text_body_template: | - ممنون برای قبول دعتونامه به %{site_name} -- خوش آمدید! - - - برای شما یک حساب کاربری جدید ساختیم **%{username}** و شما الان در سیستم هستید. می توانید اسم خود را عوض کنید با مراجعه به [your user profile][prefs]. - - برای ورود بعدتر : - - - 1. همیشه برای ورود ** از ایمیل آدرسی استفاده کن که در دعوتنامه اصلی استفاده کردید**. در غیر اینصورت نمی تونیم بگوییم این شمایید! - - - 2. رمز عبور خیلی خوبی بساز برای [کاربری نمایه ات][prefs]٬ و برای ورود از آن استفاده کن. - - %{new_user_tips} - - - ما به [رفتار جامعه ای متمدن] همیشه اعتقاد داریم (%{base_url}/guidelines). - - - از بودنتان در انجمن لذت ببرید! - - - (اگر نیاز به تماس با یکی از مدیران[staff members] را دارید(%{base_url}/about) به عنوان یک کاربر جدید٬ فقط به این پیام پاسخ دهید. ) - - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "پشتیبان گیری با موفقیت انجام شد" backup_failed: @@ -1291,6 +1280,9 @@ fa_IR: title: "شرایط استفاده از خدمات" privacy_topic: title: "سیاست حفظ حریم خصوصی" + badges: + welcome: + name: خوش آمدید admin_login: success: "ایمیل ارسال شد " error: "خطا!" @@ -1301,10 +1293,30 @@ fa_IR: performance_report: initial_post_raw: این مطلب شامل گزارش عملکرد روزانه سایت شماست. initial_topic_title: گزارش عملکرد وب‌سایت - date: - <<: *datetime_formats - time: - <<: *datetime_formats + tags: + title: "برچسب" + wizard: + step: + forum_title: + title: "نام" + contact: + fields: + contact_email: + label: "ایمیل" + placeholder: "name@example.com" + contact_url: + placeholder: "http://www.example.com/contact-us" + homepage: + title: "صفحه اصلی" + fields: + homepage_style: + choices: + latest: + label: "آخرین‌ ارسال‌ها" + categories: + label: "دسته‌بندی‌ها" + emoji: + title: "شکلک" activemodel: errors: <<: *errors diff --git a/config/locales/server.fi.yml b/config/locales/server.fi.yml index a9d9f68e290..d19716f03e0 100644 --- a/config/locales/server.fi.yml +++ b/config/locales/server.fi.yml @@ -32,6 +32,7 @@ fi: purge_reason: "Hylätty, aktivoimaton tili poistettiin automaattisesti" disable_remote_images_download_reason: "Linkattujen kuvien lataaminen poistettiin käytöstä vähäisen tallennustilan vuoksi." anonymous: "Anonyymejä" + remove_posts_deleted_by_author: "Kirjoittajan poistama" emails: incoming: default_subject: "Uusi sähköposti osoitteesta %{email}" @@ -72,6 +73,8 @@ fi: inclusion: ei ole listalla invalid: ei kelpaa is_invalid: "vaikuttaa epäselvältä, olihan se kokonainen virke?" + contains_censored_words: "sisältää yhden tai useamman sensuroidun sanan: %{censored_words}" + matches_censored_pattern: "täyttää sensuroidun säännöllisen lausekkeen: %{censored_pattern}" less_than: täytyy olla vähemmän kuin %{count} less_than_or_equal_to: täytyy olla yhtä suuri tai pienempi kuin %{count} not_a_number: ei ole numero @@ -106,7 +109,8 @@ fi: default_categories_already_selected: "Et voi valita aluetta, joka on käytössä toisella listalla" s3_upload_bucket_is_required: "Et voi ottaa s3 latausta käyttöön, jos et ole määrittänyt 's3_upload_bucket'." bulk_invite: - file_should_be_csv: "Ladattavan tiedoston pitäisi olla csv- tai txt-muodossa." + file_should_be_csv: "Ladattavan tiedoston tulee olla CSV-muodossa." + error: "Tiedoston lataus epäonnistui. Yritä myöhemmin uudelleen." backup: operation_already_running: "Tehtävä on parhaillaan käynnissä. Uutta tehtävää ei voi aloittaa juuri nyt." backup_file_should_be_tar_gz: "Varmuuskopion tulisi olla .tar.gz-pakattu tiedosto." @@ -124,6 +128,11 @@ fi: embed: start_discussion: "Lisää kommentti" continue: "Siirry keskusteluun" + error: "Virhe upotettaessa" + referer: "Referer-viite:" + mismatch: "Referer-viite ei täsmää mihinkään näistä isännistä:" + no_hosts: "Isäntiä ei ole määritetty upotusta varten." + configure: "Määritä upottaminen" more_replies: one: "1 muu kommentti" other: "%{count} muuta kommenttia" @@ -157,6 +166,7 @@ fi: spamming_host: "Pahoittelut, linkit tuolle sivulle eivät ole sallittuja." user_is_suspended: "Hyllytetyt käyttäjät eivät saa luoda viestejä." topic_not_found: "Jotain on mennyt pieleen. Ehkä tämä ketju on suljettu tai poistettu sillä välin, kun katselit sitä?" + not_accepting_pms: "Pahoittelut, %{username} ei ota vastaan yksityisviestejä tällä hetkellä." just_posted_that: "on liian samanlainen kuin aiempi viestisi" invalid_characters: "sisältää epäkelpoja merkkejä" is_invalid: "vaikuttaa epäselvältä, olihan se kokonainen virke?" @@ -272,6 +282,7 @@ fi: name: "Alueen nimi" topic: title: 'Otsikko' + featured_link: 'Ketjulinkki' post: raw: "Leipäteksti" user_profile: @@ -285,12 +296,15 @@ fi: too_many_users: "Voit lähettää varoituksia vain yhdelle käyttäjälle kerrallaan." cant_send_pm: "Pahoittelut, et voi lähettää tälle käyttäjälle yksityisviestiä." no_user_selected: "Sinun täytyy valita kelpaava käyttäjä." + featured_link: + invalid: "ei ole käypä. URL:in tulisi sisältää http:// tai https://." + invalid_category: "ei voi muokata tällä alueella." user: attributes: password: - common: "on yksi 10 000 yleisimmästä salasanasta. Ole hyvä ja valitse turvallisempi salasana." - same_as_username: "on sama kuin käyttäjätunnuksesi. Ole hyvä ja valitse turvallisempi salasana." - same_as_email: "on sama kuin sähköpostiosoitteesi. Ole hyvä ja valitse turvallisempi salasana." + common: "on yksi 10 000 yleisimmästä salasanasta. Valitse turvallisempi salasana." + same_as_username: "on sama kuin käyttäjätunnuksesi. Valitse turvallisempi salasana." + same_as_email: "on sama kuin sähköpostiosoitteesi. Valitse turvallisempi salasana." same_as_current: "on sama kuin nykyinen salasanasi." ip_address: signup_not_allowed: "Kirjautuminen ei ole sallittu tälle tilille." @@ -315,7 +329,24 @@ fi: meta_category_description: "Keskustelua tästä sivustosta, sen järjestämisestä, siitä miten se toimii ja miten sitä voisi parantaa." staff_category_name: "Henkilökunta" staff_category_description: "Yksityinen alue henkilökunnan keskusteluille. Ketjut näkyvät ainoastaan ylläpitäjille ja valvojille." + assets_topic_title: "Sivuston designiin liittyviä hyödykkeitä" assets_topic_body: "Tämä on pysyvä ketju, joka näkyy ainoastaan henkilökunnalle. Se on tarkoitettu sivuston käyttämien kuvien ja muiden tiedostojen tallentamiseen. Älä poista sitä!\n\n\nTässä ova ohjeet sen käyttämiseen:\n\n\n1. Vastaa tähän ketjuun.\n2. Lataa kaikki kuvat, joita haluat käyttää logoina, faviconina jne tänne. (Käytä viestieditorin työkalupalkin painiketta, tai raahaa tai liitä kuvat).\n3. Lähetä viesti\n4. Klikkaa hiiren oikealla näppäimellä, tai klikkaa muokkaa-näppäintä muokataksesi viestiäsi, jotta saat kuvien polun näkyviin. Kopioi talteen polut kuviin.\n5. Liitä kuvien polut [perusasetuksiin](/admin/site_settings/category/required).\n\n\nLisäksi, jos sinun täytyy sallia uusia tiedostomuotoja, muokkaa `sallitut tiedostopäätteet` listaa [tiedostojen asetuksissa](/admin/site_settings/category/files)." + discourse_welcome_topic: + title: "Tervetuloa käyttämään Discoursea" + body: |2 + + Tämän kiinnitetyn ketjun ensimmäinen kappale on sivustolla vierailevalle näkyvä tervetulotoivotus. Se on tärkeä! + + **Muokkaa tästä** tiivis kuvaus yhteisöstäsi: + + - Kenelle se on suunnattu? + - Mistä täällä keskustellaan? + - Miksi heidän kannattaa käydä täällä? + - Mistä he löytävät lisätietoa (linkkejä, ohjeita jne.)? + + + + Saattaa olla hyvä sulkea tämä ketju ylläpitäjän :wrench: -valikon kautta (oikealla ylhäällä sekä sivun pohjalla), jottei vastauksia kasaannu ilmoituksen alle. lounge_welcome: title: "Tervetuloa Loungeen" body: |2 @@ -327,7 +358,7 @@ fi: Voit nyt… * Muokata minkä hyvänsä ketjun otsikkoa - * Vaihtaa minkä hyvänsä ketjun toiselle alueelle + * Siirtää minkä tahansa ketjun toiselle alueelle * Lisätä linkkejä, joita hakukoneet seuraavat ([nofollow](http://en.wikipedia.org/wiki/Nofollow) on poistettu) * Päästä suljetulle Lounge-alueelle, joka näkyy vain luottamustason 3 ja korkeammille käyttäjille * Piilottaa viestin yhdellä liputuksella @@ -336,7 +367,7 @@ fi: Kiitos, että olet tämän yhteisön arvokas jäsen! - (Saadaksesi lisätietoja luottamustasoista, [katso tämä englanninkielinen ketju][trust]. Huomaa, että pysyäksesi mestarina sinun pitää täyttää vaatimukset jatkossakin. ) + (Saadaksesi lisätietoja luottamustasoista, [katso tämä englanninkielinen ketju][trust]. Huomaa, että pysyäksesi mestarina sinun pitää täyttää vaatimukset jatkossakin.) [trust]: https://meta.discourse.org/t/what-do-user-trust-levels-do/4924 category: @@ -372,21 +403,22 @@ fi: change_failed_explanation: "Yritit alentaa käyttäjän %{user_name} luottamustasolle '%{new_trust_level}'. Käyttäjän luottamustaso on jo valmiiksi '%{current_trust_level}'. %{user_name} jatkaa edelleen luottamustasolla '%{current_trust_level}' - jos haluat alentaa luottamustasoa, lukitse se ensin" rate_limiter: slow_down: "Olet tehnyt tämän toiminnon liian monta kertaa, yritä uudelleen myöhemmin." - too_many_requests: "Tämä toiminto voidaan suorittaa vain määrätyn monta kertaa päivässä. Ole hyvä ja odota %{time_left} ja yritä sitten uudelleen." + too_many_requests: "Tämä toiminto voidaan suorittaa vain määrätyn monta kertaa päivässä. Odota %{time_left} ja yritä sitten uudelleen." by_type: - first_day_replies_per_day: "Uusi käyttäjä ei voi ensimmäisenä päivänään kirjoittaa enempää viestejä. Ole hyvä ja odota %{time_left} ja yritä sitten uudelleen." - first_day_topics_per_day: "Uusi käyttäjä ei voi ensimmäisenä päivänään luoda enempää ketjuja. Ole hyvä ja odota %{time_left} ja yritä sitten uudelleen." - create_topic: "Yrität luoda ketjuja liian nopeasti. Ole hyvä ja odota %{time_left} ja yritä sitten uudelleen." - create_post: "Yrität vastata liian nopeasti. Ole hyvä ja odota %{time_left} ja yritä sitten uudelleen." - delete_post: "Poistat viestejä liian nopeasti. Ole hyvä ja odota %{time_left} ja yritä sitten uudelleen." - topics_per_day: "Olet luonut enimmäismäärän uusia ketjuja tälle päivälle. Ole hyvä ja odota %{time_left} ja yritä sitten uudelleen." - pms_per_day: "Olet lähettänyt enimmäismäärän viestejä tälle päivälle. Ole hyvä ja odota %{time_left} ja yritä sitten uudelleen." - create_like: "Olet tykännyt enimmäismäärän tälle päivälle. Ole hyvä ja odota %{time_left} ja yritä sitten uudelleen." - create_bookmark: "Olet lisännyt enimmäismäärän kirjanmerkkejä tälle päivälle. Odota %{time_left} ennen kuin yrität uudelleen." - edit_post: "Olet saavuttanut muokkausten enimmäismäärän tälle päivälle. Odota %{time_left} ennen kuin yrität uudelleen." - live_post_counts: "Kysyt viestimääriä liian nopealla tahdilla. Odota %{time_left} ennen kuin yrität uudelleen." - unsubscribe_via_email: "Olet perunut enimmäismäärän sähköpostitse tänään. Odota %{time_left} ennen uudelleen yrittämistä." - topic_invitations_per_day: "Olet kutsunut enimmäismäärän tälle päivälle. Odota %{time_left} ennen uudelleen yrittämistä." + first_day_replies_per_day: "Uusi käyttäjä ei voi ensimmäisenä päivänään kirjoittaa enempää viestejä. Odota %{time_left} ja yritä sitten uudelleen." + first_day_topics_per_day: "Uusi käyttäjä ei voi ensimmäisenä päivänään luoda enempää ketjuja. Odota %{time_left} ja yritä sitten uudelleen." + create_topic: "Yrität luoda ketjuja liian nopeasti. Odota %{time_left} ja yritä sitten uudelleen." + create_post: "Yrität vastata liian nopeasti. Odota %{time_left} ja yritä sitten uudelleen." + delete_post: "Poistat viestejä liian nopeasti. Odota %{time_left} ja yritä sitten uudelleen." + public_group_membership: "Liityt/eroat ryhmistä liian nopeasti. Odota %{time_left} ja yritä sitten uudelleen." + topics_per_day: "Olet luonut enimmäismäärän uusia ketjuja tälle päivälle. Odota %{time_left} ja yritä sitten uudelleen." + pms_per_day: "Olet lähettänyt enimmäismäärän viestejä tälle päivälle. Odota %{time_left} ja yritä sitten uudelleen." + create_like: "Olet tykännyt enimmäismäärän tälle päivälle. Odota %{time_left} ja yritä sitten uudelleen." + create_bookmark: "Olet lisännyt enimmäismäärän kirjanmerkkejä tälle päivälle. Odota %{time_left} ja yritä sitten uudelleen." + edit_post: "Olet saavuttanut muokkausten enimmäismäärän tälle päivälle. Odota %{time_left} ja yritä sitten uudelleen." + live_post_counts: "Kysyt viestimääriä liian nopealla tahdilla. Odota %{time_left} ja yritä sitten uudelleen." + unsubscribe_via_email: "Olet perunut enimmäismäärän sähköpostitse tänään. Odota %{time_left} ja yritä sitten uudelleen." + topic_invitations_per_day: "Olet kutsunut enimmäismäärän tälle päivälle. Odota %{time_left} ja yritä sitten uudelleen." hours: one: "1 tunti" other: "%{count} tuntia" @@ -578,7 +610,7 @@ fi: mailing_list_mode: "Poistu postituslistatilasta" disable_digest_emails: "Älä lähetä minulle sähköpostikoosteita" all: "Älä lähetä minulle sähköpostia sivustolta %{sitename}" - different_user_description: "Olet kirjautunut sisään eri käyttäjänä kuin jolle sähköposti lähetettiin. Ole hyvä ja kirjaudu ulos tai siirry anonyymitilaan, ja yritä sitten uudelleen." + different_user_description: "Olet kirjautunut sisään eri käyttäjänä kuin jolle sähköposti lähetettiin. Kirjaudu ulos tai siirry anonyymitilaan ja yritä sitten uudelleen." not_found_description: "Pahoittelut, tätä tilauksen perumista ei löytynyt. Kenties sinulle lähetetty linkki on vanhentunut?" log_out: "Kirjaudu ulos" user_api_key: @@ -770,10 +802,14 @@ fi: min_first_post_length: "Ketjun aloitusviestin (leipätekstin) merkkien minimimäärä" min_private_message_post_length: "Viestin merkkien minimimäärä viesteille" max_post_length: "Viestin merkkien minimimäärä" + topic_featured_link_enabled: "Ota käyttöön ketjulinkit." + show_topic_featured_link_in_digest: "Näytä ketjulinkki tiivistelmäsähköpostissa." min_topic_title_length: "Viestin otsikon merkkien minimimäärä" max_topic_title_length: "Viestin otsikon merkkien maksimimäärä" min_private_message_title_length: "Viestin otsikon merkkien minimimäärä viestille" min_search_term_length: "Haun merkkien minimimäärä" + search_prefer_recent_posts: "Jos hakeminen suurelta palstaltasi on hidasta, tämä asetus kokeilee hakemistorakennetta, jossa tuoreimmat viestit ovat ensin" + search_recent_posts_size: "Kuinka monta tuoretta viestiä pidetään hakemistossa" allow_uncategorized_topics: "Salli ketjujen luominen valitsematta aluetta. VAROITUS: Alueettomat ketjut täytyy siirtää jollekin alueelle ennen kuin poistat asetuksen käytöstä." allow_duplicate_topic_titles: "Salli ketjun luominen identtisellä otsikolla." unique_posts_mins: "Kuinka monen minuutin kuluttua käyttäjä voi lähettää uudestaan samansisältöisen viestin" @@ -815,6 +851,7 @@ fi: notification_email: "Sähköpostiosoite, josta kaikki tärkeät järjestelmän lähettämät sähköpostiviestit lähetetään. Verkkotunnuksen SPF, DKIM ja reverse PTR tietueiden täytyy olla kunnossa, jotta sähköpostit menevät perille." email_custom_headers: "Pystyviivalla eroteltu lista mukautetuista sähköpostin tunnisteista" email_subject: "Mukauta sähköpostiviestien otsikon muoto. Katso englanninkielinen ohje: https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801" + force_https: "Pakota sivusto käyttämään vain HTTPS:ää. VAROITUS: älä ota tätä käyttöön ennen kuin HTTPS on täysin käytössä ja toimii täysin kaikkialla! Tarkastitko käyttämäsi CDN, kaikki sosiaaliset kirjautumiset ja kaikki ulkoiset logot / muut riippuvuudet ovat myös HTTPS-yhteensopivia?" summary_score_threshold: "Viestin minimipistemäärä, jotta se näytetään ketjun tiivistelmässä." summary_posts_required: "Montako viestiä ketjussa täytyy olla, jotta ketjun tiivistelmä otetaan käyttöön" summary_likes_required: "Montako tykkäystä ketjussa pitää olla, jotta ketjun tiivistelmä otetaan käyttöön" @@ -873,9 +910,8 @@ fi: show_email_on_profile: "Näytä käyttäjän sähköpostiosoite profiilissa (näkyy vain käyttäjälle itselleen ja henkilökunnalle)" prioritize_username_in_ux: "Näytä käyttäjänimi ensimmäisenä käyttäjäsivulla, -kortissa ja viesteissä (jos poistetaan käytöstä, nimi näytetään ensin)" email_token_valid_hours: "Unohtuneen salasanan / tilin vahvistamisen tokenit ovat voimassa (n) tuntia." - email_token_grace_period_hours: "Unohtuneen salasanan / tilin vahvistamisen tokenit ovat vielä voimassa (n) tuntia käyttämisen jälkeen." enable_badges: "Ota käyttöön ansiomerkkijärjestelmä" - enable_whispers: "Salli henkilökunnan keskustella yksityisestä ketjun sisällä. (kokeellinen)" + enable_whispers: "Salli henkilökunnan yksityiskeskustelu ketjujen sisällä." allow_index_in_robots_txt: "Määrittele robots.txt-tiedostossa, että hakukoneet saavat luetteloida sivuston." email_domains_blacklist: "Pystyviivalla eroteltu lista sähköposti-verkkotunnuksista, joista käyttäjät eivät voi luoda tiliä. Esimerkiksi mailinator.com|trashmail.net" email_domains_whitelist: "Pystyviivalla eroteltu lista sähköposti-verkkotunnuksista, joista käyttäjien pitää luoda tilinsä. VAROITUS: Käyttäjiä, joiden sähköpostiosoite on muusta verkkotunnuksesta ei sallita!" @@ -942,6 +978,7 @@ fi: top_topics_formula_log_views_multiplier: "katselukertojen logaritmin kerroin (n) Huiput-listauksen kaavassa: `log(katselut) * (n) + avausviestin tykkäykset * 0.5 + PIENEMPI(tykkäysten määrä / viestien määrä, 3) + 10 + log(viestien määrä)`" top_topics_formula_first_post_likes_multiplier: "avausviestin tykkäysmäärän kerroin (n) Huiput-listauksen kaavassa: `log(katselut) * 2 + avausviestin tykkäykset * (n) + PIENEMPI(tykkäysten määrä / viestien määrä, 3) + 10 + log(viestien määrä)`" top_topics_formula_least_likes_per_post_multiplier: "tykkäykset/viestit -suhteen enimmäisarvo (n) Huiput-listauksen kaavassa: `log(katselut) * 2 + avausviestin tykkäykset * 0.5 + PIENEMPI(tykkäysten määrä / viestien määrä, (n)) + 10 + log(viestien määrä)`" + rebake_old_posts_count: "Kuinka monta vanhaa viestiä rakennetaan uudelleen 15 minuutissa." rate_limit_create_topic: "Ketjun luomisen jälkeen käyttäjän täytyy odottaa (n) sekuntia voidakseen luoda uuden ketjun." rate_limit_create_post: "Viestin luomisen jälkeen käyttäjän täytyy odottaa (n) sekuntia voidakseen luoda uuden viestin." rate_limit_new_user_create_topic: "Ketjun luomisen jälkeen uuden käyttäjän täytyy odottaa (n) sekuntia voidakseen luoda uuden ketjun." @@ -975,6 +1012,7 @@ fi: external_system_avatars_enabled: "Käytä ulkopuolista avatarpalvelua." external_system_avatars_url: "Ulkoisen avatarpalvelun URL. Sallitut vaihdokset ovat {username} {first_letter} {color} {size}" default_opengraph_image_url: "Oletuksena käytettävän opengraph-kuvan URL." + twitter_summary_large_image_url: "Oletuksena käytettävän Twitter-tiivistelmäkortin kuva (tulisi olla leveydeltään ainakin 280 px leveä ja 150 px korkea)." allow_all_attachments_for_group_messages: "Sali kaikki sähköpostiliitteet ryhmäviestessä." convert_pasted_images_to_hq_jpg: "Muuta liitetyt kuvat korkealaatuisiksi JPG-tiedostoiksi" convert_pasted_images_quality: "Muunnetun JPG-tiedoston laatu (1 on huonoin laatu, 100 on paras laatu)." @@ -1016,7 +1054,7 @@ fi: newuser_max_mentions_per_post: "Kuinka monta @nimi mainintaa uusi käyttäjä voi lisätä viestiin." newuser_max_replies_per_topic: "Uuden käyttäjän viestien maksimimäärä samassa ketjussa, kunnes joku vastaa heille." max_mentions_per_post: "Kuinka monta @nimi mainintaa kukaan voi lisätä viestiin." - max_users_notified_per_group_mention: "Kuinka moni voi saada ilmoituksen, kun ryhmään viitataan (jos raja ylittyy, kukaan ei saa ilmoitusta)" + max_users_notified_per_group_mention: "Kuinka moni voi saada ilmoituksen, kun ryhmä mainitaan (jos raja ylittyy, kukaan ei saa ilmoitusta)" create_thumbnails: "Luo esikatselu- ja lightbox-kuvia, jotka ovat liian suuria mahtuakseen viestiin." email_time_window_mins: "Odota (n) minuuttia ennen ilmoitussähköpostien lähettämistä, jotta käyttäjällä on aikaa muokata ja viimeistellä viestinsä." private_email_time_window_seconds: "Odota (n) sekuntia ennen sähköposti-ilmoitusten lähettämistä käyttäjille, jotta kirjoittajalla on mahdollisuus tehdä muokkaukset ja viimeistellä viestinsä." @@ -1036,6 +1074,7 @@ fi: max_attachment_size_kb: "Liitetyn tiedoston suurin sallittu koko kilotavuissa. Tämä pitää asettaa myös nginxin (client_max_body_size) / apachen tai proxyn asetuksista." authorized_extensions: "Liitetiedostojen sallitut tiedostopäätteet (käytä '*' salliaksesi kaikki tiedostotyypit)" max_similar_results: "Kuinka monta samankaltaista ketjua näytetään viestikentän yläpuolella uutta ketjua luotaessa. Vertailu perustuu sekä otsikkoon että leipätekstiin." + max_image_megapixels: "Kuvan enimmäiskoko megapikseleinä." title_prettify: "Estä yleiset kirjoitusvirheet otsikossa, kuten pelkät isot kirjaimet, pieni ensimmäinen kirjain, useat !- ja ?-merkit ym." topic_views_heat_low: "Näin monen katselun jälkeen katselut-saraketta korostetaan hieman." topic_views_heat_medium: "Näin monen katselun jälkeen katselut-saraketta korostetaan kohtalaisesti." @@ -1091,9 +1130,14 @@ fi: bounce_score_threshold: "Palautuspistemäärä, jonka ylityttyä käyttäjälle ei lähetetä sähköpostia." bounce_score_threshold_deactivate: "Palautuspistemäärä, jonka ylityttyä käyttäjätili poistetaan käytöstä." reset_bounce_score_after_days: "Nollaa palautuspisteet X päivä kuluttua." + attachment_content_type_blacklist: "Lista avainsanoja, jota käytetään liitteiden estämisessä niiden sisältötyypin perusteella." + attachment_filename_blacklist: "Lista avainsanoja, jota käytetään liitteiden estämisessä niiden tiedostonimen perusteella." + enable_forwarded_emails: "[BETA] Salli käyttäjän luoda ketju välittämällä saapunut sähköpostiviesti." + always_show_trimmed_content: "Näytä kaikkialla saapuvien sähköpostien karsitut osat. VAROITUS: voi paljastaa sähköpostiosoitteita." manual_polling_enabled: "Työnnä sähköpostit käyttäen sähköpostivastausten APIa." pop3_polling_enabled: "Pollaa sähköpostivastaukset POP3:lla." pop3_polling_ssl: "Käytä SSL-salausta yhdistettäessä POP3-palvelimeen. (Suositellaan)" + pop3_polling_openssl_verify: "Varmenna TLS-palvelinsertifikaatti (Oletus: päällä)" pop3_polling_period_mins: "Tiheys minuuteissa kuinka usein POP3 tililtä tarkastetaan uudet sähköpostit. HUOM: vaatii uudelleenkäynnistyksen." pop3_polling_port: "POP3 pollauksen portti." pop3_polling_host: "POP3 pollauksen host." @@ -1116,19 +1160,27 @@ fi: allow_animated_thumbnails: "Luo animoidut esikatselukuvat animoiduista gif-tiedostoista." default_avatars: "Verkko-osoitteet profiilikuviin, joita käytetään oletuksena uusille käyttäjille." automatically_download_gravatars: "Lataa käyttäjille Gravatarit automaattisesti tilin luonnin ja sähköpostin vaihdon yhteydessä." + digest_topics: "Yläraja sähköpostikoosteessa näytettävien suosittujen ketjujen määrälle." + digest_posts: "Yläraja sähköpostikoosteessa näytettävien suosittujen viestien määrälle." + digest_other_topics: "Yläraja sähköpostikoosteen 'Uutta seuraamissasi ketjuissa ja alueissa' -osiossa näytettävien ketjujen määrälle." digest_min_excerpt_length: "Vähimmäispituus merkeissä viestin katkelmalle, joka näytetään sähköpostikoosteissa." delete_digest_email_after_days: "Älä lähetä sähköpostikoosteita käyttäjille, joita ei ole nähty sivustolla yli (n) päivään." digest_suppress_categories: "Älä liitä näiden alueiden viestejä sähköpostikoosteisiin." disable_digest_emails: "Poista sähköpostikoosteet kaikilta käyttäjiltä." + email_accent_bg_color: "Kakkosväri, jota käytetään joidenkin elementtien taustavärinä sähköpostiviesteissä. Anna värin nimi englanniksi ('red') tai sen Hex-arvo ('#FF000')." + email_accent_fg_color: "Sähköpostiviestin taustavärin päällä olevan tekstin väri HTML-sähköpostiviesteissä. Anna värin nimi englanniksi ('white') tai sen Hex-arvo ('#FFFFFF')." + email_link_color: "Linkkien väri HTML-sähköpostiviesteissä. Anna värin nimi ('blue') tai sen Hex-arvo ('#0000FF')." detect_custom_avatars: "Tarkistetaanko, ovatko käyttäjät ladanneet oman profiilikuvan." max_daily_gravatar_crawls: "Korkeintaan kuinka monta kertaa Discourse tarkistaa avatarit Gravatarista päivässä" public_user_custom_fields: "Whitelist käyttäjän mukautetuista kentistä, jotka voidaan näyttää julkisesti." staff_user_custom_fields: "Whitelist käyttäjän mukautetuista kentistä, jotka voidaan näyttää henkilökunnalle." enable_user_directory: "Näytä hakemisto käyttäjistä" + enable_group_directory: "Tarjoa luettelo ryhmistä selailtavaksi" allow_anonymous_posting: "Salli käyttäjien vaihtaa anonyymiin tilaan" anonymous_posting_min_trust_level: "Anonyymin tilan käyttämiseen vaadittava luottamustila" anonymous_account_duration_minutes: "Suojellaksesi anonymiteettiä, luo uusi anonyymi tili N minuutin välein jokaiselle käyttäjälle. Esimerkki: jos arvoksi asetetaan 600, kun 600 minuuttia tulee kuluneeksi edellisestä viestistä JA käyttäjä vaihtaa anonyymiin tilaan, luodaan uusi anonyymi tili." hide_user_profiles_from_public: "Älä näytä käyttäjäkortteja, käyttäjäprofiileita tai käyttäjähakemistoa kirjautumattomille käyttäjille." + user_website_domains_whitelist: "Käyttäjän kotisivu voi olla näiden verkkotunnusten alainen. Pystyviivoin erotettu lista." allow_profile_backgrounds: "Salli käyttäjien ladata profiilin taustakuva." sequential_replies_threshold: "Kuinka monen peräkkäisen viestin jälkeen yhdessä ketjussa käyttäjää muistutetaan peräkkäisistä vastauksista." enable_mobile_theme: "Mobiililaitteet käyttävät erillistä teemaa ja kahden välillä on mahdollista vaihtaa. Poista asetus käytöstä, jos haluat käyttää omaa tyylitiedostoa, joka on mukautuva eri laitteille." @@ -1140,6 +1192,8 @@ fi: automatically_unpin_topics: "Poista ketjun kiinnitys automaattisesti, kun käyttäjä on sen lopussa." read_time_word_count: "Sanamäärä minuutissa, jota käytetään lukuajan arviointiin." topic_page_title_includes_category: "Ketjusivu sisältää alueen nimen." + native_app_install_banner: "Tarjoaa toistuvasti vieraileville Discoursen käyttöjärjestelmäkohtaista sovellusta." + max_prints_per_hour_per_user: "Tulostuspyyntöjen (/print) enimmäismäärä (aseta 0 poistaaksesi käytöstä)" full_name_required: "Koko nimi on käyttäjäprofiilin vaadittu kohta" enable_names: "Näytä käyttäjän koko nimi profiilissa, käyttäjäkortissa ja sähköposteissa. Poista käytöstä piilottaaksesi koko nimen kaikkialla." display_name_on_posts: "Näytä käyttäjän pitkä nimi viesteissä @nimen lisäksi." @@ -1149,17 +1203,18 @@ fi: default_code_lang: "Oletusarvoinen ohjelmointikieli syntaksin korostukseen Github koodiblokeissa (lang-auto, ruby, python jne.)" warn_reviving_old_topic_age: "Kun käyttäjä alkaa kirjoittamaan vastausta ketjuun, jonka uusin viesti on tätä vanhempi päivissä, näytetään varoitus. Poista käytöstä asettamalla arvoksi 0." autohighlight_all_code: "Pakota koodin korostus kaikkiin esimuotoiltuihin tekstiblokkeihin, vaikka käyttäjä ei määrittelisi kieltä." + highlighted_languages: "Käytettävät syntaksinkorostussäännöt. (Varoitus: liian monen ohjelmointikielen käyttö voi vaikuttaa suorituskykyyn) ks. demo https://highlightjs.org/static/demo/" feed_polling_enabled: "VAIN UPOTUS: Upotetaanko RSS/ATOM syöte viesteinä." feed_polling_url: "VAIN UPOTUS: RSS/ATOM syötteen URL." embed_by_username: "Sen käyttäjän Discourse käyttäjänimi, joka luo upotetut ketjut." embed_username_key_from_feed: "Avain, jolla erotetaan Discourse-käyttäjänimi syötteestä." embed_truncate: "Typistä upotetut viestit." + allowed_href_schemes: "Linkeissä sallitut skeemat http:n ja https:n lisäksi." embed_post_limit: "Upotettavien viestien maksimimäärä." embed_username_required: "Käyttäjänimi vaaditaan ketjun luomiseksi." embed_whitelist_selector: "CSS valitsin elementeille, jotka sallitaan upotetuissa viesteissä." embed_blacklist_selector: "CSS valitstin elementeille, jotka poistetaan upotetuista viesteistä." notify_about_flags_after: "Jos liputuksia ei ole käsitelty näin moneen tuntiin, lähetä sähköposti contact_email osoitteeseen. Aseta 0 ottaaksesi pois käytöstä." - enable_cdn_js_debugging: "Salli /logs näyttää kunnolliset virheilmoitukset lisäämällä crossorigin permissions kaikkiin sisällytettyihin js-kirjastoihin." show_create_topics_notice: "Jos palstalla on vähemmän kuin 5 julkista ketjua, huomauta ylläpitäjiä ketjujen luonnista." delete_drafts_older_than_n_days: Poista yli (n) päivää vanhat luonnokset. bootstrap_mode_min_users: "Vähimmäismäärä käyttäjiä, joka vaaditaan aloitustilan poistamiseen (aseta 0 poistaaksesi käytöstä)" @@ -1198,6 +1253,7 @@ fi: default_categories_watching: "Lista oletuksena tarkkailtavista alueista." default_categories_tracking: "Lista oletuksena seurattavista alueista." default_categories_muted: "Lista oletuksena vaimennetuista alueista." + default_categories_watching_first_post: "Lista alueista, joiden ketjujen ensimmäisiä viestejä tarkkaillaan oletuksena." max_user_api_reqs_per_day: "Rajapintapyyntöjen päivittäinen enimmäismäärä rajapinnan avainta kohden" max_user_api_reqs_per_minute: "Rajapintapyyntöjen enimmäismäärä minuuttia kohden rajapinnan avainta kohden" allow_user_api_keys: "Salli rajapinnan käyttäjäavainten muodostaminen" @@ -1242,6 +1298,7 @@ fi: reply_by_email_address_is_empty: "'reply by email address' täytyy olla asetettuna ennen sähköpostivastausten ottamista käyttöön." email_polling_disabled: "Sinun täytyy ottaa käyttöön joko manuaalinen tai POP3 pollaus ennen sähköpostivastauksia." user_locale_not_enabled: "'allow user locale' täytyy olla asetettuna ennen tämän asetuksen ottamista käyttöön." + invalid_regex: "Säännöllinen lauseke ei kelpaa tai ei ole sallittu." search: within_post: "#%{post_number} käyttäjältä %{username}" types: @@ -1361,6 +1418,8 @@ fi: ip_address: blocked: "Uusien tilien luonti tästä IP-osoitteesta ei ole sallittu." max_new_accounts_per_registration_ip: "Rekisteröitymisiä ei oteta vastaan IP-osoitteestasi (maksimimäärä saavutettu). Ota yhteyttä henkilökuntaan." + website: + domain_not_allowed: "Verkkosivu ei kelpaa. Sallitus verkkotunnukset ovat: %{domains}" flags_reminder: flags_were_submitted: one: "Viestejä liputettiin yli tunti sitten. Tarkasta liputukset." @@ -1420,7 +1479,7 @@ fi: invite_forum_mailer: subject_template: "%{invitee_name} kutsui sinut sivustolle %{site_domain_name}" text_body_template: | - %{invitee_name} kutsui sinut sivustolle + %{invitee_name} kutsui sinut liittymään sivustolle > **%{site_title}** > @@ -1430,25 +1489,24 @@ fi: %{invite_link} - Tämän kutsun lähetti luotettu käyttäjä, joten sinulle luodaan tili automaattisesti. + Tämän kutsun lähetti luotettu käyttäjä, joten kun klikkaat, sinulle luodaan tämän sähköpostiosoitteen alainen käyttäjätili automaattisesti. custom_invite_forum_mailer: subject_template: "%{invitee_name} kutsui sinut sivustolle %{site_domain_name}" text_body_template: | - %{invitee_name} kutsui sinut sivustolle + %{invitee_name} kutsui sinut liittymään sivustolle > **%{site_title}** > > %{site_description} - Viesti käyttäjältä %{invitee_name}: - + Viesti käyttäjältä %{invitee_name} sinulle: %{user_custom_message} Jos kiinnostuit, klikkaa alla olevaa linkkiä: %{invite_link} - Tämän kutsun lähetti luotettu käyttäjä, joten sinun ei tarvitse kirjautua sisään. + Tämän kutsun lähetti luotettu käyttäjä, joten kun klikkaat, sinulle luodaan tämän sähköpostiosoitteen alainen käyttäjätili automaattisesti. invite_password_instructions: subject_template: "Aseta salasana %{site_name} -tunnuksellesi" text_body_template: | @@ -1568,6 +1626,11 @@ fi: Kuitenkin, jos viesti piilotetaan toisen kerran, se pysyy piilotettuna, kunnes henkilökunta selvittää tilanteen – josta voi olla muita seuraumuksia, kuten tilisi hyllyttäminen. Saadaksesi lisätietoja, lue [yhteisön säännöt](%{base_url}/guidelines). + usage_tips: + text_body_template: | + [Tässä blogikirjoituksessa](http://blog.discourse.org/2016/12/discourse-new-user-tips-and-tricks/) on joitakin käteviä vinkkejä uudelle käyttäjälle. + + Sitä mukaa kun toimit täällä, opimme tuntemaan sinut ja väliaikaisia uuden käyttäjän rajoitteita poistetaan automaattisesti. Ajan myötä nouset ylemmille [luottamustasoille](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924) ja saat valtuuksia joiden avulla voit osallistua yhteisömme ylläpitoon. welcome_user: subject_template: "Tervetuloa sivustolle %{site_name}!" text_body_template: | @@ -1583,26 +1646,23 @@ fi: welcome_invite: subject_template: "Tervetuloa sivustolle %{site_name}!" text_body_template: | - Kiitos kutsun hyväksymisestä sivustolle %{site_name} -- tervetuloa! + Kiitos kun hyväksyit kutsun sivustolle %{site_name} -- tervetuloa! - Olemme luoneet sinulle uuden käyttäjätunnuksen: **%{username}** ja olet nyt kirjautuneena sisään. Voit vaihtaa nimeäsi [käyttäjäprofiilistasi][prefs]. + - Loimme sinulle käyttäjätilin **%{username}**. [Käyttäjäasetuksissa][prefs] voit muuttaa nimeäsi ja salasanaasi. - Kirjautuaksesi uudestaan sisään myöhemmin: - - 1. Käytä aina **samaa sähköpostiosoitetta, jonne vastaanotit alkuperäisen kutsun**. Muuten emme voi tietää, että olet sinä! - - 2. Luo salasana [käyttäjäprofiilissasi][prefs], ja käytä sitä kirjautumiseen. + - Kun kirjaudut sisään, **käytä samaa sähköpostiosoitetta kuin johon kutsu saapui** — muuten emme voi tietää oletko se sinä! %{new_user_tips} - Me uskomme [sivistyneeseen kanssakäymiseen](%{base_url}/guidelines). + Uskomme [sivistyneeseen yhteisökäyttäytymiseen](%{base_url}/guidelines) aina. Toivottavasti viihdyt! - (Jos haluat keskustella [henkilökunnan jäsenten](%{base_url}/about) kanssa, vastaa vain tähän viestiin) + (Jos sinulla on asiaa [henkilökunnalle](%{base_url}/about) uutena käyttäjänä, vastaa vain tähän viestiin.) [prefs]: %{user_preferences_url} backup_succeeded: + title: "Varmuuskopiointi onnistui" subject_template: "Varmuuskopiointi suoritettu onnistuneesti" text_body_template: | Varmuuskopiointi onnistui. @@ -1615,6 +1675,7 @@ fi: %{logs} ``` backup_failed: + title: "Varmuuskopiointi epäonnistui" subject_template: "Varmmuskopiointi epäonnistui" text_body_template: | Varmuuskopiointi epäonnistui. @@ -1625,6 +1686,7 @@ fi: %{logs} ``` restore_succeeded: + title: "Palautus onnistui" subject_template: "Palauttaminen suoritettu onnistuneesti" text_body_template: | Palauttaminen onnistui. @@ -1635,6 +1697,7 @@ fi: %{logs} ``` restore_failed: + title: "Palautus epäonnistui" subject_template: "Palauttaminen epäonnistui" text_body_template: | Palauttaminen epäonnistui. @@ -1645,9 +1708,11 @@ fi: %{logs} ``` bulk_invite_succeeded: + title: "Massakutsun lähetys onnistui" subject_template: "Massakutsun käsittely onnistui." text_body_template: "Massakutsutiedostosi on käsitelty, %{sent} kutsua lähetetty." bulk_invite_failed: + title: "Massakutsun lähetys epäonnistui" subject_template: "Massakutsun käsittelyssä tapahtui virhe" text_body_template: | Massakutsutiedostosi on käsitelty, %{sent} kutsua lähetettiin joista %{failed} virhe(ttä). @@ -1658,6 +1723,7 @@ fi: %{logs} ``` csv_export_succeeded: + title: "CSV:n vienti onnistui" subject_template: "Datan vieminen on tehty" text_body_template: | Datan vienti onnistui. @@ -1666,21 +1732,25 @@ fi: Linkki tiedostoon on voimassa 48 tuntia. csv_export_failed: + title: "CSV:n vienti epäonnistui" subject_template: "Datan vienti epäonnistui" text_body_template: "Pahoittelemme, mutta datan vientisi epäonnistui. Tarkasta lokit tai ota yhteyttä henkilökuntaan." email_reject_insufficient_trust_level: + title: "Sähköposti hylätty - riittämätön luottamustaso" subject_template: "[%{site_name}] Sähköpostiongelma -- Riittämätön luottamustaso" text_body_template: | Pahoittelut, sähköpostiviestiäsi tänne: %{destination} (otsikolla %{former_title}) ei voitu toimittaa. Tilisi luottamustaso ei ole riittävä, jotta saisit lähettää uusia ketjuja tähän sähköpostiosoitteeseen. Jos uskot, että tämä johtuu virheestä, ota yhteyttä henkilökuntaan. email_reject_user_not_found: + title: "Sähköposti hylätty - käyttäjää ei löytynyt" subject_template: "[%{site_name}] Sähköpostiongelma -- Käyttäjää ei löytynyt" text_body_template: | Pahoittelemme, mutta sähköpostin lähettäminen tänne %{destination} (otsikolla %{former_title}) ei onnistunut. Vastauksesi lähetettiin tuntemattomasta sähköpostiosoitteesta. Yritä lähettää viesti toisesta osoitteesta, tai ota yhteyttä henkilökuntaan. email_reject_screened_email: + title: "Sähköposti hylätty - estetty sähköpostiosoite" subject_template: "[%{site_name}] Sähköpostiongelma-- Estetty sähköpostiosoite" text_body_template: |+ Pahoittelemme, mutta sähköpostin lähettäminen tänne %{destination} (otsikolla %{former_title}) ei onnistunut. @@ -1688,30 +1758,35 @@ fi: Viestisi lähetettiin estetystä sähköpostiosoitteesta. Yritä lähettää viesti toisesta sähköpostiosoitteesta tai ota yhteyttä henkilökuntaan. email_reject_inactive_user: + title: "Sähköposti hylätty - aktivoimaton käyttäjä" subject_template: "[%{site_name}] Sähköpostiongelma -- Aktivoimaton käyttäjä" text_body_template: | Pahoittelemme, mutta sähköpostin lähettäminen tänne %{destination} (otsikolla %{former_title}) ei onnistunut. Käyttäjätiliä tällä sähköpostiosoitteella ei ole aktivoitu. Aktivoi käyttäjätili ennen sähköpostien lähettämistä. email_reject_blocked_user: + title: "Sähköposti hylätty - estetty käyttäjä" subject_template: "[%{site_name}] Sähköpostiongelma-- Estetty käyttäjä" text_body_template: | Pahoittelemme, mutta sähköpostiviesetisi tänne %{destination} (otsikolla %{former_title}) ei onnistunut. Käyttäjätili tällä sähköpostiosoitteella on estetty. email_reject_reply_user_not_matching: + title: "Sähköposti hylätty - käyttäjä ei täsmää" subject_template: "[%{site_name}] Sähköpostiongelma -- Odottamaton vastausosoite" text_body_template: | Pahoittelut, sähköpostiviestisi lähetys kohteeseen %{destination} (titled %{former_title}) ei onnistunut. Viestisi ei saapunut siitä sähköpostiosoitteesta josta odotimme, joten emme voineet olla varmoja lähettäjästä. Kokeile lähettää viestisi toisesta sähköpostiosoitteesta tai ota yhteyttä henkilökuntaan. email_reject_no_account: + title: "Sähköposti hylätty - ei käyttäjätiliä" subject_template: "[%{site_name}] Sähköpostiongelma -- Tuntematon tili" text_body_template: | Pahoittelut, sähköpostiviestisi lähetys kohteeseen %{destination} (titled %{former_title}) ei onnistunut. Sähköpostiosoitteesi ei vastaa yhtäkään käyttäjistä. Kokeile lähettää viestisi toisesta sähköpostiosoitteesta tai ota yhteyttä henkilökuntaan. email_reject_empty: + title: "Sähköposti hylätty - tyhjä" subject_template: "[%{site_name}] Sähköpostiongelma -- Ei sisältöä" text_body_template: |+ Pahoittelemme, mutta sähköpostin lähettäminen tänne %{destination} (otsikolla %{former_title}) ei onnistunut. @@ -1721,30 +1796,35 @@ fi: Jos saat tämän viestin ja viestisi _sisälsi_ sisältöä, yritä uudestaan yksinkertaisemmalla muotoilulla. email_reject_parsing: + title: "Sähköposti hylätty - jäsennys" subject_template: "[%{site_name}] Sähköpostiongelma -- Sisältöä ei tunnistettu" text_body_template: | Pahoittelemme, mutta sähköpostin lähettäminen tänne %{destination} (otsikolla %{former_title}) ei onnistunut. Emme tunnistaneet sähköpostiviestistäsi sisältöä. **Varmista, että kirjoitit viestisi sähköpostiviestin alkuun** - emme pysty käsittelemään lainausten sekaan kirjoitettuja vastauksia. email_reject_invalid_access: + title: "Sähköposti hylätty - pääsy estetty" subject_template: "[%{site_name}] Sähköpostiongelma -- Pääsy estetty" text_body_template: | Pahoittelut, sähköpostiviestiäsi tänne: %{destination} (otsikolla %{former_title}) ei voitu toimittaa. Tilisi luottamustaso ei ole riittävä, jotta saisit luoda uusia ketjuja tälle alueelle. Jos uskot, että tämä johtuu virheestä, ota yhteyttä henkilökuntaan. email_reject_strangers_not_allowed: + title: "Sähköposti hylätty - vierailla ei pääsyä" subject_template: "[%{site_name}] Sähköpostiongelma -- Pääsy estetty" text_body_template: | Pahoittelut, sähköpostiviestisi lähetys kohteeseen %{destination} (otsikolla %{former_title}) ei onnistunut. Alueelle jolle lähetit viestin voivat kirjoittaa ne, joilla on käypä käyttäjätunnus ja sähköpostiosoite. Jos uskot tämän olevan virhe, ota yhteyttä henkilökuntaan. email_reject_invalid_post: + title: "Sähköposti hylätty - viesti ei kelpaa" subject_template: "[%{site_name}] Sähköpostiongelma -- Lähetysvirhe" text_body_template: | Pahoittelemme: sähköpostiviestisi kohteeseen %{destination} (titled %{former_title}) ei toiminut odotetusti. - Mahdollisia syitä ovat muuan muassa: ei-tuettu muotoilu, liian suuri viesti, liian pieni viesti. Ole hyvä ja yritä uudelleen; voit myös lähettää viestisi sivuston kautta, jos tämä ongelma ei vaikuta poistuvan. + Mahdollisia syitä ovat ainakin: ei-tuettu muotoilu, liian suuri viesti, liian pieni viesti. Ole hyvä ja yritä uudelleen; voit myös lähettää viestisi sivuston kautta, jos tämä ongelma ei vaikuta poistuvan. email_reject_invalid_post_specified: + title: "Sähköposti hylätty - viesti ei kelpaa, tarkennettu" subject_template: "[%{site_name}] Sähköpostiongelma -- Lähetysvirhe" text_body_template: | Pahoittelemme, mutta sähköpostin lähettäminen tänne %{destination} (otsikolla %{former_title}) ei onnistunut. @@ -1755,36 +1835,42 @@ fi: Jos voit korjata ongelman, yritä uudelleen. email_reject_invalid_post_action: + title: "Sähköposti hylätty - kielletty viestitoiminto" subject_template: "[%{site_name}] Sähköpostiongelma -- Kielletty viestitoiminto" text_body_template: | Pahoittelemme, mutta sähköpostin lähettäminen tänne %{destination} (otsikolla %{former_title}) ei onnistunut. Toimintoa ei tunnistettu. Yritä uudelleen tai lähetä viesti nettisivun kautta, jos ongelma jatkuu. email_reject_reply_key: + title: "Sähköposti hylätty - vastausavain" subject_template: "[%{site_name}] Sähköpostiongelma -- Tuntematon vastausavain" text_body_template: | Pahoittelut, sähköpostiviestisi lähetys kohteeseen %{destination} (titled %{former_title}) ei onnistunut. Sähköpostiviestin vastaustunniste, engl. 'reply key', ei ole kelvollinen, minkä vuoksi ei tiedetä, mihin asiaan viestisi oli tarkoitus vastata. Ota yhteyttä henkilökuntaan. email_reject_bad_destination_address: + title: "Sähköposti hylätty - tuntematon vastaanottajaosoite" subject_template: "[%{site_name}] Sähköpostiongelma -- Tuntematon Vastaanottaja: -osoite" text_body_template: | Pahoittelut, sähköpostiviestisi lähetys kohteeseen %{destination} (titled %{former_title}) ei onnistunut. Viestisi kohdesähköpostiosoitteet olivat tuntemattomia. Ole hyvä ja varmistu, että lähetit viestin oikeaan osoitteeseen. email_reject_topic_not_found: + title: "Sähköposti hylätty - ketjua ei löytynyt" subject_template: "[%{site_name}] Sähköpostiongelma -- Ketjua ei löytynyt" text_body_template: | Pahoittelut, sähköpostiviestisi lähetys kohteeseen %{destination} (otsikolla %{former_title}) ei onnistunut. Ketjua johon yritit kirjoittaa ei ole enää olemassa -- ehkä se poistettiin? Jos uskot tämän olevan virhe, ota yhteyttä henkilökuntaan. email_reject_topic_closed: + title: "Sähköposti hylätty - ketju suljettu" subject_template: "[%{site_name}] Sähköpostiongelma -- Suljettu ketju" text_body_template: | Pahoittelut, sähköpostiviestiäsi tänne: %{destination} (otsikolla %{former_title}) ei voitu toimittaa. Ketju, johon yritit vastata on tällä hetkellä suljettu, eikä siihen voi vastata. Jos uskot, että on tapahtunut virhe, ota yhteyttä palstan henkilökuntaan. email_reject_auto_generated: + title: "Sähköposti hylätty - automaattivastaus" subject_template: "[%{site_name}] Sähköpostiongelma -- Automaattivastaus" text_body_template: | Pahoittelut, sähköpostiviestisi lähetys kohteeseen %{destination} (otsikolla %{former_title}) ei onnistunut. @@ -2039,10 +2125,24 @@ fi: %{message} digest: why: "Lyhyt kooste siitä mitä on tapahtunut sivustolla %{site_link} viimeisimmän vierailusi jälkeen %{last_seen_at}." + since_last_visit: "Viime vierailusi jälkeen" + new_topics: "Uutta ketjua" + unread_messages: "Lukematonta viestiä" + unread_notifications: "Lukematonta ilmoitusta" + liked_received: "Saatua tykkäystä" + new_posts: "Uutta viestiä" + new_users: "Uutta käyttäjää" + popular_topics: "Suosittuja ketjuja" + follow_topic: "Seuraa tätä ketjua" + join_the_discussion: "Lue lisää" + popular_posts: "Suosittuja viestejä" + from_topic_label: "Lähettäjä" + more_new: "Uutta sinulle" subject_template: "[%{site_name}] Kooste" unsubscribe: "Tämä kooste lähetettiin sivustolta %{site_link}, koska emme ole nähneet sinua vähään aikaan. Jos et halua vastaanottaa näitä viestejä %{unsubscribe_link}." click_here: "klikkaa tästä" from: "%{site_name} kooste" + preheader: "Lyhyt yhteenveto tapahtumista viime vierailusi (%{last_seen_at}) jälkeen" mailing_list: why: "Kaikki toiminta sivustolla [%{site_name}] ajalla %{date}" subject_template: "[%{site_name}] Kooste ajalle %{date}" @@ -2162,6 +2262,7 @@ fi: too_large: "Pahoittelut, tiedosto jonka latausta yritit on liian suuri ( suurin tiedostokoko on %{max_size_kb}KB)." images: too_large: "Pahoittelut, kuva jonka yritit ladata on liian suuri (suurin sallittu kuvakoko on %{max_size_kb}KB), pienennä kuvaa ja yritä uudestaan." + larger_than_x_megapixels: "Pahoittelut, kuva jota yrität lähettää on liian suuri (maksimikoko on %{max_image_megapixels} megapikseliä). Muuta kuvan kokoa ja yritä uudelleen." size_not_found: "Pahoittelut, mutta emme pystyneet selvittämään kuvan kokoa. Ehkä kuvatiedosto on vahingoittunut?" avatar: missing: "Pahoittelut, emme löydä profiilikuvaa, joka olisi yhdistetty tähän sähköpostiosoitteeseen. Voitko yrittää ladata sen uudestaan?" @@ -2541,6 +2642,20 @@ fi: button: "Rekisteröidy" title: "Rekisteröi ylläpitäjätunnus" help: "aloita rekisteröimällä uusi tunnus" + no_emails: "Valitettavasti ylläpitäjän sähköpostiosoitetta ei määritetty asennuksen aikana, joten asennuksen viimeistely voi olla vaikeaa." + confirm_email: + title: "Vahvista sähköpostisi" + message: "

    Lähetimme vahvistusviestin osoitteeseen %{email}. Ota tili käyttöön seuraamalla viestin ohjeita.

    Jos viesti ei saavu, varmista että näppäilit sähköpostin oikein Discourseen ja tarkista roskapostikansiosi.

    " + resend_email: + title: "Lähetä vahvistusviesti uudelleen" + message: "Lähetimme uuden vahvistusviestin osoitteeseen %{email}" + safe_mode: + title: "Siirry vikasietotilaan" + description: "Vikasietotilassa voit testata sivustoasi ilman lisäosia ja sivuston mukautuksia." + no_customizations: "Poista käytöstä sivuston mukautukset" + only_official: "Poista käytöstä epäviralliset lisäosat" + no_plugins: "Poista käytöstä kaikki lisäosat" + enter: "Siirry vikasietotilaan" wizard: title: "Discoursen asennus" step: @@ -2564,10 +2679,11 @@ fi: fields: welcome: label: "Tervetuloa-ketju" - description: "

    Kuinka kuvailisit yhteisöä hississä ventovieraalle, jos sinulla olisi minuutti aikaa?

    • Keille nämä keskustelut on suunnattu?
    • Mistä täällä puhutaan?
    • Miksi täällä kannattaa käydä?

    Tervetuloa-ketju on ensimmäinen asia, jonka palstalle saapunut näkee. Ajattele sitä yhden kappaleen mittaisena \"hissipuheena\" tai \"perimmäisenä tavoitteena\".

    " + description: "

    How Kuinka kuvailisit yhteisöä hississä ventovieraalle, jos sinulla olisi minuutti aikaa?

    • Keille nämä keskustelut on suunnattu?
    • Mistä täällä puhutaan?
    • Miksi täällä kannattaa käydä?

    Tervetuloa-ketju on ensimmäinen asia, jonka palstalle saapunut näkee. Ajattele sitä yhden kappaleen mittaisena \"hissipuheena\" tai \"perimmäisenä tavoitteena\".

    " one_paragraph: "Pidä tervetuloviesti yhden kappaleen mittaisena." privacy: - description: "

    Onko yhteisö avoin kaikille vai onko pääsy riippuvainen jäsenyydestä, kutsusta tai hyväksynnästä? Jos haluat, voit laittaa kaiken alulle yksityisesti ja muuttaa foorumin julkiseksi myöhemmin.

    Muista, että voit aina lähettää kutsuja ketjujen alalaidasta kuin myös omalta käyttäjäsivultasikin.

    " + title: "Käyttöoikeudet" + description: "

    Onko yhteisö avoin kaikille vai onko pääsy riippuvainen jäsenyydestä, kutsusta tai hyväksynnästä? Jos haluat, voit laittaa kaiken alulle yksityisesti ja muuttaa foorumin julkiseksi myöhemmin.

    Voit aina lähettää kutsuja ketjujen alalaidasta kuin myös omalta käyttäjäsivultasikin.

    " fields: privacy: choices: @@ -2587,12 +2703,13 @@ fi: contact_url: label: "Internet-sivu" placeholder: "http://www.example.com/contact-us" + description: "Sinun tai organisaatiosi yleinen yhteydenottosivu. Näytetään Tietoja-sivulla." site_contact: label: "Automaattiset viestit" description: "Tämän käyttäjän nimissä Discourse lähettää kaikki automaattiset yksityisviestit käyttäjälle. Tärkeimpänä, käyttäjä on uudelle käyttäjälle lähetettävän tervetuloviestin lähettäjä." corporate: title: "Organisaatio" - description: "Nämä nimet näkyvät rekisteriselosteen and käyttöehtojen yhteydessä, joita voit milloin vain muokata henkilökunta-alueella. Jos taustalla ei ole yritystä, voit hypätä tämän vaiheen yli toistaiseksi." + description: "Nämä nimet näkyvät rekisteriselosteen ja käyttöehtojen yhteydessä, joita voit milloin vain muokata henkilökunta-alueella. Jos taustalla ei ole yritystä, voit hypätä tämän vaiheen yli toistaiseksi." fields: company_short_name: label: "Yrityksen nimi (lyhyesti)" @@ -2638,7 +2755,7 @@ fi: homepage_style: choices: latest: - label: "Tuoreimmat" + label: "Tuoreimmat ketjut" categories: label: "Keskustelualueet" emoji: diff --git a/config/locales/server.fr.yml b/config/locales/server.fr.yml index ae38c7dcd7d..10270963be4 100644 --- a/config/locales/server.fr.yml +++ b/config/locales/server.fr.yml @@ -32,6 +32,7 @@ fr: purge_reason: "Supprimé automatiquement comme compte abandonné et non activé" disable_remote_images_download_reason: "Le téléchargement des images externes a été désactivé faute de place suffisante sur le disque." anonymous: "Anonyme" + remove_posts_deleted_by_author: "Supprimé par l'auteur" emails: incoming: default_subject: "Courriel entrant de %{email}" @@ -106,7 +107,8 @@ fr: default_categories_already_selected: "Vous ne pouvez pas séléctionner une catégorie qui est utilisée dans une autre liste." s3_upload_bucket_is_required: "Vous ne pouvez pas activer l'upload sur S3 avant d'avoir renseigné le 's3_upload_bucket'." bulk_invite: - file_should_be_csv: "Le fichier envoyé doit être au format csv ou txt." + file_should_be_csv: "Le fichier envoyé doit être au format CSV." + error: "Il y a eu une erreur en envoyant ce fichier. Merci de réessayer plus tard." backup: operation_already_running: "Une opération est en cours d'exécution. Vous ne pouvez pas démarrer un nouveau processus pour l'instant." backup_file_should_be_tar_gz: "Le fichier de sauvegarde doit être une archive .tar.gz." @@ -124,6 +126,11 @@ fr: embed: start_discussion: "Démarrer la discussion" continue: "Continuer la discussion" + error: "Erreur d'intégration" + referer: "Référent :" + mismatch: "Le référent ne correspondait à aucun des hôtes suivants :" + no_hosts: "Aucun hôte n'a été configuré pour l'intégration." + configure: "Configurer l'intégration" more_replies: one: "1 réponse supplémentaire" other: "%{count} réponses supplémentaires" @@ -157,6 +164,7 @@ fr: spamming_host: "Désolé, vous ne pouvez pas insérer de lien vers ce domaine." user_is_suspended: "Les utilisateurs suspendus ne sont pas autorisés à poster de messages." topic_not_found: "Une erreur est survenue. Peut-être que ce sujet a été fermé ou supprimé pendant que vous le regardiez ?" + not_accepting_pms: "Désolé, %{username} n'accepte pas de messages pour le moment." just_posted_that: "est trop similaire à ce que vous avez récemment posté" invalid_characters: "contient des caractères invalides" is_invalid: "ne semble pas clair, est-ce une phrase complète ?" @@ -270,6 +278,7 @@ fr: name: "Nom de la catégorie" topic: title: 'Titre' + featured_link: 'Lien associé' post: raw: "Corps" user_profile: @@ -283,6 +292,9 @@ fr: too_many_users: "Vous ne pouvez envoyer des avertissements qu'à un utilisateur à la fois." cant_send_pm: "Désolé, vous ne pouvez pas envoyer de message privé à cet utilisateur." no_user_selected: "Vous devez choisir un utilisateur valide." + featured_link: + invalid: "est invalide. L'URL doit inclure http:// ou https://." + invalid_category: "ne peut pas être modifié dans cette catégorie." user: attributes: password: @@ -313,7 +325,24 @@ fr: meta_category_description: "Discussions à propos du site, son organisation, son fonctionnement, et comment nous pouvons l'améliorer." staff_category_name: "Responsables" staff_category_description: "Catégorie privée pour les discussions de l'équipe du forum. Les sujets ne sont visibles que pour les administrateurs et les modérateurs." + assets_topic_title: "Ressources pour le style du site" assets_topic_body: "Ceci est un sujet permanent, visible uniquement par l'équipe, pour stocker les images et fichiers utilisés pour le design du site. Ne pas le supprimer !\n\n\nMarche à suivre:\n\n1. Répondre à ce sujet\n2. Envoyer toutes les images que vous voulez utilisés comme logos, favicons, et tout ce que vous souhaitez. (Utiliser l'icone dans la barre d'édition ou glisser-déposer ou coller les images)\n3. Envoyer votre réponse\n4. Afin d'obtenir le chemin complet de votre image, faites un clic-droit dessus ou éditer votre message et copier le chemin.\n5. Coller le chemin de l'image dans les [paramètres requis](/admin/site_settings/category/required).\n\nDe plus, si vous souhaitez envoyer d'autres formats de fichier, modifier l'option `authorized_extensions` dans les [paramètres de fichier](/admin/site_settings/category/files)." + discourse_welcome_topic: + title: "Bienvenue sur Discourse" + body: |2 + + Le premier paragraphe de ce sujet épinglé sera visible comme message de bienvenue à tous les nouveaux visiteurs de votre page d'accueil. Il est important ! + + **Modifier le** en une brève description de votre communauté : + + - Pour qui est-elle destinée ? + - Que peuvent-ils y trouver ? + - Pourquoi doivent-ils venir ici ? + - Où peuvent-ils en lire plus (liens, ressources, etc.) ? + + + + Vous voulez peut-être fermer ce sujet via l'administration :wrench: (dans le coin supérieur droit et le bas) afin que des réponses ne s'accumulent pas après une annonce. lounge_welcome: title: "Bienvenue dans le salon" body: |2 @@ -377,6 +406,7 @@ fr: create_topic: "Vous créez des sujets trop rapidement. Patientez s'il vous plaît %{time_left} avant d'essayer à nouveau." create_post: "Vous répondez trop rapidement. Patientez s'il vous plaît %{time_left} avant d'essayer à nouveau." delete_post: "Vous effacez des messages trop rapidement. Patientez s'il vous plaît %{time_left} avant d'essayer à nouveau." + public_group_membership: "Vous rejoignez et/ou quittez des groupes trop souvent. Veuillez attendre %{time_left} avant d'essayer à nouveau." topics_per_day: "Vous avez atteint le nombre maximum de nouveaux sujets pour aujourd'hui. Patientez s'il vous plaît %{time_left} avant d'essayer à nouveau." pms_per_day: "Vous avez atteint le nombre maximum de nouveaux messages pour aujourd'hui. Patientez s'il vous plaît %{time_left} avant d'essayer à nouveau." create_like: "Vous avez atteint le nombre maximum de J'aime pour aujourd'hui. Patientez s'il vous plaît %{time_left} avant d'essayer à nouveau." @@ -533,6 +563,7 @@ fr: long_form: 'a voté pour ce message' user_activity: no_bookmarks: + self: "Vous n'avez mis de signets à aucun message ; mettre des signets vous permet de facilement les retrouver par la suite." others: "Aucun signet." no_likes_given: self: "Vous n'avez aimé aucun message" @@ -767,6 +798,8 @@ fr: min_first_post_length: "Longueur minimale d'un premier message (corps de sujet) en nombre de caractères" min_private_message_post_length: "Longueur minimale des messages en nombre de caractères" max_post_length: "Longueur maximale autorisée des messages en nombres de caractères" + topic_featured_link_enabled: "Activer la création de sujets avec lien" + show_topic_featured_link_in_digest: "Afficher les sujets avec lien dans le résumé par courriel." min_topic_title_length: "Longueur minimale autorisée des titres de sujet en nombre de caractères" max_topic_title_length: "Longueur maximale autorisée des titres de sujet en nombre de caractères" min_private_message_title_length: "Longueur minimale pour un titre de message en nombre de caractères" @@ -820,7 +853,7 @@ fr: summary_posts_required: "Nombre minimum de messages dans un sujet avant que le 'Résumé du sujet' soit activé" summary_likes_required: "Nombre de J'aime minimum dans un sujet avant que le 'Résumé du sujet' soit activé" summary_percent_filter: "Quand un utilisateur clique sur « Résumer ce sujet », montrer le top % des messages" - summary_max_results: "Nombre maximum de messages retournés par 'Résumé de ce sujet'" + summary_max_results: "Nombre maximum de messages retournés par « Résumer ce sujet »" enable_private_messages: "Autoriser les utilisateurs de niveau de confiance 1 à créer des messages et à répondre (configurable via le niveau de confiance minimum pour envoyer des messages). Notez que les responsables peuvent toujours envoyer des messages." enable_long_polling: "Utiliser les requêtes longues pour le flux de notifications." long_polling_base_url: "Racine de l'URL utilisée pour les requêtes longues (dans le cas de l'utilisation d'un CDN pour fournir du contenu dynamique, pensez à le configurer en mode \"origin pull\") par exemple : http://origin.site.com" @@ -875,9 +908,8 @@ fr: show_email_on_profile: "Afficher l'adresse du courriel de l'utilisateur sur leur page utilisateur (seulement visible pour l'utilisateur et les équipes techniques)" prioritize_username_in_ux: "Afficher le pseudonyme en premier sur la page d'un utilisateur, sa carte et ses messages (si désactivé, le nom est affiché en premier)" email_token_valid_hours: "Les jetons (tokens) de Mot de passe oublié / Activation de comptes sont valides (n) jours." - email_token_grace_period_hours: "Les jetons (tokens) de Mot de passe oublié / Activation de comptes sont encore valides pour une période de grâce de (n) heures après leur expiration." enable_badges: "Activer le système de badges" - enable_whispers: "Permettre la communication privée entre responsables au sein d'un sujet (expérimental)." + enable_whispers: "Autoriser les communications privées entre responsables au sein d'un sujet." allow_index_in_robots_txt: "Préciser dans robots.txt que le site est autorisé à être indexé par les robots des moteurs de recherche." email_domains_blacklist: "Liste des domaines de courriel qui ne sont pas autorisés lors de la création de compte, délimitée par des pipes. Exemple : mailinator.com|trashmail.net" email_domains_whitelist: "Liste des domaines de courriel avec lesquelles les utilisateurs DOIVENT s'enregistrer, délimités par un pipe. ATTENTION : les utilisateurs ayant une adresse de courriel sur un autre domaine ne pourront pas s'enregistrer." @@ -908,6 +940,7 @@ fr: sso_overrides_name: "Surcharger les noms complets locaux avec les noms complets externes d'un SSO à chaque connexion, et prévenir les modifications locales." sso_overrides_avatar: "Surcharge les avatars des utilisateurs avec les avatars d'un SSO. Si activé, il est fortement recommandé de désactiver allow_uploaded_avatars." sso_not_approved_url: "Rediriger les comptes SSO non validés vers cette URL" + sso_allows_all_return_paths: "Ne pas restreindre le domaine pour les return_paths fournis par le SSO (par défaut, le chemin de retour doit être sur le site actuel)" enable_local_logins: "Activer les comptes locaux avec pseudo et mot de passe. (Note : ceci doit être activé pour que les invitations fonctionnent)" allow_new_registrations: "Autorise l'inscription des nouveaux utilisateurs. Décocher pour prévenir la création de nouveau compte." enable_signup_cta: "Afficher un rappel aux visiteurs pour les encourager à créer un compte." @@ -985,16 +1018,16 @@ fr: enable_flash_video_onebox: "Activer l'utilisation de swf et flv (Adobe Flash) dans les boites imbriquées. ATTENTION : cela pourrait introduire un risque de sécurité." default_invitee_trust_level: "Niveau de confiance par défaut (0-4) pour les invités." default_trust_level: "Niveau de confiance par défaut (entre 0 et 4) pour tous les nouveaux utilisateurs. ATTENTION ! Changer ce paramètre peut vous exposer à des spams." - tl1_requires_topics_entered: "A combien de sujet un nouvel utilisateur doit avoir participé pour être promu au niveau de confiance 1." + tl1_requires_topics_entered: "À combien de sujets un nouvel utilisateur doit avoir participé pour être promu au niveau de confiance 1." tl1_requires_read_posts: "Combien de messages un nouvel utilisateur doit avoir lu pour être promu au niveau de confiance 1." tl1_requires_time_spent_mins: "Combien de minutes un nouvel utilisateur doit avoir passées à lire des messages pour être promu au niveau de confiance 1." - tl2_requires_topics_entered: "A combien de sujet un utilisateur doit avoir participé pour être promu au niveau de confiance 2." + tl2_requires_topics_entered: "À combien de sujets un utilisateur doit avoir participé pour être promu au niveau de confiance 2." tl2_requires_read_posts: "Combien de message un utilisateur doit avoir lu pour être promu au niveau de confiance 2." tl2_requires_time_spent_mins: "Combien de minutes un utilisateur doit avoir passées à lire des messages pour être promu au niveau de confiance 2." tl2_requires_days_visited: "Combien de jours un utilisateur doit visiter le site pour être promu au niveau de confiance 2." tl2_requires_likes_received: "Combien de J'aime un utilisateur doit recevoir pour être promu au niveau de confiance 2." tl2_requires_likes_given: "Combien de J'aime un utilisateur doit donner pour être promu au niveau de confiance 2." - tl2_requires_topic_reply_count: "A combien de sujet un utilisateur doit avoir participé pour être promu au niveau de confiance 2." + tl2_requires_topic_reply_count: "À combien de sujets un utilisateur doit avoir participé pour être promu au niveau de confiance 2." tl3_time_period: "Période de temps requise pour accéder au niveau de confiance 3 (en jours)" tl3_requires_days_visited: "Nombre minimum de jours qu'un utilisateur doit avoir passé sur le site dans les (tl3 time period) derniers jours pour être éligible au niveau de confiance 3. Fixer à plus que la période pour désactiver les promotions. (0 ou plus)" tl3_requires_topics_replied_to: "Nombre minimum de sujets auquel un utilisateur doit avoir répondu dans les (tl3 time period) derniers jours pour être éligible au niveau de confiance 3. (0 ou plus)" @@ -1128,19 +1161,25 @@ fr: automatically_download_gravatars: "Télécharger les gravatars pour les utilisateurs lors de la création de compte ou de la modification de courriel." digest_topics: "Le nombre maximum de sujets populaires à afficher dans le résumé par courriel." digest_posts: "Le nombre maximum de messages populaires à afficher dans le résumé par courriel." + digest_other_topics: "Le nombre maximum de sujets à afficher dans la section « Nouveautés dans les sujets et catégories que vous suivez » du résumé par courriel." digest_min_excerpt_length: "Longueur minimale (en caractères) de l'extrait des messages dans le résumé par courriel." delete_digest_email_after_days: "Ne pas envoyer de résumés par courriel aux utilisateurs qui n'ont pas visité le site depuis plus de (n) jours." digest_suppress_categories: "Ne pas inclure ces catégories dans les résumés par courriel." disable_digest_emails: "Désactiver les résumés par courriel pour tous les utilisateurs." + email_accent_bg_color: "La couleur d'accentuation utilisée comme arrière-plan de certains éléments des courriels HTML. Entrez un nom de couleur (« red ») ou une valeur hexadécimale (« #FF0000 »)." + email_accent_fg_color: "La couleur des textes rendus sur la couleur d'arrière-plan des courriels HTML. Entrez un nom de couleur (« white ») ou une valeur hexadécimale (« #FFFFFF »)." + email_link_color: "La couleur des liens dans les courriels HTML. Entrez un nom de couleur (« blue ») ou une valeur hexadécimale (« #0000FF »)." detect_custom_avatars: "Vérifier ou non si les utilisateurs ont envoyé une photo de profil personnalisée." max_daily_gravatar_crawls: "Nombre maximum de fois que Discourse vérifiera Gravatar pour des avatars personnalisés en une journée." public_user_custom_fields: "Une liste blanche des champs personnalisés pour un utilisateur qui peuvent être affichés publiquement." staff_user_custom_fields: "Une liste blanche des champs personnalisés pour un utilisateur qui peuvent être vus par l'équipe." enable_user_directory: "Fournir un répertoire des utilisateurs" + enable_group_directory: "Proposer un répertoire pour parcourir les groupes" allow_anonymous_posting: "Permettre aux utilisateurs de passer en mode anonyme" anonymous_posting_min_trust_level: "Le niveau de confiance minimum pour passer en mode anonyme." anonymous_account_duration_minutes: "Pour protéger l'anonymat, créer un nouveau compte anonyme tous les N minutes pour chaque utilisateur. Exemple: si 600 est choisi, dès 600 minutes après le dernier message ET que l'utilisateur passe en mode anonyme, un nouveau compte anonyme lui sera crée." hide_user_profiles_from_public: "Cacher les cartes, les profils et le répertoire d'utilisateurs aux visiteurs." + user_website_domains_whitelist: "Les sites Web des utilisateurs vont être vérifiés contre ces domaines. Liste délimitée par des pipes (|)." allow_profile_backgrounds: "Autoriser les utilisateurs à envoyer des arrières-plans de profil." sequential_replies_threshold: "Nombre de messages successifs qu'un utilisateur peut poster dans un sujet avant d'être averti d'avoir posté un nombre excessif de réponses qui se suivent." enable_mobile_theme: "Les appareils mobiles utilisent un thème adapté aux mobiles, avec la possibilité de passer à la totalité du site. Désactivez cette option si vous voulez utiliser une feuille de style personnalisée qui répond à tous les types de client." @@ -1153,6 +1192,7 @@ fr: automatically_unpin_topics: "Désépingler automatiquement le sujet lorsque l'utilisateur atteint la fin." read_time_word_count: "Nombre de mots par minute servant de base de calcul à l'estimation du temps de lecture." topic_page_title_includes_category: "Le titre de la page du sujet inclut le nom de la catégorie." + native_app_install_banner: "Propose aux visiteurs réguliers d'installer l'application Discourse native." max_prints_per_hour_per_user: "Nombre maximum d'accès à la page /print (mettre à 0 pour désactiver)" full_name_required: "Le nom complet est requis dans le profil utilisateur." enable_names: "Autoriser l'affichage des noms complets des utilisateurs dans leur profil, sur leur carte d'utilisateur et dans les courriels. Décocher pour cacher les noms complets partout." @@ -1176,7 +1216,6 @@ fr: embed_whitelist_selector: "Sélecteur CSS pour les éléments qui seront autorisés dans les contenus embarqués." embed_blacklist_selector: "Sélecteur CSS pour les éléments qui seront interdits dans les contenus embarqués." notify_about_flags_after: "Si il y a des signalements qui n'ont pas été traités après ce nombre d'heure, envoyer un courriel à contact_email. Désactiver la fonctionnalité en indiquan 0." - enable_cdn_js_debugging: "Autoriser /logs à afficher correctement les erreurs en ajoutant des permissions de crossorigin sur toutes les inclusions de js." show_create_topics_notice: "Si le site contient moins de 5 sujets publics, afficher un message pour demander aux administrateurs de créer d'autres sujets." delete_drafts_older_than_n_days: Supprimer les brouillons plus vieux que (n) jours. bootstrap_mode_min_users: "Nombre minimum d'utilisateurs nécessaire pour désactiver le mode de démarrage (mettre à 0 pour désactiver)" @@ -1253,11 +1292,11 @@ fr: invalid_string_min_max: "Doit être compris(e) entre %{min} et %{max} caractères." invalid_string_min: "Doit être d'au moins %{count} caractères." invalid_string_max: "Ne doit pas être supérieur à %{max} caractères." - invalid_reply_by_email_address: "La valeur doit contenir '%{reply_key}' et être différente de la notification email." - invalid_alternative_reply_by_email_addresses: "Toutes les valeurs doivent contenir '%{reply_key}' et être différentes de l'adresse courriel de notification." - pop3_polling_host_is_empty: "Vous devez indiquer le \"nom d'un serveur pop3\" avant d'activer le relevé via POP3." - pop3_polling_username_is_empty: "Vous devez indiquer le \"login utilisateur pop3\" avant d'activer le relevé via POP3." - pop3_polling_password_is_empty: "Vous devez indiquer le \"mot de passe pop3\" avant d'activer le relevé via POP3." + invalid_reply_by_email_address: "La valeur doit contenir « %{reply_key} » et être différente du courriel de notification." + invalid_alternative_reply_by_email_addresses: "Toutes les valeurs doivent contenir « %{reply_key} » et être différentes du courriel de notification." + pop3_polling_host_is_empty: "Vous devez définir « pop3 polling host » avant d'activer le relevé via POP3." + pop3_polling_username_is_empty: "Vous devez définir « pop3 polling username » avant d'activer le relevé via POP3." + pop3_polling_password_is_empty: "Vous devez définir « pop3 polling password » avant d'activer le relevé via POP3." pop3_polling_authentication_failed: "Echec d'authentication POP3. Veuillez contrôler vos détails POP3." reply_by_email_address_is_empty: "Vous devez renseigner une 'adresse de réponse par courriel' avant d'activer la réponse par courriel." email_polling_disabled: "Vous devez activer le relevé manuel ou via POP3 avant d'activer les réponses par courriel." @@ -1366,6 +1405,8 @@ fr: user: no_accounts_associated: "Aucun compte associé" deactivated: "A été désactivé à cause de trop de courriels rejetés vers '%{email}'." + deactivated_by_staff: "Désactivé par un responsable" + activated_by_staff: "Activé par un responsable" username: short: "doit être d'au moins %{min} caractères" long: "ne doit pas être supérieur à %{max} caractères" @@ -1383,6 +1424,8 @@ fr: ip_address: blocked: "Les nouvelles inscriptions ne sont pas acceptées depuis votre adresse IP." max_new_accounts_per_registration_ip: "Les nouvelles inscriptions ne sont pas autorisées depuis votre adresse IP (limite atteinte). Contactez un responsable." + website: + domain_not_allowed: "Site Web invalide. Les domaines autorisés sont : %{domains}" flags_reminder: flags_were_submitted: one: "Un signalement a été soumis il y a plus d'une heure. Veuillez la passer en revue." @@ -1442,36 +1485,8 @@ fr: Cette invitation provient d'un utilisateur de confiance, vous pouvez donc répondre immédiatement. invite_forum_mailer: subject_template: "%{invitee_name} vous a invité(e) à rejoindre %{site_domain_name}" - text_body_template: | - %{invitee_name} vous a invité(e) à rejoindre - - > **%{site_title}** - > - > %{site_description} - - Si cela vous intéresse, cliquez sur le lien ci-dessous : - - %{invite_link} - - Cette invitation provient d'un utilisateur de confiance, un compte sera automatiquement créé pour vous. custom_invite_forum_mailer: subject_template: "%{invitee_name} vous a invité(e) à rejoindre %{site_domain_name}" - text_body_template: | - %{invitee_name} vous a invité(e) à rejoindre - - > **%{site_title}** - > - > %{site_description} - - Message de %{invitee_name} : - - %{user_custom_message} - - Si cela vous intéresse, cliquez sur le lien ci-dessous : - - %{invite_link} - - Cette invitation provient d'un utilisateur de confiance, un compte sera automatiquement créé pour vous. invite_password_instructions: subject_template: "Renseignez le mot de passe pour votre compte utilisateur %{site_name} " text_body_template: | @@ -1607,26 +1622,6 @@ fr: (Si, en tant que nouvel utilisateur, vous avez besoin de communiquer avec un [responsable](%{base_url}/about), répondez simplement à ce message.) welcome_invite: subject_template: "Bienvenue sur %{site_name} !" - text_body_template: | - Merci d'avoir accepté votre invitation sur %{site_name} et bienvenue ! - - Nous avons créé un nouveau compte : **%{username}**, et vous y êtes connecté. Vous pouvez changer votre pseudo en allant sur [votre profil][prefs]. - - Pour vous reconnecter : - - 1. Toujours **utiliser la même adresse de courriel que celle de l'invitation** que vous avez reçue. Autrement, nous ne pourrons pas vous reconnaître. - - 2. Créer un mot de passe unique sur votre [sur votre profil][prefs] et connectez-vous avec. - - %{new_user_tips} - - Nous croyons au [comportement communautaire civilisé](%{base_url}/guidelines) en tous temps. - - Amusez-vous bien ! - - (Si, en tant que nouvel utilisateur, vous avez besoin de communiquer avec un [responsable](%{base_url}/about), répondez simplement à ce message). - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "Sauvegarde terminée avec succès" text_body_template: | @@ -2066,6 +2061,7 @@ fr: new_topics: "Nouveaux sujets" unread_messages: "Messages non lus" unread_notifications: "Notifications non lues" + liked_received: "J'aime reçus" new_posts: "Nouveaux messages" new_users: "Nouveaux utilisateurs" popular_topics: "Sujets populaires" @@ -2073,7 +2069,7 @@ fr: join_the_discussion: "Lire la suite" popular_posts: "Messages populaires" from_topic_label: "De" - more_new: "Nouveautés dans les sujets et catégories que vous suivez" + more_new: "Nouveau pour vous" subject_template: "[%{site_name}] Résumé" unsubscribe: "Ce résumé est envoyé depuis %{site_link} lorsque nous ne vous voyons plus depuis un moment. Pour se désabonner %{unsubscribe_link}." click_here: "cliquez ici" @@ -2693,11 +2689,9 @@ fr: fields: welcome: label: "Sujet de bienvenue" - description: "

    Comment décririez-vous votre communauté à un inconnu en environ 1 minute ?

    • Pour qui sont destinées ces discussions ?
    • Que puis-je trouver ici ?
    • Pourquoi dois-je la visiter ?

    Votre sujet de bienvenue est la première chose que les nouveaux visiteurs vont voir. Voyez le comme votre unique paragraphe qui définit votre mission et différence.

    " one_paragraph: "Veuillez restreindre votre message de bienvenue à un paragraphe." privacy: title: "Accès" - description: "

    Votre communauté est-elle ouverte à tous ou restreinte par adhésion, invitation et approbation ? Si vous préférez, vous pouvez préparer le site en mode privé puis passer en public par la suite.

    Rappelez-vous aussi que vous pouvez toujours envoyer des invitations depuis les sujets ou votre page de profil utilisateur.

    " fields: privacy: choices: @@ -2723,7 +2717,6 @@ fr: description: "Tous les messages privés automatiques de Discourse seront envoyés par cet utilisateur. Plus important, cet utilisateur sera l'envoyeur désigné de tous les messages de bienvenue à destination des nouveaux utilisateurs." corporate: title: "Organisation" - description: "Ces noms seront renseignés dans les pages Politique de confidentialité et Conditions générales d'utilisation que vous pouvez modifier à tout moment depuis la catégorie Staff. Si vous n'avez pas de société, vous pouvez ignorer cette étape pour le moment." fields: company_short_name: label: "Nom de société (court)" @@ -2738,7 +2731,6 @@ fr: title: "Thème" fields: theme_id: - description: "Préférez-vous une palette de couleurs claires ou sombres pour commencer ? Vous pouvez toujours personnaliser l'aspect du site dans Administration, Personaliser." choices: default: label: "Clair" @@ -2763,7 +2755,6 @@ fr: label: "Grande icône" description: "Icône utilisée pour représenter le site sur les appareils modernes et que rend bien à des tailles plus grandes. La taille minimale conseillée est de 144px par 144px." homepage: - description: "Nous recommandons d'afficher les sujets récents sur votre page d'accueil mais vous pouvez choisir d'y afficher les catégories (groupes de sujets) si vous préférez." title: "Page d'accueil" fields: homepage_style: @@ -2774,7 +2765,6 @@ fr: label: "Catégories" emoji: title: "Emoji" - description: "Quel style d'Emoji préférez-vous pour votre communauté ? Vous pouvez toujours ajouter des Emoji supplémentaires dans Administration, Personnaliser, Emoji." invites: title: "Inviter des responsables" description: "Vous avez presque fini ! Invitons quelques responsables pour aider à entamer les discussions avec des sujets et réponses intéressantes pour lancer la communauté." diff --git a/config/locales/server.he.yml b/config/locales/server.he.yml index 2ed083d0255..c3380806652 100644 --- a/config/locales/server.he.yml +++ b/config/locales/server.he.yml @@ -32,6 +32,7 @@ he: purge_reason: "נמחק אוטומטית כחשבון נטוש ולא פעיל" disable_remote_images_download_reason: "הורדת תמונות מרחוק נחסמה בשל היעדר מספיק שטח אחסון פנוי." anonymous: "אנונימי" + remove_posts_deleted_by_author: "נמחק על ידי הכותב" emails: incoming: default_subject: "התקבל מייל מ %{email}" @@ -72,6 +73,8 @@ he: inclusion: לא נכלל ברשימה invalid: לא תקין is_invalid: "נראה לא ברור, האם זה משפט שלם?" + contains_censored_words: "כולל אחת או יותר מהמילים המצונזרות הבאות: %{censored_words}" + matches_censored_pattern: "מתאים לביטוי הרגולרי המצונזר: %{censored_pattern}" less_than: חייב להיות פחות מ-%{count} less_than_or_equal_to: חייב להיות פחות או שווה ל-%{count} not_a_number: אינו מספר @@ -106,7 +109,8 @@ he: default_categories_already_selected: "לא ניתן לבחור קטגוריה שהשתמשו בה ברשימה אחרת." s3_upload_bucket_is_required: "אינכם יכולים להעלות ל-S3 ללא 's3_upload_bucket'." bulk_invite: - file_should_be_csv: "הקובץ המועלה צריך להיות בפורמט csv או txt." + file_should_be_csv: "הקובץ שמועלה אמור להיות בפורמט csv." + error: "ארעה שגיאה בהעלת הקובץ. אנא נסו שוב מאוחר יותר." backup: operation_already_running: "פעולה רצה כרגע. לא יכול להתחיל עבודה חדשה עכשיו." backup_file_should_be_tar_gz: "קובץ הגיבוי צריך להיות .tar.gz." @@ -124,6 +128,11 @@ he: embed: start_discussion: "התחלת דיון" continue: "המשך דיון" + error: "תקלה בשילוב" + referer: "מפנה:" + mismatch: "המפנה לא התאים לאף אחד מהשרתים הבאים:" + no_hosts: "אף שרת לא הוגדר לשילוב." + configure: "הגדרת שילוב (Embedding)" more_replies: one: "עוד תגובה אחת" other: "עוד %{count} תגובות" @@ -157,6 +166,7 @@ he: spamming_host: "סליחה אך אינכם יכולים להוסיף קישור לאתר זה." user_is_suspended: "משתמשים מושעים אינם מורשים לפרסם." topic_not_found: "משהו השתבש אולי נושא זה נסגר או נמחק בזמן שקראתם אותו?" + not_accepting_pms: "מצטעים, %{username} לא מקבל הודעות כרגע." just_posted_that: "דומה מידי למה שפרסמתם לאחרונה" invalid_characters: "מכיל תווים לא תקניים" is_invalid: "נראה לא ברור, האם זה משפט שלם?" @@ -268,6 +278,7 @@ he: name: "שם קטגוריה" topic: title: 'כותרת' + featured_link: 'קישור מומלץ' post: raw: "גוף" user_profile: @@ -281,6 +292,9 @@ he: too_many_users: "אתם יכולים לשלוח אזהרות רק למשתמש/ת אחד בכל פעם." cant_send_pm: "מצטערים, אינכם יכולים לשלוח הודעה פרטית למשתמש זה." no_user_selected: "עליכם לבחור משתמש/ת תקניים." + featured_link: + invalid: "אינו תקין. URL אמור לכלול http:// או https://." + invalid_category: "לא ניתן לעריכה בקטגוריה זו." user: attributes: password: @@ -311,7 +325,24 @@ he: meta_category_description: "דיון אודות אתר זה, הארגון שמאחוריו, איך הוא פועל ואיך נוכל לשפר אותו." staff_category_name: "צוות" staff_category_description: "קטגוריה פרטית לדיוני הצוות. נושאים נראים רק למנהלים ומנהלים ראשיים." + assets_topic_title: "נכסים לעיצוב האתר" assets_topic_body: "זהו נושא קבוע, הגלוי רק לצוות, לשמירת תמונות וקבצים שמשמשים לעיצוב האתר. אל תמחקו אותו!\n\n\nכיצד:\n\n\n1. הגיבו לנושא זה.\n2. העלו כאן את כל התמונות שברצונכם שישמשו כלוגואים, לוגואים מוקטנים (favicons) וכן הלאה. (השתמשו בלוגו ההעלאה בסרגל הכלים בעורך הפוסט, או גררו-שחררו או הדביקו את התמונות.)\n3. שלחו את התגובה כדי לפרסם אותה.\n4. הקליקו עם הכפתור הימני על התמונות בפרסום החדש שלכם כדי להשיג את הכתובת של התמונה שהועלתה, או הקליקו על סמל העריכה כדי לערוך את הפוסט ולאחזר את הכתובת של התמונות. העתיקו את הכתובות.\n5. הדביקו את כתובות התמונות אל תוך [הגדרות בסיסיות](/admin/site_settings/category/required).\n\nאם אתכם צריכים לאפשר העלאת קבצים מסוגים שונים, ערכו את \"הרחבות מאושרות\" בתוך [הגדרות_קובץ](/admin/site_settings/category/files)." + discourse_welcome_topic: + title: "ברוכים הבאים לדיסקורס" + body: |2 + + הפסקה הראשונה של נושא נעוץ זה תראה כהודעת ״ברוכים הבאים״ לכל המבקרים החדשים באתר הבית שלכם. היא חשובה! + + **עירכו זאת** לתיאור קצר של הקהילה שלכם: + + - למי היא נועדה? + - מה הם יכולים למצוא כאן? + - למה כדאי להם לבוא לפה? + - איפה אפשר לקרוא עוד (קישורים, מקורות, וכד׳)? + + + + ייתכן ותרצו לסגור נושא זה באמצעות :wrench: הניהול (בפינות משמאל למעלה ולמטה), כדי שתגובות לא ייערמו על גבי כרזה. lounge_welcome: title: "ברוכים הבאים ללאונג'" body: |2 @@ -374,6 +405,7 @@ he: create_topic: "אתם יוצרים נושא חדש מהר מדי. אנא המתנו %{time_left} לפני ניסיון חוזר לבצע פעולה זו." create_post: "אתם מגיבים מהר מדי. אנא המתינו %{time_left} לפני ניסיון חוזר לבצע פעולה זו." delete_post: "אתם מוחקים פוסטים מהר מידי. אנא המתינו %{time_left} לפני שאתם מנסים שוב." + public_group_membership: "אתם מצטרפים/עוזבים קבוצות בתדירות גבוהה מידי. אנא המתינו %{time_left} לפני שתנסו שוב." topics_per_day: "הגעתם למספר המירבי של נושאים חדשים היום. אנא המתינו %{time_left} לפני ניסיון חוזר לבצע פעולה זו." pms_per_day: "הגעתם למספר המירבי של הודעות היום. אנא המתינו %{time_left} לפני ניסיון חוזר לבצע פעולה זו." create_like: "הגעתם למספר המירבי של לייקים היום. אנא המתינו %{time_left} לפני ניסיון חוזר לבצע פעולה זו." @@ -765,6 +797,8 @@ he: min_first_post_length: "אורך מינימלי מותר לפוסט ראשון (בגוף הנושא) בתווים " min_private_message_post_length: "אורך הפוסט המינימלי המותר בתווים להודעות" max_post_length: "מספר התווים המקסימלי כאורך פוסט" + topic_featured_link_enabled: "איפשור של פרסום קישור עם נושאים." + show_topic_featured_link_in_digest: "הצגת קישור מומלץ של הנושא במייל התמצות." min_topic_title_length: "מספר התווים המינימלי הנדרש לכותרת נושא" max_topic_title_length: "מספר התווים המקסימלי המותר לכותרת נושא" min_private_message_title_length: "אורך הכותרת המנימילי המותר להודעה בתווים" @@ -873,9 +907,8 @@ he: show_email_on_profile: "הצגת כתובת הדוא\"ל של המשתמשים בעמוד הפרופיל שלהם (גלוי רק להם ולצוות)" prioritize_username_in_ux: "הציגו שם-משתמש ראשון בדף המשתמש, כרטיס המשתמש ופוסטים (כשמנוטרל השם מופיע קודם)" email_token_valid_hours: "סיסמאות שכחת סיסמה / הפעלת חשבון תקפים במשך (n) שעות." - email_token_grace_period_hours: "סיסמאות שכחת סיסמה / הפעלת חשבון עדיין זמינים לזמן חסד של (n) שעות לאחר שהופקו." enable_badges: "הפעלת מערכת העיטורים" - enable_whispers: "הודעות פרטיות בין חברי הצוות אפשריות בתוך הנושא (ניסיוני)" + enable_whispers: "אפשרו לצוות לקיים תקשורת פרטית בתוך נושאים." allow_index_in_robots_txt: "פרטו ב-robots.txt שלאתר זה מותר להיות מאונדקס על ידי מנועי חיפוש." email_domains_blacklist: "רשימה מופרדת בצינור (pipe) של דומיינים של אימייל אשר מהם משתמשים לא מורשים לרשום חשבונות. למשל: mailinator.com|trashmail.net" email_domains_whitelist: "רשימה מופרדת בצינור (pipe) אשר ר-ק ממנה משתמשים יכולים לרשום חשבונות. א-ז-ה-ר-ה: משתמשים עם אימיילים מדומיינים אחרים לא יורשו!" @@ -906,6 +939,7 @@ he: sso_overrides_name: "דורס שם מלא מקומי עם שם מלא מאתר חיצוני מתוכן SSO בכל התחברות, מונע שינויים מקומיים." sso_overrides_avatar: "מעקף אווטאר של משתמש בעזרת אווטר אתר חיצוני מ-SSO Payload. אם אפשרות זו מופעלת, מומלץ מאוד לבטל את האפשרות להעלאת אווטר." sso_not_approved_url: "SSO של חשבונות שלא אושרו יופנו ל URL זה" + sso_allows_all_return_paths: "אל תגבילו את שמות המתחם של נתיבי החזרה (return_paths) שניתנים על ידי ה-SSO (כברירת מחדל, נתיבי החזרה חייבים להיות באתר הנוכחי)" enable_local_logins: "אפשרו התחברות שמבוססת על שמות משתמשים וסיסמאות מקומיים. (שימו לב: אפשרות זו חייבת להיות מותרת כדי שהזמנות להצטרפות יפעלו)" allow_new_registrations: "אפשרו הרשמות משתמשים חדשים. בטלו סימון זה כדי למנוע יצירת חשבונות חדשים." enable_signup_cta: "הציגו מודעה למשתמשים אנונימיים חוזרים שמציעה להם להרשם כדי לקבל חשבון." @@ -932,7 +966,7 @@ he: automatic_backups_enabled: "הרץ גיבויים אוטומטים כמו שמוגדר בתדירות הגיבויים" backup_frequency: "באיזו תכיפות אנחנו מגבים את האתר, בימים." enable_s3_backups: "העלאת גיבויים ל-S3 לאחר השלמתם. חשוב: דורש הזנת הרשאות S3 תקפות להגדרות הקבצים." - s3_backup_bucket: "הדלי המרוחק שבו לשמור גיבויים. אזהרה: סימו לב שהוא דלי פרטי." + s3_backup_bucket: "הדלי המרוחק שבו לשמור גיבויים. אזהרה: שימו לב שהוא דלי פרטי." s3_disable_cleanup: "בטלו את ההסרה של גיבויים מ S3 כאשר הם מוסרים מקומית." backup_time_of_day: "הגדרת זמן לגיבוי לפי UTC." backup_with_uploads: "כללו העלאות בגיבויים התקופתיים. ביטול של אפשרות זו תגבה רק את בסיס הנתונים." @@ -1038,6 +1072,7 @@ he: max_attachment_size_kb: "הגודל המקסימלי בקילו-בתים (kBs) של קבצים להעלאה. הגדרה זו חייבת להיות מוגדרת ב-nginx (client_max_body_size) / apache או בפרוקסי." authorized_extensions: "רשימה של סיומות מותרות להעלאה (השתמשו ב '*' כדי לאפשר את כל סוגי הקבצים)" max_similar_results: "כמה נושאים דומים להציג מעל לעורך כאשר מחברים נושא חדש. ההשוואה מבוססת על הכותרת וגוף הפוסט." + max_image_megapixels: "מספר מקסימלי מותר של מגה-פיקסלים לתמונה." title_prettify: "מניעת טעויות נפוצות בכותרת, בכללן טעויות עם אותיות גדולות באנגלית, מספר ! ו ?, נקודה מיותרת בסוף, וכד׳" topic_views_heat_low: "לאחר כמות זו של צפיות, שדה הצפיות יהיה קצת יותר בהיר." topic_views_heat_medium: "לאחר כמות צפיות זו, שדה הצפיות יודגש באופן בינוני." @@ -1131,15 +1166,20 @@ he: delete_digest_email_after_days: "השתקת מיילי סיכום למשתמשים שלא ביקרו באתר למעלה מ (n) ימים." digest_suppress_categories: "וותרו על קטגוריות אלו במיילים מסכמים." disable_digest_emails: "בטל סיכומי מיילים לכל המשתמשים." + email_accent_bg_color: "צבע האקסנט שיעשה בו שימוש כרקע לחלק מהאלמנטים של מיילים מסוג HTML. הכניסו שם צבע ('red') או ערך הקסדצימלי ('#FF000')." + email_accent_fg_color: "צבע הטקסט שמופיע על צבע הרקע של מיילים מסוג HTML. הכניסו שם צבע ('white') או ערך הקסדצימלי ('#FFFFFF')." + email_link_color: "צבע הקישורים במיילים מסוג HTML. הכניסו שם צבע ('blue') או ערך הקסדצימלי ('#0000FF')." detect_custom_avatars: "האם לבדוק או לא לבדוק שמשתמשים העלו תמונות פרופיל אישיות." max_daily_gravatar_crawls: "מספר הפעמים המקסימלי ש-Discourse יבדוק אווטרים ב-Gravatar ביום" public_user_custom_fields: "רשימה לבנה (whitelist) של שדות מותאמים למשתמש שיכולים להיות מוצגים באופן פומבי." staff_user_custom_fields: "רשימה לבנה (whitelist) של שדות מותאמים למשתמש שיכולים להיות מוצגים לאנשי צוות." enable_user_directory: "ספקו ספריייה של משתמשים לגלישה" + enable_group_directory: "ספקו ספריה של קבוצות לסיור" allow_anonymous_posting: "אפשרו למשתמשים לעבור למצב אנונימי" anonymous_posting_min_trust_level: "רמת האמון המינמלית הנדרשת כדי לאפשר פרסום אנונימי" anonymous_account_duration_minutes: "בכדי להגן על האנונימות צרו חשבון אנונימי כל N דקות לכל משתמש. לדוגמה: אם מכוון ל-600, כאשר יעברו 600 דקות מהפרסום האחרון והמשתמש/ת יחליפו לזהות אנונימית, חשבון אנונימי חדש יווצר." hide_user_profiles_from_public: "נטרלו כרטיסי משתמשים, פרופילי משתמשים ומדריך משתמשים למשתמשים אנונימיים." + user_website_domains_whitelist: "אתרי משתמשים יאומתו עם מתחמים אלו. רשימה מופרדת על ידי קווים-אנכיים." allow_profile_backgrounds: "אפשרו למשתמשים להעלות רקעים לפרופיל." sequential_replies_threshold: "מספר הפוסטים שעל משתמש לפרסם אחד-לאחר-השני בנושא לפני שמזכירים לו שהוא משאיר יותר מידי תגובות ברצף." enable_mobile_theme: "מכשירים ניידים משתמשים בתבנית ידידותית אליהם, עם היכולת להחליף אותה לאתר המלא. נטרלו זאת אם אתם מעוניינים ב stylesheet מותאם שהוא רספונסיבי לחלוטין." @@ -1152,6 +1192,7 @@ he: automatically_unpin_topics: "הסרת נעיצה אוטומטית של נושאים כאשר המשתמשים מגיעים לתחתית." read_time_word_count: "מספר המילים לדקה כדי להעריך את זמן הקריאה." topic_page_title_includes_category: "כותרת דף נושא כוללת את שם הקטגוריה." + native_app_install_banner: "בקשו ממבקרים חוזרים להתקין את אפליקציית Discourse." max_prints_per_hour_per_user: "מספר מקסימלי של צפיות בדף /print (הדפסה) (קיבעו ל 0 כדי לנטרל)" full_name_required: "שם מלא הוא שדה נדרש לפרופיל משתמש/ת." enable_names: "הצגת השם המלא של המשתמש/ת בעמודי הפרופיל שלהם, בכרטיסי המשתמש ובדוא\"ל שלהם. נטרלו להסתרת השם המלא בכל מקום." @@ -1175,7 +1216,6 @@ he: embed_whitelist_selector: "בוררי CSS לאלמנטים שיותר להטמיע." embed_blacklist_selector: "בוררי CSS לאלמנטים שיוסרו מן ההטמעות." notify_about_flags_after: "אם יש דגלים שלא טופלו לאחר כמות זו של שעות, שילחו אימייל ל contact_email. קבעו 0 לניטרול." - enable_cdn_js_debugging: "אפשרו ל-/logs להציג שגיאות בצורה נכונה באמצעות הוספת הרשאות לגישה בין אתרים (crossorigin permissions) בכל ה-js הכלולים." show_create_topics_notice: "אם לאתר פחות מ-5 נושאים פומביים, הציגו מודעה המבקשת מן המנהלים ליצור עוד נושאים." delete_drafts_older_than_n_days: מחקו טיוטות בנות יותר מ (n) ימים. bootstrap_mode_min_users: "מספר משתמשים מינימלי שנדרש כדי לנטרל מצב איתחול (קבעו ל 0 כדי לנטרל)" @@ -1365,6 +1405,8 @@ he: user: no_accounts_associated: "אין חשבונות מקושרים." deactivated: "הושבת בעקבות מיילים רבים מידי שהוחזרו ל '%{email}'." + deactivated_by_staff: "נוטרל על ידי הצוות" + activated_by_staff: "הופעל על ידי הצוות" username: short: "חייבים להיות לפחות %{min} תווים" long: "נדרשים לא יותר מ-%{max} תווים" @@ -1382,6 +1424,8 @@ he: ip_address: blocked: "הרשמות חדשות אסורות מכתובת ה-IP שלך." max_new_accounts_per_registration_ip: "הרשמות חדשות אסורות מכתובת ה-IP שלך. (עברת את הסף המותר) צרו קשר עם איש צוות." + website: + domain_not_allowed: "אתר לא תקין. מתחמים מותרים: %{domains}" flags_reminder: flags_were_submitted: one: "דגלים נשלחו לפני למעלה משעה. אנא סיקרו אותם." @@ -1390,6 +1434,7 @@ he: one: "דגל אחד ממתין לטיפול" other: "%{count} דגלים ממתינים לטיפול" unsubscribe_mailer: + title: "שולח-מיילים לביטול מנוי" subject_template: "אשרו שאינכם מעוניינים יותר לקבל עדכוני דוא\"ל מ%{site_title}" text_body_template: | מישהו (כנראה אתם?) ביקש לא לקבל יותר עדכוני מייל מ %{site_domain_name} לכתובת זו. @@ -1400,6 +1445,7 @@ he: אם אתם מעוניינים להמשיך לקבל עדכונים במייל, אתם יכולים להתעלם ממייל זה. invite_mailer: + title: "שולח-מיילים להזמנה" subject_template: "הוזמנת על ידי %{invitee_name} ל '%{topic_title}' ב%{site_domain_name}" text_body_template: | %{invitee_name} הזמין/הזמינה אותך לדיון @@ -1418,6 +1464,7 @@ he: הזמנה זו נשלחה על ידי משתמש/ת מוכר/ת ולכן אתם יכולים להשיב לדיון הנ"ל באופן מיידי. custom_invite_mailer: + title: "שולח-מיילים מותאם-אישית להזמנה" subject_template: "%{invitee_name} הזמין/הזמינה אותך לדיון '%{topic_title}' באתר %{site_domain_name}" text_body_template: | %{invitee_name} הזמין/הזמינה אותך לדיון @@ -1439,6 +1486,7 @@ he: הזמנה זו נשלחה על ידי משתמש מוכר, כך שתוכלו להגיב לדיון מיידית. invite_forum_mailer: + title: "שולח-מיילים להזמנה לפורום" subject_template: "%{invitee_name} הזמינ/ה אתכם להצטרף ל%{site_domain_name}" text_body_template: | %{invitee_name} הזמין/ה אתכם להצטרף ל @@ -1451,8 +1499,9 @@ he: %{invite_link} - הזמנה זו נשלחה ממשתמש/ת מוכר/ת באתר. החשבון יווצר עבורכם באופן אוטומטי. + הזמנה זו נשלחה ממשתמש/ת מוכר/ת באתר, כך שהחשבון יווצר עבורכם באופן אוטומטי עם כתובת מייל זו. custom_invite_forum_mailer: + title: "שולח-מיילים להזמנה לפורום" subject_template: "%{invitee_name} הזמין/ה אתכם להצטרף ל %{site_domain_name}" text_body_template: | %{invitee_name} הזמינו אתכם להצטרף ל @@ -1469,14 +1518,16 @@ he: %{invite_link} - הזמנה זו נשלחה ממשתמשים מוכרים באתר, כך שהחשבון שלכם יווצר באופן אוטומטי. + הזמנה זו נשלחה ממשתמשים מוכרים באתר, כך שהחשבון שלכם יווצר באופן אוטומטי עבור כתובת מייל זו. invite_password_instructions: + title: "הנחיות סיסמה למוזמנים" subject_template: "צרו סיסמה עבור חשבון ה-%{site_name} שלכם." text_body_template: | תודה שקיבלתם את ההזמנה שלכם ל %{site_name} -- ברוכים הבאים! לחצו על הקישור בשביל לבחור סיסמה: %{base_url}/users/password-reset/%{email_token} (אם הקישור פג תוקף, בחרו ב"שכחתי את הסיסמה שלי" בהתחברות.) test_mailer: + title: "שולח-מיילים לבדיקה" subject_template: "[%{site_name}] מייל בדיקת שליחתיות" text_body_template: | זהו מייל בדיקה מ @@ -1520,6 +1571,7 @@ he: [mj]: https://www.mailjet.com/pricing [mt]: http://www.mail-tester.com/ new_version_mailer: + title: "שולח-מיילים של גרסה חדשה" subject_template: "[%{site_name}] גרסת Discourse חדשה, עדכון זמין." text_body_template: | יש! יצאה גרסה חדשה של [Discourse](http://www.discourse.org) @@ -1533,6 +1585,7 @@ he: - בקרו את [meta.discourse.org](https://meta.discourse.org) לחדשות, דיונים, ותמיכה ב Discourse new_version_mailer_with_notes: + title: "שולח-מיילים של גרסה חדשה עם הערות" subject_template: "[%{site_name}] עדכון זמין" text_body_template: | יש! יצאה גרסה חדשה של [Discourse](http://www.discourse.org) @@ -1550,6 +1603,7 @@ he: %{notes} queued_posts_reminder: + title: "תזכורת פוסטים בתור" subject_template: one: "[%{site_name}] פוסט 1 מחכה לסקירה" other: "[%{site_name}] %{count} פוסטים ממתינים לסקירה" @@ -1571,6 +1625,7 @@ he: temporarily_closed_due_to_flags: "נושא זה סגור באופן זמני בעקבות מספר רב של דגלים של הקהילה. " system_messages: post_hidden: + title: "פוסט חבוי" subject_template: "פוסט הוסתר על ידי דגלים של הקהילה" text_body_template: | שלום, @@ -1588,95 +1643,11 @@ he: להנחיות נוספות, אנא פנו ל[הנחיות הקהילה](%{base_url}/guidelines). usage_tips: text_body_template: | - כמה טיפים לשימוש במערכת:: - איך קוראים + כמה טיפים לגבי איך להתחיל כמשתמשים חדשים, [ראו את הפוסט הזה](http://blog.discourse.org/2016/12/discourse-new-user-tips-and-tricks/). - כדי לקרוא עוד, פשוט המשיכו לגלול מטה! - - כאשר יופיעו תגובות נוספות או נושאים חדשים, הם יצוצו אוטומטית - אין צורך לרענן את העמוד. - ניווט - - כדי לחפש, להגיע לעמוד המשתמש/ת שלך או להגיע לתפריט ☰, השתמשו באייקונים הקטנים שלמעלה מימין. - - כשתבחר/י בכותרת של נושא, מיד תועברו לתשובה הראשונה שלא קראתם עדיין באותו הנושא. כדי להיכנס ישר לראש רשימת הפרסומים, או לתחתית שלה, לחצו על מספר התגובות המופיע לצד שם הנושא, או על התאריך. - - - - כשאתם קוראים נושא, השתמשו בסרגל הזמנים שלצידו כדי לדלג למעלה, למטה או לחלק האחרון שקראתם. במסכים קטנים, לחצו על סרגל ההתקדמות שלמטה על מנת להרחיבו: - - - - אתם יכולים גם ללחוץ על ? במקלת כדי לראות רשימה של קיצורי מקלדת סופר-מהירים. - משלוח תגובות - - כדי להכניס ציטוט, סמנו את הטקסט שברצונכם לצטט, ואז לחצו על כדי לפתוח את העורך. עשו זאת כמה פעמים כדי להוסיף ציטוטים נוספים: - - - - את/ה תמיד יכולים להמשיך לקרוא בזמן שאתם מחברים תגובה, ואנחנו נשמור עבורכם את הטיוטה ככל שתתקדמו בכתיבתה. - - כדי לעדכן מישהו או מישהי בתגובה שכתבתם, הזכירו את שמם. הקלידו @ כדי להתחיל בבחירת שם המשתמש/ת שלהם: - - - - כדי להשתמש ב[אימו'גים סטנדרטיים](http://www.emoji.codes/), פשוט הקלידו : כדי לבחור בהם לפי שם, או השתמשו בצירופי הסמיילים המקובלים :wink:. - - - - כדי ליצור סיכום של קישור מהאינטרנט, הדיברו אותו בשורה נפרדת משל עצמו: - - - - התגובה שלכם יכולה להיבנות באמצעות קוד HTML פשוט, BBCode או [Markdown](http://commonmark.org/help/): - - This is **bold**. - This is bold. - This is [b]bold[/b]. - - כדי לקבל עוד טיפים לעיצוב טקסט, נסו את ההדרכה האינטרקטיבית הכיפית שלנו. זה לוקח רק 10 דקות!(http://commonmark.org/help/tutorial/) - - פעולות - - יש לחצני פעולות מתחת לכל פרסום: - - - - - - כדי לספר למישהו/מישהי שנהניתם והערכתם את הפרסום שלהם, השתמש בלחצן like/אהבתי. שתפו את שאהבתם! - - - העתיקו והדביקו קישור לכל תגובה או נושאים שאהבתים בעזרת לחצן ה**link/קישור**. - - - השתמשו ב כדי להציג עוד לחצנים ועוד פעולות. Flag/סמנו כדי לדווח למי שכתבו את הפרסום, או [לצוות שלנו](%{base_url}/about), על בעיה. הוסיפו Bookmark/סימניה כדי לאתר לאתר את הפרסום הזה בהמשך בעמוד דרך עמוד הפרופיל שלכם. - - ## התראות - - כאשר מישהו או מישהי מגיבים אליכם, מצטטים את הפרסום שלכם, מזכירים את @שם_המשתמש/ת שלכם או אפילו מקשרים אל הפרסום שלכם, מיד יופיע מספר בפינה השמאלית העליונה של המסך. לחצו עליו על מנת להציג את ההתראות שלכם. - - - - אל תחששו להחמיץ תגובות - תקבלו דוא"ל על כל התראה שמגיעה כשאתם לא מחוברים. - - ## העדפות - - - כל הנושאים שפורסמו לפני פחות מיומיים נחשבים חדשים. - - כל נושא בו השתתפתם באופן פעיל (אם יצרתם אותו, הגבתם אליו או קראתם אותו במשך זמן כלשהו) יהיה באופן אוטומטי תחת מעקב שלכם. - - תוכלו לראות את האינדיקציות למספרי ההודעות החדשות ואלו שלא קראתם לצד הנושאים: - - - - תוכלו לשנות את סוג ההתראות לכל נושא בעזרת סרגל ההתראות שמתחת ומצד שמאל לכל נושא. - - - - תוכלו גם לכוון התראות לפי קטגוריה, אם תרצו לצפות או להשתיק כל נושא בקטגוריה מסויימת. - - כדי לשנות את ההעדפות הללו, ראו את [עמוד העדפות המשתמש/ת](%{base_url}/my/preferences) שלך. - - ## אמון הקהילה - - זה נהדר לפגוש אתכם כאן! ככל שתפעלו כאן, וככל שיעבור הזמן, נלמד להכיר וחלק ממגבלות המשתמש/ת החדשים יוסרו. המשיכו להשתתף, ועם הזמן תזכו בעוד [רמות אמון](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924) שמאפשרות יכולות מיוחדות שיאפשרו לכם לסייע בניהול המשותף של הקהילה. + ככל שתשתתפו כאן, נכיר אתכם, ומגבלות זמניות על משתמשים חדשים יוסרו. במהלך הזמן תצבעו [דרגות אמון](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924) שכוללות יכולות לסייע לנו לנהל את הקהילה שלנו ביחד. welcome_user: + title: "ברוכים הבאים למשתמש/ת" subject_template: "ברוכים הבאים ל %{site_name}!" text_body_template: | תודה שהצטרפתם ל %{site_name}! @@ -1689,17 +1660,14 @@ he: (אם ברצונכם לתקשר עם [מנהל האתר](%{base_url}/about) כמשתמשים חדשים, השיבו להודעה הזו.) welcome_invite: + title: "הזמנת ברוכים הבאים" subject_template: "ברוכים הבאים ל %{site_name}!" text_body_template: | - תודה שקיבלתם את ההזמנה שלכם ל %{site_name} - ברוכים הבאים! + תודה שקיבלתם את ההזמנה שלכם ל %{site_name} -- ברוכים הבאים! - יצרנו חשבון חדש **%{username}** בשבילכם, ואתם מחוברים. תוכלו תמיד לשנות את שמכם באמצעות ביקור [בפרופיל שלכם][prefs]. + - יצרנו חשבון חדש **%{username}** בשבילכם. שנו את שימכם או את הסיסמה על ידי ביקור ב[פרופיל שלכם][prefs]. - על מנת להתחבר שוב: - - 1. השתמשו תמיד **באותו חשבון מייל מההזמנה המקורית** בעת ההתחברות. אחרת לא נוכל לדעת שאלו אתם! - - 2. צרו סיסמה ייחודית עבור [הפרופיל שלכם] [prefs] והשתמשו בה בשביל להתחבר. + - כאשר אתם מתחברים, אנא **השתמשו באותו חשבון מייל מההזמנה המקורית** — אחרת לא נוכל לדעת שאלו אתם! %{new_user_tips} @@ -1711,6 +1679,7 @@ he: [prefs]: %{user_preferences_url} backup_succeeded: + title: "גיבוי הצליח" subject_template: "הגיבוי הושלם בהצלחה." text_body_template: | הגיבוי הצליח. @@ -1723,6 +1692,7 @@ he: %{logs} ``` backup_failed: + title: "גיבוי נכשל" subject_template: "הגיבוי נכשל." text_body_template: | הגיבוי נכשל. @@ -1733,6 +1703,7 @@ he: %{logs} ``` restore_succeeded: + title: "שחזור הצליח" subject_template: "השחזור הסתיים בהצלחה." text_body_template: | השחזור הצליח. @@ -1743,6 +1714,7 @@ he: %{logs} ``` restore_failed: + title: "שחזור נכשל" subject_template: "השחזור נכשל" text_body_template: | השחזור נכשל. @@ -1753,9 +1725,11 @@ he: %{logs} ``` bulk_invite_succeeded: + title: "הזמנה קבוצתית הצליחה" subject_template: "ההזמנה הקבוצתית עובדה בהצלחה" text_body_template: "ההזמנה המרוכזת שלכם עובדה, %{sent} הזמנות נשלחו." bulk_invite_failed: + title: "הזמנה קבוצתית נכשלה" subject_template: "ההזמנה המרוכזת עובדה עם שגיאות" text_body_template: | ההזמנה הקבוצתית שלך עובדה, %{sent} הזמנות נשלחו עם %{failed} תקלה/ות. @@ -1768,6 +1742,7 @@ he: %{logs} ``` csv_export_succeeded: + title: "יצוא CSV הצליח" subject_template: "יצוא הנתונים הושלם" text_body_template: | הנתונים שלך יוצאו בהצלחה! :dvd: @@ -1776,51 +1751,60 @@ he: לינק ההורדה יהיה זמין במשך 48 שעות. csv_export_failed: + title: "יצוא CSV נכשל" subject_template: "ייצוא הנתונים נכשל" text_body_template: "צר לנו, אך ייצוא הנתונים שלכם נכשל. אנא בדקו את רישומי המערכת או צרו קשר עם איש/אשת צוות." email_reject_insufficient_trust_level: + title: "מייל נדחה, רמת אמון לא מספיקה" subject_template: "[%{site_name}] בעיית מייל -- רמת אמון לא מספיקה" text_body_template: | אנחנו מצטערים, אך הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. לחשבון שלכם אין את רמת האמון הנדרשת כדי לפרסם נושאים חדשים לכתובת מייל זו. אם אתם חושבים שזו טעות, אנא פנו לחבר צוות. email_reject_user_not_found: + title: "מייל נדחה, משתמש לא נמצא" subject_template: "[%{site_name}] בעיית מייל -- משתמש לא נמצא" text_body_template: | אנחנו מצטערים, אבל הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. התגובה שלכם נשלחה מכתובת מייל לא ידועה. נסו לשלוח מכתובת מייל אחרת, או ליצור קשר עם חבר צוות. email_reject_screened_email: + title: "מייל נדחה, מייל מסונן" subject_template: "[%{site_name}] בעיית מייל -- מייל חסום" text_body_template: | אנחנו מצטערים, אך הודעת המייל ל %{destination} (עם הכותרת %{former_title}) לא עבדה. התשובה שלכם נשלחה מכתובת מייל חסומה. נסו לשלוח מכתובת מייל אחרת, או צרו קשר עם חבר צוות. email_reject_inactive_user: + title: "מייל נדחה, משתמש לא פעיל" subject_template: "[%{site_name}] בעיית מייל -- משתמש לא-פעיל" text_body_template: | אנחנו מצטערים, אך הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. החשבון שלכם שמקושר לכתובת המייל הזו לא הופעל. אנא הפעילו את החשבון שלכם לפני שאתם שולחים מיילים למערכת. email_reject_blocked_user: + title: "מייל נדחה, משתמש חסום" subject_template: "[%{site_name}] בעיית מייל -- משתמש חסום" text_body_template: | אנחנו מצטערים, אך הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. חשבונכם שקשור לכתובת מייל זו נחסם. email_reject_reply_user_not_matching: + title: "דחיית מייל משתמש/ת לא מתאימים" subject_template: "[%{site_name}] בעיית מייל -- נמען לא תואם" text_body_template: | אנחנו מצטערים, אך הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. התשובה שלכם נשלחה מכתובת מייל שונה מזו שציפינו לה, אז אנחנו לא בטוחים אם זה אותו אדם. נסו לשלוח מכתובת מייל אחרת, או ליצור קשר עם חבר צוות. email_reject_no_account: + title: "מייל נדחה, אין חשבון" subject_template: "[%{site_name}] בעיית מייל -- חשבון לא מזוהה" text_body_template: | אנחנו מצטערים, אך הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. אנחנו לא מוצאים חשבונות שמתאימים לכתובת המייל שלכם. נסו לשלוח מכתובת מייל אחרת, או צרו קשר עם חבר צוות. email_reject_empty: + title: "מייל נדחה, ריק" subject_template: "[%{site_name}] בעיית מייל -- ללא תוכן" text_body_template: | אנחנו מצטערים, אך הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. @@ -1829,30 +1813,35 @@ he: אם אתם מקבלים את ההודעה הזו ו_כן_ כללתם תגובה, נסו שוב עם סיגנון פשוט יותר. email_reject_parsing: + title: "מייל נדחה, פענוח" subject_template: "[%{site_name}] בעיית מייל -- תוכן לא זוהה." text_body_template: | אנחנו מצטערים, אך הודעת המייל שלכם ל- %{destination} (עם הכותרת %{former_title}) לא עבדה. לא מצאנו תוכן במייל שלכם. **אנא ודאו שהתגובה שלכם בראש המייל** -- אנחנו לא יכולים לעבד תגובות בין השורות. email_reject_invalid_access: + title: "דחיית מייל גישה לא-מורשית" subject_template: "[%{site_name}] בעיית מייל -- גישה לא תקינה" text_body_template: | אנחנו מצטערים, אבל הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. לחשבון שלכם אין מספיק הרשאות כדי לפרסם נושאים חדשים בקטגוריה זו. אם אתם מאמינים שזו טעות, צרו קשר עם חבר צוות. email_reject_strangers_not_allowed: + title: "דחיית מייל זרים לא מורשים" subject_template: "[%{site_name}] בעיית מייל -- גישה לא נכונה" text_body_template: | אנחנו מצטערים, אבל הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. הקטגוריה ששלחתם אליה את המייל הזה מאפשרת רק תגובות ממשתמשים עם חשבונות תקינים וכתובות מייל ידועות. אם אתם מאמינים שזו טעות, אנא פנו לחבר צוות. email_reject_invalid_post: + title: "דחיית מייל פוסט לא-תקין" subject_template: "[%{site_name}] בעיית מייל -- תקלה בפרסום" text_body_template: | אנחנו מצטערים, אך הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. גורמים אפשריים: עיצוב מורכב, הודעה ארוכה מידי, הודעה קצרה מידי. אנא נסו שוב, או פרסמו דרך האתר אם התקלה חוזרת. email_reject_invalid_post_specified: + title: "דחיית מייל הוגדר פוסט לא-תקני" subject_template: "[%{site_name}] בעיית מייל -- תקלה בפרסום" text_body_template: | אנחנו מצטערים, אך הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. @@ -1863,42 +1852,49 @@ he: אם תוכלו לתקן את הבעיה, אנא נסו שוב. email_reject_invalid_post_action: + title: "דחיית מייל פעולת פוסט לא-תקנית" subject_template: "[%{site_name}] בעיית מייל -- פעולה לא-תקנית" text_body_template: | אנחנו מצטערים, אך הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. הפעולה לא זוהתה. אנא נסו שוב, או פרסמו דרך האתר אם התקלה נמשכת. email_reject_reply_key: + title: "דחיית מייל מפתח תגובה" subject_template: "[%{site_name}] בעיית מייל -- תו תגובה לא מוכר" text_body_template: | אנחנו מצטערים, אך הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. מפתח התגובה במייל לא תקין או לא ידוע, אז לא יכולנו להבין למה המייל הזה מגיב. אנא פנו לחבר צוות. email_reject_bad_destination_address: + title: "דחיית מייל כתובת יעד לא-נכונה" subject_template: "[%{site_name}] בעיית מייל -- כתובת To: לא ידועה" text_body_template: | אנחנו מצטערים, אבל הודעת המייל שלכם ל %{destination} (עם הכותרת %{former_title}) לא עבדה. אף אחד מייעדי המייל לא זוהה. אנא וודאו שאתם שולחים לכתובת המייל הנכונה שניתנה על-ידי הצוות. email_reject_topic_not_found: + title: "דחיית מייל נושא לא נמצא" subject_template: "[%{site_name}] בעיית מייל -- לא נמצא נושא" text_body_template: | אנחנו מצטערים, אך הודעת המייל ל %{destination} (עם הכותרת %{former_title}) לא עבדה. הנושא שאתם מנסים להגיב אליו כבר לא קיים -- אולי הוא נמחק? אם אתם מאמינים שזו טעות, אנא פנו לחבר צוות. email_reject_topic_closed: + title: "דחיית מייל נושא סגור" subject_template: "[%{site_name}] בעיית מייל -- נושא נסגר" text_body_template: | אנחנו מצטערים, אך הודעת המייל ל %{destination} (עם הכותרת %{former_title}) לא עבדה. הנושא שאתם מגיבים אליו סגור כרגע ולא מקבל יותר תגובות. אם אתם מאמינים שזו טעות, אנא פנו לחבר צוות. email_reject_auto_generated: + title: "דחיית מייל נוצר אוטומטית" subject_template: "[%{site_name}] בעיית מייל -- תגובה נוצרה אוטומטית" text_body_template: | אנחנו מצטערים, אבל משהו לא עבד עם הודעת הדוא"ל שלך, שנשלחה אל %{destination} (titled %{former_title}). המייל ששלחת סומן כ"נכתב אוטומטית", מה שאומר שהוא נכתב על ידי מחשב ולא הוקלד על ידי אדם; איננו יכולים לקבל מיילים שכאלה. אם אתם מאמינים שזוהי תקלה, אנא צרו קשר עם איש/אשת צוות. email_error_notification: + title: "התראת בעיית מייל" subject_template: "[%{site_name}] בעיית מייל -- בעיית אימות POP" text_body_template: | למרבה הצער, ארעה תקלה בזמן תשאול מיילים משרת ה POP. @@ -1907,6 +1903,7 @@ he: אם יש ממשק ווב לחשבון ה POP, ייתכן ותצטרכו להתחבר לאתר וקבוע את ההגדרות שלכם שם. too_many_spam_flags: + title: "יותר מידי דיגלי ספאם" subject_template: "חשבון חדש בהשהיה" text_body_template: | שלום, @@ -1917,6 +1914,7 @@ he: להנחיות נוספות, אנא פנו ל[הנחיות הקהילה](%{base_url}/guidelines). too_many_tl3_flags: + title: "יותר מידי דגלי רמת-אמון 3" subject_template: "חשבון חדש בהשהיה" text_body_template: | שלום, @@ -1927,6 +1925,7 @@ he: לפרטים נוספים, אנא פנו ל[הנחיות הקהילה](%{base_url}/guidelines). blocked_by_staff: + title: "נחסם על ידי הצוות" subject_template: "חשבון זמנית בהשהיה" text_body_template: | שלום, @@ -1937,6 +1936,7 @@ he: להנחיות נוספות, אנא פנו ל[הנחיות הקהילה](%{base_url}/guidelines). user_automatically_blocked: + title: "משתמש נחסם אוטומטית" subject_template: "המשתמש החדש %{username} נחסם על ידי דגלים של הקהילה" text_body_template: | זוהי הודעה אוטומטית. @@ -1947,6 +1947,7 @@ he: סף זה ניתן לשינוי באמצעות הגדרת האתר `block_new_user`. spam_post_blocked: + title: "פוסט ספאם נחסם" subject_template: "פוסים של המשתמש/ת החדש/ה %{username} נחסמו בשל קישורים חוזרים." text_body_template: | זוהי הודעה אוטומטית. @@ -1957,6 +1958,7 @@ he: ניתן לכוון זאת בהגדרות האתר `newuser_spam_host_threshold` ו`white_listed_spam_host_domains`. unblocked: + title: "לא-חסום" subject_template: "החשבון כבר לא מושהה" text_body_template: | שלום, @@ -1965,6 +1967,7 @@ he: אתם יכולים עכשיו ליצור נושאים חדשים, ושוב להגיב לנושאים קיימים. תודה על הסבלנות. pending_users_reminder: + title: "תזכורת משתמשים ממתינים" subject_template: one: "משתמש 1 ממתין לאישורכם" other: "%{count} משתמשים ממתינים לאישורכם" @@ -1973,9 +1976,11 @@ he: [אנא סיקרו אותם באזור הניהול](%{base_url}/admin/users/list/pending). download_remote_images_disabled: + title: "הורדת תמונות מרוחקות מנוטרלת" subject_template: "הורדת תמונות מרחוק מנוטרלת" text_body_template: "האפשרות \"הורדת תמונות מרוחקות\" נוטרלה בגלל שכל שטח האכסון שמוקצה ל\"תמונות שהורדו מרחוק\" נוצל." dashboard_problems: + title: "בעיות בלוח המכוונים" subject_template: "נמצאו בעיות" text_body_template: | כמה בעיות מדווחות ללוח המכוונים של האדמיניסטרטור. @@ -2027,6 +2032,7 @@ he: > %{site_title} -- %{site_description} user_invited_to_private_message_pm: + title: "משתמש/ת הוזמן/ה להודעה פרטית" subject_template: "[%{site_name}] %{username} הזמין אותך להודעה '%{topic_title}'" text_body_template: | %{header_instructions} @@ -2035,6 +2041,7 @@ he: %{respond_instructions} user_invited_to_private_message_pm_staged: + title: "משתמש/ת הוזמן/ה להודעה פרטית מדורגת" subject_template: "הוזמנת לדיון '%{topic_title}' על ידי [%{site_name}] %{username}" text_body_template: | %{header_instructions} @@ -2043,6 +2050,7 @@ he: %{respond_instructions} user_invited_to_topic: + title: "משתמש/ת הוזמן/ה לנושא" subject_template: "הוזמנת לדיון שכותרתו '%{topic_title}' על ידי [%{site_name}] %{username}" text_body_template: | %{header_instructions} @@ -2051,6 +2059,7 @@ he: %{respond_instructions} user_replied: + title: "משתמש/ת הגיב" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2061,6 +2070,7 @@ he: %{respond_instructions} user_replied_pm: + title: "משתמש/ת הגיב/ה בהודעה פרטית" subject_template: "[%{site_name}] [PM] %{topic_title}" text_body_template: | %{header_instructions} @@ -2071,6 +2081,7 @@ he: %{respond_instructions} user_quoted: + title: "משתמש/ת צוטט/ה" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2081,6 +2092,7 @@ he: %{respond_instructions} user_linked: + title: "משתמש/ת קושר/ה" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2091,6 +2103,7 @@ he: %{respond_instructions} user_mentioned: + title: "משתמש/ת הוזכר/ה" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2101,6 +2114,7 @@ he: %{respond_instructions} user_group_mentioned: + title: "קבוצת משתמש הוזכרה" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2111,6 +2125,7 @@ he: %{respond_instructions} user_posted: + title: "משתמש/ה פרסם/ה" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2121,6 +2136,7 @@ he: %{respond_instructions} user_watching_first_post: + title: "משתמש/ת צופה בפוסט ראשון" subject_template: "[%{site_name}] %{topic_title}" text_body_template: | %{header_instructions} @@ -2131,6 +2147,7 @@ he: %{respond_instructions} user_posted_pm: + title: "משתמש/ת פרסם/ה הודעה פרטית" subject_template: "[%{site_name}] [PM] %{topic_title}" text_body_template: | %{header_instructions} @@ -2141,6 +2158,7 @@ he: %{respond_instructions} user_posted_pm_staged: + title: "משתמש/ת פרסם/ה הודעה פרטית מדורגת" subject_template: "%{optional_re}%{topic_title}" text_body_template: |2 @@ -2151,6 +2169,7 @@ he: new_topics: "נושאים חדשים" unread_messages: "הודעות שלא נקראו" unread_notifications: "התראות שלא נקראו" + liked_received: "לייקים שהתקבלו" new_posts: "פוסטים חדשים" new_users: "משתמשים חדשים" popular_topics: "נושאים פופולאריים" @@ -2158,7 +2177,7 @@ he: join_the_discussion: "קראו עוד" popular_posts: "פוסטים פופולאריים" from_topic_label: "מאת" - more_new: "חדש בנושאים וקרטגוריות שאתם עוקבים אחריהם" + more_new: "חדש בשבילכם" subject_template: "[%{site_name}] סיכום" unsubscribe: "סיכום זה נשלח מ %{site_link} כאשר אנחנו לא רואים אתכם לאורך זמן. כדי לבטל את המנוי %{unsubscribe_link}." click_here: "לחצו כאן" @@ -2174,6 +2193,7 @@ he: view_this_topic: "צפו בנושא זה" back_to_top: "חזרה למעלה" forgot_password: + title: "שכח/ה סיסמה" subject_template: "[%{site_name}] איפוס סיסמה" text_body_template: | מישהו ביקש לאפס את הסיסמה שלכם ב [%{site_name}](%{base_url}). @@ -2183,6 +2203,7 @@ he: לחצו על הקישור הבא כדי לבחור סיסמה חדשה: %{base_url}/users/password-reset/%{email_token} set_password: + title: "קביעת סיסמה" subject_template: "[%{site_name}] קביעת סיסמה" text_body_template: | מישהו ביקש להוסיף סיסמה לחשבון שלכם ב [%{site_name}](%{base_url}). לחילופין, תוכלו להתחבר באמצעות כל שירות נתמך (גוגל, פייסבוק, וכד׳) שמקושר לכתובת מייל תקינה. @@ -2192,6 +2213,7 @@ he: לחצו על הלינק הבא כדי לבחור סיסמה: %{base_url}/users/password-reset/%{email_token} admin_login: + title: "התחברות אדמיניסטרטור" subject_template: "[%{site_name}] התחברות" text_body_template: | מישהו ביקש להתחבר לחשבונכם ב [%{site_name}](%{base_url}). @@ -2199,6 +2221,7 @@ he: לחצו על הקישור הבא להתחבר: %{base_url}/users/admin-login/%{email_token} account_created: + title: "חשבון נוצר" subject_template: "[%{site_name}] החשבון החדש שלך" text_body_template: | חשבון חדש נוצר עבורך ב%{site_name} @@ -2206,12 +2229,14 @@ he: הקישו על הקישור המצורף כדי להגדיר סיסמה לחשבונכם החדש: %{base_url}/users/password-reset/%{email_token} confirm_new_email: + title: "אישור מייל חדש" subject_template: "[%{site_name}] אשרו את כתובת המייל החדשה שלכם" text_body_template: | אשרו את כתובת המייל החדשה שלכם עבור %{site_name} על ידי לחיצה על הקישור הבא: %{base_url}/users/authorize-email/%{email_token} confirm_old_email: + title: "אישור מייל ישן" subject_template: "[%{site_name}] אשרו את כתובת המייל הנוכחית שלכם" text_body_template: | לפני שתוכלו להחליף את כתובת המייל שלכם, אנחנו צריכים שתאשרו שאתם שולטים @@ -2222,6 +2247,7 @@ he: %{base_url}/users/authorize-email/%{email_token} notify_old_email: + title: "התראת מייל ישן" subject_template: "[%{site_name}] כתובת המייל שלכם שונתה" text_body_template: | זוהי הודעה אוטומטית כדי ליידע אתכם שכתובת המייל שלכם עבור %{site_name} שונתה. אם זה נעשה בטעות, אנא צרו קשר עם מנהל האתר. @@ -2230,6 +2256,7 @@ he: %{new_email} signup_after_approval: + title: "הרשמה אחרי אישור" subject_template: "אושרתם באתר %{site_name}!" text_body_template: | ברוכים הבאים ל%{site_name}! @@ -2249,6 +2276,7 @@ he: (אם אתם צריכים ליצור קשר עם [חברי צוות](%{base_url}/about) כחברים חדשים, רק השיבו להודעה זאת.) signup: + title: "הרשמה" subject_template: "[%{site_name}] אשרו את חשבונכם החדש" text_body_template: | ברוכים הבאים ל %{site_name}! @@ -2282,6 +2310,7 @@ he: too_large: "מצטערים, הקובץ שאתם מנסים להעלות גדול מידי (הגודל המקסימלי המותר הוא %{max_size_kb}KB)." images: too_large: "סליחה, אך התמונה שאתם מנסים להעלות גדולה מידי. (הגודל המקסימלי הוא %{max_size_kb}KB), אנא שנו את הגודל ונסו שנית." + larger_than_x_megapixels: "מצטערים, התמונה שאתם מנסים להעלות היא גדולמה מידי (הגודל המירבי הוא %{max_image_megapixels}-מגה-פיקסלים), אנא שנו את גודלה ונסו שוב." size_not_found: "מצטערים, אבל לא יכולנו לקבוע את גודל התמונה. אולי יש בעיה טכנית בתמונה?" avatar: missing: "מצטערים, אנחנו לא יכולים למצוא אף דמות שמקושרת לכתובת מייל זו. תוכלו להעלות זאת שוב?" @@ -2920,7 +2949,7 @@ he: fields: welcome: label: "נושא ברוכים-הבאים" - description: "

    כיצד הייתם מתארים את הקהילה שלכם לאדם זר במעלית אם יש לכם רק דקה אחת?

    • עבור מי נועדו דיונים אלו?
    • מה אוכל למצוא פה?
    • למה כדאי לי לבקר?

    נושא הברוכים-הבאים שלכם הוא הדבר הראשון שמבקרים חדשים יראו. חישבו עליו כפסקה אחת של ׳נאום המעלית׳ או ׳הצהרת הכוונות׳ שלכם.

    " + description: "

    כיצד הייתם מתארים את הקהילה שלכם לאדם זר במעלית אם יש לכם רק דקה 1?

    • עבור מי נועדו דיונים אלו?
    • מה אוכל למצוא פה?
    • למה כדאי לי לבקר?

    נושא הברוכים-הבאים שלכם הוא הדבר הראשון שמבקרים חדשים יקראו. חישבו עליו כפסקה אחת של ׳נאום המעלית׳ או ׳הצהרת הכוונות׳ שלכם.

    " one_paragraph: "אנא הגבילו את הודעת הברוכים-הבאים שלכם לפסקה אחת." privacy: title: "גישה" @@ -2965,7 +2994,7 @@ he: title: "תמה" fields: theme_id: - description: "האם אתם מעדיפים להתחיל עם סכמת צבעים בהירה או כהה? תמיד תוכלו להמשיך ולהתאים את המראה של האתר שלכם באמצעות ״ניהול״ > ״התאמה-אישית״." + description: "האם אתם מעדיפים להתחיל עם סכמת צבעים בהירה או כהה? תוכלו בהמשך להתאים אישית את הנראות של האתר שלכם תחת ניהול, התאמה-אישית." choices: default: label: "בהיר פשוט" @@ -2990,7 +3019,7 @@ he: label: "אייקון גדול" description: "תמונה שמשמשת לייצוג האתר שלכם במכשירים מודרניים ונראית טוב בגדלים גדולים יותר. הגודל המומלץ הוא לפחות 144 על 144 פיקסלים." homepage: - description: "אנחנו ממליצים להציג את הנושאים האחרונים בדף הבית שלכם, אבל אתם יכולים לבחור להראות קטגוריות (קבוצות של נושאים) על דף הבית אם אתם מעדיפים." + description: "אנחנו ממליצים להציג את הנושאים האחרונים בדף הבית שלכם, אבל אתם יכולים גם להציג קטגוריות (קבוצות נושאים) בדף הבית אם תעדיפו." title: "דף הבית" fields: homepage_style: @@ -3001,7 +3030,7 @@ he: label: "קטגוריות" emoji: title: "אמוג׳י" - description: "איזה סגנון אמוג׳י אתם מעדיפים עבור הקהילה שלכם? תמיד תוכלו להוסיף עוד אמוג׳י בהמשך באמצעות ״ניהול״ > ״התאמה״ > ״אמוג׳י״." + description: "איזה סגנון אמוג׳יז תעדיפו לקהילה שלכם? אתם יכולים להוסיף עוד אמוג׳יז מותאמים אישית תחת ניהול, התאמה אישית, אמוג׳י." invites: title: "הזמינו צוות" description: "כמעט סיימתם! בואו נזמין כמ חברי צוות כדי לסייע לזרוע את הדיונים עם נושאים מעניינים ותגובות שיניעו קדימה את הקהילה שלכם." diff --git a/config/locales/server.id.yml b/config/locales/server.id.yml index 90efb2a7cec..488efd69012 100644 --- a/config/locales/server.id.yml +++ b/config/locales/server.id.yml @@ -81,8 +81,6 @@ id: max_username_length_exists: "Anda tidak boleh menentukan jumlah karakter maksimum username dibawah username terpendek. " max_username_length_range: "Anda tidak bisa menentukan jumlah maksimum dibawah jumlah minimum." default_categories_already_selected: "Anda tidak boleh memilih kategori yang digunakan di daftar lainnya." - bulk_invite: - file_should_be_csv: "File yang diunggah harus dalam format csv atau txt." backup: operation_already_running: "Proses lain sedang berjalan. Tidak dapat menjalankan proses baru saat ini." backup_file_should_be_tar_gz: "File backup harus berupa arsip .tar.gz." diff --git a/config/locales/server.it.yml b/config/locales/server.it.yml index 2bb5bcf28d9..c394329c4fd 100644 --- a/config/locales/server.it.yml +++ b/config/locales/server.it.yml @@ -106,7 +106,7 @@ it: default_categories_already_selected: "Non puoi selezionare una categoria usata in un'altra lista." s3_upload_bucket_is_required: "Non è possibile attivare i caricamenti da S3 a meno che non imposti l'opzione 's3_upload_bucket'." bulk_invite: - file_should_be_csv: "Il file caricato deve essere in formato csv o txt." + file_should_be_csv: "Il file caricato deve essere in formato csv." backup: operation_already_running: "Una operazione è in esecuzione. Non è possibile avviarne una nuova adesso." backup_file_should_be_tar_gz: "Il file di backup deve essere un archivio .tar.gz" @@ -558,7 +558,7 @@ it: stop_watching_topic: "Smetti di osservare questo argomento, %{link}" mute_topic: "Silenziare tutte le notifiche per questo argomento, %{link}" unwatch_category: "Smetti di osservare tutti gli argomenti in %{category}" - mailing_list_mode: "Disabilita la modalità Mailing list" + mailing_list_mode: "Disabilita la modalità mailing list" disable_digest_emails: "Smetti di inviarmi email ripielogative" all: "Non inviare alcuna email da %{sitename}" different_user_description: "Sei attualmente connesso con un utente diverso da quello a cui abbiamo scritto. Per favore disconnettiti, oppure attiva la modalità anonima, e riprova." @@ -569,8 +569,8 @@ it: read: "lettura" read_write: "lettura/scrittura" scopes: - message_bus: "Aggiornamenti in Tempo Reale" - notifications: "Leggi e elimina tutte le notifiche" + message_bus: "Aggiornamenti in tempo reale" + notifications: "Leggi e elimina le notifiche" read: "Leggi tutto" write: "Scrivi tutto" reports: @@ -674,9 +674,9 @@ it: xaxis: "Giorno" yaxis: "Pagine viste da utenti connessi su mobile" page_view_anon_mobile_reqs: - title: "Visualizzazioni pagina da visitatori Anonimi" + title: "Visualizzazioni pagina da visitatori anonimi" xaxis: "Giorno" - yaxis: "Visualizzazioni pagina da visitatori Anonimi su dispositivi mobili" + yaxis: "Visualizzazioni pagina da visitatori anonimi su dispositivi mobili" http_background_reqs: title: "Background" xaxis: "Giorno" @@ -818,7 +818,6 @@ it: redirect_users_to_top_page: "Redirigi automaticamente i nuovi utenti e quelli assenti da tempo sulla pagina degli argomenti di punta." show_email_on_profile: "Mostra l'email di un utente nel suo profilo (visibile solo a se stesso e allo staff)" email_token_valid_hours: "I messaggi di password dimenticata / attivazione account sono validi per (n) ore." - email_token_grace_period_hours: "I messaggi di password dimenticata / attivazione account sono ancora validi per un periodo di grazia di (n) ore dopo essere stati convalidati." enable_badges: "Attiva il sistema a distintivi" allow_index_in_robots_txt: "Specifica nel file robots.txt che questo sito permette l'indicizzazione da parte dei motori di ricerca." email_domains_blacklist: "Una lista di domini email separati dal carattere pipe \"|\" con cui gli utenti non possono registrare un account. Ad esempio: mailinator.com/trashmail.net" @@ -1588,6 +1587,73 @@ it: title: "Etichette" staff_tag_remove_disallowed: "L'etichetta \"%{tag}\" può essere cancellata soltanto dallo staff." rss_by_tag: "Argomenti etichettati %{tag}" + wizard: + step: + introduction: + title: "Introduzione" + fields: + welcome: + label: "Argomento di Benvenuto" + privacy: + title: "Accesso" + fields: + privacy: + choices: + open: + label: "Pubblico" + restricted: + label: "Privato" + contact: + title: "Contatto" + fields: + contact_email: + label: "Email" + placeholder: "nome@esempio.com" + contact_url: + label: "Sito Web" + site_contact: + label: "Messaggi Automatici" + corporate: + title: "Società" + fields: + company_short_name: + label: "Nome Azienda (breve)" + company_full_name: + label: "Nome Azienda (completo)" + company_domain: + label: "Nome Dominio Azienda" + colors: + title: "Tema" + fields: + theme_id: + choices: + default: + label: "Semplice Chiaro" + dark: + label: "Semplice Scuro" + logos: + title: "Loghi" + fields: + logo_url: + label: "Logo Primario" + logo_small_url: + label: "Logo Piccolo" + icons: + title: "Icone" + fields: + favicon_url: + label: "Icona Piccola" + apple_touch_icon_url: + label: "Icona Grande" + homepage: + title: "Homepage" + fields: + homepage_style: + choices: + categories: + label: "Categorie" + emoji: + title: "Emoji" activemodel: errors: <<: *errors diff --git a/config/locales/server.ja.yml b/config/locales/server.ja.yml index 21b58c03224..cf4ba71ae60 100644 --- a/config/locales/server.ja.yml +++ b/config/locales/server.ja.yml @@ -77,8 +77,6 @@ ja: load_from_remote: "投稿の読み込みに失敗しました。" site_settings: min_username_length_range: "最小値を最大値より上にすることはできません。" - bulk_invite: - file_should_be_csv: "アップロードするファイルは、csv または txt 形式である必要があります。" backup: operation_already_running: "操作を実行しています。他の操作はできません。" backup_file_should_be_tar_gz: "バックアップファイルは .tar.gz形式である必要があります。" @@ -102,10 +100,10 @@ ja: in_reply_to: "▶ %{username}" replies: other: "%{count} 通の返信" - no_mentions_allowed: "あなたは他のユーザへメンションを送ることができません。" - no_images_allowed: "新規ユーザは投稿に画像を付ける事はできません。" + no_mentions_allowed: "あなたは他のユーザーへメンションを送ることができません。" + no_images_allowed: "新規ユーザーは投稿に画像を付ける事はできません。" spamming_host: "申し訳ありませんが、このホストへのリンクを貼ることはできません。" - user_is_suspended: "凍結中のユーザは投稿できません。" + user_is_suspended: "凍結中のユーザーは投稿できません。" topic_not_found: "問題が発生しました。トピックがクローズしたか、閲覧中に削除された可能性があります。" just_posted_that: "は最近の投稿と内容がほぼ一緒です" invalid_characters: "は不正な文字を含んでいます" @@ -174,11 +172,11 @@ ja: こまごまと何度も返信するより、まとまって返信をすることで、より見やすく、より話しやすくなります。 dominating_topic: | - ### 他のユーザも議論に参加させてあげましょう + ### 他のユーザーも議論に参加させてあげましょう - このトピックはあなたにとても重要なもののようですね – ここの回答のうち %{percent}% 以上があなたによってなされています。 + このトピックはあなたにとても重要なもののようですね – ここへ %{percent}% 以上の返信をあなたが行っています。 - 他のユーザが回答するために十分な時間的猶予を与えているか、ちょっと振り返ってみませんか? + 他のユーザーも返信するためにも、ある程度時間を開けているか確認してみましょう。 too_many_replies: | ### このトピックに回答出来る制限を超えました @@ -206,14 +204,14 @@ ja: attributes: base: warning_requires_pm: "プライベートメッセージでのみ警告を送ることができます" - too_many_users: "1度に1ユーザにしか警告を送る事はできません" - cant_send_pm: "申し訳ありません。このユーザにはプライベートメッセージを送る事ができません" - no_user_selected: "有効なユーザを選択してください" + too_many_users: "一度に1ユーザーにしか警告を送る事はできません" + cant_send_pm: "申し訳ありません。このユーザーにはプライベートメッセージを送る事ができません" + no_user_selected: "有効なユーザーを選択してください" user: attributes: password: common: "は10000最も一般的なパスワードのいずれかである。より安全なパスワードを使用してください。" - same_as_username: "はあなたのユーザ名と同じです。より安全なパスワードを使用してください" + same_as_username: "はあなたのユーザー名と同じです。より安全なパスワードを使用してください" same_as_email: "はあなたのメールアドレスと同じです。より安全なパスワードを使用してください" ip_address: signup_not_allowed: "このアカウントからのサインアップできません。" @@ -268,12 +266,14 @@ ja: topic_exists_no_oldest: "%{count}個のトピックを持っているため、このカテゴリを削除できません。" trust_levels: newuser: - title: "新しいユーザ" + title: "新しいユーザー" basic: - title: "ベーシックユーザ" - change_failed_explanation: "%{user_name} を '%{new_trust_level}' に格下げしようとしましたが、既にトラストレベルが '%{current_trust_level}' です。%{user_name} は '%{current_trust_level}' のままになります - もしユーザーを降格させたい場合は、トラストレベルをロックしてください" + title: "ベーシックユーザー" + change_failed_explanation: "%{user_name} を '%{new_trust_level}' に下げようとしましたが、既にトラストレベルが '%{current_trust_level}' です。%{user_name} は '%{current_trust_level}' のままになります - もしユーザーを降格させたい場合は、トラストレベルをロックしてください" rate_limiter: too_many_requests: "このアクションを一日の間に実施可能な回数が決まっています。%{time_left}待ってから再度試してください。" + by_type: + public_group_membership: "グループへの参加/離脱が多すぎます。%{time_left}お待ち下さい。" hours: other: "%{count} 時間" minutes: @@ -367,7 +367,7 @@ ja: long_form: '不適切として通報する' notify_user: title: '@{{username}}へメッセージを送る' - long_form: 'メッセージが送られたユーザ' + long_form: 'メッセージが送られたユーザー' email_title: '「%{title}」にの投稿' email_body: "%{link}\n\n%{message}" notify_moderators: @@ -402,28 +402,33 @@ ja: email_title: 'トピック"%{title}" は不適切な可能性があるため、管理人による確認を必要とする。' email_body: "%{link}\n\n%{message}" flagging: - you_must_edit: '

    投稿が他のユーザから通報されました。投稿したメッセージを確認してください。

    ' - user_must_edit: '

    この投稿は他のユーザから通報されたため、非表示にされています。

    ' + you_must_edit: '

    投稿が他のユーザーから通報されました。投稿したメッセージを確認してください。

    ' + user_must_edit: '

    この投稿は他のユーザーから通報されたため、非表示にされています。

    ' archetypes: regular: title: "通常のトピック" banner: title: "バナートピック" message: - make: "このトピックはバナートピックに設定されています。ユーザが解除しない限り、ページ毎の一番上に表示されます" + make: "このトピックはバナートピックに設定されています。ユーザーが解除しない限り、ページ毎の一番上に表示されます" remove: "このトピックはバナーではなくなりました。トップページには表示されなくなります" + unsubscribe: + unwatch_category: "%{category}内の全トピックのウォッチを解除" + user_api_key: + title: "アプリケーションアクセスの認証" + description: "\"%{application_name}\" があなたのアカウントへのアクセスを要求しています: " reports: visits: - title: "訪問ユーザ" + title: "訪問ユーザー" xaxis: "日" yaxis: "訪問者数" signups: - title: "新規ユーザ" + title: "新規ユーザー" xaxis: "日" - yaxis: "新規ユーザ数" + yaxis: "新規ユーザー数" profile_views: xaxis: "日" - yaxis: "ユーザプロフィールの閲覧数" + yaxis: "ユーザープロフィールの閲覧数" topics: title: "トピック" xaxis: "日" @@ -451,13 +456,13 @@ ja: users_by_trust_level: title: "ユーザーごとのトラストレベル" xaxis: "トラストレベル" - yaxis: "ユーザ数" + yaxis: "ユーザー数" emails: title: "送信メール" xaxis: "日" yaxis: "メールの数" user_to_user_private_messages: - title: "ユーザ to ユーザ" + title: "ユーザーからユーザーへ" xaxis: "日" yaxis: "メッセージ数" system_private_messages: @@ -473,12 +478,12 @@ ja: xaxis: "日" yaxis: "メッセージ数" notify_user_private_messages: - title: "ユーザ通知" + title: "ユーザーの通知" xaxis: "日" yaxis: "メッセージ数" top_referrers: title: "トップリファラ" - xaxis: "ユーザ" + xaxis: "ユーザー" num_clicks: "クリック" num_topics: "トピック" top_traffic_sources: @@ -486,19 +491,19 @@ ja: xaxis: "ドメイン" num_clicks: "クリック" num_topics: "トピック" - num_users: "ユーザ" + num_users: "ユーザー" top_referred_topics: title: "トップ被参照トピック" xaxis: "トピック" num_clicks: "クリック" page_view_anon_reqs: - title: "匿名ユーザ" + title: "匿名ユーザー" xaxis: "日" - yaxis: "匿名ユーザからの閲覧数" + yaxis: "匿名ユーザーからの閲覧数" page_view_logged_in_reqs: title: "ログイン" xaxis: "日" - yaxis: "ログインユーザからの閲覧数" + yaxis: "ログインユーザーからの閲覧数" page_view_crawler_reqs: title: "クローラー" xaxis: "日" @@ -508,13 +513,13 @@ ja: xaxis: "日" yaxis: "合計閲覧数" page_view_logged_in_mobile_reqs: - title: "ログインユーザからの閲覧数" + title: "ログインユーザーからの閲覧数" xaxis: "日" - yaxis: "モバイルでログインしているユーザからの閲覧数" + yaxis: "モバイルでログインしているユーザーからの閲覧数" page_view_anon_mobile_reqs: - title: "匿名ユーザからの閲覧数" + title: "匿名ユーザーからの閲覧数" xaxis: "日" - yaxis: "モバイルで閲覧している匿名ユーザの閲覧数" + yaxis: "モバイルで閲覧している匿名ユーザーの閲覧数" http_background_reqs: title: "背景" xaxis: "日" @@ -548,7 +553,7 @@ ja: xaxis: "日" yaxis: "合計" mobile_visits: - title: "訪問ユーザ" + title: "訪問ユーザー" xaxis: "日" yaxis: "訪問者数" dashboard: @@ -569,7 +574,7 @@ ja: censored_words: "自動的に ■■■■ で置換されます" delete_old_hidden_posts: "30日以上非表示になっている投稿を自動で削除します" default_locale: "この Discourse インスタンスのデフォルト言語 (ISO 639-1 Code)" - allow_user_locale: "ユーザーが各自の言語設定を選択できるようにする" + allow_user_locale: "ユーザーが言語を選択できるようにする" min_post_length: "投稿を許可する最少の文字数" min_first_post_length: "最初の投稿(投稿本文)を許可する最少の文字数" min_private_message_post_length: "メッセージに投稿可能な最少の文字数" @@ -652,7 +657,6 @@ ja: redirect_users_to_top_page: "新規ユーザーと長く不在のユーザーをトップページに自動的にリダイレクトさせる" show_email_on_profile: "プロフィールのメールアドレスを表示(自分とスタッフのみ閲覧できます)" email_token_valid_hours: "パスワードリマインダ、アカウントアクティベート時のトークンを何時間有効にするか" - email_token_grace_period_hours: "パスワードリマインダ、アカウントアクティベート時のトークンを無効するときに、何時間猶予を与えるか" enable_badges: "バッジ機能を有効にする" allow_index_in_robots_txt: "サーチエンジンにインデックスを許可するようにrobots.txtを指定する" email_domains_blacklist: "ユーザーがアカウント登録をすることができない、パイプ区切りのドメイン名のリスト。 例 : mailinator.com|trashmail.net" @@ -860,7 +864,6 @@ ja: embed_whitelist_selector: "embedを許可するエレメントのCSS Selector" embed_blacklist_selector: "embedから削除するエレメントのCSS Selector" notify_about_flags_after: "この数時間後に処理されていない通報がある場合は、contact_emailにメールを送信する。0を設定すると無効になります" - enable_cdn_js_debugging: "全てのJSにcrossorigin権限を追加することで、/logsに適切なエラーを表示することを許可する" show_create_topics_notice: "サイトにpublicなトピックが5よりも少ない場合、トピックを作成するための通知が管理者に表示される" delete_drafts_older_than_n_days: (n) 日間経過したドラフトを削除 prevent_anons_from_downloading_files: "匿名ユーザーが添付ファイルをダウンロードするのを防止。警告: 画像ではなく、添付ファイルとして投稿された全てのファイルが対象です" @@ -1038,25 +1041,6 @@ ja: (もし[スタッフメンバー](%{base_url}/about) に新規ユーザーとして連絡する必要がある場合、このメッセージに返信してください) welcome_invite: subject_template: "%{site_name}へようこそ!" - text_body_template: | - %{site_name}へようこそ! - アカウント **%{username}** を作成し、ログインしています。 - - 名前の変更は [自分のユーザプロフィール][prefs] より行ってください。 - - 次回からログインする際は、 - - 1. 招待時に使用したメールアドレスを使用してください。 - - 2.[自分のユーザプロフィール][prefs]からパスワードを設定して、ログインのときは設定したパスワードを使用してください。 - - %{new_user_tips} [civilized community behavior](%{base_url}/guidelines)をお守りいただき、健全なコミュニティとなるよう皆様のご協力をお願いいたします。 - - それではお楽しみください! - - (もし、[スタッフ](%{base_url}/about) と連絡を取る必要がある場合はこのメッセージに返信してください) - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "バックアップは正常に完了しました" backup_failed: diff --git a/config/locales/server.ko.yml b/config/locales/server.ko.yml index 9a084a5ade4..c2600466249 100644 --- a/config/locales/server.ko.yml +++ b/config/locales/server.ko.yml @@ -75,8 +75,6 @@ ko: other: '%{model} 저장 시에 %{count}개의 에러가 발생하여 진행을 못했습니다.' embed: load_from_remote: "글 로딩 중 오류가 발생하였습니다." - bulk_invite: - file_should_be_csv: "CSV 또는 TXT형식의 파일을 업로드해야 합니다." backup: operation_already_running: "현재 %{operation} 작업중입니다. %{operation} 작업을 지금 시작할 수 없습니다." backup_file_should_be_tar_gz: "백업 파일은 .tar.gz형식의 파일이어야 합니다." @@ -655,7 +653,6 @@ ko: redirect_users_to_top_page: "신규 사용자와 오랜만에 방문한 사용자를 인기글 페이지로 리다이렉트." show_email_on_profile: "사용자 프로필에서 자신의 이메일 주소 보기(본인과 관리자만 볼 수 있음)" email_token_valid_hours: "비밀번호 찾기, 계정 활성화에 사용되는 토큰의 유효 기간(시간)" - email_token_grace_period_hours: "비밀번호 찾기, 계정 활성화에 사용되는 토큰은 사용되어진 이후 유효한 기간(시간)" enable_badges: "배지 기능 사용" allow_index_in_robots_txt: "이 사이트가 검색엔진에 의해 인덱스되는 것을 허용합니다.(robots.txt 수정)" email_domains_blacklist: "가입 금지된 이메일 도메인 목록, 파이프 기호로 구분. 예: mailinator.com|trashmail.net" @@ -854,7 +851,6 @@ ko: embed_whitelist_selector: "embed에서 보여져야 할 DOM element 선택하는 CSS 셀렉터" embed_blacklist_selector: "embed에서 지워져야 할 DOM element 선택하는 CSS 셀렉터" notify_about_flags_after: "이 시간동안 처리되지 않은 신고가 들어와 있으면, contact_email 주소로 이메일을 보냅니다. 0으로 넣으면 비활성화됩니다." - enable_cdn_js_debugging: "/logs에서 적절한 모든 js를 포함해 crossorigin 권한 오류가 뜨도록 합니다." show_create_topics_notice: "이 사이트에 5개 이하의 공개 글타래가 있으면, 관리자에게 글타래 좀 만들라고 알려줍니다." delete_drafts_older_than_n_days: (n) 일지난 임시 보관글 삭제하기 prevent_anons_from_downloading_files: "익명 사용자가 다운로드를 받지 못하게 합니다. 경고: 이미지 파일 외 모든 첨부파일이 다운로드 받지 못하게 됩니다." @@ -1016,26 +1012,6 @@ ko: (할 말이 있을 땐 새 사용자로서 [스태프](%{base_url}/about)들에게 이야기 주세요, 이 메세지에 답글로 주시면 바로 올라갑니다.) welcome_invite: subject_template: "%{site_name} 사이트에 오신것을 환영합니다!" - text_body_template: | - %{site_name}의 초대에 응해주셔서 감사합니다 반갑습니다! - - **%{username}**로 새 사용자를 만들었고 로그인된 상태입니다. [사용자 정보][prefs]에 들어가 이름을 바꿀 수 있습니다. - - 나중에 다시 로그인하려면: - - 1. 항상 **초대 받은 이메일 주소를 사용해서** 로그인해주셔야지 안 그러면 같은 사람이라고 인식 못할 겁니다! - - 2. [사용자 정보][prefs],에서 유니크한 비밀번호를 만들어 사용해주세요. - - %{new_user_tips} - - 우리는 [문화시민의 커뮤니티 활동 지침](%{base_url}/guidelines)을 항상 따릅니다. - - 커뮤니티를 즐려주세요! - - (할 말이 있을 땐 새 사용자로서 [스태프](%{base_url}/about)들에게 이야기주세요, 이 메세지에 답글로 주시면 바로 올라갑니다.) - - [사용자 정보 설정]: %{user_preferences_url} backup_succeeded: subject_template: "백업 성공" backup_failed: diff --git a/config/locales/server.nb_NO.yml b/config/locales/server.nb_NO.yml index 6be16a01b71..abca0984f5e 100644 --- a/config/locales/server.nb_NO.yml +++ b/config/locales/server.nb_NO.yml @@ -7,16 +7,21 @@ nb_NO: dates: - short_date_no_year: "D MMM" - short_date: "D MMM, YYYY" - long_date: "MMMM D, YYYY h:mma" + short_date_no_year: "D. MMM" + short_date: "D. MMM, YYYY" + long_date: "D. MMMM, YYYY h:mma" datetime_formats: &datetime_formats formats: short: "%d-%m-%Y" short_no_year: "%B %-d" + date_only: "%B %-d, %Y" long: "%B %-d, %Y, %l:%M%P" + date: + month_names: [null, januar, februar, mars, april, mai, juni, juli, august, september, oktober, november, desember] + <<: *datetime_formats time: am: "am" + pm: "pm" <<: *datetime_formats title: "Discourse" topics: "Emner" @@ -24,15 +29,30 @@ nb_NO: loading: "Laster" powered_by_html: 'Drevet av Discourse, best nyttet med JavaScript på' log_in: "Logg inn" + purge_reason: "Automatisk slettet som som forlatt, uaktivert konto" disable_remote_images_download_reason: "Nedlasting av bilder ble deaktivert grunnet mangel på tilgjengelig diskplass." anonymous: "Anonym" + remove_posts_deleted_by_author: "Slettet av forfatter" emails: incoming: - default_subject: "Innkommende epost fra %{email}" + default_subject: "Innkommende e-post fra %{email}" + show_trimmed_content: "Vis beskjært innhold" + errors: + no_message_id_error: "Skjer når en e-post ikke har noen «Message-Id»-header." + auto_generated_email_error: "Skjer når «Precedence»-headeren er satt til list, junk, bulk eller auto_reply eller når en annen header innholder auto-submitted, auto-replied eller auto-generated." + no_body_detected_error: "Skjer når vi ikke kunne trekke ut meldingskroppen eller det ikke var noen vedlegg." + inactive_user_error: "Skjer når senderen ikke er aktiv." + blocked_user_error: "Skjer når avsenderen har blitt blokkert." + bad_destination_address: "Skjer når ingen av adressene i To-, Cc- eller Bcc-feltene passer med en konfigurert innkommende e-postadresse." + strangers_not_allowed_error: "Skjer når en bruker forsøket å opprette et nytt emne i en kategori som han eller hun ikke er medlem av." + insufficient_trust_level_error: "Skjer når en bruker forsøket å opprette et nytt emne i en kategori som han eller hun ikke har tillitsnivå for." + reply_user_not_matching_error: "Skjer når et innkommende svar kommer fra en annen e-postadresse enn varselet var sendt til." + topic_not_found_error: "Skjer når et svar blir mottatt, men det tilhørene emnet er slettet." + topic_closed_error: "Skjer når et svar blir mottatt, men det tilhørene emnet er stengt." errors: &errors format: '%{attribute} %{message}' messages: - too_long_validation: "er begrenset til %{max} karakterer; du brukte %{length}." + too_long_validation: "er begrenset til %{max} tegn; du brukte %{length}." invalid_boolean: "Ugyldig boolsk verdi." taken: "er allerede tatt" accepted: må bli godkjent @@ -48,6 +68,7 @@ nb_NO: has_already_been_used: "har allerede blitt brukt" inclusion: er ikke inkludert i listen invalid: er ugyldig + is_invalid: "virker uklart, er det en komplett setning?" less_than: må være mindre enn %{count} less_than_or_equal_to: må være lik eller mindre enn %{count} not_a_number: er ikke et nummer @@ -76,17 +97,21 @@ nb_NO: load_from_remote: "Det oppstod et problem med innlastingen av innlegget." site_settings: min_username_length_range: "Du kan ikke sette minimum høyere enn maksimum." + max_username_length_range: "Du kan ikke sette maksimum under minimum." default_categories_already_selected: "Du kan ikke velge en annen kategori brukt i en annen liste." bulk_invite: - file_should_be_csv: "Den opplastede filen må være i .csv eller .txt format." + file_should_be_csv: "Filen som lastes opp burde være i csv format." + error: "Det skjedde en feil når filen ble lastet opp. Prøv igjen senere. " backup: operation_already_running: "En prosess kjører allerede. Kan ikke starte en ny jobb akkurat nå." backup_file_should_be_tar_gz: "Backup-filen må være en .tar.gz arkiveringsfil." not_enough_space_on_disk: "Det er ikke nok plass på disk til å laste opp denne backupen." + invalid_filename: "Det sikkerhetskopierte filnavnet inneholder ugyldige tegn. Gyldige tegn er a-z 0-9 . - _." not_logged_in: "Du må være logget inn for å gjøre dette." not_found: "Den etterspurte URL eller ressurs ble ikke funnet" invalid_access: "Du har ingen tilgang til denne resurssen." read_only_mode_enabled: "Siden er i skrivebeskyttet modus. Alle interaksjoner er utilgjengelige." + reading_time: "Lese tid" likes: "Likes" too_many_replies: one: "Vi beklager, men nye brukere er midlertidig begrenset til 1 svar i det samme emnet." @@ -94,6 +119,11 @@ nb_NO: embed: start_discussion: "Start Diskusjon" continue: "Fortsett Diskusjon" + error: "Feil ved innbygging" + referer: "Referer:" + mismatch: "Referer passet ikke med noen av de følgende vertsnavnene:" + no_hosts: "Vertsnavn for innbygging." + configure: "Sett opp innbygging" more_replies: one: "1 svar til" other: "%{count} svar til" @@ -104,6 +134,11 @@ nb_NO: replies: one: "1 svar" other: "%{count} svar" + no_mentions_allowed: "Beklager, du kan ikke nevne andre brukere." + too_many_mentions: + one: "Beklager, du kan bare nevne en bruker i et innlegg. " + other: "Beklager, du kan bare nevne %{count} brukere i et innlegg. " + no_mentions_allowed_newuser: "Beklager, nye brukere kan ikke nevne andre brukere." no_images_allowed: "Beklager, nye brukere kan ikke legge til bilder i et innlegg." too_many_images: one: "Beklager, nye brukere kan bare legge til ett bilde i et innlegg." @@ -112,10 +147,11 @@ nb_NO: too_many_attachments: one: "Beklager, nye brukere kan bare laste opp ett vedlegg til et innlegg." other: "Beklager, nye brukere kan bare laste opp %{count} vedlegg til et innlegg." + no_links_allowed: "Beklager, nye brukere kan ikke publisere innlegg med lenker." spamming_host: "Beklager, du kan ikke lenke til det domenet." user_is_suspended: "Utviste brukere kan ikke skrive innlegg." topic_not_found: "Noe gikk galt. Kanskje emnet har blitt lukket eller slettet samtidig som du har sett på det?" - just_posted_that: "er for likt det du nylig postet." + just_posted_that: "er for likt det du nylig publiserte." invalid_characters: "inneholder ugyldige tegn" next_page: "neste side →" prev_page: "← forrige side" @@ -130,10 +166,15 @@ nb_NO: read_full_topic: "Les hele emnet" private_message_abbrev: "Mld" rss_description: - latest: "Nylige emner" + latest: "Siste emner" hot: "Populære emner" top: "Mest Populære Emner" - posts: "Nyeste innnlegg" + posts: "Siste innlegg" + private_posts: "Siste private meldinger" + group_posts: "Siste innlegg fra %{group_name}" + user_posts: "Siste innlegg av @%{username}" + user_topics: "Siste emner av @%{username}" + tag: "Emner merket med stikkord" too_late_to_edit: "Det innlegget ble laget for lenge siden. Det kan ikke lenger bli redigert eller slettet." excerpt_image: "bilde" queue: @@ -156,15 +197,15 @@ nb_NO: one: "1 innlegg" other: "%{count} innlegg" new-topic: | - Velkommen til %{site_name} — **takk for at du startet et nytt innlegg!** + Velkommen til %{site_name}. **Takk for at du starter et nytt innlegg!** - - Høres tittelen på innlegget interessant ut hvis du leser det høyt? Er det en god oppsummering? + - Høres tittelen på innlegget interessant ut hvis du leser den høyt? Er den en god oppsummering? - - Hvem vil være interessert i dette? Hvorfor betyr det noe? Hva slags respons er du ute etter? + - Hvem vil være interessert i dette? Hvorfor har det noe å si? Hva slags respons er du ute etter? - - Bruk relevante begreper i emnet så andre kan *finne* det. Venligst velg en kategori for å gruppere emnet ditt med andre liknende emner. + - Bruk relevante begrep i emnet så andre kan *finne* det. Velg en kategori for å gruppere emnet ditt med andre lignende emner. - [Se våre retningslinjer](/guidelines) for mer informasjon. Denne meldingen vises kun for ditt første %{education_posts_text}. + [Se retningslinjene for dette nettstedet](/guidelines) for mer informasjon. Denne meldingen vises kun for ditt/dine første %{education_posts_text}. new-reply: | Velkommen til %{site_name} — **takk for at du bidrar!** @@ -172,9 +213,17 @@ nb_NO: - Vær snill mot andre medlemmer. - - Konstruktiv kritikk ønskes velkommen, men husk å kritiser *idéer,* ikke mennesker. + - Konstruktiv kritikk er velkommen, men husk å kritisere *idéer,* ikke mennesker. - For mer informasjon [se våre retningslinjer](/guidelines). Dette panelet vil kun vises for ditt/dine første %{education_posts_text}. + For mer informasjon [se retningslinjene våre](/guidelines). Dette panelet vil kun vises for ditt/dine første %{education_posts_text}. + avatar: | + ### Hva med et bilde til kontoen din? + + Du har opprettet noen innlegg og svar, men profilbildet ditt er ikke så unikt som du er -- det er bare en bokstav. + + Har du tenkt på å **[gå til brukerprofilen din](%{profile_path})** og laste opp et bilde som representerer deg? + + Det er enklere å følge diskusjoner og finne interessante personer i samtaler når alle har et unikt profilbilde! sequential_replies: | ### Vurder å svare til flere innlegg på samme tid @@ -190,7 +239,7 @@ nb_NO: Er du sikker du gir nok tid til andre å dele sine innspill også? too_many_replies: | - ### Du har nådd det maksimale antallet mulige svar for dette emnet + ### Du har nådd maksimalt antallet mulige svar for dette emnet Vi beklager, men nye brukere er midlertidig begrenset til %{newuser_max_replies_per_topic} svar per emne. @@ -205,6 +254,9 @@ nb_NO: attributes: category: name: "Kategorinavn" + topic: + title: 'Tittel' + featured_link: 'Framhevet lenke' post: raw: "Body" user_profile: @@ -218,31 +270,43 @@ nb_NO: too_many_users: "Du kan bare sende advarsel til en bruker om gangen." cant_send_pm: "Beklager, du kan ikke sende en privat melding til den brukeren." no_user_selected: "Du må velge en gyldig bruker. " + featured_link: + invalid: "er ugyldig. Nettadressen bør inneholde http:// eller https://" user: attributes: password: common: "er et av de 10000 mest vanlige passordene. Venligst benytt et mer sikkert passord." - same_as_username: "er det somme som ditt brukernavn. Vennligst ta i bruk et mer sikkert passord." - same_as_email: "er det samme som din e-mail. Vennligst ta i bruk et mer sikkert passord." + same_as_username: "er det somme som brukernavnet ditt. Benytt et sikrere passord." + same_as_email: "er det samme som din e-mail. Benytt et sikrere passord." + same_as_current: "er det samme som nåværende passord." ip_address: signup_not_allowed: "Registrering er ikke tillatt fra denne kontoen." color_scheme_color: attributes: hex: invalid: "er ikke en gyldig farge" + post_reply: + base: + different_topic: "Innlegg og svar må tilhøre samme kategori." + web_hook: + attributes: + payload_url: + invalid: "URL-adresse er ikke gyldig. Adressen skal starte med http:// eller https:// og ingen blanke tegn er tillatt." <<: *errors user_profile: no_info_me: "
    Om meg-feltet på din profil er for øyeblikket blankt, ønsker du å fylle det ut?
    " no_info_other: "
    %{name} har ikke skrevet noe i Om meg-feltet på sin profil ennå
    " vip_category_name: "Salong" - vip_category_description: "En kategori tilgjengelig for brukere med tillitsnivå 3 og høyere." - meta_category_name: "Tilbakemelding" - meta_category_description: "Diskusjon om denne nettsiden, organiseringen av den, hvordan den fungerer og hvordan vi kan forbedre den." + vip_category_description: "En kategori tilgjengelig for brukere på tillitsnivå 3 og høyere." + meta_category_name: "Tilbakemeldinger" + meta_category_description: "Diskusjon om dette nettstedet, hvordan det er organisert, hvordan det fungerer og hvordan vi kan forbedre det." staff_category_name: "Stab" staff_category_description: "Privat kategori for diskusjoner blant staben. Emner er kun synlige for administratorer og moderatorer." assets_topic_body: "Dette er et permanent emne, synlig bare for staben, for å lagre bilder of filer brukt i designet på siden. Ikke slett det!\n\n\nHvordan legge til nye filer:\n\n\n1. Svar på dette emnet.\n2. Last opp alle bilder du vil bruke, som logoer, favicons osv. (Bare dra bildene inn i skrivefeltet, eller bruk knappen for opplasting.)\n3. Send ditt svar.\n4. Høyrklikk bildene i din nye post for å få lenken til de opplastede bildene, eller klikk på redigeringsikonet for å kopiere lenkene fra skrivefeltet.\n5. Lim disse lenkene inn i [basic settings](/admin/site_settings/category/required).\n\n\nHvis du trenger å tillate andre filtyper, rediger `authorized_extensions` i [file settings](/admin/site_settings/category/files)." + discourse_welcome_topic: + title: "Velkommen til Discourse" lounge_welcome: - title: "Velkommen til Salongen" + title: "Velkommen til salongen" body: |2 Gratulerer! :confetti_ball: @@ -254,19 +318,19 @@ nb_NO: * Redigere tittelen på alle emner * Endre kategorien på alle emner * Få lenkene dine fulgt opp ([automatisk nofollow](http://en.wikipedia.org/wiki/Nofollow) er fjernet) - * Tilgang til en privat Lounge kategori bare synlig for brukere med tillitsnivå 3 eller høyere. - * All spam du flagger vil bli gjemt umiddelbart. + * Tilgang til en privat salong-kategori som bare er synlig for brukere på tillitsnivå 3 eller høyere. + * All søppelpost du flagger vil bli gjemt umiddelbart. Her er den [oppdaterte listen over andre "trofaste"](/badges/3/regular). Si gjerne hei! Takk for at du er en aktiv del av fellesskapet vårt. - (For mer informasjon om tillitsnivå, [see dette emnet][trust]. Vennligst merk at bare medlemmer som fortsetter å oppfylle kravene over tid vil forbli *trofaste*.) + (For mer informasjon om tillitsnivå, [see dette emnet][trust]. Merk deg at bare medlemmer som fortsetter å oppfylle kravene over tid vil forbli *trofaste*.) [trust]: https://meta.discourse.org/t/what-do-user-trust-levels-do/4924 category: topic_prefix: "Om kategorien %{category} " - replace_paragraph: "(Erstatt dette første avsnittet med en kort beskrivelse av den nye kategorien din. Denne teksten vil vises i oversikten over kategorier, så prøv å holde den under 200 ord. **Til du endrer denne beskrivelsen eller oppretter emner vil denne kategorien ikke vises på kategorier-siden.**)" + replace_paragraph: "(Erstatt dette første avsnittet med en kort beskrivelse av den nye kategorien din. Denne teksten vil vises i oversikten over kategorier, så prøv å holde den under 200 ord. **Inntil du endrer denne beskrivelsen eller oppretter emner, vil denne kategorien ikke vises på kategorier-siden.**)" post_template: "%{replace_paragraph}\n\nBruk de følgende avsnittene for en lengre beskrivelse, eller for å beskrive retningslinjer eller regler for kategorien:\n\n- Hvorfor skal folk bruke denne kategorien? Hva er den ment for?\n\n- På hvilken måte skiller den seg fra de andre kategoriene vi allerede har?\n\n- Hva skal emner i denne kategorien generelt sett inneholde?\n\n- Trenger vi denne kategorien? Kan vi slå den sammen med en annen kategori eller underkategori?\n" errors: uncategorized_parent: "Ukategorisert kan ikke ha en foreldrekategori" @@ -279,6 +343,7 @@ nb_NO: one: "Kan ikke slette denne kategorien fordi den har 1 emne. Eldste emne er %{topic_link}." other: "Kan ikke slette denne kategorien fordi den har %{count} emner. Eldste emne er %{topic_link}." topic_exists_no_oldest: "Kan ikke slette denne kategorien fordi emneantallet er %{count}." + uncategorized_description: "Emner som ikke trenger en kategori eller som ikke passer i noen av de eksisterende." trust_levels: newuser: title: "ny bruker" @@ -286,8 +351,16 @@ nb_NO: title: " bruker" member: title: "medlem" + regular: + title: "trofast" + leader: + title: "leder" rate_limiter: too_many_requests: "Vi har en daglig begrensning for hvor mange ganger den handlingen kan utføres. Venligst vent %{time_left} før du prøver igjen." + by_type: + first_day_replies_per_day: "Du har nådd det maksimale antall svar en ny bruker kan publisere på sin første dag. Vær så snill og vent %{time_left} før du prøver igjen." + first_day_topics_per_day: "Du har nådd det maksimale antall emner en ny bruker kan publisere på sin første dag. Vær så snill og vent %{time_left} før du prøver igjen." + topics_per_day: "Du har oppnådd høyest antall innlegg for i dag. Vær så snill og vent %{time_left} før du prøver igjen." hours: one: "1 time" other: "%{count} timer" @@ -369,6 +442,7 @@ nb_NO: one: "nesten 1 år siden" other: "nesten %{count} år siden" password_reset: + no_token: "Beklager, den lenken for å endre passord er for gammel. Velg logg inn-knappen bruk 'Jeg glemte passordet mitt' for å motta en ny lenke." choose_new: "Venligst velg et nytt passord" choose: "Venligst velg et passord" update: 'Oppdater passord' @@ -378,18 +452,21 @@ nb_NO: success_unapproved: "Du har endret ditt passord." continue: "Fortsett til %{site_name}" change_email: - confirmed: "Epostaddressen din har blitt oppdatert." + confirmed: "E-postaddressen din er blitt oppdatert." please_continue: "Fortsett til %{site_name}" - error: "Det oppsto en feil ved endring av din epostadresse. Kanskje addressen allerede er i bruk?" + error: "Det oppsto en feil ved endring av din e-postadresse. Kanskje addressen allerede er i bruk?" + authorizing_old: + title: "Takk for at du bekreftet din nåværende e-postadresse" + description: "Vi sender deg en e-post til din nye adresse for bekreftelse." activation: already_done: "Beklager, denne bekreftelseslenken er ikke lenger gyldig. Kanskje er kontoen din allerede aktivert?" please_continue: "Din nye konto er registrert; du vil bli videresendt til hjemmesiden. " continue_button: "Fortsett til %{site_name}" welcome_to: "Velkommen til %{site_name}!" - approval_required: "En moderator må manuelt godkjenne kontoen din før du får tilgang til forumet. Du vil motta en epost når kontoen din er godkjent!" + approval_required: "En moderator må manuelt godkjenne kontoen din før du får tilgang til forumet. Du vil motta en e-post når kontoen din er godkjent!" post_action_types: off_topic: - title: 'Off-Topic' + title: 'Urelatert' description: 'Dette innlegget er ikke relevant til den aktuelle emne som definert av tittelen og første innlegget, og burde sannsynligvis flyttes et annet sted. ' long_form: 'markerte dette som urelevant' spam: @@ -400,9 +477,10 @@ nb_NO: email_body: "%{link}\n\n%{message}" inappropriate: title: 'Upassende' - description: 'Dette innlegget har innhold som for en fornuftig person vil kunne være fornærmende, nedverdigende eller brudd på retningslinjene til dette nettsamfunnet.' + description: 'Dette innlegget har innhold som for en fornuftig person vil kunne være fornærmende, nedverdigende eller brudd på retningslinjene til denne gemenskapen.' long_form: 'markerte dette som upassende' notify_user: + title: 'Send en melding til @{{username}}' long_form: 'sendt melding til bruker' email_title: 'Ditt innlegg i "%{title}"' email_body: "%{link}\n\n%{message}" @@ -421,6 +499,12 @@ nb_NO: title: 'Stem' description: 'Stem på dette innlegget' long_form: 'stemte for dette innlegget' + user_activity: + no_bookmarks: + others: "Ingen bokmerker." + no_likes_given: + self: "Du har ikke likt noen innlegg." + others: "Ingen likte innlegg. " topic_flag_types: spam: title: 'Spam' @@ -428,7 +512,7 @@ nb_NO: long_form: 'rapporterte dette som spam' inappropriate: title: 'Upassende' - description: 'Dette innlegget har innhold som en fornuftig person vil anslå å være fornærmende, nedverdigende eller brudd på retningslinjene til dette nettsamfunnet.' + description: 'Dette innlegget har innhold som en fornuftig person vil anslå å være fornærmende, nedverdigende eller brudd på retningslinjene til denne gemenskapen.' long_form: 'markerte dette som upassende' notify_moderators: title: "Noe annet" @@ -436,8 +520,8 @@ nb_NO: email_title: 'Emne "%{title}" krever moderator oppmerksomhet' email_body: "%{link}\n\n%{message}" flagging: - you_must_edit: '

    Innlegget ditt har blitt rapportert av nettsamfunnet. Venligst sjekk dine meldinger.

    ' - user_must_edit: '

    Dette innlegget ble rapportert av nettsamfunnet og er midlertidig skjult.

    ' + you_must_edit: '

    Innlegget ditt har blitt rapportert av nettsamfunnet. Sjekk meldingene dine.

    ' + user_must_edit: '

    Dette innlegget ble rapportert av gemenskapen og er midlertidig skjult.

    ' archetypes: regular: title: "Vanlig emne" @@ -446,6 +530,20 @@ nb_NO: message: make: "Dette emnet er nå en banner. Det vil vises på toppen av hver side til brukeren lukker det." remove: "Dette emnet er ikke lenger en banner. Det vil ikke lenger vises på toppen av hver side." + unsubscribe: + stop_watching_topic: "Slutt å følge dette emnet, %{link}" + mute_topic: "Demp alle varslene for dette emnet, %{link}" + unwatch_category: "Slutt å følge alle emner i %{category}" + mailing_list_mode: "Slå av e-postlistemodus" + disable_digest_emails: "Slutt å sende meg oppsummerings-eposter" + log_out: "Logg ut" + user_api_key: + read: "les" + read_write: "les/skriv" + scopes: + message_bus: "Sanntidsoppdateringer" + read: "Les alt" + write: "Skriv alt" reports: visits: title: "Brukerbesøk" @@ -456,7 +554,9 @@ nb_NO: xaxis: "Dag" yaxis: "Antall nye brukere" profile_views: + title: "Visninger av brukerprofil" xaxis: "Dag" + yaxis: "Antallet brukerprofiler vist" topics: title: "Emner" xaxis: "Dag" @@ -527,23 +627,28 @@ nb_NO: page_view_anon_reqs: title: "Anonym" xaxis: "Dag" + yaxis: "Anonyme sidevisninger" page_view_logged_in_reqs: title: "Innlogget" xaxis: "Dag" + yaxis: "Innloggede sidevisninger" page_view_crawler_reqs: title: "Web crawlere" xaxis: "Dag" page_view_total_reqs: title: "Totalt" xaxis: "Dag" + yaxis: "Totalt antall sidevisninger" page_view_logged_in_mobile_reqs: + title: "Innloggede sidevisninger" xaxis: "Dag" + yaxis: "Innloggede sidevisninger fra mobil" page_view_anon_mobile_reqs: xaxis: "Dag" http_background_reqs: title: "Bakgrunn" xaxis: "Dag" - yaxis: "Forespørsler for live-oppdateringer og -sporing" + yaxis: "Forespørsler brukt for direkte-oppdateringer og -overvåkning" http_2xx_reqs: title: "Status 2xx (OK)" xaxis: "Dag" @@ -578,71 +683,112 @@ nb_NO: yaxis: "Antall besøk" dashboard: rails_env_warning: "Serveren din kjører i %{env] modus." - host_names_warning: "Din config/database.yml fil bruker standard localhost hostnavn. Venligst legg inn ditt ønskede hostnavn" + host_names_warning: "Din config/database.yml-fil bruker forvalgt lokalvert-vertsnavn. Oppdater det til å bruke din sides vertsnavn." memory_warning: 'Serveren din kjører med mindre enn 1 GB med minne. Minst 1 GB RAM er anbefalt.' site_settings: censored_words: "Ord som automatisk vil bli erstattet med ■■■■" - delete_old_hidden_posts: "Auto-slett skjulte innlegg som er skjult i mer enn 30 dager." + delete_old_hidden_posts: "Slett automatisk skjulte innlegg som har vært skjult i mer enn 30 dager." default_locale: "Standard språk for denne instansen av Discourse (ISO 639-1 Kode)" - allow_user_locale: "Tillta at brukere velger eget språk" + allow_user_locale: "Tillat brukere å velge eget språk" min_post_length: "Minimum tillatt lengde for innlegg i tegn" min_first_post_length: "Minimum tillatt lengde på for teksten i første innlegg" + min_private_message_post_length: "Minste tillatte innleggslengde for meldinger i antall tegn" max_post_length: "Maksimum tillatt lengde for innlegg i tegn" min_topic_title_length: "Minimum tillatt lengde for tittel i tegn" max_topic_title_length: "Maksimum tillatt lengde for innlegg i tegn" + min_private_message_title_length: "Minste antall tegn tillatt til bruk for tittellengde i meldinger" min_search_term_length: "Minimum lengde på søkeord i tegn" - allow_duplicate_topic_titles: "Tillat emner med lik, duplikat tittel." - unique_posts_mins: "Hvor mange minutter før en bruker kan lage en post med det samme innholdet igjen" + allow_duplicate_topic_titles: "Tillat flere emner med identisk tittel." + unique_posts_mins: "Hvor mange minutter før en bruker kan lage et innlegg med det samme innholdet igjen" educate_until_posts: "Når bruker begynner å skrive på de første (n) innleggene, vis pop-up med opplæringspanelet for nye brukere i editoren." title: "Navnet på denne siden, slik du vil ha det i title-taggen." site_description: "Beskriv siden med en setning, vil brukes i description-taggen." - contact_email: "Epost til ansvarlig kontakt for denne siden. Brukes til kritiske påminninger som uhåndterte flagg, kontakt-adresse på /about siden." + contact_email: "Epost til ansvarlig kontakt for denne siden. Brukes til kritiske påminninger som uhåndterte flagg og som kontakt-adresse på /about-siden." contact_url: "Kontakt URL for siden. Brukes på /about siden." - queue_jobs: "KUN FOR UTVIKLERE! ADVARSEL! Jobber køes som standard i Sidekiq. Hvis det slås av vil siden ikke fungere. " + queue_jobs: "KUN FOR UTVIKLERE! ADVARSEL! Jobber køes som forvalg i Sidekiq. Hvis det slås av vil siden ikke fungere. " crawl_images: "Hent bilder fra ekstern URL for å sette inn korrekt høyde og bredde." download_remote_images_to_local: "Konverter eksterne bilder ved å laste de ned lokalt, dette forhindrer ødelagte bilder." download_remote_images_threshold: "Minimum ledig diskplass for å kunne laste ned eksterne bilder (i prosent)" disabled_image_download_domains: "Eksterne bilder vil aldri bli lastet ned fra disse domenene (pipe-separert liste)." + editing_grace_period: "(n) sekunder etter publisering vil redigering ikke opprette en ny versjon i redigeringsloggen." post_edit_time_limit: "Forfattere kan redigere eller slette innleggene sine (n) minutter etter opprettelse. Sett 0 for uendelig." - edit_history_visible_to_public: "Alle kan se tidligere versjoner av et redigert innlegg. Hvis det er slått av kan kun stab se det." + edit_history_visible_to_public: "Alle kan se tidligere versjoner av et redigert innlegg. Hvis det er slått av kan kun staben se det." delete_removed_posts_after: "Innlegg som blir fjernet av forfatter blir automatisk slettet etter (n) timer. Sett til 0 og innleggene blir slettet øyeblikkelig." max_image_width: "Maksimal thumbnail bredde for bilder i et innlegg" max_image_height: "Maksimal thumbnail høyde for bilder i et innlegg" - post_excerpt_maxlength: "Maksimal lengde på et utdrag eller oppsummering av innlegg." + post_excerpt_maxlength: "Maksimal lengde på utdrag eller oppsummering av innlegg." apple_touch_icon_url: "Ikon brukt på Apple touch enheter. Anbefalt størrelse er 144px x 144px." + summary_max_results: "Maksimalt antall innlegg som returneres av 'Oppsummer dette emnet'" allow_moderators_to_create_categories: "Tillat moderatorer å opprette nye kategorier" - show_email_on_profile: "Vis brukerens epostadresse i profilen (kun synlig for brukeren selv og forum staff)" + topics_per_period_in_top_summary: "Antall topp-emner vises som forvalg i oppsummeringen av topp-emner." + show_email_on_profile: "Vis brukerens e-postadresse i profilen (kun synlig for brukeren selv og forumstaben)" email_token_valid_hours: "Glemt passord / aktiver konto tokens er gyldig for (n) timer." enable_badges: "Aktiver badge system" log_out_strict: "Ved utlogging, logg ut av ALLE enheter som er pålogget" invite_expiry_days: "Hvor lenge en bruker invitasjons nøkkel er gyldig i dager" + min_username_length: "Minste antall tegn tillatt for brukernavn." + max_username_length: "Største antall tegn tillatt for brukernavn." + min_password_length: "Minimums passordslengde." + min_admin_password_length: "Minimums passordslengde for administrator." rate_limit_create_post: "Etter et innlegg må ny brukere vente (n) sekunder før de kan skrive et nytt" rate_limit_new_user_create_post: "Etter et innlegg må ny brukere vente (n) sekunder før de kan skrive et nytt" max_likes_per_day: "Maximum antall liker per bruker per dag" newuser_max_links: "Hvor mange linker en ny bruker kan legge til i et innlegg." newuser_max_images: "Hvor mange bilder en ny bruker kan legge til i et innlegg." title_prettify: "Unngå vanlige skrivefeil i titler, sånn som store bokstaver, liten bokstav først, mange !, ? og punktum på slutten, osv." - faq_url: "Hvis du har en FAQ på et annet nettsted du gjerne vil bruke, vennligst sett inn URL'en her." + faq_url: "Hvis du har O-S-S på et annet nettsted du gjerne vil bruke, skriv inn nettadressen her." tos_url: "Dersom du har et bruksvilkår-dokument et annet sted som du vil bruke, skriv inn den fullstendige URL-en her." privacy_policy_url: "Dersom du har en personvernerklæring et annet sted som du vil bruke, skriv inn den fullstendige URL-en her." delete_user_max_post_age: "Ikke tillatt å slette brukere hvor deres første innlegg er mer enn (x) dager gamle." email_editable: "Tillat brukere å endre deres email etter at de har registrert seg." + digest_topics: "Maksimalt antall populære emner å vise i oppsummerings-e-posten." + digest_posts: "Maksimalt antall populære innlegg å vise i oppsummerings-e-posten." + digest_other_topics: "Maksimalt antall emner å vise i delen 'Nytt i emner og kategorier du følger' i oppsummerings-e-posten." + digest_min_excerpt_length: "Minimal lengde på utdrag av innlegg i e-post-oppsummeringen, i antall tegn." + delete_digest_email_after_days: "Utelat oppsummerings-eposter for brukere ikke sett på nettstedet siden mer enn (n) dager." + digest_suppress_categories: "Utelat disse kategoriene i oppsummerings-eposter" + disable_digest_emails: "Deaktivér oppsummerings-eposter for alle brukere." allow_profile_backgrounds: "Gi brukere mulighet til å laste opp profilbakgrunner." - enable_mobile_theme: "Mobilenheter bruker et mobilvennlig tema, med muligheten til å gå til den fulle siden. Deaktiver dette hvis du ønsker å bruke et tilpasset stilark." + enable_mobile_theme: "Mobilenheter bruker et mobilvennlig drakt, med muligheten til å gå til den fulle siden. Deaktiver dette hvis du ønsker å bruke et tilpasset stilark." dominating_topic_minimum_percent: "Hvor mange innlegg en bruker kan lage innenfor en topic før de blir påminnet om dominering av en topic." + automatically_unpin_topics: "Automatisk fjern feste for emner når brukeren når bunnen." + embed_post_limit: "Maksimalt antall innlegg som skal bygges inn." + embed_username_required: "Brukernavn kreves for opprettelse av emne." enable_emoji: "Aktiver emoji." emoji_set: "Hvordan vil du ha din emoji?" + default_email_digest_frequency: "Forvalgt innstilling for hvor ofte brukere mottar oppsummerings-e-poster" + default_include_tl0_in_digests: "La det være forvalgt innstilling å inkludere innlegg fra nye brukere i oppsummerings-e-poster. Brukere kan endre dette i innstillingene sine." + default_email_mailing_list_mode_frequency: "Brukere som slår på e-postlistemodus, vil motta e-poster så ofte som forvalg" + disable_mailing_list_mode: "Forby brukere å slå på e-postlistemodus" + default_email_previous_replies: "Inkludér tidligere svar i e-poster som forvalg." + default_topics_automatic_unpin: "Automatisk fjern feste for emner når brukeren når bunnen som forvalg." + default_categories_watching: "Liste med kategorier som følges som forvalg" + default_categories_tracking: "Liste med kategorier som overvåkes som forvalg" + default_categories_muted: "Liste med kategorier som blir dempet som forvalg" + default_categories_watching_first_post: "Liste med kategorier hvor det første innlegget i hvert nye emne følges som forvalg." + remove_muted_tags_from_latest: "Ikke vis emner med dempede stikkord i listen med siste emner." + company_short_name: "Firmanavn (kort)" + company_full_name: "Firmanavn (hele)" + company_domain: "Firmadomene" errors: invalid_email: "Ugyldig e-mail adresse" + invalid_username: "Ingen bruker med det brukernavnet." + invalid_integer_min_max: "Verdien må være mellom %{min} og %{max}." invalid_string: "Ugyldig verdi" + invalid_string_min: "Må være minst %{min} tegn." + invalid_string_max: "Må ikke være mer enn %{max} tegn." search: types: category: 'Kategorier' topic: 'Resultater' user: 'Brukere' + most_posts: "Flest innlegg" + most_recent_poster: "Ferskeste innlegg av" redirected_to_top_reasons: new_user: "Velkommen til vårt forum! Dette er de mest populære emnene for tiden. " not_seen_in_a_month: "Velkommen tilbake! Nå har ikke vi sett deg på en stund. Dette er de mest populære emnene for tiden." + change_owner: + deleted_user: "en slettet bruker" topic_statuses: archived_enabled: "Dette emnet er nå arkivert. Det er fryst og kan ikke bli endret på noen måte. " archived_disabled: "Dette emnet er ikke lenger arkivert. Det er ikke lenger fryst, og kan endres." @@ -668,30 +814,39 @@ nb_NO: other: "Dette emnet ble automatisk lukket %{count} minutter etter siste innlegg. Emnet kan ikke lenger svares på. " autoclosed_disabled: "Dette emnet er nå åpent. Emnet kan svares på. " autoclosed_disabled_lastpost: "Dette emnet er åpnet. Nye svar er tillatt." - pinned_enabled: "Dette emnet er nå fastsatt. Det vil vises i toppen av sin kategori og alle emne lister frem til en administrator, for alle, eller brukerne for dem selv løsgjør emnet. " - pinned_disabled: "Dette emnet er ikke lenger fastsatt. Det vil ikke lenger vises i toppen av sin kategori." - pinned_globally_enabled: "Dette emnet er nå fastsatt globalt. Det vil vises i toppen av sin kategori og alle emne lister frem til administrator, for alle, eller brukerne for dem selv løsgjør emnet. " - pinned_globally_disabled: "Dette emnet er ikke lenger fastsatt. Det vil ikke lenger vises i toppen av sin kategori." + pinned_enabled: "Dette emnet er nå festet. Det vil vises i toppen av sin kategori inntil festet fjernes av en administrator eller av enkeltbrukere for seg selv." + pinned_disabled: "Dette emnet er ikke lenger festet. Det vil ikke lenger vises i toppen av sin kategori." + pinned_globally_enabled: "Dette emnet er nå festet globalt. Det vil vises i toppen av sin kategori og alle emne lister inntil festet fjernes for alle av staben, eller for enkelte brukere av dem selv." + pinned_globally_disabled: "Dette emnet er ikke lenger festet. Det vil ikke lenger vises i toppen av sin kategori." visible_enabled: "Dette emnet er nå listet. Det vil vises i emne listene. " visible_disabled: "Dette ement er ikke lenger listet. Det vil ikke lenger bli vist i noen av emnelistene. Den eneste måten å få tilgang til dette emnet er via en direkte link. " login: incorrect_username_email_or_password: "Feil brukernavn, email eller passord" - wait_approval: "Takk for at du registrerte deg. Vi vil gi deg beskjed når din konto har blitt godkjent." + wait_approval: "Takk for at du registrerte deg. Vi vil varsle deg når din konto er blitt godkjent." active: "Kontoen din har blitt godkjent og er klar for bruk." - activate_email: "

    Nesten ferdig! Vi har sendt en e-post til %{email}. Vennligst trykk på lenken i e-posten for å aktivere kontoen din.

    Hvis den ikke dukker opp, sjekk søppepostmappen din eller logg inn på nytt for å sende en ny-epost.

    " + activate_email: "

    Nesten ferdig! Vi har sendt en e-post til %{email}. Følg lenken i e-posten for å aktivere kontoen din.

    Hvis den ikke dukker opp, sjekk søppepostmappen din eller logg inn på nytt for utsending av ny e-post.

    " + not_available: "Ikke mulig. Prøv %{suggestion}?" something_already_taken: "Noe gikk galt, kanskje brukernavn eller email er allerede i bruk? Prøv 'glemt passord' linken." - omniauth_error_unknown: "Noe gikk galt under innloggingsprosessen, vennligst prøv igjen." + omniauth_error_unknown: "Noe gikk galt under innloggingsprosessen, prøv igjen." + new_registrations_disabled: "Nye kontoregistreringer tillates ikke per nå." password_too_long: "Passord er begrenset til 200 tegn." + reserved_username: "Det brukernavnet tillates ikke." missing_user_field: "Du har ikke fylt ut alle brukerfeltene." - already_logged_in: "Oisann, ser ut som du prøver å akteptere en invitasjon for en en annen bruker. Hvis du ikke er %{current_user}, vennligst logg ut og prøv igjen." + already_logged_in: "Oisann, ser ut som du prøver å akseptere en invitasjon for en en annen bruker. Hvis du ikke er %{current_user}, logg ut og prøv igjen." user: + no_accounts_associated: "Ingen tilknyttede kontoer" username: - short: "må være minst %{min} tegn" + short: "må være på minst %{min} tegn" long: "kan ikke være mer enn %{max} tegn" unique: "må være unik" blank: "Må være til stede" email: blocked: "er ikke tillatt." + ip_address: + blocked: "Nye registreringer er ikke tillatt fra IP-adressen din." + max_new_accounts_per_registration_ip: "Nye registreringer er ikke tillatt fra IP-adressen din (maksimalt antall nådd). Ta kontakt med et medlem av staben." + new_version_mailer_with_notes: + subject_template: "[%{site_name}]-oppdatering tilgjengelig" flags_dispositions: agreed: "Takk for at du sier ifra. Vi er enig at det er et problem her og vi ser på saken." disagreed: "Takk for at du sier ifra. Vi skal se på det. " @@ -702,10 +857,48 @@ nb_NO: subject_template: "Velkommen til %{site_name}!" welcome_invite: subject_template: "Velkommen til %{site_name}!" + backup_failed: + subject_template: "Sikkerhetskopiering mislyktes" + restore_failed: + subject_template: "Gjenoppretting mislyktes" + too_many_spam_flags: + subject_template: "Ny konto på vent" + too_many_tl3_flags: + subject_template: "Ny konto på vent" + unblocked: + subject_template: "Kontoen er ikke lenger på vent" + unsubscribe_mailing_list: | + Du mottar dette fordi du har slått på e-postlistemodus. + + For å melde deg av disse e-postene [klikk her](%{unsubscribe_url}). user_notifications: + previous_discussion: "Tidligere svar" digest: why: "Dette har skjedd på %{site_link} siden ditt forrige besøk %{last_seen_at}" + since_last_visit: "Siden siste besøk" + new_topics: "Nye emner" + unread_messages: "Uleste meldinger" + unread_notifications: "Uleste varslinger." + new_posts: "Nye innlegg" + new_users: "Nye brukere" + popular_topics: "Populære emner" + follow_topic: "Følg dette emnet" + join_the_discussion: "Les mer" + popular_posts: "Populære innlegg" + from_topic_label: "Fra" + more_new: "Nytt for deg" + subject_template: "[%{site_name}] Oppsummering" + unsubscribe: "Denne oppsummeringen blir sendt fra %{site_link} når vi ikke har sett deg på en stund. For å melde deg av %{unsubscribe_link}." click_here: "trykk her" + from: "%{site_name} oppsummering" + preheader: "En kort oppsummering siden ditt siste besøk på %{last_seen_at}" + mailing_list: + subject_template: "[%{site_name}] Oppsummering for %{date}" + unsubscribe: "Denne oppsummeringen sendes daglig fordi e-postlistemodus er aktivert. For å melde deg deg av %{unsubscribe_link}." + from: "%{site_name}-oppsummering" + new_topics: "Nye emner" + view_this_topic: "Vis dette emnet" + back_to_top: "Tilbake til toppen" account_created: subject_template: "[%{site_name}] Din Nye Konto" text_body_template: | @@ -713,6 +906,12 @@ nb_NO: Trykk på følgende link for å velge et passord for kontoen din: %{base_url}/users/password-reset/%{email_token} + confirm_new_email: + subject_template: "[%{site_name}] Bekreft e-postadressen din" + confirm_old_email: + subject_template: "[%{site_name}] Bekreft nåværende e-postadresse" + notify_old_email: + subject_template: "[%{site_name}] Din e-postadresse har blitt endret" signup: subject_template: "[%{site_name}] Bekreft din nye konto" text_body_template: | @@ -722,6 +921,7 @@ nb_NO: %{base_url}/users/activate-account/%{email_token} page_not_found: title: "Oisann! Den siden finnes ikke eller er privat." + popular_topics: "Populært" recent_topics: "Nylig" see_more: "Mer" search_title: "Søk i denne siden" @@ -742,9 +942,12 @@ nb_NO: size_not_found: "Beklager, vi kunne ikke fastslå størrelsen på bildet ditt. Kanskje bildet ditt er blitt ødelagt?" email_log: no_user: "Finner ikke brukeren med id %{user_id}" + anonymous_user: "Brukeren er anonym" + seen_recently: "Brukeren ble sett nylig" post_deleted: "innlegget var " user_suspended: "Brukeren var suspendert" already_read: "bruker har allerede lest dette innlegget" + message_blank: "meldingen er tom" about: "Om" guidelines: "Retningslinjer" privacy: "Personvern" @@ -860,11 +1063,11 @@ nb_NO: ## [Hvilke opplysninger samler vi?](#samle) - Vi samler opplysninger fra deg når du registrerer deg på siden vår og samler data når du deltar på forumet ved å lese, skrive og evaluere innholdet som deles her. + Vi samler opplysninger fra deg når du registrerer deg på nettstedet vårt, og vi samler data når du deltar på forumet ved å lese, skrive og evaluere innholdet som deles her. - Når du registrerer seg på siden vår, kan du bli bedt om å oppgi navnet og e-postadressen din. Imidlertid kan du besøke siden vår uten å registrere deg. E-postadressen din vil bli bekreftet med en e-post som inneholder en unik lenke. Hvis siden den lenker til, blir besøkt, vet vi at du har kontroll over e-postadressen. + Når du registrerer deg på nettstedet vårt, kan du bli bedt om å oppgi navnet og e-postadressen din. Imidlertid kan du besøke nettstedet vårt uten å registrere deg. E-postadressen din vil bli bekreftet med en e-post som inneholder en unik lenke. Hvis siden den lenker til, blir besøkt, vet vi at du har kontroll over e-postadressen. - Når du registrerer deg og skriver innlegg, registrerer vi e-postadressen som innlegget stammer fra. Vi kan også oppbevare logger som inkluderer e-postadressen til alle forespørslene sendt til tjeneren vår. + Når du registrerer deg og skriver innlegg, registrerer vi IP-adressen som innlegget stammer fra. Vi kan også oppbevare logger som inkluderer IP-adressen til alle forespørslene sendt til tjeneren vår. @@ -872,7 +1075,7 @@ nb_NO: Alle opplysningene vi samler fra deg, kan bli brukt på en av følgende måter: - * For å gjøre opplevelsen din mer personlig. Opplysningene dine hjelper oss å reagere bedre på dine individuelle behov. + * For å gjøre opplevelsen din mer personlig. Opplysningene dine hjelper oss å svare bedre på dine individuelle behov. * For å forbedre nettstedet vårt. Vi jobber konstant for å forbedre nettstedets tilbud basert på opplysningene og tilbakemeldingene vi mottar fra deg. * For å forbedre vår kundeservice. Dine opplysninger hjelper oss å svare mer effektivt på dine forespørsler sendt til kundeservice eller behov om støtte. * For å sende periodiske e-poster. E-postadressen du oppgir, kan bli brukt til å sende deg informasjon, påminnelser som du ber om ved endringer av emner eller ved svar til brukernavnet ditt, til henvendelser, og/eller andre forspørsler eller andre spørsmål. @@ -889,8 +1092,8 @@ nb_NO: Vi vil forsøke i god tro å: - * Oppbevare tjener-logger som inneholder IP-adressen til alle forspørslene til denne tjeneren ikke lenger enn i 90 dager. - * Oppbevare IP-adressene forbundet med registrerte brukere og deres innlegg ikke lenger enn 5 år. + * Ikke oppbevare tjener-logger som inneholder IP-adressen til alle forspørslene til denne tjeneren ikke lenger enn i 90 dager. + * Ikke oppbevare IP-adressene forbundet med registrerte brukere og deres innlegg lenger enn i 5 år. @@ -916,7 +1119,7 @@ nb_NO: ## [Overensstemmelse med Children's Online Privacy Protection Act](#coppa) - Nettstedet, produktene og tjenestene våre er rettet mot folk som er minst 13 år gamle. Dersom denne tjeneren er i USA, og du er under 13 år i henhold til kravene i COPPA ([Children's Online Privacy Protection Act](https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act)), ikke bruk denne siden. + Nettstedet, produktene og tjenestene våre er rettet mot folk som er minst 13 år gamle. Dersom denne tjeneren er i USA, og du er under 13 år i henhold til kravene i COPPA ([Children's Online Privacy Protection Act](https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act)), ikke bruk dette nettstedet. @@ -937,12 +1140,85 @@ nb_NO: Dersom vi beslutter å endre personvernerklæringen vår, vil vi publisere disse endringene på denne siden. Dette dokumentet er lisensiert under CC-BY-SA. De ble sist oppdatert 31. mai 2013. + badges: + editor: + name: Tekstbehandler + member: + name: Medlem + anniversary: + name: Jubileum + good_topic: + name: Bra emne + champion: + description: Inviterte fem medlemmer + first_quote: + name: Første sitering + description: Siterte et innlegg + read_guidelines: + name: Les retningslinjene + famous_link: + name: Berømt lenke + appreciated: + name: Verdsatt + out_of_love: + name: Ikke mer kjærlighet å gi + thank_you: + name: Takk skal du ha + gives_back: + name: Gir tilbake + first_onebox: + long_description: Dette merket tildeles den første gangen du publiserer et innlegg med en lenke på en egen linje, som deretter automatisk blir utvidet til en miniboks med en kort oppsummering av lenken, en tittel og (dersom tilgjengelig) et bilde. + admin_login: + success: "E-post sendt" + error: "Feil!" + submit_button: "Send e-post" + tags: + title: "Stikkord" + finish_installation: + confirm_email: + title: "Bekreft din e-postadresse" + resend_email: + title: "Send aktivterings-epost på nytt" + message: "

    Vi har sendt aktiverings-eposten på nytt til %{email}" + safe_mode: + title: "Start sikkerhetsmodus" + description: "Sikkerhetsmodus lar deg teste nettstedet ditt uten at tillegg eller tilpasninger lastes." wizard: step: - corporate: - description: "Disse navnene vil bli satt inn i din Personvernerklæring og dine Bruksvilkår, som du kan endre når som helst i stab-kategorien. Hvis du ikke har et firma, kan du gjerne hoppe over dette steget." - date: - <<: *datetime_formats + contact: + fields: + contact_email: + label: "E-post" + placeholder: "navn@example.com" + logos: + title: "Logoer" + fields: + logo_url: + label: "Primær logo" + description: "Logoen som vises oppe til venstre på nettstedet. Bruk et bilde med en bred rektangelform." + logo_small_url: + label: "Kompakt logo" + description: "En kompakt versjon av logoen. Vises oppe til venstre npr du blar nedover. Bruk et bilde med kvadratisk form." + icons: + title: "Ikoner" + fields: + favicon_url: + label: "Lite ikon" + description: "Et ikon som representerer nettstedet ditt i nettlesere. Bør se bra ut i så liten størrelse som 32 ganger 32 piksler." + apple_touch_icon_url: + label: "Stort ikon" + description: "Et ikon som representerer nettstedet ditt på moderne enheter og ser bra ut i større størrelser. Anbefalt størrelse er minst 144 ganger 144 piksler." + homepage: + title: "Hjemmeside" + fields: + homepage_style: + choices: + latest: + label: "Siste emner" + categories: + label: "Kategorier" + emoji: + title: "Emoji" activemodel: errors: <<: *errors diff --git a/config/locales/server.nl.yml b/config/locales/server.nl.yml index 166ed34cb6c..43c687ff00c 100644 --- a/config/locales/server.nl.yml +++ b/config/locales/server.nl.yml @@ -32,6 +32,7 @@ nl: purge_reason: "Automatisch verwijderd, account gedeactiveerd." disable_remote_images_download_reason: "Het downloaden van plaatjes is uitgeschakeld omdat er niet genoeg schijfruimte beschikbaar is." anonymous: "Anoniem" + remove_posts_deleted_by_author: "Verwijderd door gebruiker" emails: incoming: default_subject: "Inkomende e-mail van %{email}" @@ -71,6 +72,7 @@ nl: has_already_been_used: "is al gebruikt" inclusion: komt niet voor in de lijst invalid: is ongeldig + is_invalid: "lijkt onduidelijk, is het een volledige zin?" less_than: moet minder zijn dan %{count} less_than_or_equal_to: moet minder zijn dan of gelijk zijn aan %{count} not_a_number: is niet een getal @@ -105,11 +107,13 @@ nl: default_categories_already_selected: "Je kan geen categorie selecteren die wordt gebruikt in een andere lijst." s3_upload_bucket_is_required: "U kunt niet de uploads van de S3 toestaan totdat u de 's3_upload_bucket' hebt verleend." bulk_invite: - file_should_be_csv: "Het bestand moet in csv- of txt-formaat zijn." + file_should_be_csv: "Het geüploade bestand moet in csv-formaat zijn." + error: "Er trad een fout op tijdens het uploaden van dat bestand. Probeer het later nog eens." backup: operation_already_running: "Er wordt al een opdracht uitgevoerd. Kan nu niet een nieuwe opdracht starten." backup_file_should_be_tar_gz: "Het backupbestand moet een .tar.gz archief zijn." not_enough_space_on_disk: "Er is niet voldoende ruimte op de schijf vrij om deze backup te uploaden." + invalid_filename: "De naam van het backup-bestand bevat ongeldige tekens. Geldige tekens zijn a-z 0-9 . - _." not_logged_in: "Om dat te kunnen doen moet je ingelogd zijn." not_found: "De opgevraagde URL of resource kan niet gevonden worden." invalid_access: "Je hebt geen permissie om de opgevraagde resource te bekijken." @@ -122,6 +126,8 @@ nl: embed: start_discussion: "Reageer" continue: "Ga verder met de discussie" + error: "Fout bij embedden" + configure: "Configureer Embedden" more_replies: one: "Nog 1 reactie" other: "Nog %{count} reacties" @@ -157,6 +163,7 @@ nl: topic_not_found: "Er is iets fout gegaan. Wellicht is het topic gesloten of verwijderd terwijl je er naar keek?" just_posted_that: "lijkt teveel op het bericht dat je net geschreven hebt" invalid_characters: "bevat ongeldige tekens" + is_invalid: "lijkt onduidelijk, is het een volledige zin?" next_page: "volgende pagina →" prev_page: "← vorige pagina" page_num: "Pagina %{num}" @@ -267,6 +274,7 @@ nl: name: "Naam categorie" topic: title: 'Titel' + featured_link: 'Uitgelichte link' post: raw: "Inhoud" user_profile: @@ -280,18 +288,29 @@ nl: too_many_users: "Je kunt een waarschuwing per keer slechts naar één ander lid sturen." cant_send_pm: "Sorry, je kan geen privébericht sturen naar deze persoon." no_user_selected: "Je moet een geldige gebruiker selecteren." + featured_link: + invalid: "is ongeldig. URL moet http:// of https:// bevatten." + invalid_category: "kan niet worden gewijzigd in deze categorie." user: attributes: password: common: "is een van de 10000 meest gebruikte wachtwoorden. Gebruik een veiliger wachtwoord." same_as_username: "is hetzelfde als je gebruikersnaam. Gebruik een veiliger wachtwoord." same_as_email: "is hetzelfde als je e-mailadres. Gebruik een veiliger wachtwoord." + same_as_current: "is hetzelfde als je huidige wachtwoord." ip_address: signup_not_allowed: "Inschrijven vanaf dit account is niet toegestaan." color_scheme_color: attributes: hex: invalid: "is niet een geldige kleur" + post_reply: + base: + different_topic: "Het bericht en antwoord moeten bij hetzelfde topic horen." + web_hook: + attributes: + payload_url: + invalid: "De URL is ongeldig. URL's moeten http:// of https:// bevatten. En een leeg veld is niet toegestaan." <<: *errors user_profile: no_info_me: "

    Het Over Mij-profielveld is nog leeg, zou je deze willen invullen?
    " @@ -303,6 +322,8 @@ nl: staff_category_name: "Staf" staff_category_description: "Privécategorie voor stafgesprekken. Topics zijn alleen zichtbaar voor admins en moderatoren." assets_topic_body: "Dit is een permanent topic, dat alleen zichtbaar is voor de staf, en dient als opslag voor afbeeldingen en documenten die worden gebruikt in het design van de site . Gooi deze niet weg!\n\n\nHoe het werkt:\n\n\n1. Antwoord op dit topic.\n2. Upload hier alle afbeeldingen die je wenst te gebruiken als logo's, favicons enzovoort. (Gebruik het upload icoon in de toolbar, sleep afbeeldingen, of plak afbeeldingen.)\n3. Verzend je bericht om het te posten.\n4. Klik met de rechtermuisknop op de afbeeldingen in je nieuwe bericht om het pad naar de geüploade afbeelding te verkrijgen, of klik het bewerken icoon om je bericht te wijzigen en zo het pad naar de afbeeldingen te verkrijgen. Kopieer het pad naar de afbeeldingen.\n5. Plak deze paden naar de afbeeldingen in [basic settings](/admin/site_settings/category/required).\n\n\nAls je andere bestandstypen wilt kunnen uploaden, moet je dit instellen in `authorized_extensions` in de [file settings](/admin/site_settings/category/files)." + discourse_welcome_topic: + title: "Welkom bij Discourse" lounge_welcome: title: "Welkom in de Lounge" body: |2 @@ -468,6 +489,7 @@ nl: please_continue: "Ga verder naar %{site_name}" error: "Er ging iets mis bij het wijzigen van je e-mailadres. Wellicht is deze al in gebruik?" error_staged: "Er ging iets mis bij het wijzigen van je e-mailadres. Het adres is reeds in gebruik door een staged gebruiker." + already_done: "Sorry, de bevestigingslink is niet langer geldig. Misschien is je e-mail al veranderd?" authorizing_old: title: "Dank voor het bevestigen van je e-mailadres" description: "We sturen nu ter bevestiging een e-mail naar je nieuwe adres." @@ -478,6 +500,7 @@ nl: continue_button: "Ga verder naar %{site_name}" welcome_to: "Welkom bij %{site_name}!" approval_required: "Een moderator moet je nieuwe account handmatig activeren voordat je toegang krijgt tot dit forum. Je krijgt een e-mail van ons wanneer je account is goedgekeurd!" + missing_session: "We kunnen niet vaststellen of je account is aangemaakt, wees er alsjeblieft zeker van dat je cookies accepteert." post_action_types: off_topic: title: 'Off-topic' @@ -517,6 +540,9 @@ nl: title: 'Stem' description: 'Stem op dit bericht' long_form: 'heeft op dit bericht gestemd' + user_activity: + no_bookmarks: + self: "Je hebt geen favoriete berichten, als favoriet gemarkeerde berichten kun je later makkelijk terugvinden." topic_flag_types: spam: title: 'Spam' @@ -631,19 +657,27 @@ nl: page_view_anon_reqs: title: "Anoniem" xaxis: "Dag" + yaxis: "Anonieme paginaweergaven" page_view_logged_in_reqs: title: "Ingelogd" xaxis: "Dag" + yaxis: "Ingelogde paginaweergaven" page_view_crawler_reqs: title: "Web Crawlers" xaxis: "Dag" + yaxis: "Web Crawler paginaweergaven" page_view_total_reqs: title: "Totaal" xaxis: "Dag" + yaxis: "Totaal paginaweergaven" page_view_logged_in_mobile_reqs: + title: "Ingelogde paginaweergaven" xaxis: "Dag" + yaxis: "Mobiele ingelogde paginaweergaven" page_view_anon_mobile_reqs: + title: "Anonieme paginaweergaven" xaxis: "Dag" + yaxis: "Mobiele anonieme paginaweergaven" http_background_reqs: title: "Achtergrond" xaxis: "Dag" @@ -789,9 +823,7 @@ nl: top_page_default_timeframe: "Standaard tijdspanne voor de top overzicht pagina." show_email_on_profile: "Laat e-mail van gebruikers zien in hun profiel (alleen zichtbaar voor henzelf en staf)" email_token_valid_hours: "Wachtwoord vergeten / activeer account tokens zijn (n) uur geldig." - email_token_grace_period_hours: "Wachtwoord vergeten / activeer account tokens zijn nog geldig gedurende een respijtperiode van (n) uur na het benutten." enable_badges: "Activeer het badgesysteem" - enable_whispers: "Sta private communicatie tussen medewerkers toe in een topic. (experimenteel)" allow_index_in_robots_txt: "Specificeer in robots.txt dat de site geïndexeerd mag worden door zoekmachines." email_domains_blacklist: "Een lijst van e-maildomeinen gescheiden door een vertikaal streepje (pipe), die niet worden toegestaan. Voorbeeld: mailingen.com|trashmail.net" email_domains_whitelist: "Een lijst van e-maildomeinen gescheiden door een vertikaal streepje (pipe), die zijn voorgeschreven om te worden toegelaten. WAARSCHUWING: Gebruikers met andere e-maildomeinen dan opgenomen in de lijst worden NIET toegelaten." @@ -1018,7 +1050,6 @@ nl: embed_whitelist_selector: "CSS-selector voor de elementen die zijn toegestaan in invoegberichten." embed_blacklist_selector: "CSS-selector voor de elementen die zijn verwijderd uit invoegberichten." notify_about_flags_after: "Als er vlaggen zijn die nog niet zijn afgehandeld na dit aantal uren, stuur dan een e-mail naar de contact_email. Zet op 0 om uit te schakelen." - enable_cdn_js_debugging: "Laat /logs juiste errors weergeven door crossorigin toestemmingen toe te voegen op alle js includes." show_create_topics_notice: "Als de site minder dan 5 publieke topics heeft, toon dan een melding waarin admins gevraagd wordt om een aantal topics te creëren." delete_drafts_older_than_n_days: Verwijder concepten ouder dan (n) dagen. prevent_anons_from_downloading_files: "Voorkom dat anonieme gebruikers bijlagen mogen downloaden. WAARSCHUWING: hierdoor zullen website onderdelen, anders dan afbeeldingen, die zijn gepost als bijlage niet langer werken." @@ -1225,21 +1256,43 @@ nl: welcome_invite: subject_template: "Welkom bij %{site_name}!" backup_succeeded: + title: "Backup Geslaagd" subject_template: "Backup succesvol uitgevoerd" backup_failed: + title: "Backup Mislukt" subject_template: "Backup mislukt" restore_succeeded: + title: "Terugzetten van backup geslaagd" subject_template: "Het terugzetten van de backup is geslaagd." restore_failed: + title: "Terugzetten van backup mislukt" subject_template: "Terugzetten van backup is mislukt" bulk_invite_succeeded: + title: "Bulk Uitnodiging Geslaagd" subject_template: "Massale uitnodiging aan gebruikers met succes verwerkt" text_body_template: "Je bestand voor een massale uitnodiging aan gebruikers is verwerkt. Er zijn %{sent} uitnodigingen verstuurd." bulk_invite_failed: + title: "Groepsuitnodiging Mislukt" subject_template: "Massale uitnodiging aan gebruikers verwerkt, met fouten" + text_body_template: | + Je bestand met gebruikers uitnodigingen is verwerkt, %{sent} uitnodigingen zijn verzonden met %{failed} fout(en). + + Verslag: + + ``` + %{logs} + ``` csv_export_succeeded: + title: "CSV Export Geslaagd" subject_template: "Export succesvol afgerond." + text_body_template: | + Data export was succesvol!:dvd: + + %{file_name} (%{file_size}) + + Bovenstaande download link is 48 uur geldig. csv_export_failed: + title: "CSV Export Mislukt" subject_template: "Export mislukt" text_body_template: "Het spijt ons, maar de export is mislukt. Bekijk de logbestanden of neem contact op met de staf." email_reject_insufficient_trust_level: @@ -1328,8 +1381,23 @@ nl: subject_template: "[%{site_name}] E-mailprobleem -- Automatisch gegenereerde reactie" email_error_notification: subject_template: "[%{site_name}] Email probleem -- POP authenticatie fout" + blocked_by_staff: + subject_template: "Account tijdelijk geblokkeerd" + user_automatically_blocked: + title: "Gebruiker Automatisch Geblokkeerd" + subject_template: "Nieuwe gebruiker %{username} geblokkeerd wegens meldingen van andere gebruikers" spam_post_blocked: + title: "Spam bericht geblokkeerd" subject_template: "Berichten van nieuwe gebruiker %{username} geblokkeerd vanwege herhaalde links" + unblocked: + title: "Gedeblokkeerd" + subject_template: "Account niet langer geblokkeerd" + text_body_template: | + Hallo, + + Dit is een automatisch bericht van %{site_name} om je te informeren dat de staff naar je account hebben gekeken en je account is nu niet langer geblokkeerd. + + Je kan weer nieuwe topics beginnen en reageren op bestaande topics. Bedankt voor je geduld. pending_users_reminder: subject_template: one: "1 gebruiker wacht op goedkeuring" @@ -1340,6 +1408,8 @@ nl: [Beoordeel deze gebruikers in het admingedeelte](/admin/users/list/pending). download_remote_images_disabled: subject_template: "Het downloaden van externe afbeeldingen is uitgeschakeld" + dashboard_problems: + title: "Dashboard Problemen" subject_re: "Re:" subject_pm: "[PM]" user_notifications: @@ -1496,6 +1566,27 @@ nl: initial_topic_title: Performancerapportages van de website topic_invite: user_exists: "Sorry, die gebruiker is al uitgenodigd. Je kan een gebruiker maar een keer voor een topic uitnodigen." + safe_mode: + no_customizations: "Alle website-aanpassingen uitschakelen" + only_official: "Niet-officiële plug-ins uitschakelen" + no_plugins: "Alle plug-ins uitschakelen" + wizard: + step: + forum_title: + title: "Naam" + homepage: + fields: + homepage_style: + choices: + categories: + label: "Categorieën" + invites: + description: "Je bent bijna klaar! Nodig wat stafleden uit om te helpen met het starten van discussies met interessante topics en berichten om je gemeenschap op te zetten." + finished: + title: "Je Discourse staat klaar!" + description: | +

    Als je deze instellingen ooit aan wilt passen, bezoek dan je beheerafdeling; vind het naast het moersleutelicoon in het sitemenu.

    +

    Veel plezier, en succes met het opbouwen van je nieuwe gemeenschap!

    activemodel: errors: <<: *errors diff --git a/config/locales/server.pl_PL.yml b/config/locales/server.pl_PL.yml index fd70af35f59..b18d5fd7e47 100644 --- a/config/locales/server.pl_PL.yml +++ b/config/locales/server.pl_PL.yml @@ -15,6 +15,7 @@ pl_PL: short: "%d.%m.%Y" short_no_year: "%-d %B" date_only: "%-d %b %Y" + long: "%B %-d, %Y, %l:%M%P" date: month_names: [null, Styczeń, Luty, Marzec, Kwiecień, Maj, Czerwiec, Lipiec, Sierpień, Wrzesień, Październik, Listopad, Grudzień] <<: *datetime_formats @@ -28,13 +29,17 @@ pl_PL: loading: "Ładowanie" powered_by_html: 'Zasilane przez Discourse, najlepiej oglądać z włączonym JavaScriptem' log_in: "Logowanie" + purge_reason: "Automatycznie usunięte jako porzucone, dezaktywowane konto." disable_remote_images_download_reason: "Pobieranie zewnętrznych grafik zostało wyłączone z uwagi na niską ilość wolnego miejsca na dysku." anonymous: "Anonim" + remove_posts_deleted_by_author: "Usunięte przez autora" emails: incoming: default_subject: "Przychodzący email od %{email}" show_trimmed_content: "Pokaż skróconą zawartość" + maximum_staged_user_per_email_reached: "Osiągnięto maksymalną ilość użytkowników zarejestrowanych przez email." errors: + empty_email_error: "Zdarza się kiedy mail jaki dostaliśmy jest pusty." no_message_id_error: "Zdarza się kiedy email nie posiada nagłówka 'Message-Id'." inactive_user_error: "Zdarza się kiedy nadawca jest nie aktywny." blocked_user_error: "Zdarza się kiedy nadawca jest zablokowany." @@ -95,11 +100,13 @@ pl_PL: default_categories_already_selected: "Nie możesz wybrać kategorii użytej w innej liście." s3_upload_bucket_is_required: "Nie możesz wysyłać na S3 jeżeli nie podasz 's3_upload_bucket'." bulk_invite: - file_should_be_csv: "Wysłany plik powinien być w formacie CSV lub TXT." + file_should_be_csv: "Wgrywany plik powinien być formatu csv." + error: "Wystąpił błąd podczas wgrywania tego pliku. Spróbuj ponownie później." backup: operation_already_running: "Operacja jest już uruchomiona. Nie można teraz utworzyć nowej." backup_file_should_be_tar_gz: "Plik z kopią zapasową powinien mieć postać archiwum .tar.gz." not_enough_space_on_disk: "Nie ma wystarczającej ilości wolnego miejsca, aby wczytać tę kopię zapasową." + invalid_filename: "Plik kopii zapasowej zawiera nieprawidłowe znaki. Nieprawidłowe znaki to a-z 0-9 . - _." not_logged_in: "Aby to zrobić musisz się zalogować." not_found: "Żądany URL lub źródło nie mógł zostać znaleziony." invalid_access: "Nie jesteś uprawniony, by zobaczyć żądane źródło." @@ -172,7 +179,7 @@ pl_PL: email_already_used_in_category: "'%{email}' jest już używany przez kategorię '%{category_name}'." default_names: everyone: "wszyscy" - admins: "admini" + admins: "administratorzy" moderators: "moderatorzy" staff: "zespół" trust_level_0: "poziom_zaufania_0" @@ -248,6 +255,7 @@ pl_PL: name: "Nazwa kategorii" topic: title: 'Tytuł' + featured_link: 'Polecany link' post: raw: "Treść" user_profile: @@ -261,12 +269,16 @@ pl_PL: too_many_users: "Jedno ostrzeżenie możesz wysłać tylko do pojedynczego użytkownika." cant_send_pm: "Przepraszamy, niestety nie możesz wysłać prywatnej wiadomości temu użytkownikowi." no_user_selected: "Musisz wybrać poprawnego użytkownika," + featured_link: + invalid: "Link jest nieprawidłowy, powinien zawierać http:// lub https://." + invalid_category: "nie może być edytowany w tej kategorii." user: attributes: password: common: "jest jednym z 10000 najczęściej używanych haseł. Wybierz inne, bardziej bezpieczne hasło." same_as_username: "jest takie same jak Twoja nazwa użytkownika. Proszę użyj bardziej bezpiecznego hasła. " same_as_email: "jest takie same jak Twój email. Proszę użyj bardziej bezpiecznego hasła. " + same_as_current: "Hasło jest takie same jak aktualne." ip_address: signup_not_allowed: "Rejestracja z tego konta jest niemożliwa." color_scheme_color: @@ -276,6 +288,10 @@ pl_PL: post_reply: base: different_topic: "Wpis i odpowiedź muszą należeć do tego samego tematu." + web_hook: + attributes: + payload_url: + invalid: "Link jest nieprawidłowy, powinien zawierać http:// lub https://. Puste pole jest niedozwolone." <<: *errors user_profile: no_info_me: "
    Pole O mnie w Twoim profilu jest obecnie puste, czy chcesz je wypełnić?
    " @@ -327,6 +343,7 @@ pl_PL: few: "Nie można usunąć tej kategorii ponieważ zawiera %{count} tematy. Najstarszy z nich: %{topic_link}." other: "Nie można usunąć tej kategorii ponieważ zawiera %{count} tematów. Najstarszy z nich: %{topic_link}." topic_exists_no_oldest: "Nie można usunąć tej kategorii z uwagi na liczbę tematów: %{count}." + uncategorized_description: "Tematy które nie potrzebują kategorii, albo nie nadają się do żadnej innej." trust_levels: newuser: title: "nowy" @@ -334,6 +351,8 @@ pl_PL: title: "początkujący" member: title: "uczestnik" + regular: + title: "zwyczajny" leader: title: "lider" change_failed_explanation: "Twoja próba obniżenia poziomu %{user_name} do '%{new_trust_level}' była nieudana. Ten użytkownik posiada już poziom '%{current_trust_level}'. %{user_name} pozostanie na poziomie '%{current_trust_level}' - jeśli chcesz to zmienić, najpierw zablokuj poziom zaufania temu użytkownikowi." @@ -515,6 +534,12 @@ pl_PL: title: 'Głosuj' description: 'Głosuj za tym wpisem' long_form: 'zagłosowano za tym wpisem' + user_activity: + no_bookmarks: + others: "Brak zakładek." + no_likes_given: + self: "Nie masz lajkowanych postów." + others: "Brak lajkowanych postów." topic_flag_types: spam: title: 'Spam' @@ -540,6 +565,8 @@ pl_PL: message: make: "Ten temat został ustawiony jako baner. Będzie pojawiać się na górze każdej strony do czasu zamknięcia przez użytkownika." remove: "Ten temat nie jest już banerem. Nie będzie pojawiać się na górze każdej strony." + unsubscribed: + title: "Od subskrybuj!" unsubscribe: title: "Wypisz" stop_watching_topic: "Przestań obserwować ten temat, %{link}" @@ -550,8 +577,16 @@ pl_PL: log_out: "Wyloguj" user_api_key: title: "Zezwolić na dostęp aplikacji" + authorize: "Autoryzuj" read: "odczyt" read_write: "odzczyt/zapis" + scopes: + message_bus: "Aktualizacje" + notifications: "Przeczytaj i wyczyść powiadomienia" + push: "Powiadomienia push dla zewnętrznych usług" + session_info: "Czytaj informację o sesji użytkowników" + read: "Czytaj wszystko." + write: "Zapisz wszystko" reports: visits: title: "Wizyty użytkowników" @@ -635,19 +670,27 @@ pl_PL: page_view_anon_reqs: title: "Anonimowy" xaxis: "Dzień" + yaxis: "Anonimowe odsłony" page_view_logged_in_reqs: title: "Zalogowany" xaxis: "Dzień" + yaxis: "Zalogowane odsłony" page_view_crawler_reqs: title: "Bot indeksujący" xaxis: "Dzień" + yaxis: "Odsłony botów indeksujących" page_view_total_reqs: title: "Łącznie" xaxis: "Dzień" + yaxis: "Wszystkie odsłony" page_view_logged_in_mobile_reqs: + title: "Zalogowane odsłony" xaxis: "Dzień" + yaxis: "Odsłony użytkowników mobilnych" page_view_anon_mobile_reqs: + title: "Anonimowe odsłony" xaxis: "Dzień" + yaxis: "Odsłony anonimowych użytkowników mobilnych" http_background_reqs: title: "Tło" xaxis: "Dzień" @@ -707,10 +750,14 @@ pl_PL: min_first_post_length: "Minimalna długość treści (liczba znaków) pierwszego wpisu w temacie " min_private_message_post_length: "Minimalna długość treści wiadomości " max_post_length: "Maksymalna długość wpisu, w znakach" + topic_featured_link_enabled: "Włącz dodawanie linków w tematach." + show_topic_featured_link_in_digest: "Pokazuj polecany link tematu w podsumowaniu mailowym." min_topic_title_length: "Minimalna długość tytułu tematu, w znakach" max_topic_title_length: "Maksymalna długość tytułu tematu, w znakach" min_private_message_title_length: "Minimalna liczba znaków w temacie wiadomości " min_search_term_length: "Minimalna długość wyszukiwanego tekstu, w znakach" + search_prefer_recent_posts: "Jeśli wyszukiwanie na twoim duży forum jest wolne, ta opcja pozwala zaindeskować ostanie posty wpierw." + search_recent_posts_size: "Jak dużo ostanich postów trzymać w indexie" allow_uncategorized_topics: "Zezwól na tworzenie tematów bez kategorii. UWAGA: jeśli jest jakiś nieskategoryzowany temat, musisz go przypisać do kategorii, zanim wyłączysz tę opcję." allow_duplicate_topic_titles: "Pozwól na tworzenie tematów o identycznych tytułach." unique_posts_mins: "Ile minut musi upłynąć zanim użytkownik będzie mógł ponownie zrobić wpis z tą samą treścią" @@ -736,6 +783,7 @@ pl_PL: fixed_category_positions_on_create: "Jeżeli jest sprawdzone to porządkowanie kategorii będzie zależało od stworzonego tematu (requires fixed_category_positions). " post_excerpt_maxlength: "Maksymalna długość podsumowania / streszczenia wpisu." post_onebox_maxlength: "Maksymalna długość (ilość znaków) treści wpisu osadzonego via Onebox" + max_oneboxes_per_post: "Masymalna ilość oneboxów w poście." logo_url: "Zdjęcie logo w lewym górnym rogu twojej strony powinno mieć kształt szerokiego prostokąta. Jeśli zostawisz miejsce puste, wyświetlany będzie tytuł strony." apple_touch_icon_url: "Ikona używana przez urządzenia Apple. Rekomendowany wymiar to 144px na 144px." notification_email: "Adres z którego wysyłane będą wszystkie istotne emaile systemowe.\nKonieczna jest poprawna konfiguracja rekordów SPF, DKIM oraz zwrotnego PTR użytej domeny." @@ -768,6 +816,7 @@ pl_PL: show_email_on_profile: "Pokazuj email użytkownika w jego profilu (widoczny jedynie dla użytkownika i personelu)." email_token_valid_hours: "Tokeny resetujące hasło / aktywujące konto są ważne przez (n) godzin." enable_badges: "Włącz system odznak" + enable_whispers: "Pozwalaj administracji na prywatną rozmowę w tematach." log_out_strict: "Po wylogowaniu wyloguj WSZYSTKIE sesje użytkownika na wszystkich urządzeniach." port: "OSTRZEŻENIE! Tylko dla Developera! Użyj ten port HTTP zamiast domyślnego portu 80. Pozostaw puste pole, domyślnie port 80" force_hostname: "OSTRZEŻENIE! Tylko dla Developera! Określ nazwę hosta w adresie URL. Pozostaw domyślnie puste." @@ -854,6 +903,7 @@ pl_PL: reply_by_email_address: "Template for reply by email incoming email address, for example: %{reply_key}@reply.example.com or replies+%{reply_key}@example.com" ignore_by_title: "Ignoruj przychodzące wiadomości e-mail w oparciu o ich tytuł." pop3_polling_ssl: "Używaj SSL podczas łączenia z serwerem POP3. (Rekomendowane)" + pop3_polling_openssl_verify: "Sprawdź certyfikat TLS serwera (domyślnie: włączone)" relative_date_duration: "Liczba dni od wysłania wpisu gdy wyświetlana jest data relatywna (7d) zamiast absolutnej (20 Lut)." delete_all_posts_max: "The maximum number of posts that can be deleted at once with the Delete All Posts button. If a user has more than this many posts, the posts cannot all be deleted at once and the user can't be deleted." email_editable: "Allow users to change their e-mail address after registration." @@ -868,8 +918,11 @@ pl_PL: enable_emoji: "Włącz obsługę emoji" emoji_set: "Jaki jest twój preferowany styl emoji?" approve_unless_trust_level: "Posty użytkowników poniżej tego poziomu zaufania muszą być zatwierdzane" + default_other_external_links_in_new_tab: "Otwórz linki zewnętrzne w nowej karcie domyślnie." default_categories_watching: "Lista kategorii obserwowanych domyślnie." default_categories_tracking: "Lista kategorii śledzonych domyślnie." + company_short_name: "Nazwa firmy (skrócona)" + company_full_name: "Nazwa firmy (pełna)" errors: invalid_email: "Nieprawidłowy adres email." invalid_username: "Użytkownik o takiej nazwie nie istnieje." @@ -1054,6 +1107,12 @@ pl_PL: csv_export_failed: subject_template: "Nieudany eksport danych" text_body_template: "Przepraszamy, ale eksport danych zakończył się niepowodzeniem. Sprawdź logi lub skontaktuj się z operatorami serwisu." + too_many_spam_flags: + subject_template: "Nowe konto zawieszone" + too_many_tl3_flags: + subject_template: "Nowe konto zawieszone" + blocked_by_staff: + subject_template: "Konto tymczasowo zawieszone" pending_users_reminder: subject_template: one: "1 użytkownik czeka na zatwierdzenie" @@ -1078,7 +1137,23 @@ pl_PL: user_posted_pm: subject_template: "[%{site_name}] [PW] %{topic_title}" digest: + new_topics: "Nowe tematy" + new_posts: "Nowe wpisy" + new_users: "Nowi użytkownicy" + popular_topics: "Popularne tematy" + follow_topic: "Śledź ten temat" + join_the_discussion: "Czytaj więcej" + popular_posts: "Popularne wpisy" + from_topic_label: "Od" + subject_template: "%{site_name} Podsumowanie" click_here: "kliknij tutaj" + from: "%{site_name} podsumowanie" + mailing_list: + from: "%{site_name} podsumowanie" + new_topics: "Nowe tematy" + topic_updates: "Aktualizacje tematu" + view_this_topic: "Zobacz ten temat" + back_to_top: "Powrót do góry" forgot_password: subject_template: "[%{site_name}] Reset hasła" text_body_template: | @@ -1104,6 +1179,8 @@ pl_PL: Kliknij na linku poniżej, aby ustawić swoje hasło: %{base_url}/users/password-reset/%{email_token} + confirm_old_email: + subject_template: "[%{site_name}] Potwierdź aktualny adres email" signup_after_approval: subject_template: "Zostałeś zaakceptowany na forum %{site_name}!" text_body_template: |+ @@ -1134,6 +1211,7 @@ pl_PL: Jeśli powyższy link nie jest klikalny, spróbuj skopiować i wkleić go do pasku adresu Twojej przeglądarki. page_not_found: + title: "Ups! Ta strona nie istnieje lub jest prywatna." popular_topics: "Popularne" recent_topics: "Ostatnie" see_more: "Więcej" @@ -1153,15 +1231,19 @@ pl_PL: edit_reason: "lokalne kopie pobranych obrazów" unauthorized: "Sorry, the file you are trying to upload is not authorized (authorized extensions: %{authorized_extensions})." pasted_image_filename: "Wklejone zdjęcie" + file_missing: "Przepraszamy, należy podać plik do przesłania." images: size_not_found: "Przepraszamy, ale nie udało się ustalić rozmiaru obrazu. Może twój obraz jest uszkodzony?" email_log: no_user: "Nie można znaleźć użytkownika z ID %{user_id}" + anonymous_user: "Użytkownik anonimowy" post_deleted: "Wpis został usunięty przez autora" user_suspended: "użytkownik został zawieszony" already_read: "użytkownik przeczytał ten post" + message_blank: "wiadomość jest pusta" color_schemes: base_theme_name: "Podstawa" + about: "O stronie" guidelines: "Przewodnik" privacy: "Prywatność" edit_this_page: "Edytuj tę stronę" @@ -1176,6 +1258,13 @@ pl_PL: title: "Warunki użytkowania" privacy_topic: title: "Polityka prywatności" + badges: + first_mention: + name: Pierwsze Wspomnienie + first_onebox: + name: Pierwszy Onebox + first_reply_by_email: + name: Pierwsza Odpowiedz przez Email admin_login: success: "Email wysłany" error: "Błąd!" @@ -1186,6 +1275,85 @@ pl_PL: performance_report: initial_post_raw: 'Ten temat zawiera codzienne raporty wydajności dla twojej witryny. ' initial_topic_title: 'Testy wydajności witryny. ' + safe_mode: + no_customizations: "Wyłącz własną personalizację strony" + only_official: "Wyłącz nieoficjalne wtyczki" + no_plugins: "Wyłącz wszystkie wtyczki" + enter: "Włącz Tryb Bezpieczny" + wizard: + title: "Instalacja Discourse" + step: + forum_title: + title: "Imię" + privacy: + title: "Dostęp" + fields: + privacy: + choices: + open: + label: "Publiczne" + description: "Wszyscy mają dostęp do społeczności, mogą się rejestrować aby zakładać konta" + restricted: + label: "Prywatne" + description: "Tylko osoby zaproszone mają dostęp do społeczności" + contact: + title: "Dane kontaktowe" + fields: + contact_email: + label: "E-mail" + placeholder: "name@example.com" + contact_url: + label: "Strona kontaktowa" + site_contact: + label: "Automatyczne wiadomości" + corporate: + title: "Organizacja" + fields: + company_short_name: + label: "Nazwa organizacji (krótka)" + placeholder: "Initech" + company_full_name: + label: "Nazwa organizacji (pełna)" + placeholder: "Initech, Inc." + company_domain: + label: "Domena Organizacji" + placeholder: "initech.com" + colors: + title: "Motyw" + fields: + theme_id: + choices: + default: + label: "Prosty Jasny" + dark: + label: "Prosty Ciemny" + logos: + title: "Loga" + fields: + logo_url: + label: "Podstawowe logo" + icons: + title: "Ikony" + fields: + favicon_url: + label: "Mała ikona" + apple_touch_icon_url: + label: "Duża ikona" + homepage: + title: "Strona Główna" + fields: + homepage_style: + choices: + latest: + label: "Ostatnie Tematy" + categories: + label: "Kategorie" + emoji: + title: "Emotikony" + invites: + title: "Zaproś administrację" + finished: + title: "Twój Discourse jest Gotowy!" activemodel: errors: <<: *errors diff --git a/config/locales/server.pt.yml b/config/locales/server.pt.yml index 51436d27118..bffebe7ea04 100644 --- a/config/locales/server.pt.yml +++ b/config/locales/server.pt.yml @@ -106,7 +106,8 @@ pt: default_categories_already_selected: "Não pode selecionar uma categoria usada noutra lista." s3_upload_bucket_is_required: "Não pode ativar carregamentos para o S3 excepto se tiver fornecido o 's3_upload_bucket'." bulk_invite: - file_should_be_csv: "O ficheiro a carregar deve estar em formato csv ou txt." + file_should_be_csv: "O ficheiro carregado deve ser do formato CSV." + error: "Ocorreu um erro ao carregar esse ficheiro. Por favor tente mais tarde." backup: operation_already_running: "Existe atualmente uma operação em execução. Neste momento não é possível iniciar um novo trabalho. " backup_file_should_be_tar_gz: "O ficheiro da cópia de segurança deve ser um arquivo .tar.gz" @@ -272,6 +273,7 @@ pt: name: "Nome da Categoria" topic: title: 'Título' + featured_link: 'Ligação Destacada' post: raw: "Corpo" user_profile: @@ -285,6 +287,9 @@ pt: too_many_users: "Apenas pode enviar avisos a um utilizador de cada vez." cant_send_pm: "Pedimos desculpa, não pode enviar uma mensagem privada a esse utilizador." no_user_selected: "Tem que selecionar um utilizador válido." + featured_link: + invalid: "é inválida. URL deve incluir http:// ou https://." + invalid_category: "não pode ser editada nesta categoria." user: attributes: password: @@ -771,6 +776,8 @@ pt: min_first_post_length: "Tamanho mínimo permitido para a primeira mensagem (corpo do tópico), em caracteres" min_private_message_post_length: "Tamanho mínimo permitido para mensagens, em caracteres" max_post_length: "Tamanho máximo permitido por mensagem, em caracteres" + topic_featured_link_enabled: "Permitir publicar uma ligação com tópicos." + show_topic_featured_link_in_digest: "Mostrar a ligação destacada do tópico no email de resumo." min_topic_title_length: "Tamanho mínimo permitido por título de cada tópico, em caracteres" max_topic_title_length: "Tamanho máximo permitido por título de cada tópico, em caracteres" min_private_message_title_length: "Tamanho mínimo permitido por título nas mensagens, em caracteres" @@ -879,9 +886,8 @@ pt: show_email_on_profile: "Mostrar o email do utilizador no seu perfil (apenas visível para si próprio e para o pessoal)" prioritize_username_in_ux: "Mostrar o nome de utilizador primeiro na página de utilizador, cartão de utilizador e publicações (quando o nome desactivado é mostrado primeiro)" email_token_valid_hours: "Os símbolos para palavra-passe esquecida /conta ativada são válidos por (n) horas." - email_token_grace_period_hours: "Os símbolos para palavra-passe esquecida /conta ativada são válidos por um período de carência de (n) horas após serem recuperados" enable_badges: "Ativar o sistema de distintivos" - enable_whispers: "Permitir comunicação privada do pessoal dentro de tópico (experimental)" + enable_whispers: "Permitir à equipa de apio comunicar de forma privada dentro de tópicos." allow_index_in_robots_txt: "Especificar em robots.txt que este sítio permite ser indexado pelos motores de pesquisa." email_domains_blacklist: "Lista de domínios de email que os utilizadores não podem usar para registo de contas. Exemplo: mailinator.com|trashmail.net" email_domains_whitelist: "Lista de domínios de email que os utilizadores DEVEM usar para registar contas. AVISO: Utilizadores com domínios de email diferentes dos listados não serão permitidos!" @@ -1181,7 +1187,6 @@ pt: embed_whitelist_selector: "Seletor CSS para elementos permitidos em incorporações." embed_blacklist_selector: "Seletor CSS para elementos que foram removidos de incorporações." notify_about_flags_after: "Se houver sinalizações que não tenham sido tratadas após tantas horas, envie um email para 'contact_email'. Configurar a 0 para desativar." - enable_cdn_js_debugging: "Permitir que /logs exiba erros próprios ao adicionar permissões de origem-cruzada em todos os js incluídos." show_create_topics_notice: "Se o sítio tem menos de 5 tópicos públicos, mostrar um aviso pedindo aos administradores a criação de mais tópicos." delete_drafts_older_than_n_days: Eliminar rascunhos mais antigos que (n) days. bootstrap_mode_min_users: "Número mínimo de utilizadores necessários para desactivar o modo de inicialização (coloque 0 para desactivar)" @@ -1447,36 +1452,8 @@ pt: Este convite é de um utilizador confiável, por isso pode responder ao debate imediatamente. invite_forum_mailer: subject_template: "%{invitee_name} convidou-o a juntar-se a %{site_domain_name}" - text_body_template: | - %{invitee_name} convidou-o para - - > **%{site_title}** - > - > %{site_description} - - Se está interessado, clique na ligação abaixo: - - %{invite_link} - - Este convite é de um utilizador confiável, por isso uma conta será criada para si automaticamente. custom_invite_forum_mailer: subject_template: "%{invitee_name} convidou-o para %{site_domain_name}" - text_body_template: | - %{invitee_name} convidou-o para - - > **%{site_title}** - > - > %{site_description} - - Mensagem de %{invitee_name}: - - %{user_custom_message} - - Se está interessado, clique na ligação abaixo: - - %{invite_link} - - Este convite é de um utilizador confiável, por isso uma conta será criada para si automaticamente. invite_password_instructions: subject_template: "Configurar a palavra-passe para a sua conta %{site_name}" text_body_template: | @@ -1596,99 +1573,6 @@ pt: Contudo, se a publicação for ocultada pela comunidade uma segunda vez, irá manter-se ocultada até ser tratada pelo pessoal – e poderão ocorrer outras medidas, incluindo uma possível suspensão da sua conta. Para orientação adicional, por favor consulte as [orientações da comunidade](%{base_url}/guidelines). - usage_tips: - text_body_template: | - Aqui ficam algumas dicas para que possa começar: - - ## Leitura - - Para ler mais, **simplesmente continue a arrastar para baixo!** - - À medida que novas respostas ou novos tópicos surgem, estes irão surgir automaticamente – não é necessário atualizar a página. - - ## Navegação - - - Para pesquisar, a sua página de utilizador, ou o menu , utilize **os botões-ícone no canto superior direito**. - - - A selecção de um título do tópico leva-o sempre para a **próxima resposta não lida** no tópico. Para entrar na parte superior ou inferior, seleccione a contagem de respostas ou última data de resposta. - - - - - Ao ler um tópico, selecione a linha do tempo à direita para saltar para o topo, fundo, ou a última posição lida. Em ecrãs mais pequenos, selecione a barra de progresso no canto inferior direito para expandi-la: - - - - Também pode premir ? no seu teclado para mostrar uma lista de atalhos de teclado super-rápidos. - - ## Responder - - Para inserir uma citação, selecione o texto que deseja citar, e de seguida prima qualquer botão de Responder para abrir o editor. Repita para múltiplas citações. - - - - Pode continuar sempre a ler enquanto compõe a sua resposta, e nós automaticamente guardamos rascunhos enquanto escreve. - - Para notificar alguém sobre a sua resposta, mencione o nome correspondente. Escreva `@` para começar a selecionar um nome de utilizador. - - - - Para utilizar [Emoji padrão](http://www.emoji.codes/), simplesmente digite `:` para encontrar por nome, ou as tradicionais carinhas risonhas `;)` - - - - Para gerar um sumário para uma ligação, cole-o numa linha por si só: - - - - A sua resposta pode ser formatada com HTML simplificado, BBCode ou [Markdown](http://commonmark.org/help/): - - Isto é negrito. - Isto é [b]negrito[/b]. - Isto é **negrito**. - - Para mais dicas sobre formatação, [experimente o nosso tutorial interactivo de 10mn!](http://commonmark.org/help/tutorial/) - - ## Acções - - Existem botões de acção no final de cada publicação: - - - - - Para deixar alguém saber que desfrutou e apreciou as suas mensagens, utilize o botão **gosto**. Partilhe o amor! - - - Obtenha uma ligação copiável e colável para qualquer resposta ou tópico via o botão **ligação**. - - - Use o botão mostrar mais para revelar mais ações. **Denuncie** para privadamente deixar o autor, ou [a nossa equipa de apoio](%{base_url}/about), saber sobre um problema. **Adicione um marcador** para encontrar esta publicação mais tarde na sua página de perfil. - - ## Notificações - - Quando alguém lhe responde, cita a sua publicação ou menciona o seu `@nome-de-utilizador`, um número irá aparecer imediatamente no canto superior direito na página. Selecione-o para aceder às suas **notificações**. - - - - Não se preocupe com perder uma resposta – irá receber por email quaisquer notificações que chegarem enquanto estiver ausente. - - ## Preferências - - - Todos os tópicos com menos de **dois dias de idade** são considerados novos. - - - Qualquer tópico em que tenha **participado activamente** (criado, respondido, ou lido por um período extenso) será automaticamente seguido em seu nome. - - Verá os indicadores numéricos de respostas novas e não lidas junto destes tópicos: - - - - Pode alterar as suas notificações para qualquer tópico através do controlo de notificações no final, e no lado direito, de cada tópico. - - - - Pode também configurar estados de notificação por categoria, se quiser vigiar ou silenciar cada novo tópico numa categoria específica. - - Para mudar qualquer uma destas preferências, veja [as suas preferências de utilizador](%{base_url}/my/preferences). - - ## Confiança da Comunidade - - É fantástico encontra-lo aqui! À medida que for participando aqui, iremos conhecendo-lo, e as suas limitações temporárias de novo utlizador serão levantadas. Continue a participar, e ganhará novos [níveis de confiança](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924), que incluem abilidades especiais para nos ajudar a gerir a nossa comunidade juntos. welcome_user: subject_template: "Bem-vindo a %{site_name}!" text_body_template: | @@ -1703,26 +1587,6 @@ pt: (Se precisar de comunicar com [membros do pessoal](%{base_url}/about) como um novo utilizador, simplesmente responda a esta mensagem.) welcome_invite: subject_template: "Bem-vindo a %{site_name}!" - text_body_template: | - Obrigado por ter aceitado o convite para %{site_name} -- bem-vindo! - - Criámos uma nova conta **%{username}** para si, e neste momento encontra-se com sessão iniciada. Pode mudar o seu nome ao visitar [o seu perfil de utilizador][prefs]. - - Para iniciar sessão novamente mais tarde: - - 1. Use sempre **o mesmo endereço de email do convite original** quando iniciar sessão. De outra forma não saberemos que é você! - - 2. Crie uma palavra-passe única para [o seu perfil de utilizador][prefs], e use-o para iniciar sessão. - - %{new_user_tips} - - Nós acreditamos num [comportamento civilizado da comunidade](%{base_url}/guidelines) em qualquer altura. - - Desfrute da sua estadia! - - (Se precisar de comunicar com [membros do pessoal](%{base_url}/about) como um novo utilizador, simplesmente responda a esta mensagem.) - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "Cópia de segurança completa corretamente" text_body_template: | @@ -2176,7 +2040,6 @@ pt: join_the_discussion: "Ler Mais" popular_posts: "Publicações Populares" from_topic_label: "De" - more_new: "Novidades em tópicos e categorias que acompanha" subject_template: "Sumário de [%{site_name}] " unsubscribe: "Este resumo é enviado de %{site_link} quando não o vemos há algum tempo. Para anular a subscrição %{unsubscribe_link}." click_here: "clique aqui" @@ -2935,11 +2798,9 @@ pt: fields: welcome: label: "Tópico de Boas-vindas" - description: "

    Como é que descreveria a sua comunidade a um estranho num elevador em cerca de 1 minuto?

    • Para quem são estas conversas?
    • O que posso encontrar aqui?
    • Porque devo vir cá?

    O tópico de boas-vindas é a primeira coisa que visitantes verão. Pense nele como num discurso curto ou introdução de um paragrafo.

    " one_paragraph: "Por favor limite a sua mensagem de boas-vindas a um paragrafo." privacy: title: "Acesso" - description: "

    A sua comunidade é aberta a todos, ou é restrita por inscrição, convite ou aprovação? Se preferir, pode configurar o sítio em privado, e depois torná-lo público.

    Lembre-se que pode sempre mandar convites a partir de um tópico, ou da sua página de utilizador também.

    " fields: privacy: choices: @@ -2965,7 +2826,6 @@ pt: description: "Todas as mensagens pessoais automatizadas do Discourse serão enviadas deste utilizador. Acima de tudo, este utilizador será o remetente de todas as mensagens de boas-vindas automaticamente enviadas a novos utilizadores." corporate: title: "Organização" - description: "Estes nomes serão introduzidos na sua Política de Privacidade, que pode editar a qualquer instante na categoria da Equipa de Apoio. Se não tiver uma empresa, sinta-se à vontade para saltar este passo." fields: company_short_name: label: "Nome da Empresa (curto)" @@ -2980,7 +2840,6 @@ pt: title: "Tema" fields: theme_id: - description: "Prefere um tema claro ou escuro para começar? Pode sempre personalizar a aparência do seu sítio via Administração, Personalizar." choices: default: label: "Claro Simples" @@ -3005,7 +2864,6 @@ pt: label: "Ícone Grande" description: "Imagem do ícone usado para representar o seu sítio em navegadores da internet que têm bom aspecto em tamanhos grandes como 144px por 144px." homepage: - description: "Recomendamos que mostre tópicos recentes na sua página de início, mas pode escolher mostrar categorias (grupos de tópicos) na sua página de início se preferir." title: "Página de início" fields: homepage_style: @@ -3016,7 +2874,6 @@ pt: label: "Categorias" emoji: title: "Emoji" - description: "Que estilo de Emoji prefere para a sua comunidade? Pode sempre adicionar mais Emoji personalizados via Administração, Personalizar, Emoji." invites: title: "Convidar Equipa de Apoio" description: "Está quase completo! Vamos convidar algumas pessoas para a equipa de apoio para ajudar a disseminar as suas conversas com tópicos e respostas interessantes para que a sua comunidade ganhe tração." diff --git a/config/locales/server.pt_BR.yml b/config/locales/server.pt_BR.yml index 878d528b56d..b84717e1c93 100644 --- a/config/locales/server.pt_BR.yml +++ b/config/locales/server.pt_BR.yml @@ -8,7 +8,7 @@ pt_BR: dates: short_date_no_year: "D MMM" - short_date: "D MMM, YYYY" + short_date: "D MMM, AAAA" long_date: "D de MMMM de YYYY h:mma" datetime_formats: &datetime_formats formats: @@ -105,8 +105,6 @@ pt_BR: max_username_length_range: "Você não pode definir o máximo abaixo no mínimo." default_categories_already_selected: "Você não pode selecionar uma categoria usada noutra lista." s3_upload_bucket_is_required: "Você não pode habilitar uploads para o S3 a não ser que tenha provido o 's3_upload_bucket'." - bulk_invite: - file_should_be_csv: "O arquivo enviado deve ser do formado csv ou txt." backup: operation_already_running: "Uma operação está sendo executada. Não é possível iniciar um novo trabalho agora." backup_file_should_be_tar_gz: "O arquivo de backup deve ser um arquivo .tar.gz." @@ -270,6 +268,7 @@ pt_BR: name: "Nome da Categoria" topic: title: 'Título' + featured_link: 'Link Em Destaque' post: raw: "Corpo" user_profile: @@ -531,6 +530,9 @@ pt_BR: title: 'Vote' description: 'Votar nesta postagem' long_form: 'voto computado para esta postagem' + user_activity: + no_bookmarks: + others: "Nenhum favorito." topic_flag_types: spam: title: 'Spam' @@ -866,9 +868,7 @@ pt_BR: show_email_on_profile: "Mostrar o email de um usuário em seus perfis (apenas visível a eles mesmos e staff)" prioritize_username_in_ux: "Mostrar primeiro o nome de usuário na página do usuário, cartão do usuário e publicações (quando desabilitado, o nome será mostrado primeiro) " email_token_valid_hours: "Tokens de Esqueceu senha / ativar conta são válidas por (n) horas." - email_token_grace_period_hours: "Tokens de esqueceu senha / ativar conta ainda serão válidas por um período extra de (n) horas depois de serem resgatados." enable_badges: "Habilita o sistema de emblemas" - enable_whispers: "Permitir comunicação privativa da equipe dentro de um tópico. (experimental)" allow_index_in_robots_txt: "Especificar no robots.txt que este site é permitido de ser indexado por sistemas de busca na web." email_domains_blacklist: "Lista delimitada por barras (|) de domínios de email que não são permitidos registros de contas. Exemplo: mailinator.com|trashmail.net" email_domains_whitelist: "Lista separada por barra (|) de domínios de email que usuários DEVEM usar para registrar contas. CUIDADO: Usuário com domínio de email diferentes da lista não serão permitidos!" @@ -1103,7 +1103,6 @@ pt_BR: embed_whitelist_selector: "Seletor CSS para os elementos que são permitidos em embeds." embed_blacklist_selector: "Selector CSS para elementos que são removidos dos embeds." notify_about_flags_after: "Se houver sinalizações sem ações após muitas horas, envia um e-mail para contact_email. Ajuste para 0 para desligar." - enable_cdn_js_debugging: "Permitir /logs de mostrar os devidos erros ao adicionar permissões de crossorigin em todos os includes de js." show_create_topics_notice: "Se o site tem menos de 5 tópicos públicos, mostrar um aviso pedindo para os administradores criarem alguns tópicos." delete_drafts_older_than_n_days: Apagar rascunhos mais antigos do que (N) dias. prevent_anons_from_downloading_files: "Impedir que usuários anônimos façam download de arquivos anexados. AVISO: isso irá impedir quaisquer componentes do site que não sejam imagens, tendo sido postados como anexos, de funcionar." @@ -1300,100 +1299,6 @@ pt_BR: deferred_and_deleted: "Obrigado por nos avisar. Nós removemos o post." temporarily_closed_due_to_flags: "Este tópico foi temporariamente fechado devido a um grande número de sinalizações da comunidade." system_messages: - usage_tips: - text_body_template: | - Eis algumas dicas rápidas para iniciar: - - ## Leitura - - Para ler mais, **basta continuar rolando a página para baixo!** - - À medida que novas respostas ou tópicos forem chegando, eles irão aparecer automaticamente -- não há necessidade de refrescar a página. - - ## Navegação - - - Para fazer buscas, voltar para a sua página de usuário, ou acessar o menu , use os **botões com ícone no lado superior direito**. - - - Selecionando o título do tópico sempre leva para a próxima **mensagem não lida** daquele tópico. Para entrar no início ou no final, selecione o contador de mensagens ou a data da última mensagem. - - - - - Enquanto estiver lendo um tópico, use a linha do tempo do lado direito para ir ao início, final ou a local da última leitura. Em telas pequenas, selecione a barra de progresso verde no canto inferior direito para acessar os controles de navegação: - - - - Você também pode selecionar a tecla ? para ver uma lista com todos os atalhos do teclado. - - ## Respostas - - Para inserir uma citação, selecione o texto desejado e pressione qualquer botão de Resposta para abrir o editor: - - - - Para citações múltiplas, repita o mesmo processo. - - - - Você pode continuar lendo enquanto compõe uma resposta. O rascunho da sua mensagem é salvo automaticamente enquanto você escreve. - - Para notificar alguém da sua resposta, mencione o nome da pessoa. Digite `@` para selecionar o nome de um usuário. - - - - Para usar [Emojis comuns](http://www.emoji.codes/), basta ou digitar `:` para ver a lista de opções, ou usar um dos sorrisos tradicionais `:)` :smile: - - - - Para gerar o resumo de um link, copie-o em uma linha por conta própria: - - - Você pode formatar as suas respostas usando HTML simples, BBCode, ou [Markdown](http://commonmark.org/help/): - - Este está em negrito. - Este está em [b]negrito[/b]. - Este está em **negrito**. - - Para outras dicas de formatação, [experimente os nossos tutoriais interativos de 10 minutos!](http://commonmark.org/help/tutorial/) - - ## Ações - - Há "botões de ação" embaixo de cada resposta. - - - - - Para indicar que você gostou de uma resposta, use o botão **Like** ("Curtir"). - - - Use o botão **Link** para pegar um link direto para qualquer tópico ou resposta. - - - Use o botão para revelar mais ações. O botão **Flag** notifica, de forma privada, o autor ou a [nossa equipe](%{base_url}/about), de algum problema. O **Bookmark** serve para consultar depois o tópico na sua página de usuário. - - ## Notificações - - Quando alguém responder a uma mensagem sua, citar sua mensagem, mencionar o seu `@nomedeusuário`, ou mesmo criar um link para um comentário seu, um número irá aparecer imediatamente próximo ao seu avatar no canto superior direito da página. Clique neste número para acessar as suas **notificações**. - - - - Não se preocupe se perder uma resposta – você receberá um email com as respostas (e mensagens) caso não esteja online quando elas chegarem. - - ## Preferências - - - Todos os tópicos com menos de dois dias são considerados novos. - - - Todos os tópicos dos quais você tenha **participado ativamente** (que tenha respondido, criado, ou lido por um certo tempo) serão automaticamente rastreados para você. - - Você irá ver números indicando respostas novas e não lidas próximos a estes tópicos: - - - - Você pode mudar as notificações de qualquer tópico por meio do controle de notificações que fica embaixo, no lado direito de cada tópico. - - - - Você também pode configurar as notificações por categoria. Para mudar as configurações, veja as [suas preferências de usuário](%{base_url}/my/preferences). - - ## Níveis de Confiança Comunitária - - É um prazer conhecer você! Conforme for participando, irá ganhando confiança da comunidade e as suas restrições de usuário novato serão removidas automaticamente. Ao atingir [níveis de confiança](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924) mais altos, você ganhará habilidades especiais que lhe permitirão ajudar a gerenciar a comunidade junto conosco. welcome_user: subject_template: "Bem-vindo ao %{site_name}!" text_body_template: | @@ -1408,26 +1313,6 @@ pt_BR: (Se precisar se comunicar com [membros da equipe](%{base_url}/about) como um novo usuário, apenas responda a esta mensagem.) welcome_invite: subject_template: "Bem-vindo ao %{site_name}!" - text_body_template: | - Obrigado por aceitar seu convite para %{site_name} -- bem vindo! - - Nós criamos uma nova conta **%{username}** para você, e você está autenticado. Pode mudar seu nome visitando o [perfil de seu usuário][prefs]. - - Para entrar novamente depois: - - 1. Sempre **use o mesmo endereço de email de seu convite original** quando se registrou. Caso contrário não saberemos que é você! - - 2. Crie uma senha única para o [perfil de seu usuário][prefs], e use para entrar. - - %{new_user_tips} - - Nós acreditamos sempre em [comportamento comunitário civilizado](%{base_url}/guidelines). - - Aproveite sua participação! - - (Se precisar se comunicar com um [membro da equipe](%{base_url}/about) como novo usuário, apenas responda a esta mensagem.) - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "Backup completado com sucesso" backup_failed: @@ -1644,10 +1529,17 @@ pt_BR: %{message} digest: why: "Um breve resumo de %{site_link} desde que viu pela última vez em %{last_seen_at}." + since_last_visit: "Desde a sua última visita" new_topics: "Novos Tópicos" + unread_messages: "Mensagens Não-lidas" + unread_notifications: "Notificações Não-lidas" + new_posts: "Novas Mensagens" new_users: "Usuários Novos" popular_topics: "Tópicos Populares" + follow_topic: "Seguir esse tópico" join_the_discussion: "Leia Mais" + popular_posts: "Publicações Populares" + from_topic_label: "De" subject_template: "[%{site_name}] Resumo das discussões" unsubscribe: "Este resumo é enviado por %{site_link} quando não o vemos há algum tempo. Para cancelar a assinatura %{unsubscribe_link}." click_here: "clique aqui" @@ -2043,7 +1935,6 @@ pt_BR: title: "Tema" fields: theme_id: - description: "Você prefere um esquema de cores claro ou escuro para começar? Você poderá, futuramente, trocar o esquema de cores do seu site através da Aba: Admin, Configurações." choices: default: label: "Claro Simples" @@ -2068,7 +1959,6 @@ pt_BR: label: "Ícone Largo" description: "Ícone usado para representar seu site em dispositivos modernos, que tenha boa aparência em tamanhos maiores. O tamanho recomendado é pelo menos 144px por 144px." homepage: - description: "Recomendamos mostrar os últimos tópicos na sua página inicial, mas você pode escolher mostrar categorias (grupos de tópicos) na página inicial, se preferir." title: "Página Inicial" fields: homepage_style: @@ -2079,7 +1969,6 @@ pt_BR: label: "Categorias" emoji: title: "Emoji" - description: "Qual estilo de Emoji se adequa melhor para sua comunidade? Você poderá sempre adicionar novas customizações de Emojis através da aba: Admin > Customizar > Emoji." invites: title: "Convidar um grupo" finished: diff --git a/config/locales/server.ro.yml b/config/locales/server.ro.yml index 2c4fb758267..de0a5159465 100644 --- a/config/locales/server.ro.yml +++ b/config/locales/server.ro.yml @@ -110,7 +110,8 @@ ro: default_categories_already_selected: "Nu poți selecta o categorie folosită într-o altă listă." s3_upload_bucket_is_required: "Nu poți activa încărcările pe S3 dacă nu ai introdus 's3_upload_bucket'." bulk_invite: - file_should_be_csv: "Fișierul încărcat ar trebui să fie în format csv sau txt." + file_should_be_csv: "Fișierul de încărcat trebuie să fie în format csv." + error: "A apărut o eroare la încărcarea acestui fișier. Te rugăm să încerci din nou, mai târziu." backup: operation_already_running: "O operație este în desfășurare. Nu poți începe alta nouă." backup_file_should_be_tar_gz: "Fișierul backup ar trebui să fie arhivat cu extensia .tar.gz." @@ -129,6 +130,11 @@ ro: embed: start_discussion: "Pornește discuție" continue: "Continuă discuție" + error: "Eroare la încorporare" + referer: "Referent:" + mismatch: "Referentul nu corespunde nici uneia dintre următoarele gazde:" + no_hosts: "Nu s-a setat nicio gazdă pentru încorporare." + configure: "Configurează încorporarea" more_replies: one: "Încă un răspuns" few: "Încă %{count} răspunsuri" @@ -283,6 +289,7 @@ ro: name: "Numele categoriei" topic: title: 'Titlu' + featured_link: 'Link promovat' post: raw: "Corp" user_profile: @@ -296,6 +303,9 @@ ro: too_many_users: "Poți trimite avertizări la un singur utilizator odată." cant_send_pm: "Ne pare rău, nu poți trimite un mesaj privat acestui utilizator." no_user_selected: "Trebuie selectat un nume de utilizator valid." + featured_link: + invalid: "e invalid. URL-ul trebuie să includă http:// sau https://." + invalid_category: "nu poate fi editat în această categorie." user: attributes: password: @@ -391,6 +401,7 @@ ro: create_topic: "Ai atins numărul maxim de subiecte. Te rugăm să aștepți %{time_left} înainte să încerci din nou." create_post: "Răspunzi prea rapid. Te rugăm să aștepți %{time_left} înainte să încerci din nou." delete_post: "ștergi postările prea rapid. Te rugăm să aștepți %{time_left} înainte să încerci din nou." + public_group_membership: "Ieși/intri din/în grupuri prea frecvent. Te rugăm așteaptă %{time_left} până să încerci din nou." topics_per_day: "Ai atins numărul maxim de subiecte noi pe ziua de azi. Te rugăm să aștepți %{time_left} înainte să încerci din nou." pms_per_day: "Ai atins numărul maxim de mesaje pe ziua de azi. Te rugăm să aștepți %{time_left} înainte să încerci din nou." create_like: "Ai atins numărul maxim de aprecieri pe ziua de azi. Te rugăm să aștepți %{time_left} înainte să încerci din nou." @@ -808,6 +819,8 @@ ro: min_first_post_length: "Numărul minim de caractere permis pentru prima postare (în corpul mesajului)" min_private_message_post_length: "Numărul minim de caractere permis pentru mesaje, per postare" max_post_length: "Lungimea maximă permisă a postării, în caractere" + topic_featured_link_enabled: "Activează postarea unui link cu subiecte." + show_topic_featured_link_in_digest: "Arată link-ul promovat al subiectului în rezumatul pe email." min_topic_title_length: "Minimul de caractere permis în titlul unui subiect" max_topic_title_length: "Maximul de caractere permis în titlul unui subiect" min_private_message_title_length: "Numărul minim de caractere permis în titlul unui mesaj" @@ -916,9 +929,8 @@ ro: show_email_on_profile: "Afișează adresa de email a unui utilizator în pagina sa de utilizator (vizibilă numai pentru el și pentru membrii echipei)" prioritize_username_in_ux: "Afișează întâi nume utilizator pe pagina utilizator, pe cardul utilizator și în postări (dacă e dezactivat, se afișează întâi numele)" email_token_valid_hours: "Tokenul uitat parolă / activează cont sunt valabili pentru (n) ore." - email_token_grace_period_hours: "Tokenul Parola uitată / activează cont sunt încă valabili pe o perioadă de grație de (n) ore după ce au fost acceptați." enable_badges: "Activează sistemul de ecusoane" - enable_whispers: "Permite membrilor echipei să comunice privat în cadrul unui subiect. (experimental)" + enable_whispers: "Permite membrilor echipei să comunice privat în cadrul subiectelor." allow_index_in_robots_txt: "Specifică în robots.txt că acest site poate fi indexat de motoarele de căutare web." email_domains_blacklist: "O listă de domenii de email separate cu simbolul | (pipe) ale căror utilizatori nu au permisiunea să înregistreze conturi. Exemplu: mailinator.com|trashmail.net" email_domains_whitelist: "O listă de domenii de email (separate cu simbolul | (pipe)) cu care utilizatorii TREBUIE să se înregistreze. ATENȚIE: utilizatorii cu alte domenii de email decât cele listate nu vor avea permisiunea să se înregistreze." @@ -949,6 +961,7 @@ ro: sso_overrides_name: "Suprascrie numele întreg de pe local cu numele întreg din datele SSO la fiecare autentificare și împiedică schimbările locale." sso_overrides_avatar: "Suprascrie avatarul utilizatorului cu avatarul din datele SSO. Dacă este activat, se recomandă călduros dezactivarea allow_uploaded_avatars" sso_not_approved_url: "Redirecționează conturile neaprobate SSO către acest URL" + sso_allows_all_return_paths: "Nu restricționa domeniul pentru return_paths furnizate de SSO (implicit, calea de întoarcere trebuie să fie pe site-ul curent)" enable_local_logins: "Activează numele de utilizator local și conturile bazate pe autentificare cu parolă. (Notă: Pentru ca invitațiile să funcționeze, această opțiune trebuie să fie activată)" allow_new_registrations: "Permite înregistrarea noilor utilizatori. Debifați pentru a restricționa pe oricine să creeze un cont nou." enable_signup_cta: "Arată o notificare către utilizatorii anonimi care revin prin care să le ceri să se înscrie pentru a avea un cont pe site." @@ -1174,6 +1187,9 @@ ro: delete_digest_email_after_days: "Nu trimite emailuri-rezumat utilizatorilor care nu au fost văzuți pe site de mai mult de (n) zile." digest_suppress_categories: "Nu include aceste categorii în emailurile-rezumat." disable_digest_emails: "Dezactivează emailurile-rezumat pentru toți utilizatorii." + email_accent_bg_color: "Culoarea accent care să fie folosită ca fundal pentru unele elemente din emailurile HTML. Introdu numele culorii („roșu”) sau valoarea hex ('#FF000')." + email_accent_fg_color: "Culoarea textului redat pe culoarea de fundal a emailurilor HTML. Introdu un nume de culoare („alb”) sau o valoare hex ('#FFFFFF')." + email_link_color: "Culoarea link-urilor din emailurile HTML. Introdu un nume de culoare („albastru”) sau o valoare hex ('#0000FF')." detect_custom_avatars: "Dacă sau nu să verifice dacă utilizatorii și-au încărcat poze de profil personalizate." max_daily_gravatar_crawls: "Numărul maxim zilnic de verificări pe care Discourse le va face pe Gravatar pentru a vedea dacă există avatare personalizate." public_user_custom_fields: "O listă albă cu câmpuri personalizate pentru utilizator, ce se pot afișa public." @@ -1218,7 +1234,6 @@ ro: embed_whitelist_selector: "Selector CSS pentru elementele ce sunt permise în încorporări." embed_blacklist_selector: "Selector CSS pentru elementele ce sunt șterse din încorporări" notify_about_flags_after: "Dacă sunt marcaje ce nu au fost aranjate după atâtea ore, trimite un email către email-ul de contact . Setează la 0 pentru a dezactiva." - enable_cdn_js_debugging: "Permite /logs să afișeze corect erorile adăugând permisiuni crossorigin pe toate js includes." show_create_topics_notice: "Dacă site-ul are mai puțin de 5 subiecte publice, afișează o notificare prin care se cere adminilor să creeze subiecte." delete_drafts_older_than_n_days: șterge drafturile mai vechi de (n) zile. bootstrap_mode_min_users: "Numărul minim de utilizatori necesar pentru dezactivarea modului bootstrap (0 pentru dezactivare)" @@ -1494,36 +1509,8 @@ ro: Această invitație este de la un utilizator verificat, deci poți răspunde de îndată ce dorești. invite_forum_mailer: subject_template: "%{invitee_name} te-a invitat să te alături pe %{site_domain_name}" - text_body_template: | - %{invitee_name} te-a invitat să te alături pe - - > **%{site_title}** - > - > %{site_description} - - Dacă te interesează, dă click pe link-ul de mai jos: - - %{invite_link} - - Această invitație vine de la un utilizator verificat, așa că ți se va crea automat un cont. custom_invite_forum_mailer: subject_template: "%{invitee_name} te-a invitat să te alături pe %{site_domain_name}" - text_body_template: | - %{invitee_name} te-a invitat să te alaturi pe - - > **%{site_title}** - > - > %{site_description} - - Mesaj de la %{invitee_name}: - - %{user_custom_message} - - Dacă te interesează, dă click pe link-ul de mai jos: - - %{invite_link} - - Această invitație vine de la un utilizator verificat, așa că ți se va crea automat un cont. invite_password_instructions: subject_template: "Setează parolă pentru contul tău %{site_name}" text_body_template: | @@ -1646,97 +1633,9 @@ ro: Pentru îndreptări suplimentare, te rugăm să citești [ghidul comunității](%{base_url}/guidelines). usage_tips: text_body_template: | - Aici sunt câteva sfaturi rapide pentru început: + Citește câteva sfaturi rapide destinate noilor utilizatori, [urmărind această postare pe blog](http://blog.discourse.org/2016/12/discourse-new-user-tips-and-tricks/). - ## Citirea - - Pentru a citi mai mult, **dă scroll în jos!** - - Pe măsură ce sunt postate noi răspunsuri și noi subiecte, ele vor apărea în mod automat - nu e nevoie să reîmprospătezi pagina. - - ## Navigarea - - - Pentru a folosi căutarea, pentru a accesa pagina ta de utilizator, sau meniul , folosește **butoanele icoană din dreapta-sus**. - - - Selectarea unui titlu de subiect te va duce întotdeauna la **următorul răspuns necitit** din subiect. Pentru a intra la începutul sau la sfârșitul listei de mesaje, selectează contorul de răspunsuri sau data ultimului răspuns. - - - - - Atunci când citești un subiect, poți folosi bara temporală din dreapta pentru a sări la începutul listei de mesaje, la sfârșitul ei sau la ultima poziție citită. Pe ecranele mai mici, selectează bara de progres din dreapta-jos pentru a o expanda: - - - - De asemenea, poți apăsa tasta ? pentru o lista ultra-rapidă de scurtături de tastatură. - - ## Răspunsul - - Pentru a introduce un citat, sleceează textul pe care dorești să îl citezi, apoi apasă orice buton Răspunde pentru a deschide editorul. Pentru mai multe citate repetă operațiunea. - - - - Întotdeauna poți să continui să citești în timp ce ăți compui răspunsul, iar noi vom salva automat drafturile, pe măsură ce scrii. - - Pentru a notifica pe cineva cu privire la răspunsul tău, menționează-i numele. Apasă `@` pentru a selecta un utilizator. - - - - Pentru a folosi [Emoji standard](http://www.emoji.codes/), apasă pur și simplu `:` pentru a sorta după nume, sau folosește tradiționalele smileys `;)` - - - - Pentru a genera un onebox pentru un link anume, lipiți-l pe o linie, de unul singur: - - - - Răspunsul tău poate fi formatat folosind HTML simplu, BBCode, sau [Markdown](http://commonmark.org/help/): - - Acesta este bold. - Acesta este [b]bold[/b]. - Acesta este **bold**. - - Pentru mai multe sfaturi privind formatarea, [încearcă tutorialul nostru interactiv și amuzant de numai 10 minute!](http://commonmark.org/help/tutorial/) - - ## Acțiunile - - Există butoane de acțiune în partea de jos a fiecărei postări: - - - - - Pentru a-i spune cuiva că ți-a făcut plăcere și ai apreciat postarea sa, folosește butonul **apreciere**. Împărtășește apreciere! - - - Folosind butonul **Distribuie** poți prelua un link ce se poate copia-lipi. - - - Folosește butonul arată mai mult pentru a descoperi mai multe acțiuni **Marchează cu marcaj de avertizare** pentru a informa în mod privat autorul, sau [echipa noastră](%{base_url}/about), cu privire la o anumită problemă. Folosește **Semn de carte** pentru a găsi această postare mai târziu, în pagina ta de profil. - - ## Notificările - - Când cineva îți răspunde la o postare, te citează, te menționează `@nume utilizator`, sau pune un link la un post al tău, îți va apărea imediat un număr în partea din dreapta-sus a paginii. Selectează-l pentru a-ți accesa **notificările**. - - - - Nu îți face griji că ai putea pierde vreun răspuns - vei primi pe email orice notificări apar cât ești plecat. - - ## Preferințele - - - Toate subiectele mai **recente de doua zile** sunt considerate noi. - - - Orice subiect la care **ai participat în mod activ** (creându-l, răspunzând la el, sau citindu-l pe o perioadă mai îndelungată) va fi urmărit în mod automat pentru uzul tău. - - Vei vedea indicatoarele "nou" și "număr necitite" alături de următoarele subiecte: - - - - Poți schimba notificările pentru fiecare subiect prin controlul de notificări aflat jos, în partea dreapta, la fiecare subiect. - - - - Poți de asemenea să alegi starea notificărilor pe categorii, dacă vrei să urmărești sau să ignori fiecare nou subiect dintr-o categorie specifică. - - Pentru a schimba oricare dintre aceste preferințe, mergi la [preferințe utilizator](%{base_url}/my/preferences). - - ## Încrederea comunității - - Ne bucurăm de cunoștință! Pe măsură ce vei participa aici, de-a lungul timpului te vom cunoaște mai bine și limitările temporare de nou utilizator ce ți se aplică, vor fi ridicate. Continua să participi și, cu timpul, vei câștiga noi [niveluri de încredere](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924) ce vor include abilități speciale pentru a ne ajuta să gestionăm împreună această comunitate. + Pe măsură ce participi aici, vom ajunge să te cunoaștem iar limitările temporare aferente unui utilizator nou, îți vor fi ridicate. Cu timpul vei câștiga [niveluri de încredere](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924) care includ abilități speciale și care îți vor da posibilitatea să ne ajuți să ne gestionăm împreuna comunitatea. welcome_user: subject_template: "Bine ai venit pe %{site_name}!" text_body_template: | @@ -1751,26 +1650,6 @@ ro: (Dacă ai nevoie să comunici cu [membrii echipei](%{base_url}/about) din postura de nou utilizator, pur și simplu dă reply la acest mesaj.) welcome_invite: subject_template: "Bine ai venit pe %{site_name}!" - text_body_template: | - Îți mulțumim că ai acceptat invitația pe %{site_name} -- bun venit! - - Am creat pentru tine un nou cont **%{username}**, și acum ești autentificat. Îți poți schimba numele vizitându-ți [profilul utilizator][prefs]. - - Pentru a te autentifica mai târziu: - - 1. Întotdeauna **folosește aceeași adresă de email ca cea din invitația originală** atunci când te autentifici. Altfel nu ne vom putea da seama că ești tu! - - 2. Creează o parolă unică pentru [profilul utilizator][prefs], și folosește-o la autentificare. - - %{new_user_tips} - - Noi credem într-un [comportament civilizat al comunității](%{base_url}/guidelines) indiferent de circumstanțe. - - ședere plăcută! - - (Dacă ai nevoie să comunici cu [membrii echipei](%{base_url}/about) din postura de nou utilizator, pur și simplu dă reply la acest mesaj.) - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "Backup terminat cu succes" text_body_template: | @@ -2214,6 +2093,7 @@ ro: new_topics: "Subiecte noi" unread_messages: "Mesaje necitite" unread_notifications: "Notificări necitite" + liked_received: "Aprecieri primite" new_posts: "Postări noi" new_users: "Utilizatori noi" popular_topics: "Subiecte notorii" @@ -2221,7 +2101,6 @@ ro: join_the_discussion: "Citește mai mult" popular_posts: "Postări notorii" from_topic_label: "De la" - more_new: "Noutăți în subiectele și categoriile pe care le urmărești" subject_template: "[%{site_name}] Rezumat" unsubscribe: "Acest rezumat este transmis de pe %{site_link} când a trecut ceva vreme de când nu te-am mai văzut. Pentru a te dezabona, %{unsubscribe_link}." click_here: "click aici" @@ -2975,11 +2854,9 @@ ro: fields: welcome: label: "Subiect de bun venit" - description: "

    Cum ți-ai descrie comunitatea unui străin din lift, într-un minut?

    • Cui îi sunt destinate aceste discuții?
    • Ce pot găsi aici?
    • De ce să vă vizitez?

    Subiectul vostru de bun venit este primul lucru pe care îl vor vedea noii vizitatori Gândește-te la el ca laun paragraf/b> de 'agățat în lift' sau 'declarație de misiune'.

    " one_paragraph: "Te rugăm să îți restrângi mesajul de bun venit la un paragraf." privacy: title: "Acces" - description: "

    Este comunitatea voastră deschisă tuturor, sau este limită prin apartenență, invitații, sau aprobare? Dacă preferi, poți să setezi lucrurile pe privat și să comuți mai târziu pe public.

    Amintește-ți că întotdeauna poți să trimiți invitații din subiecte sau din pagina cu profilul tău de utilizator

    " fields: privacy: choices: @@ -3005,7 +2882,6 @@ ro: description: "Toate mesajele personale automate din Discourse vor fi trimite de la acest utilizator. Ce-i mai important este că acest utilizator va fi desemnat să trimită fiecare mesaj de bun venit ce se trimite automat noilor utilizatori." corporate: title: "Organizație" - description: "Aceste nume vor fi introduse în Politica de confidențialitate și Condițiile generale de utilizare, pe care le poți edita oricând în categoria Echipa. Dacă nu ai o firmă, poți sări momentan peste acest pas." fields: company_short_name: label: "Numele firmei (scurt)" @@ -3020,7 +2896,6 @@ ro: title: "Temă" fields: theme_id: - description: "Preferi o schemă de culori luminoasă sau una întunecată pentru început? Întotdeauna poți continua personalizarea aspectului site-ului via Admin, Personalizare." choices: default: label: "Luminos simplu" @@ -3045,7 +2920,6 @@ ro: label: "Iconiță mare" description: "Iconiță utilizata pentru a-ți reprezenta site-ul pe dispozitive moderne și care arată bine la dimensiuni mai mari. Dimensiunea recomandată este de 144px pe 144px." homepage: - description: "Recomandăm afișarea celor subiectelor recente pe pagina principală, dar, dacă preferi, poți să alegi afișarea categoriilor (grupuri de subiecte)." title: "Pagina principală" fields: homepage_style: @@ -3056,7 +2930,6 @@ ro: label: "Categorii" emoji: title: "Emoji" - description: "Ce stil de Emoji preferi pentru comunitatea ta? Întotdeauna poți să adaugi mai multe emoji personalizate via Admin, Personalizări, Emoji." invites: title: "Invită membrii echipei" description: "Aproape ai terminat! Hai să invităm niște membri ai echipei să dea o mână de ajutor și să presare discuțiile cu subiecte și răspunsuri interesante, pentru a lansa comunitatea." diff --git a/config/locales/server.ru.yml b/config/locales/server.ru.yml index 84277c5611d..48ea5176e6c 100644 --- a/config/locales/server.ru.yml +++ b/config/locales/server.ru.yml @@ -32,6 +32,7 @@ ru: purge_reason: "Деактивированная учетная запись будет автоматически удалена как заброшенная" disable_remote_images_download_reason: "Загрузка картинок была отключена из-за недостаточности места на диске." anonymous: "Гость" + remove_posts_deleted_by_author: "Удалено автором" emails: incoming: default_subject: "Входящее письмо от %{email}" @@ -72,6 +73,7 @@ ru: inclusion: не включен в список invalid: неверный is_invalid: "Не совсем ясно, это предложение закончено?" + contains_censored_words: "содержит одно или более нецензурных слов: %{censored_words}" less_than: должен быть меньше %{count} less_than_or_equal_to: должен быть меньше или равен %{count} not_a_number: не число @@ -110,7 +112,8 @@ ru: default_categories_already_selected: "Нельзя выбрать раздел, используемый в другом списке." s3_upload_bucket_is_required: "Нельзя включить загрузки на S3, пока не задана настройка 's3_upload_bucket'." bulk_invite: - file_should_be_csv: "Загружаемый файл должен быть в формате CSV или TXT." + file_should_be_csv: "Загружаемый файл должен быть в csv-формате." + error: "Произошла ошибка при загрузке файла. Пожалуйста, повторите попытку позже." backup: operation_already_running: "Действие уже выполняется, поэтому невозможно начать новое действие прямо сейчас." backup_file_should_be_tar_gz: "Файл резервной копии должен быть архивом в формате .TAR.GZ." @@ -177,6 +180,7 @@ ru: spamming_host: "Извините, вы не можете разместить ссылку в этом сообщении." user_is_suspended: "Заблокированным пользователям запрещено писать." topic_not_found: "Что-то пошло не так. Возможно, эта тема была закрыта или заархивирована, пока вы ее читали?" + not_accepting_pms: "К сожалению, %{username} не принимает сообщения в данный момент." just_posted_that: "слишком схоже с уже опубликованным Вами сообщением" invalid_characters: "содержит недопустимые символы" is_invalid: "Не совсем ясно, это предложение закончено?" @@ -307,6 +311,9 @@ ru: too_many_users: "Можно отправлять предупреждения только одному пользователю за раз." cant_send_pm: "Извините, вы не можете посылать личные сообщения данному пользователю." no_user_selected: "Вы должны выбрать корректного пользователя." + featured_link: + invalid: "недействителен. URL должен включать http:// или https://." + invalid_category: "не может быть изменено в данной категории." user: attributes: password: @@ -338,6 +345,8 @@ ru: staff_category_name: "Персонал" staff_category_description: "Приватный раздел для персонала, в котором темы видны только администраторам и модераторам." assets_topic_body: "Это постоянная тема, для хранения изображений и файлов, используемых в дизайне сайта, доступная только сотрудникам. Не удаляйте её! \n\n\nВаши действия:\n\n\n1. Ответьте в эту тему.\n2. Загрузите все изображения, которые вы хотите использовать для логотипов, значков и т.д. сюда. (Используйте значок на панели инструментов в редакторе сообщений, перетащите мышкой, или вставьте изображения из буфера.) \n3. Сохраните свое сообщение.\n4. Щелкните правой кнопкой мыши изображении в новом сообщении, чтобы получить путь к загруженным изображениям, или щелкните значок редактирования и получите путь к изображениям. Скопируйте пути к изображениям.\n5. Вставьте эти пути в [Настройки сайта] (/admin/site_settings/category/required) .\n\n\nЕсли Вам нужно активировать дополнительные типы файлов, отредактируйте `authorized_extensions` во вкладке [Файлы] (/admin/site_settings/category/files)." + discourse_welcome_topic: + title: "Добро пожаловать в Discourse" lounge_welcome: title: "Добро пожаловать в Фойе" body: |2 @@ -403,6 +412,7 @@ ru: create_topic: "Вы создаете темы слишком быстро. Пожалуйста, подождите %{time_left}, затем повторите попытку" create_post: "Вы отвечаете слишком быстро. Пожалуйста, подождите %{time_left} слева, затем повторите попытку." delete_post: "Вы удаляете сообщения слишком быстро. Пожалуйста, подождите %{time_left} перед следующей попыткой." + public_group_membership: "Вы присоединяетесь/покидаете группы слишком часто. Пожалуйста, подождите %{time_left} перед следующей попыткой." topics_per_day: "Вы достигли лимита новых тем на сегодня. Пожалуйста, подождите %{time_left} перед следующей попыткой." pms_per_day: "Вы достигли лимита сообщений на сегодня. Пожалуйста, подождите %{time_left} перед следующей попыткой." create_like: "Вы достигли лимита симпатий на сегодня. Пожалуйста, подождите %{time_left} перед следующей попыткой." @@ -605,6 +615,11 @@ ru: title: 'Проголосовать' description: 'Проголосовать за это сообщение' long_form: 'проголосовало за это сообщение' + user_activity: + no_bookmarks: + others: "Закладок нет." + no_likes_given: + others: "Понравившихся сообщений нет." topic_flag_types: spam: title: 'Спам' @@ -638,14 +653,21 @@ ru: stop_watching_topic: "Прекратить наблюдение за этой темой, %{link}" mute_topic: "Отключение всех уведомлений по этой теме, %{link}" unwatch_category: "Прекратить наблюдение за всеми темами раздела %{category}" + mailing_list_mode: "Отключить почтовую рассылку" + all: "Не отправлять мне почту с %{sitename}" log_out: "Выйти" user_api_key: + title: "Разрешить доступ к приложению" read: "чтение" read_write: "чтение/запись" - description: "\"% {Application_name}\" запрашивает следующий доступ к вашей учетной записи:" + description: "\"%{application_name}\" запрашивает следующий доступ к Вашей учетной записи:" no_trust_level: "К сожалению, вы не обладаете необходимым уровнем доверия для доступа к API" scopes: message_bus: "Текущие обновления" + notifications: "Прочитать и стереть уведомления" + session_info: "Прочитать информацию о сеансе пользователя" + read: "Прочитать всё" + write: "Написать всё" reports: visits: title: "Визиты форумчан" @@ -738,6 +760,7 @@ ru: page_view_total_reqs: title: "Всего" xaxis: "Дата" + yaxis: "Всего Просмотров Страниц" page_view_logged_in_mobile_reqs: xaxis: "Дата" page_view_anon_mobile_reqs: @@ -800,6 +823,7 @@ ru: min_first_post_length: "Минимально допустимое количество символов в первом сообщении (или теле темы)" min_private_message_post_length: "Минимально допустимое количество символов в сообщении в беседе." max_post_length: "Максимально допустимое количество символов в одном сообщении." + topic_featured_link_enabled: "Разрешить публиковать ссылку с темами." min_topic_title_length: "Минимально допустимое количество символов в названии темы." max_topic_title_length: "Максимально допустимое количество символов в названии темы." min_private_message_title_length: "Минимально допустимое количество символов в заголовке сообщения в беседе." @@ -843,6 +867,8 @@ ru: anon_polling_interval: "Как часто следует анонимным клиентам опрашивать сервер, в миллисекундах" background_polling_interval: "Как часто следует клиентам опрашивать сервер, в миллисекундах (когда окно находится в фоновом режиме)" cooldown_minutes_after_hiding_posts: "Количество минут, которое должен подождать пользователь перед редактированием сообщения скрытого по жалобам" + max_topics_in_first_day: "Максимальное количество тем, которое пользователь может создать в течение 24 часов с момента создания своего первого сообщения" + max_replies_in_first_day: "Максимальное количество ответов, которое пользователь может сделать в течение 24 часов с момента создания своего первого сообщения" tl2_additional_likes_per_day_multiplier: "Увеличить лимит лайков в день для tl2 (member) до" tl3_additional_likes_per_day_multiplier: "Увеличить лимит лайков в день для tl3 (member) до" tl4_additional_likes_per_day_multiplier: "Увеличить лимит лайков в день для tl4 (leader) до" @@ -873,7 +899,6 @@ ru: redirect_users_to_top_page: "Автоматически перенаправлять новых и давно отсутствующих пользователей к началу страницы." show_email_on_profile: "Показать Email пользователя в профиле (видно только себе и персоналу)" email_token_valid_hours: "Ссылка на восстановление пароля / активацию аккаунта будет действовать в течении (n) часов." - email_token_grace_period_hours: "Ссылка на восстановление пароля / активацию аккаунта будет действовать в течении (n) часов." enable_badges: "Включить систему наград" allow_index_in_robots_txt: "Разрешить поисковикам индексировать сайт в robots.txt" email_domains_blacklist: "Список почтовых доменов, с которых запрещена регистрация учетных записей. Пример: mailinator.com trashmail.net" @@ -912,6 +937,7 @@ ru: enable_github_logins: "Разрешить идентификацию с Github, требует github_client_id и github_client_secret" github_client_id: "Клиентский id для идентификации с Github, зарегистрированный на https://github.com/settings/applications" github_client_secret: "Клиентский секрет для идентификации с Github, зарегистрированный на https://github.com/settings/applications" + readonly_mode_during_backup: "Включить режим \"только для чтения\" во время выполнения резервного копирования" allow_restore: "Позволить импорт, который может заменить ВСЕ данные сайта. Оставьте выключенным, если не планируете восстанавливать резервную копию" maximum_backups: "Максимальное количество резервных копий к сохранению. Более старые резервные копии будут автоматически удалены." backup_frequency: "Как часто создавать резервные копии форума, в днях" @@ -932,8 +958,12 @@ ru: max_private_messages_per_day: "Максимальное количество тем, которые пользователь может создать за один день." max_invites_per_day: "Максимальное количество приглашений, которое может отправить пользователь за один день." max_topic_invitations_per_day: "Максимальное количество приглашений в тему, которое может отправить пользователь в течении дня." + alert_admins_if_errors_per_minute: "Количество ошибок в минуту для предупреждения администратора. Значение 0 отключает эту опцию. ВНИМАНИЕ: требуется перезагрузка." + alert_admins_if_errors_per_hour: "Количество ошибок в час для предупреждения администратора. Значение 0 отключает эту опцию. ВНИМАНИЕ: требуется перезагрузка." + categories_topics: "Количество тем, отображаемых на странице разделов." suggested_topics: "Количество рекомендованных тем, отображаемых внизу текущей темы." limit_suggested_to_category: "Показыать только темы из текущего раздела в списке рекомендованых тем." + suggested_topics_max_days_old: "Предлагаемые темы не должны быть старше n дней." clean_up_uploads: "Удалить неиспользуемые загрузки для предотвращения хранения нелегального контента. ВНИМАНИЕ: рекомендуется сделать резервную копию директории /uploads перед включением данной настройки." clean_orphan_uploads_grace_period_hours: "Период (в часах) после которого неопубликованные вложения удаляются." purge_deleted_uploads_grace_period_days: "Период (в днях) после которого удаленные вложения очищаются." @@ -946,6 +976,8 @@ ru: s3_region: "Географический регион Amazon S3, который будет использоваться для хранения изображений" avatar_sizes: "Список автоматически сгенерированных размеров аватар." default_opengraph_image_url: "URL картинки opengraph по-умолчанию." + allow_all_attachments_for_group_messages: "Разрешить все почтовые вложения для групповых сообщений." + convert_pasted_images_quality: "Качество сконвертированного JPG файла (1 самое низкое качество, 100 наилучшее качество)." enable_flash_video_onebox: "Разрешить умную вставку ссылок sqf и flv (Adobe Flash). ВНИМАНИЕ: повышает риски безопасности сайта." default_invitee_trust_level: "Уровень доверия приглашенных пользователей по-умолчанию (от 0 до 4)." default_trust_level: "Уровень доверия по умолчанию для всех новых пользователей (0-4). ВНИМАНИЕ! Повышая уровень доверия для новых пользователей, Вы можете столкнуться с большим колличеством спама." @@ -959,12 +991,17 @@ ru: tl2_requires_likes_received: "Сколько симпатий пользователь должен получить для продвижения до уровня доверия 2." tl2_requires_likes_given: "Сколько симпатий пользователь должен выразить для продвижения до уровня доверия 2." tl2_requires_topic_reply_count: "В скольких темах пользователь должен ответить для продвижения до уровня доверия 2." + tl3_requires_topics_viewed: "Какой процент созданных тем за последние (tl3 time period) дней должен иметь пользователь для повышения уровня доверия до 3. (от 0 до 100)" + tl3_requires_posts_read: "Какой процент созданных сообщений за последние (tl3 time period) дней должен иметь пользователь для повышения уровня доверия до 3. (от 0 до 100)" tl3_requires_topics_viewed_all_time: "Сколько сообщений пользователь должен прочитать для поднятия уровня доверия до 3." tl3_requires_posts_read_all_time: "Сколько сообщений пользователь должен прочитать для поднятия уровня доверия до 3." tl3_promotion_min_duration: "Минимальное количество дней , в течении которых пользователь с уровнем доверия 3 не может быть понижен до урованя доверия 2." tl3_links_no_follow: "Не удалять rel=nofollow из ссылок от пользователей с уровнем доверия 3." min_trust_to_create_topic: "Минимальный уровень доверия для создания новой темы." min_trust_to_edit_wiki_post: "Минимальный уровень доверия, требуемый для редактирования вики-сообщения." + min_trust_to_edit_post: "Минимальный уровень доверия, требуемый для редактирования сообщений." + min_trust_to_allow_self_wiki: "Минимальный уровень доверия, требуемый для создания своего вики-сообщений." + min_trust_to_send_messages: "Минимальный уровень доверия, требуемый для создания личных сообщений." newuser_max_links: "Сколько ссылок новый пользователь может вставлять в сообщение." newuser_max_images: "Сколько изображений новый пользователь может вставлять в одно сообщение." newuser_max_attachments: "Максимальное количество вложений, которое новый пользователь может прикрепить к одному сообщению." @@ -1018,6 +1055,9 @@ ru: disable_emails: "Запретить форуму отсылать какие-либо письма." strip_images_from_short_emails: "Удалять картинки из писем размером менее 2800 байт" short_email_length: "Какие письма считать короткими, в байтах" + delete_email_logs_after_days: "Удалять журнал e-mail спустя (N) дней. 0, чтобы хранить неограниченное количество времени" + max_emails_per_day_per_user: "Максимальное количество e-mail, отправляемых пользователю в течение дня. 0, чтобы отключить это ограничение" + block_auto_generated_emails: "Блокировать входящие e-mail, которые идентифицированы как автосгенерированные." pop3_polling_enabled: "Загружать ответы в форум в виде писем с учетной записи POP3." pop3_polling_ssl: "Использовать SSL при подключениик POP3 серверу. (Рекомендовано)" pop3_polling_period_mins: "Периодичность загрузки e-mail учетной записи POP3. ВНИМАНИЕ: требует перезапуска." @@ -1036,9 +1076,12 @@ ru: username_change_period: "Количество дней после регистрации, когда пользователь сможет изменить свой псевдоним (0 - запретить изменение псевдонима)." email_editable: "Позволять пользователям изменять свой адрес электронной почты после регистрации." allow_uploaded_avatars: "Разрешить пользователям загружать свои собственные картинки профиля." + allow_animated_avatars: "Разрешить пользователям использовать анимированные GIF картинки в своём профиле. ВНИМАНИЕ: после изменения данной настройки запустите avatars:refresh rake-задачу." allow_animated_thumbnails: "Генерировать анимированные миниатюры gif-картинок." default_avatars: "URL для аватара, который будет использован по умолчанию для новых пользователей, пока они не изменят его." automatically_download_gravatars: "Скачивать аватарку Gravatar пользователя во время создания учетной записи или изменения e-mail." + email_accent_bg_color: "Акцентирующий цвет для использования в качестве фона некоторых элементов в HTML писем. Введите название цвета ('red') или hex значение ('#FF000'). " + email_link_color: "Цвет ссылок в HTML письмах. Введите название цвета ('blue') или hex значение ('#0000FF')." detect_custom_avatars: "Проверять ли, что пользователи загрузили свои собственные картинки профиля (аватарки)." max_daily_gravatar_crawls: "Максимальное количество загрузок аватаорок с Gravatar за один день" public_user_custom_fields: "Список разрешенных дополнительных полей пользователей, которые могут быть отображены публично." @@ -1072,7 +1115,6 @@ ru: embed_whitelist_selector: "CSS selector которые разрешины для использования." embed_blacklist_selector: "CSS selector которые запрещены для использования." notify_about_flags_after: "Если есть жалобы, которые не были обработаны после этого колличества часов, отправить уведомление по электронной почте на contact_email. Значение 0, чтобы отключить." - enable_cdn_js_debugging: "Добавить права crossorigin для всех js включений для правильного отображения ошибок в /logs " show_create_topics_notice: "Если общее количество тем меньше 5, показывать персоналу соощбение с просьбой создать новые темы." delete_drafts_older_than_n_days: Удалять черновики, которые старше (n) дней. prevent_anons_from_downloading_files: "Запретить анонимным пользователям скачивать вложенные файлы. ВНИМАНИЕ: при этом будут недоступны любые вложения кроме картинок." @@ -1081,6 +1123,28 @@ ru: emoji_set: "Какую коллекцию Emoji использовать?" enforce_square_emoji: "Принудительно использовать квадратные пропорции для смайликов." approve_unless_trust_level: "Сообщения для пользователей ниже этого уровня доверия подлежат проверки" + default_email_private_messages: "По умолчанию присылать почтовое уведомление, когда кто-то оставляет пользователю личное сообщение." + default_email_mailing_list_mode: "По умолчанию присылать почтовое уведомление, когда появляется новое сообщение." + default_other_external_links_in_new_tab: "По умолчанию открывать внешние ссылки в новой вкладке." + default_other_dynamic_favicon: "Показывать количество новых/обновлённых тем на иконке веб-браузера по умолчанию." + default_topics_automatic_unpin: "Автоматически откреплять темы, которые прочёл пользователь, по умолчанию." + default_categories_watching: "Список просматриваемых разделов по умолчанию." + default_categories_tracking: "Список отслеживаемых разделов по умолчанию." + tagging_enabled: "Включить теги для тем?" + min_trust_to_create_tag: "Минимальный уровень доверия для создания тега." + max_tags_per_topic: "Максимальное количество тегов, которое может быть применено к теме." + max_tag_length: "Максимальное количество символов, которое может быть использовано в теге." + max_tag_search_results: "Максимальное количество строк для отображения результатов поиска тегов." + show_filter_by_tag: "Показывать выпадающий список для фильтра списка тем по тегу." + max_tags_in_filter_list: "Максимальное количество тегов для отображения в выпадающем списке фильтрации. Будут показаны самые часто используемые теги." + tags_sort_alphabetically: "Отображать теги в алфавитном порядке. По умолчанию теги отображаются в порядке популярности." + tag_style: "Стиль отображения для значков тегов." + staff_tags: "Список тегов, который может применяться только к персоналу." + min_trust_level_to_tag_topics: "Минимальный уровень доверия для отметки тем тегами." + suppress_overlapping_tags_in_list: "Не отображать тег, если он полностью совпадают с заголовком темы" + company_short_name: "Наименование Компании (кратко)" + company_full_name: "Наименование Компании (полное)" + company_domain: "Домен Компании" errors: invalid_email: "Неправильный адрес электронной почты." invalid_username: "Пользователя с таким ником не найдено." @@ -1095,6 +1159,13 @@ ru: invalid_string_min: "Требуется хотя бы %{min} знаков." invalid_string_max: "Допустимо не более %{max} знаков." invalid_reply_by_email_address: "Значение должно содержать '%{reply_key}' и должно отличаться от письма уведомления." + invalid_alternative_reply_by_email_addresses: "Все значения должны содержать '%{reply_key}' и должны отличаться от письма уведомления." + pop3_polling_host_is_empty: "Вы должны установить 'pop3 polling host' перед включением POP3 polling." + pop3_polling_username_is_empty: "Вы должны установить 'pop3 polling username' перед включением POP3 polling." + pop3_polling_password_is_empty: "Вы должны установить 'pop3 polling password' перед включением POP3 polling." + reply_by_email_address_is_empty: "Вы должны установить 'reply by email address' перед включением возможности ответа по e-mail." + user_locale_not_enabled: "Перед включением данной настройки необходимо включить 'allow user locale'." + invalid_regex: "Регулярное выражение недействительно или не разрешено." search: within_post: "#%{post_number} от %{username}" types: @@ -1105,6 +1176,7 @@ ru: not_found: "Мы не можем найти вашу учетную запись. Пожалуйста, свяжитесь с администратором сайта." account_not_approved: "Ваша учетная запись ожидает подтверждения. Вы получите уведомление по электронной почте, когда она будет подтверждена." unknown_error: "Произошла проблема с учетной записью. Пожалуйста, свяжитесь с администратором сайта." + timeout_expired: "Время входа в учётную запись истекло, пожалуйста, попробуйте войти снова." original_poster: "Автор" most_posts: "Большинство сообщений" most_recent_poster: "Последний автор" @@ -1112,6 +1184,15 @@ ru: redirected_to_top_reasons: new_user: "Добро пожаловать в наше сообщество! Вот самые популярные недавние темы." not_seen_in_a_month: "С возвращением! Т.к. вас не было какое-то время, мы собрали список популярных тем за время вашего отсутсвия. Вот они." + merge_posts: + edit_reason: + one: "Сообщение было объединено пользователем %{username}" + few: "%{count} сообщений было объединено пользователем %{username}" + many: "%{count} сообщений было объединено пользователем %{username}" + other: "%{count} сообщений было объединено пользователем %{username}" + errors: + different_topics: "Сообщения, принадлежащие другой теме, не могут быть объединены." + different_users: "Сообщения, принадлежащие разным пользователям, не могут быть объединены." move_posts: new_topic_moderator_post: one: "Сообщение перенесено в новую тему: %{topic_link}" @@ -1135,6 +1216,16 @@ ru: archived_disabled: "Эта тема разархивирована. Она более не заморожена, и может быть изменена." closed_enabled: "Эта тема закрыта. В ней больше нельзя отвечать." closed_disabled: "Эта тема открыта. В ней можно отвечать." + autoclosed_message_max_posts: + one: "Это сообщение было автоматически закрыто, когда количество ответов достигло максимума: 1." + few: "Это сообщение было автоматически закрыто, когда количество ответов достигло максимума: %{count}." + many: "Это сообщение было автоматически закрыто, когда количество ответов достигло максимума: %{count}." + other: "Это сообщение было автоматически закрыто, когда количество ответов достигло максимума: %{count}." + autoclosed_topic_max_posts: + one: "Эта тема была автоматически закрыта, когда количество ответов достигло максимума: 1." + few: "Эта тема была автоматически закрыта, когда количество ответов достигло максимума: %{count}." + many: "Эта тема была автоматически закрыта, когда количество ответов достигло максимума: %{count}." + other: "Эта тема была автоматически закрыта, когда количество ответов достигло максимума: %{count}." autoclosed_enabled_days: one: "Эта тема была автоматически закрыта спустя 1 день. В ней больше нельзя отвечать." few: "Эта тема была автоматически закрыта спустя %{count} дня. В ней больше нельзя отвечать." @@ -1189,25 +1280,37 @@ ru: something_already_taken: "Что-то пошло не так, возможно, имя пользователя или электронный ящик уже используются. Попробуйте восстановить ваш пароль." omniauth_error: "Извините, невозможно авторизовать вашу учетную запись. Возможно, вы не подтвердили авторизацию?" omniauth_error_unknown: "В процессе входа на сайт произошла ошибка. Пожалуйста, повторите попытку." + authenticator_error_no_valid_email: "Нет разрешённых e-mail адресов, связанных с учётной записью %{account}. Вам необходимо настроить учётную запись с помощью другого e-mail адреса." new_registrations_disabled: "Новые регистрации сейчас ограничены." password_too_long: "Максимальная длина пароля - 200 символов." + email_too_long: "E-mail, который Вы указали, слишком длинный. Имя почтового ящика должно быть не длиннее 254 символов, а доменное имя не более 253 символов." reserved_username: "Такой псевдоним не разрешен." missing_user_field: "Вы не заполнили все поля пользователя" close_window: "Аутентификация выполнена. Закройте это окно для продолжения." + already_logged_in: "Ой, кажется, Вы пытаетесь принять приглашение для другого пользователя. Если Вы не %{current_user}, пожалуйста, выйдите из учётной записи и попробуйте снова." user: no_accounts_associated: "Нет ассоциированных учетных записей" + deactivated_by_staff: "Выключено персоналом" + activated_by_staff: "Включено персоналом" username: short: "минимум %{min} знаков" long: "должно быть более %{max} знаков" characters: "должно состоять только из цифр и латинских букв" unique: "должно быть уникально" blank: "необходимо заполнить" + must_begin_with_alphanumeric_or_underscore: "должно начинаться с буквы, цифры или нижнего подчёркивания" + must_end_with_alphanumeric: "должно заканчиваться буквой или цифрой" + must_not_contain_two_special_chars_in_seq: "не должно содержать последовательность 2 и более специальных символов (.-_)" + must_not_end_with_confusing_suffix: "не должно заканчиваться на .json или .png и т.д., которые могут ввести в заблуждение" email: not_allowed: "недопустимый почтовый домен. Пожалуйста, используйте другой адрес." blocked: "не разрешено." + revoked: "Отправка e-mail на '%{email}' не будет осуществляться до %{date}." ip_address: blocked: "Новые регистрации запрещены с вашего IP-адреса." max_new_accounts_per_registration_ip: "Новые регистрации запрещены с вашего IP-адреса (достигнут лимит регистраций). Свяжитесь с администрацией." + website: + domain_not_allowed: "Сайт недействителен. Допустимые домены: %{domains}" flags_reminder: subject_template: one: "1 жалоба ожидает рассмотрения" @@ -1234,6 +1337,8 @@ ru: %{invite_link} Это персональное приглашение от зарегистрированного пользователя, поэтому вы смело можете сразу же приступать к обсуждению. + custom_invite_mailer: + subject_template: "%{invitee_name} приглашает Вас присоединиться к '%{topic_title}' на сайте %{site_domain_name}" invite_forum_mailer: subject_template: "%{invitee_name} приглашает вас присоединиться к %{site_domain_name}" invite_password_instructions: @@ -1270,7 +1375,10 @@ ru: deferred_and_deleted: "Спасибо за информацию. Сообщение удалено." temporarily_closed_due_to_flags: "Эта тема временно закрыта из-за большого количества жалоб." system_messages: + post_hidden: + title: "Сообщение Скрыто" welcome_user: + title: "Приветствие Пользователя" subject_template: "Добро пожаловать на %{site_name}!" text_body_template: | Спасибо, что зарегистрировались на сайте %{site_name} и добро пожаловать! @@ -1284,33 +1392,17 @@ ru: Приятного времяпровождения! welcome_invite: subject_template: "Добро пожаловать на %{site_name}!" - text_body_template: | - Спасибо, что приняли приглашение присоединиться к сайту %{site_name} и добро пожаловать! - - Мы автоматически дали вам имя пользователя: **%{username}**, но вы можете изменить его в любое время в [вашем профиле][prefs]. - - Чтобы снова зайти на сайт: - - 1. Используйте учетную запись Facebook, Google, Twitter, или одну из множества других поддерживаемых – но она должна быть зарегистрирована на **тот же адрес электронной почты**, на который вы получили приглашение. Иначе мы не можем быть уверены, что это вы. - - 2. Придумайте уникальный пароль в [вашем профиле][prefs], затем войдите на сайт, используя его. - - %{new_user_tips} - - Мы верим в [культурное сообщество](%{base_url}/guidelines) - - Наслаждайтесь общением! - - (если ва понадобиться помощь [staff members](%{base_url}/about) вы можите задать свой вопрос, просто ответив на это сообщение.) - - [prefs]: %{user_preferences_url} backup_succeeded: + title: "Успешное Резервное Копирование" subject_template: "Резервное копирование успешно завершено" backup_failed: + title: "Неудачное Резервное Копирование" subject_template: "Резервное копирование не удалось" restore_succeeded: + title: "Успешное Восстановление Данных" subject_template: "Восстановление данных успешно завершено" restore_failed: + title: "Неудачное Восстановление Данных" subject_template: "Восстановление данных не удалось" bulk_invite_succeeded: subject_template: "Массовое приглашение пользователей успешно выполнено" @@ -1326,6 +1418,7 @@ ru: %{logs} ``` csv_export_succeeded: + title: "Успешный Экспорт CSV" subject_template: "Экспорт завершен" text_body_template: | Экспорт данных прошел успешно. @@ -1334,6 +1427,7 @@ ru: Ссылка будет действать только 48 часов. csv_export_failed: + title: "Неудачный Экспорт CSV" subject_template: "Экспорт не удался" text_body_template: "Мы сожалеем, но возникли неполадки с экспортом ваших данных. Свяжитесь с администратором сайта." email_reject_inactive_user: @@ -1361,8 +1455,16 @@ ru: subject_template: "[%{site_name}] системное сообщение - Автоматически сгенерирован ответ" email_error_notification: subject_template: "[%{site_name}] Системное сообщение -- ошибка POP аутентификации" + blocked_by_staff: + title: "Заблокировано Персоналом" + subject_template: "Учётная запись временно заблокирована" + user_automatically_blocked: + title: "Автоматическая Блокировка Пользователя" spam_post_blocked: subject_template: "Сообщения нового пользователя %{username} заблокированы из-за повторяющихся ссылок" + unblocked: + title: "Разблокировано" + subject_template: "Учётная запись больше не заблокирована" pending_users_reminder: subject_template: one: "1 пользователь ожидает рассмотрение" @@ -1380,6 +1482,10 @@ ru: subject_template: "Обнаружены проблемы" text_body_template: | Некоторые проблемы требуют вашего внимания, более детально можно прочитать [в админке](%{base_url}/admin). + unsubscribe_link: | + Чтобы отписаться от таких писем, [нажмите сюда](%{unsubscribe_url}). + unsubscribe_link_and_mail: | + Чтобы отписаться от таких писем, [нажмите сюда](%{unsubscribe_url}). subject_re: "Re:" subject_pm: "[PM]" user_notifications: @@ -1387,6 +1493,8 @@ ru: unsubscribe: title: "Отписаться" description: "Не заинтересованы в получении данных писем? Нет проблем! Нажмите на ссылку ниже, чтобы мгновенно отписаться от рассылки:" + visit_link_to_respond: "[Посетите тему](%{base_url}%{url}) чтобы ответить." + visit_link_to_respond_pm: "[Посетите сообщение](%{base_url}%{url}) чтобы ответить." posted_by: "Отправлено %{username} %{post_date}" user_invited_to_private_message_pm: subject_template: "[%{site_name}] %{username} приглашает вас к обсуждению сообщения '%{topic_title}'" @@ -1410,8 +1518,28 @@ ru: subject_template: "%{optional_re}%{topic_title}" digest: why: "Сводка обсуждений на сайте %{site_link} с момента вашего последнего визита %{last_seen_at}" + since_last_visit: "С Вашего последнего посещения" + new_topics: "Новые Темы" + unread_messages: "Непрочитанные Сообщения" + unread_notifications: "Непрочитанные Уведомления" + liked_received: "Получено Симпатий" + new_posts: "Новые Сообщения" + new_users: "Новые Пользователи" + popular_topics: "Популярные Темы" + follow_topic: "Следить за этой темой" + join_the_discussion: "Читать Далее" + popular_posts: "Популярные Сообщения" + from_topic_label: "От" + more_new: "Новое для Вас" click_here: "нажмите здесь" + mailing_list: + why: "Вся активность на сайте %{site_link} за %{date}" + new_topics: "Новые темы" + topic_updates: "Обновления темы" + view_this_topic: "Посмотреть эту тему" + back_to_top: "Наверх" forgot_password: + title: "Забыл Пароль" subject_template: "[%{site_name}] Сброс пароля" text_body_template: | Кто-то запросил смену вашего пароля на сайте [%{site_name}](%{base_url}). @@ -1421,6 +1549,7 @@ ru: Пройдите по следующей ссылке, чтобы задать новый пароль: %{base_url}/users/password-reset/%{email_token} set_password: + title: "Установить Пароль" subject_template: "[%{site_name}] Установить пароль" text_body_template: | Кто-то попросил добавить пароль в вашу учётную запись на сайте [%{site_name}](%{base_url}). Вы так же можете войти на сайт используя любой поддерживаемый онлайн-сервис (такие как Google, Facebook и другие), которые связанны с вашим электронным адресом. @@ -1439,6 +1568,7 @@ ru: Ссылка для входа: %{base_url}/users/admin-login/%{email_token} account_created: + title: "Учётная Запись Создана" subject_template: "[%{site_name}] Ваша новая учетная запись" text_body_template: | Для вас была создана новая учетная запись на сайте %{site_name} @@ -1446,6 +1576,7 @@ ru: Чтобы установить пароль, пройдите по следующей ссылке: %{base_url}/users/password-reset/%{email_token} confirm_new_email: + title: "Подтвердить Новый E-mail" subject_template: "[%{site_name}] Подтвердите новый адрес электронной почты" text_body_template: | Подтвердите ваш новый адрес электронной почты для сайта %{site_name}, перейдя по следующей ссылке: @@ -1508,7 +1639,13 @@ ru: too_large: "Файл, который вы пытаетесь загрузить, слишком большой (максимальный разрешенный размер %{max_size_kb}%kb)." images: too_large: "Изображение, которое вы пытаетесь загрузить, слишком большое (максимальный разрешенный размер %{max_size_kb}%kb), пожалуйста, уменьшите размер изображения и повторите попытку." + larger_than_x_megapixels: "Изображение, которое вы пытаетесь загрузить, слишком большое (максимально допустимый размер %{max_image_megapixels}-мегапикселей), пожалуйста, уменьшите размер изображения и повторите попытку." size_not_found: "Извините, мы не можем определить размер изображения. Возможно, изображение повреждено?" + avatar: + missing: "К сожалению, нам не удалось найти ни одного аватара, связанного с этим электронным адресом. Попытаетесь загрузить аватар снова?" + flag_reason: + sockpuppet: "Новый пользователь создал тему, а другой новый пользователь ответил с этого же IP адреса (%{ip_address}). Смотрите параметр `flag_sockpuppets` сайта." + spam_hosts: "Этот новый пользователь пытался создать множество сообщений с ссылками на один и тот же домен (%{domain}). Смотрите параметр `newuser_spam_host_threshold` сайта." email_log: no_user: "Не найти пользователя с id %{user_id}" anonymous_user: "Гость" @@ -1542,10 +1679,124 @@ ru: privacy_topic: title: "Политика конфиденциальности" badges: + editor: + name: Редактор + description: Первое редактирование сообщения + long_description: | + Эта награда даруется, когда Вы впервые редактируете одно из своих сообщений. Хотя Вы не можете править ваши сообщения постоянно, редактирование - неизменно хорошая идея - вы можете улучшать Ваши сообщения, исправлять небольшие ошибки или добавлять что-то, что Вы пропустили ранее. Редактируйте, чтобы сделать Ваши сообщения ещё лучше! + basic_user: + name: Новичок + member: + name: Участник + long_description: | + Эта награда даруется, когда Вы достигаете уровня доверия 2. Благодарим за участие на протяжении недель, чтобы действительно присоединиться к нашему сообществу. Теперь Вы можете отправлять приглашения со своей пользовательской страницы или отдельных тем, создавать групповые личные беседы и иметь немного больше симпатий ежедневно. + regular: + name: Постоялец + leader: + name: Лидер + welcome: + name: Добро пожаловать + description: Получил симпатию + autobiographer: + name: Автобиограф + description: Заполнил информацию в профиле + anniversary: + name: Годовщина + nice_post: + name: Славный Ответ + description: Получил 10 симпатий за ответ + good_post: + name: Хороший Ответ + description: Получил 25 симпатий за ответ + great_post: + name: Отличный Ответ + description: Получил 50 симпатий за ответ + nice_topic: + name: Славная Тема + good_topic: + name: Хорошая Тема + description: Получил 25 симпатий за тему + great_topic: + name: Отличная Тема + description: Получил 50 симпатий за тему + nice_share: + name: Славный Пиар + description: Поделился сообщением с 25 уникальными посетителями + good_share: + name: Хороший Пиар + description: Поделился сообщением с 300 уникальными посетителями + great_share: + name: Отличный Пиар + description: Поделился сообщением с 1000 уникальными посетителями + first_like: + name: Первая Симпатия + description: Понравилось сообщение + first_flag: + name: Первая Жалоба + description: Оставил жалобу на сообщение + promoter: + name: Промоутер + description: Пригласил нового пользователя + campaigner: + name: Активист + description: Пригласил 3 новичков + champion: + name: Чемпион + description: Пригласил 5 участников + first_share: + name: Первый Пиар + description: Поделился сообщением + first_link: + name: Первая Ссылка + description: Добавил ссылку на другую тему + first_quote: + name: Первая Цитата + description: Процитировал сообщение + reader: + name: Читатель + description: Прочитал каждый ответ в теме с более чем 100 ответами + popular_link: + name: Популярная Ссылка + description: Оставил внешнюю ссылку, которую открыли более 50 раз + hot_link: + name: Горячая Ссылка + description: Оставил внешнюю ссылку, которую открыли более 300 раз + famous_link: + name: Легендарная Ссылка + description: Оставил внешнюю ссылку, которую открыли более 1000 раз + appreciated: + name: Оценённый + description: Получил 1 симпатию, отправив 20 сообщений + respected: + name: Уважаемый + description: Получил 2 симпатии, отправив 100 сообщений + admired: + name: Почитаемый + description: Получил 5 симпатий, отправив 300 сообщений + out_of_love: + name: За Любовь + description: Использовал 50 симпатий за день + higher_love: + name: Высшая Любовь + crazy_in_love: + name: Безумная Любовь + thank_you: + name: Благодарный + gives_back: + name: Взаимная Симпатия + empathetic: + name: Чуткий + first_emoji: + name: Первый Смайлик + description: Использовал Смайлик в Сообщении first_mention: name: Первое обращение description: Упомянул другого пользователя в сообщении long_description: Эта награда выдается, когда вы впервые вставляете чей-то @псевдоним в свое сообщение. Каждое такое обращение отправит уведомление этому человеку, чтобы они были в курсе вашего сообщения. Чтобы вставить обращение к человеку по его псевдониму, или к целой группе по ее названию (если это разрешено), начните с символа @ - это удобный способ привлечь их внимание. + first_onebox: + name: Первая Умная Вставка + first_reply_by_email: + name: Первый Ответ По Почте admin_login: success: "письмо отправлено" error: "Ошибка!" @@ -1556,24 +1807,62 @@ ru: performance_report: initial_post_raw: Эта тема содержит ежедневные отчеты активности форума. initial_topic_title: Отчеты активности форума + topic_invite: + user_exists: "К сожалению, этот пользователь уже был приглашён. Вы можете пригласить пользователя в тему только один раз." + tags: + title: "Теги" + staff_tag_disallowed: "Тег \"%{tag}\" может быть применён только персоналом." + staff_tag_remove_disallowed: "Тег \"%{tag}\" может быть удалён только персоналом." + rss_by_tag: "Темы, отмеченные тегом %{tag}" finish_installation: + congratulations: "Поздравляем, Вы установили Discourse!" + register: + button: "Зарегистрироваться" + title: "Зарегистрировать Учётную Запись Администратора" + help: "зарегистрируйте новую учётную запись, чтобы начать" confirm_email: title: "Подтвердите адрес вашей электронной почты" resend_email: title: "Отправить письмо для активации повторно" + safe_mode: + title: "Войти в Безопасный Режим" + description: "Безопасный режим позволяет Вам проверить работу Вашего сайта без загрузки плагинов и настроек сайта." + no_customizations: "Отключить все настройки сайта" + only_official: "Отключить неофициальные плагины" + no_plugins: "Отключить все плагины" + enter: "Войти в Безопасный Режим" wizard: title: "Настройка Discourse" step: + locale: + title: "Добро пожаловать в Ваш Discourse!" + fields: + default_locale: + description: "Язык по умолчанию для Вашего сообщества?" forum_title: title: "Наименование" + fields: + site_description: + label: "Опишите Ваше сообщество одним коротким предложением" introduction: title: "Введение" fields: welcome: label: "Приветственная тема" + one_paragraph: "Пожалуйста, ограничьте Ваше приветственное сообщение одним абзацем." privacy: title: "Доступ" + fields: + privacy: + choices: + open: + label: "Открытое" + description: "Любой может получить доступ к этому сообществу и зарегистрировать учётную запись" + restricted: + label: "Частное" + description: "Только люди, которые приглашены или одобрены мной, могут иметь доступ к этому сообществу" contact: + title: "Контакты" fields: contact_email: placeholder: "name@example.com" @@ -1596,19 +1885,20 @@ ru: title: "Цветовая схема" fields: theme_id: - description: "Вы предпочитаете начать со светлой или темной цветовой схеме? Вы всегда сможете настроить внешний вид вашего сайта с помощью инструментов администратора." choices: default: label: "Светлая" dark: label: "Тёмная" logos: + title: "Логотипы" fields: logo_url: label: "Основная иконка" logo_small_url: label: "Компактная иконка" icons: + title: "Иконки" fields: favicon_url: label: "Маленькая иконка" diff --git a/config/locales/server.sk.yml b/config/locales/server.sk.yml index 3b95980404d..d9e61ec6bdd 100644 --- a/config/locales/server.sk.yml +++ b/config/locales/server.sk.yml @@ -99,8 +99,6 @@ sk: max_username_length_range: "Nemôžete nastaviť maximum menšie ako minimum." default_categories_already_selected: "Nemôžete vybrať kategóriu použitú v inom zozname." s3_upload_bucket_is_required: "Nemôžete nahrávať na S3 pokiaľ ste nezadali 's3_upload_bucket'." - bulk_invite: - file_should_be_csv: "Nahrávaný súbor by mal byť vo formáte csv alebo txt." backup: operation_already_running: "Prebieha spracovanie inej operácie. Momentálne sa nová úloha nedá spustiť. " backup_file_should_be_tar_gz: "Záložný súbor musí byť archív .tar.gz" @@ -831,9 +829,7 @@ sk: top_page_default_timeframe: "Východzí interval pre presmerovanie na hlavnú stránku." show_email_on_profile: "Zobraziť používateľov email na ich profile (viditeľné len nimi samotnými a obsluhou)" email_token_valid_hours: "Platnosť tokenov pre Zabudnuté heslo a aktiváciu účtu v (n) hodinách." - email_token_grace_period_hours: "Platnosť tokenov pre Zabudnuté heslo a aktiváciu účtu v (n) hodinách po ich uplatnení." enable_badges: "Povoliť systém odznakov" - enable_whispers: "Povoliť súkromnú konverzáciu pre redakciu v rámci témy. (experimantálne)" allow_index_in_robots_txt: "V súbore robots.txt nastaviť, že tieto stránky je povolené indexovať vyhľadávačmi." email_domains_blacklist: "Rúrou oddelený zoznam emailových domén, ktorých použitie nie je povolené pri registrácií. Napríklad: mailinator.com|trashmail.net" email_domains_whitelist: "Zoznam emailových domén oddelených zvislým oddelovačom \"|\", s použitím ktorých sa používateľ MUSÍ zaregistrovať. VAROVANIE: registrácia použivatelia s neuvedenými doménami nebude povolená!" @@ -1065,7 +1061,6 @@ sk: embed_whitelist_selector: "CSS prepínač na elementy, ktoré sú povolené pri vkladaní." embed_blacklist_selector: "CSS prepínač na elementy, ktoré sú vymazané pri vkladaní." notify_about_flags_after: "Ak existujú príznaky ktoré neboli vyriešené po uvedenom počte hodín, pošli email na contact_email. Pre vypnutie nastavte 0." - enable_cdn_js_debugging: "Pomocou pridania \"crossorigin\" práv pre všetky vložené js umožniť /logs riadne zobrazenie chýb." show_create_topics_notice: "Zobraz výzvu žiadajúcu administrátorov o vytvorenie nejakých tém, ak majú stránky menej ako 5 verejných tém." delete_drafts_older_than_n_days: Vymazať návrhy staršie ako (n) dní. vacuum_db_days: "Spustiť VACUUM ANALYZE na získanie DB miesto po migráciách (pre vypnutie nastavte na 0)" diff --git a/config/locales/server.sq.yml b/config/locales/server.sq.yml index 7e7b4641f2b..b3049632a47 100644 --- a/config/locales/server.sq.yml +++ b/config/locales/server.sq.yml @@ -62,8 +62,6 @@ sq: load_from_remote: "Postimi nuk mundi të ngarkohet. Riprovoheni!" site_settings: default_categories_already_selected: "Nuk mund të zgjidhni një kategori të përdorur në një tjetër listë." - bulk_invite: - file_should_be_csv: "Skedari duhet të jete i formatit csv ose txt" not_logged_in: "Ju duhet të identifikoheni për këtë veprim." invalid_access: "Ju nuk jeni të drejta për të parë burimin e kërkuar." reading_time: "Koha e leximit" @@ -657,7 +655,6 @@ sq: redirect_users_to_top_page: "Automatically redirect new and long absent users to the top page." show_email_on_profile: "Show a user's email on their profile (only visible to themselves and staff)" email_token_valid_hours: "Forgot password / activate account tokens are valid for (n) hours." - email_token_grace_period_hours: "Forgot password / activate account tokens are still valid for a grace period of (n) hours after being redeemed." enable_badges: "Aktivizo sistemin e targetave" allow_index_in_robots_txt: "Specify in robots.txt that this site is allowed to be indexed by web search engines." email_domains_blacklist: "A pipe-delimited list of email domains that users are not allowed to register accounts with. Example: mailinator.com|trashmail.net" @@ -863,7 +860,6 @@ sq: embed_whitelist_selector: "CSS selector for elements that are allowed in embeds." embed_blacklist_selector: "CSS selector for elements that are removed from embeds." notify_about_flags_after: "If there are flags that haven't been handled after this many hours, send an email to the contact_email. Set to 0 to disable." - enable_cdn_js_debugging: "Allow /logs to display proper errors by adding crossorigin permissions on all js includes." show_create_topics_notice: "If the site has fewer than 5 public topics, show a notice asking admins to create some topics." delete_drafts_older_than_n_days: Delete drafts older than (n) days. prevent_anons_from_downloading_files: "Prevent anonymous users from downloading attachments. WARNING: this will prevent any non-image site assets posted as attachments from working." @@ -1025,32 +1021,8 @@ sq: invite_forum_mailer: subject_template: "%{invitee_name} ju ka ftuar të bëheni pjesë e %{site_domain_name}" - text_body_template: | - %{invitee_name} ju ka ftuar të bëheni pjesë e - > **%{site_title}** - > - > %{site_description} - - Nëse jeni i interesuar, klikoni lidhjen e mëposhtme: - %{invite_link} - - Kjo ftesë vjen nga një përdorues i besuar, si rrjedhojë një llogari do të krijohet automatikisht për ju. custom_invite_forum_mailer: subject_template: "%{invitee_name} ju ka ftuar të bëheni pjesë e %{site_domain_name}" - text_body_template: | - %{invitee_name} ju ka ftuar të bëheni pjesë e - > **%{site_title}** - > - > %{site_description} - - Mesazhi nga %{invitee_name}: - - %{user_custom_message} - - Nëse jeni i interesuar, klikoni lidhjen e mëposhtme: - %{invite_link} - - Kjo ftesë vjen nga një përdorues i besuar, si rrjedhojë një llogari do të krijohet automatikisht për ju. invite_password_instructions: subject_template: "Vendos fjalëkalimin për llogarinë tek %{site_name}" text_body_template: |+ @@ -1114,26 +1086,6 @@ sq: (Nëse ju duhet të komunikoni me [anëtarët e stafit](%{base_url}/about) si një anëtar i ri, thjesht përgjigjuni këtij mesazhi.) welcome_invite: subject_template: "Mirë se vini tek %{site_name}!" - text_body_template: | - Thanks for accepting your invitation to %{site_name} -- welcome! - - We've created a new account **%{username}** for you, and you are logged in. You can change your name by visiting [your user profile][prefs]. - - To log in again later: - - 1. Always **use the same email address from your original invitation** when logging in. Otherwise we won't be able to tell it's you! - - 2. Create a unique password for [your user profile][prefs], and use it to log in. - - %{new_user_tips} - - We believe in [civilized community behavior](%{base_url}/guidelines) at all times. - - Enjoy your stay! - - (If you need to communicate with [staff members](%{base_url}/about) as a new user, just reply to this message.) - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "Backup completed successfully" backup_failed: diff --git a/config/locales/server.sv.yml b/config/locales/server.sv.yml index 6628bb63ad0..e2677e06f14 100644 --- a/config/locales/server.sv.yml +++ b/config/locales/server.sv.yml @@ -104,8 +104,6 @@ sv: max_username_length_range: "Du kan inte sätta maximum högre än minimum." default_categories_already_selected: "Du kan inte välja en kategori som används i en annan lista. " s3_upload_bucket_is_required: "Du kan inte aktivera uppladdning till S3 innan du har angivit 's3_upload_bucket'." - bulk_invite: - file_should_be_csv: "Den uppladdade filen ska vara i csv eller txt format." backup: operation_already_running: "En operation är redan igång. Kan inte starta ett nytt jobb just nu." backup_file_should_be_tar_gz: "Backup-filen ska vara ett .tar.gz arkiv." @@ -852,9 +850,7 @@ sv: show_email_on_profile: "Visa en användares e-postadress på deras profil (endast synlig för de själva och för personal)" prioritize_username_in_ux: "Använd användarnamn först på användarsidan, användarkortet och inlägg (när inaktiverad så visas namnet först)" email_token_valid_hours: "Glömt lösenord / aktivera konto länkar är giltiga i (n) timmar." - email_token_grace_period_hours: "Glömt lösenord / aktivera konto länkar är fortfarande giltiga i en nådefrist på (n) timmar efter att ha blivit utlösta." enable_badges: "Aktivera utmärkelsesystemet" - enable_whispers: "Tillåt privat kommunikation mellan personal inom ett ämne. (experimentellt)" allow_index_in_robots_txt: "Specificera i robots.txt att den här webbplatsen tillåter att bli indexerad av sökmotorer. " email_domains_blacklist: "En pipe-avgränsad lista av alla e-postdomän som användare inte tillåts registrera konton med. Exempel: mailinator.com, trashmail.net" email_domains_whitelist: "En pipe-avgränsad lista av alla e-postdomän som användare MÅSTE registrera konton med. VARNING: Användare med e-postdomän som inte finns på listan kommer inte att tillåtas!" @@ -1122,7 +1118,6 @@ sv: embed_whitelist_selector: "CSS-väljare för element som tillåts bäddas in. " embed_blacklist_selector: "CSS-väljare för element som tas bort från inbäddningar." notify_about_flags_after: "Skicka ett e-postmeddelande till contact_email om det finns flaggor som inte har hanterats efter så här många timmar. Ange 0 för att inaktivera." - enable_cdn_js_debugging: "Tillåt /logs att visa lämpliga fel genom att lägga till ursprungstillståndet på alla js-inkluderingar." show_create_topics_notice: "Visa en notis som ber administratörerna att skapa några ämnen om webbplatsen har färre än 5 publika ämnen." delete_drafts_older_than_n_days: Ta bort utkast som är äldre än (n) dagar. bootstrap_mode_min_users: "Minsta antal användare som krävs för att inaktivera bootstrap-läget (ange 0 för att inaktivera)" @@ -1361,36 +1356,8 @@ sv: Denna inbjudan är från en betrodd användare, så du kan direkt delta och svara i diskussionen. invite_forum_mailer: subject_template: "%{invitee_name} har bjudit in dig till %{site_domain_name}" - text_body_template: | - %{invitee_name} har bjudit in dig till - - > **%{site_title}** - > - > %{site_description} - - Om du är intresserad, klicka på länken nedan: - - %{invite_link} - - Denna inbjudan kommer från en betrodd användare, så ett konto kommer att skapas åt dig automatiskt. custom_invite_forum_mailer: subject_template: "%{invitee_name} har bjudit in dig till %{site_domain_name}" - text_body_template: | - %{invitee_name} har bjudit in dig till - - > **%{site_title}** - > - > %{site_description} - - Meddelande från %{invitee_name}: - - %{user_custom_message} - - Om du är intresserad, klicka på länken nedan: - - %{invite_link} - - Denna inbjudan kommer från en betrodd användare, så ett konto kommer att skapas åt dig automatiskt. invite_password_instructions: subject_template: "Ange lösenord för ditt konto på %{site_name}" text_body_template: | @@ -1457,26 +1424,6 @@ sv: (Om du som ny användare behöver komma i kontakt med vår [personal](%{base_url}/about), svara bara på detta meddelande) welcome_invite: subject_template: "Välkommen till %{site_name}!" - text_body_template: | - Tack för att du accepterade din inbjudan till %{site_name} -- välkommen! - - Vi har skapat ett nytt konto **%{username}** till dig och du är inloggad. Du kan byta namn genom att besöka [din användarprofil][prefs]. - - För att logga in senare: - - 1. Använda alltid **samma e-postadress som från din ursprungliga inbjudan** när du loggar in. Annars vet vi inte att det är du! - - 2. Skapa ett unikt lösenord för [din användarprofil][prefs], och använd det för att logga in. - - %{new_user_tips} - - Vi tror på ett [civiliserat beteende](%{base_url}/guidelines) vid alla tillfällen. - - Njut av din vistelse! - - (Om du som ny användare behöver komma i kontakt med vår [personal](%{base_url}/about), svara bara på detta meddelande.) - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "Säkerhetskopia skapades utan problem" backup_failed: diff --git a/config/locales/server.te.yml b/config/locales/server.te.yml index 1c8fa5ffc6c..aedbb418965 100644 --- a/config/locales/server.te.yml +++ b/config/locales/server.te.yml @@ -61,8 +61,6 @@ te: other: '%{count} దోషాల వల్ల %{model} భద్రపరుచుట వీలవలేదు' embed: load_from_remote: "ఈ టపా లోడింగులో దోషం" - bulk_invite: - file_should_be_csv: "ఎగుమతించే దస్త్రం కేవలం csv లేదా txt రూపంలో ఉండాలి" backup: operation_already_running: "ఒక పరిక్రియ ప్రస్తుతం జరుగుతోంది. కొత్త పని ఇప్పుడు మొదలుపెట్టవీలవదు." backup_file_should_be_tar_gz: "బ్యాకప్ దస్త్రం తప్పనిసరి .tar.gz కట్ట అయి ఉండాలి." diff --git a/config/locales/server.tr_TR.yml b/config/locales/server.tr_TR.yml index 0e3ef4eef73..4b0f8ae3898 100644 --- a/config/locales/server.tr_TR.yml +++ b/config/locales/server.tr_TR.yml @@ -89,8 +89,6 @@ tr_TR: max_username_length_range: "En küçük değer altında en büyük değer ayarlayamazsınız." default_categories_already_selected: "Bir başka listede kullanılan bir kategoriyi seçemezsiniz." s3_upload_bucket_is_required: "Bir 's3_upload_bucket' tanımlamadıysanız, S3 yüklemelerini etkinleştiremezsiniz." - bulk_invite: - file_should_be_csv: "Yüklenen dosya csv veya txt biçiminde olmalı. " backup: operation_already_running: "Devam eden bir işlem var. Yeni bir işlem başlatılamaz." backup_file_should_be_tar_gz: "Yedekleme dosyası .tar.gz uzantılı olmalı." @@ -785,9 +783,7 @@ tr_TR: show_email_on_profile: "Kullanıcının e-posta adresini profilinde göster (sadece kendilerine ve site görevlilerine gözükür)" prioritize_username_in_ux: "Kullanıcı sayfası, kullanıcı kartı ve gönderilerde kullanıcı adını ilk olarak göster(devre dışı ise gerçek isim önce gözükür)" email_token_valid_hours: "Parolamı unuttum / hesap etkinleştirme jetonları (n) saat geçerlidir." - email_token_grace_period_hours: "Parolamı unuttum / hesabı etkinleştir jetonları kullanıldıktan sonra (n) saat boyunca hala geçerlidir." enable_badges: "Rozet sistemini etkinleştir" - enable_whispers: "Konu içerisinde görevlilerin birbirleriyle gizli olarak iletişim kurmasına izin ver. (deneyseldir)" allow_index_in_robots_txt: "robots.txt dosyasında bu sitenin arama motorları tarafından dizinlenmesine izin verildiğini belirt." email_domains_blacklist: "Kullanıcıların kayıt olurken kullanamayacağı e-posta alan adlarının, dikey çizgilerle ayrıştırılmış listesi. Örneğin: mailinator.com|trashmail.net" email_domains_whitelist: "Kullanıcıların kayıt olurken kullanmak ZORUNDA olduğu e-posta alan adlarının, dikey çizgilerle ayrıştırılmış listesi. UYARI: Bu listede yer almayan e-posta alan adları kabul edilmeyecektir!" @@ -1040,7 +1036,6 @@ tr_TR: embed_whitelist_selector: "Yerleştirmelerde kullanılmasına izin verilen öğeler için CSS seçicisi." embed_blacklist_selector: "Yerleştirmelerden çıkartılmış öğeler için CSS seçicisi." notify_about_flags_after: "Bu kadar saat geçmesine rağmen hala ilgilenilmemiş bildirimler varsa, contact_email adresine e-posta gönder. Devre dışı bırakmak için 0 girin. " - enable_cdn_js_debugging: "/logs 'ların asli hataları tüm js içeriklerine crossorigin izinleri ekleyerek göstermesine izin ver." show_create_topics_notice: "Eğer sitede herkese açık konu sayısı 5'den az ise, yöneticiden yeni konular oluşturmasını isteyen bir uyarı iletisi göster. " delete_drafts_older_than_n_days: (n) günden eski taslakları sil. bootstrap_mode_min_users: "bootstrap modunun edilgen olması için gereken en az kullanıcı sayısı (edilgen bırakmak için 0 yapın)" @@ -1265,36 +1260,8 @@ tr_TR: Bu davet güvenilir bir kullanıcı tarafından gönderilmiştir, cevap yazarak tartışmaya hemen katılabilirsiniz. invite_forum_mailer: subject_template: "%{invitee_name} sizi %{site_domain_name} sitesine katılmanız için davet etti" - text_body_template: | - %{invitee_name} sizi foruma katılmaya davet ediyor - - > **%{site_title}** - > - > %{site_description} - - Eğer ilgileniyorsanız, aşağıdaki bağlantıya tıklayın: - - %{invite_link} - - Bu davet güvenilir bir üyeden gönderildi, bu nedenle hesabınız sizin için otomatik olarak oluşturulacak. custom_invite_forum_mailer: subject_template: "%{invitee_name} sizi %{site_domain_name} sitesine katılmaya davet etti" - text_body_template: | - %{invitee_name} sizi foruma katılmaya davet ediyor - - > **%{site_title}** - > - > %{site_description} - - %{invitee_name} diyor ki: - - %{user_custom_message} - - Eğer ilgileniyorsanız, aşağıdaki bağlantıya tıklayın: - - %{invite_link} - - Bu davet güvenilir bir üyeden gönderildi, bu nedenle hesabınız sizin için otomatik olarak oluşturulacak. invite_password_instructions: subject_template: "%{site_name} hesabınız için parola oluşturun" text_body_template: | @@ -1354,99 +1321,6 @@ tr_TR: system_messages: post_hidden: subject_template: "Gönderi topluluk bildirimleri tarafından gizlendi" - usage_tips: - text_body_template: | - İşte başlangıç için birkaç ipucu: - - ## Okuma - - Daha fazla okumak için, **yalnızca aşağı kaydırmaya devam edin!** - - As new replies or new topics arrive, they will appear automatically – no need to refresh the page. - - ## Gezinti - - - For search, your user page, or the menu, use the **icon buttons at upper right**. - - - Selecting a topic title will always take you to your **next unread reply** in the topic. To enter at the top or bottom instead, select the reply count or last reply date. - - - - - While reading a topic, use the timeline on the right to jump to the top, bottom, or your last read position. On smaller screens, select the progress bar at bottom right to expand it: - - - - Ayrıca süper hızlı klavye kısayollarının listesini görmek için ? tuşuna basabilirsiniz. - - ## Cevaplama - - To insert a quote, select the text you wish to quote, then press any Reply button to open the editor. Repeat for multiple quotes. - - - - You can always continue reading while you compose your reply, and we automatically save drafts as you write. - - Birine cevabınız hakkında bildirim yollamak için ismini kullanın. `@` yazarak kullanıcı ismi aramaya başlayabilirsiniz. - - - - To use [standard Emoji](http://www.emoji.codes/), just type `:` to match by name, or use the traditional smileys `;)` - - - - To generate a summary for a link, paste it on a line by itself: - - - - Cevabınız basit HTML, BBCode, veya [Markdown](http://commonmark.org/help/) kullanılarak biçimlendirilebilir: - - Bu kalın. - Bu da [b]kalın[/b]. - E bu da **kalın**. - - Daha fazla biçimlendirme ipucu için [10 dakikalık öğreticiyi](http://commonmark.org/help/tutorial/) deneyebilirsiniz! - - ## Eylemler - - Tüm gönderilerin altında eylem düğmeleri bulunur: - - - - - To let someone know that you enjoyed and appreciated their post, use the **like** button. Share the love! - - - Grab a copy-pasteable link to any reply or topic via the **link** button. - - - Use the show more button to reveal more actions. **Flag** to privately let the author, or [our staff](%{base_url}/about), know about a problem. **Bookmark** to find this post later on your profile page. - - ## Bildirimler - - When someone replies to you, quotes your post, mentions your `@username`, or even links to your post, a number will immediately appear at the top right of the page. Select it to access your **notifications**. - - - - Don't worry about missing a reply – you'll be emailed any notifications that arrive when you are away. - - ## Tercihler - - - All topics less than **two days old** are considered new. - - - Any topic you've **actively participated in** (by creating it, replying to it, or reading it for an extended period) will be automatically tracked on your behalf. - - You will see the new and unread number indicators next to these topics: - - - - You can change your notifications for any topic via the notification control at the bottom, and right hand side, of each topic. - - - - You can also set notification state per category, if you want to watch or mute every new topic in a specific category. - - Bu ayarların herhangi birini değiştirmek için [kullanıcı tercihleri](%{base_url}/my/preferences) sayfasını ziyaret edin. - - ## Topluluk Güvenilirliği - - It's great to meet you! As you participate here, over time we'll get to know you, and your temporary new user limitations will be lifted. Keep participating, and over time you'll gain new [trust levels](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924) that include special abilities to help us manage our community together. welcome_user: subject_template: "%{site_name} topluluğuna hoş geldiniz!" text_body_template: | @@ -1461,26 +1335,6 @@ tr_TR: (Eğer yeni bir kullanıcı olarak [görevlilerle](%{base_url}/about) iletişim kurmak isterseniz, bu iletiyi cevaplamanız yeterli.) welcome_invite: subject_template: "%{site_name} topluluğuna hoş geldiniz!" - text_body_template: | - %{site_name} davetiyenizi onayladığınız için teşekkürler -- hoş geldiniz! - - Sizin için yeni bir hesap oluşturduk: **%{username}**, ve sisteme girişiniz yapıldı. [Kullanıcı profilinizi][prefs] ziyaret ederek kullanıcı adınızı değiştirebilirsiniz. - - Daha sonra tekrar giriş yapmak için: - - 1. Giriş yaparken her zaman **ilk davetiyenizdeki ile aynı e-posta adresini kullanın**. Yoksa sizin olduğunuzu anlayamayız! - - 2. [Kullanıcı profiliniz][prefs] için yeni bir parola oluşturun ve o parola ile giriş yapın. - - %{new_user_tips} - - Biz her zaman [topluluk yönergelerimize](%{base_url}/guidelines) inanıyoruz. - - Ziyaretinizin keyfini çıkarın! - - (Eğer yeni bir kullanıcı olarak [görevlilerle](%{base_url}/about) iletişim kurmak isterseniz, bu iletiyi cevaplamanız yeterli.) - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "Yedekleme başarıyla tamamlandı" text_body_template: | @@ -1812,7 +1666,6 @@ tr_TR: follow_topic: "Bu konuyu takip et" join_the_discussion: "Devamını Oku" popular_posts: "Gözde Gönderiler" - more_new: "Takip ettiğiniz konu ve kategorideki yeniler" subject_template: "[%{site_name}] Özeti" unsubscribe: "Bir süredir görünmediğiniz için bu e-posta size %{site_link} topluluğundan gönderildi. Bu e-postaları almak istemiyorsanız %{unsubscribe_link}." click_here: "buraya tıklayın" @@ -2239,11 +2092,9 @@ tr_TR: fields: welcome: label: "Hoş geldiniz Konusu" - description: "

    Bir çay evindeki birine topluluğunuzu 1 dakikada nasıl anlatırsınız?

    • Bu tartışmalar kimler için?
    • Burada ne bulabilirim?
    • Neden ziyaret etmeliyim?

    Hoş geldiniz konusu yeni ziyaretçilerin ilk göreceği şeydir. Bunu sizin tek nefeslik 'çay konunuz' veya 'ısmarlama çayınız' olarak görebilirsiniz.

    " one_paragraph: "Lütfen hoş geldiniz iletinizi bir paragraf kadar uzunlukta tutun." privacy: title: "Erişim" - description: "

    Topluluğunuz herkese açık mı yoksa üyelik, davet veya onaylama ile kısıtlı mı? Dilerseniz bu seçeneği daha sonra değiştirebilirsiniz.

    Kullanıcı sayfanızdan ve konulardan davetiye gönderebileceğini unutmayın.

    " fields: privacy: choices: @@ -2266,7 +2117,6 @@ tr_TR: label: "Otomatik İletiler" description: "Discourse tarafından gönderilen tüm otomatik kişisel iletiler bu kullanıcı tarafından gönderilecek. Daha da önemlisi, kullanıcılara gidecek olan hoş geldiniz mesajları da bu kullanıcı tarafından gönderilecek." corporate: - description: "Bu isimler sonradan düzenleyebileceğiniz Gizlilik Politikası ve Hizmet Şartları metinlerinde kullanılacak. Eğer bir şirket söz konusu değilse bu adımı geçebilirsiniz." fields: company_short_name: label: "Firma İsmi (kısa)" @@ -2281,7 +2131,6 @@ tr_TR: title: "Tema" fields: theme_id: - description: "Başlamak için renk düzeni olarak karanlık mı yoksa aydınlık mı istersiniz? Dilediğiniz zaman daha fazla seçeneği Yönetici, Özelleştir alanında bulabilirsiniz." choices: default: label: "Basit Aydınlık" diff --git a/config/locales/server.ur.yml b/config/locales/server.ur.yml index 7dbd43329c0..ffdc57e4272 100644 --- a/config/locales/server.ur.yml +++ b/config/locales/server.ur.yml @@ -1,3379 +1,18 @@ # encoding: utf-8 -# This file contains content for the server portion of Discourse used by Ruby # -# To work with us on translations, see: +# Never edit this file. It will be overwritten when translations are pulled from Transifex. +# +# To work with us on translations, join this project: # https://www.transifex.com/projects/p/discourse-org/ -# -# This is a "source" file, which is used by Transifex to get translations for other languages. -# After this file is changed, it needs to be pushed by a maintainer to Transifex: -# -# tx push -s -# -# Read more here: https://meta.discourse.org/t/contribute-a-translation-to-discourse/14882 -# -# To validate this YAML file after you change it, please paste it into -# http://yamllint.com/ ur: - dates: - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - short_date_no_year: "D MMM" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - short_date: "D MMM, YYYY" - # Use Moment.js format string: http://momentjs.com/docs/#/displaying/format/ - long_date: "MMMM D, YYYY h:mma" - - datetime_formats: &datetime_formats - formats: - # Format directives: http://ruby-doc.org/core-2.3.1/Time.html#method-i-strftime - short: "%m-%d-%Y" - # Format directives: http://ruby-doc.org/core-2.3.1/Time.html#method-i-strftime - short_no_year: "%B %-d" - # Format directives: http://ruby-doc.org/core-2.3.1/Time.html#method-i-strftime - date_only: "%B %-d, %Y" - # Format directives: http://ruby-doc.org/core-2.3.1/Time.html#method-i-strftime - long: "%B %-d, %Y, %l:%M%P" - date: - # Do not remove the brackets and commas and do not translate the first month name. It should be "null". - month_names: - [~, January, February, March, April, May, June, July, August, September, October, November, December] - <<: *datetime_formats - time: - <<: *datetime_formats - am: "am" - pm: "pm" - - title: "Discourse" - topics: "Topics" - posts: "posts" - loading: "Loading" - powered_by_html: 'Powered by Discourse, best viewed with JavaScript enabled' - log_in: "Log In" - - purge_reason: "Automatically deleted as abandoned, deactivated account" - disable_remote_images_download_reason: "Remote images download was disabled because there wasn't enough disk space available." - anonymous: "Anonymous" - - emails: - incoming: - default_subject: "Incoming email from %{email}" - show_trimmed_content: "Show trimmed content" - maximum_staged_user_per_email_reached: "Reached maximum number of staged users created per email." - errors: - empty_email_error: "Happens when the raw mail we received was blank." - no_message_id_error: "Happens when the mail has no 'Message-Id' header." - auto_generated_email_error: "Happens when the 'precedence' header is set to: list, junk, bulk or auto_reply, or when any other header contains: auto-submitted, auto-replied or auto-generated." - no_body_detected_error: "Happens when we couldn't extract a body and there were no attachments." - inactive_user_error: "Happens when the sender is not active." - blocked_user_error: "Happens when the sender has been blocked." - bad_destination_address: "Happens when none of the email addresses in To/Cc/Bcc fields matched a configured incoming email address." - strangers_not_allowed_error: "Happens when a user tried to create a new topic in a category they're not a member of." - insufficient_trust_level_error: "Happens when a user tried to create a new topic in a category they don't have the required trust level for." - reply_user_not_matching_error: "Happens when a reply came in from a different email address the notification was sent to." - topic_not_found_error: "Happens when a reply came in but the related topic has been deleted." - topic_closed_error: "Happens when a reply came in but the related topic has been closed." - bounced_email_error: "Email is a bounced email report." - screened_email_error: "Happens when the sender's email address was already screened." - + title: "ڈسکورس" errors: &errors - format: ! '%{attribute} %{message}' messages: - too_long_validation: "is limited to %{max} characters; you entered %{length}." - invalid_boolean: "Invalid boolean." - taken: "has already been taken" - accepted: must be accepted - blank: can't be blank - present: must be blank - confirmation: ! "doesn't match %{attribute}" - empty: can't be empty - equal_to: must be equal to %{count} - even: must be even - exclusion: is reserved - greater_than: must be greater than %{count} - greater_than_or_equal_to: must be greater than or equal to %{count} - has_already_been_used: "has already been used" - inclusion: is not included in the list - invalid: is invalid - is_invalid: "seems unclear, is it a complete sentence?" - less_than: must be less than %{count} - less_than_or_equal_to: must be less than or equal to %{count} - not_a_number: is not a number - not_an_integer: must be an integer - odd: must be odd - record_invalid: ! 'Validation failed: %{errors}' - restrict_dependent_destroy: - one: "Cannot delete record because a dependent %{record} exists" - many: "Cannot delete record because dependent %{record} exist" - too_long: - one: is too long (maximum is 1 character) - other: is too long (maximum is %{count} characters) - too_short: - one: is too short (minimum is 1 character) - other: is too short (minimum is %{count} characters) - wrong_length: - one: is the wrong length (should be 1 character) - other: is the wrong length (should be %{count} characters) - other_than: "must be other than %{count}" - template: - body: ! 'There were problems with the following fields:' - header: - one: 1 error prohibited this %{model} from being saved - other: ! '%{count} errors prohibited this %{model} from being saved' - embed: - load_from_remote: "There was an error loading that post." - site_settings: - min_username_length_exists: "You cannot set the minimum username length above the shortest username." - min_username_length_range: "You cannot set the minimum above the maximum." - max_username_length_exists: "You cannot set the maximum username length below the longest username." - max_username_length_range: "You cannot set the maximum below the minimum." - default_categories_already_selected: "You cannot select a category used in another list." - s3_upload_bucket_is_required: "You cannot enable uploads to S3 unless you've provided the 's3_upload_bucket'." - + empty: ھالی نہیں ھو سکتا activemodel: errors: <<: *errors - - bulk_invite: - file_should_be_csv: "The uploaded file should be of csv or txt format." - - backup: - operation_already_running: "An operation is currently running. Can't start a new job right now." - backup_file_should_be_tar_gz: "The backup file should be a .tar.gz archive." - not_enough_space_on_disk: "There is not enough space on disk to upload this backup." - invalid_filename: "The backup filename contains invalid characters. Valid characters are a-z 0-9 . - _." - - not_logged_in: "You need to be logged in to do that." - not_found: "The requested URL or resource could not be found." - invalid_access: "You are not permitted to view the requested resource." - read_only_mode_enabled: "The site is in read only mode. Interactions are disabled." - - reading_time: "Reading time" - likes: "Likes" - - too_many_replies: - one: "We're sorry, but new users are temporarily limited to 1 reply in the same topic." - other: "We're sorry, but new users are temporarily limited to %{count} replies in the same topic." - - embed: - start_discussion: "Start Discussion" - continue: "Continue Discussion" - more_replies: - one: "1 more reply" - other: "%{count} more replies" - - loading: "Loading Discussion..." - permalink: "Permalink" - imported_from: "This is a companion discussion topic for the original entry at %{link}" - in_reply_to: "▶ %{username}" - replies: - one: "1 reply" - other: "%{count} replies" - - no_mentions_allowed: "Sorry, you can't mention other users." - too_many_mentions: - one: "Sorry, you can only mention one other user in a post." - other: "Sorry, you can only mention %{count} users in a post." - no_mentions_allowed_newuser: "Sorry, new users can't mention other users." - too_many_mentions_newuser: - one: "Sorry, new users can only mention one other user in a post." - other: "Sorry, new users can only mention %{count} users in a post." - no_images_allowed: "Sorry, new users can't put images in posts." - too_many_images: - one: "Sorry, new users can only put one image in a post." - other: "Sorry, new users can only put %{count} images in a post." - no_attachments_allowed: "Sorry, new users can't put attachments in posts." - too_many_attachments: - one: "Sorry, new users can only put one attachment in a post." - other: "Sorry, new users can only put %{count} attachments in a post." - no_links_allowed: "Sorry, new users can't put links in posts." - too_many_links: - one: "Sorry, new users can only put one link in a post." - other: "Sorry, new users can only put %{count} links in a post." - - spamming_host: "Sorry you cannot post a link to that host." - user_is_suspended: "Suspended users are not allowed to post." - topic_not_found: "Something has gone wrong. Perhaps this topic was closed or deleted while you were looking at it?" - - just_posted_that: "is too similar to what you recently posted" - invalid_characters: "contains invalid characters" - is_invalid: "seems unclear, is it a complete sentence?" - next_page: "next page →" - prev_page: "← previous page" - page_num: "Page %{num}" - home_title: "Home" - topics_in_category: "Topics in the '%{category}' category" - rss_posts_in_topic: "RSS feed of '%{topic}'" - rss_topics_in_category: "RSS feed of topics in the '%{category}' category" - author_wrote: "%{author} wrote:" - num_posts: "Posts:" - num_participants: "Participants:" - read_full_topic: "Read full topic" - private_message_abbrev: "Msg" - rss_description: - latest: "Latest topics" - hot: "Hot topics" - top: "Top topics" - posts: "Latest posts" - private_posts: "Latest private messages" - group_posts: "Latest posts from %{group_name}" - group_mentions: "Latest mentions from %{group_name}" - user_posts: "Latest posts by @%{username}" - user_topics: "Latest topics by @%{username}" - tag: "Tagged topics" - too_late_to_edit: "That post was created too long ago. It can no longer be edited or deleted." - revert_version_same: "The current version is same as the version you are trying to revert to." - - excerpt_image: "image" - - queue: - delete_reason: "Deleted via post moderation queue" - - groups: - errors: - can_not_modify_automatic: "You cannot modify an automatic group" - member_already_exist: "'%{username}' is already a member of this group." - invalid_domain: "'%{domain}' is not a valid domain." - invalid_incoming_email: "'%{email}' is not a valid email address." - email_already_used_in_group: "'%{email}' is already used by the group '%{group_name}'." - email_already_used_in_category: "'%{email}' is already used by the category '%{category_name}'." - default_names: - everyone: "everyone" - admins: "admins" - moderators: "moderators" - staff: "staff" - trust_level_0: "trust_level_0" - trust_level_1: "trust_level_1" - trust_level_2: "trust_level_2" - trust_level_3: "trust_level_3" - trust_level_4: "trust_level_4" - - education: - until_posts: - one: "1 post" - other: "%{count} posts" - - 'new-topic': | - Welcome to %{site_name} — **thanks for starting a new conversation!** - - - Does the title sound interesting if you read it out loud? Is it a good summary? - - - Who would be interested in this? Why does it matter? What kind of responses do you want? - - - Include commonly used words in your topic so others can *find* it. To group your topic with related topics, select a category. - - For more, [see our community guidelines](/guidelines). This panel will only appear for your first %{education_posts_text}. - - 'new-reply': | - Welcome to %{site_name} — **thanks for contributing!** - - - Does your reply improve the conversation in some way? - - - Be kind to your fellow community members. - - - Constructive criticism is welcome, but criticize *ideas*, not people. - - For more, [see our community guidelines](/guidelines). This panel will only appear for your first %{education_posts_text}. - - avatar: | - ### How about a picture for your account? - - You've posted a few topics and replies, but your profile picture isn't as unique as you are -- it's just a letter. - - Have you considered **[visiting your user profile](%{profile_path})** and uploading a picture that represents you? - - It's easier to follow discussions and find interesting people in conversations when everyone has a unique profile picture! - - sequential_replies: | - ### Consider replying to several posts at once - - Rather than many sequential replies to a topic, please consider a single reply that includes quotes from previous posts or @name references. - - You can edit your previous reply to add a quote by highlighting text and selecting the quote reply button that appears. - - It's easier for everyone to read topics that have fewer in-depth replies versus lots of small, individual replies. - - dominating_topic: | - ### Let others join the conversation - - This topic is clearly important to you – you've posted more than %{percent}% of the replies here. - - Are you sure you're providing adequate time for other people to share their points of view, too? - - too_many_replies: | - ### You have reached the reply limit for this topic - - We're sorry, but new users are temporarily limited to %{newuser_max_replies_per_topic} replies in the same topic. - - Instead of adding another reply, please consider editing your previous replies, or visiting other topics. - - reviving_old_topic: | - ### Revive this topic? - - The last reply to this topic is now over %{days} days old. Your reply will bump the topic to the top of its list and notify anyone previously involved in the conversation. - - Are you sure you want to continue this old conversation? - activerecord: - attributes: - category: - name: "Category Name" - topic: - title: 'Title' - post: - raw: "Body" - user_profile: - bio_raw: "About Me" - user: - ip_address: "" errors: <<: *errors - models: - topic: - attributes: - base: - warning_requires_pm: "You can only attach warnings to private messages." - too_many_users: "You can only send warnings to one user at a time." - cant_send_pm: "Sorry, you cannot send a private message to that user." - no_user_selected: "You must select a valid user." - user: - attributes: - password: - common: "is one of the 10000 most common passwords. Please use a more secure password." - same_as_username: "is the same as your username. Please use a more secure password." - same_as_email: "is the same as your email. Please use a more secure password." - same_as_current: "is the same as your current password." - ip_address: - signup_not_allowed: "Signup is not allowed from this account." - color_scheme_color: - attributes: - hex: - invalid: "is not a valid color" - post_reply: - base: - different_topic: "Post and reply must belong to the same topic." - web_hook: - attributes: - payload_url: - invalid: "URL is invalid. URL should includes http:// or https://. And no blank is allowed." - - user_profile: - no_info_me: "
    the About Me field of your profile is currently blank, would you like to fill it out?
    " - no_info_other: "
    %{name} hasn't entered anything in the About Me field of their profile yet
    " - - vip_category_name: "Lounge" - vip_category_description: "A category exclusive to members with trust level 3 and higher." - - meta_category_name: "Site Feedback" - meta_category_description: "Discussion about this site, its organization, how it works, and how we can improve it." - - staff_category_name: "Staff" - staff_category_description: "Private category for staff discussions. Topics are only visible to admins and moderators." - - assets_topic_body: "This is a permanent topic, visible only to staff, for storing images and files used in the site design. Don't delete it!\n\n\nHere's how:\n\n\n1. Reply to this topic.\n2. Upload all the images you wish to use for logos, favicons, and so forth here. (Use the upload toolbar icon in the post editor, or drag-and-drop or paste images.)\n3. Submit your reply to post it.\n4. Right click the images in your new post to get the path to the uploaded images, or click the edit icon to edit your post and retrieve the path to the images. Copy the image paths.\n5. Paste those image paths into [basic settings](/admin/site_settings/category/required).\n\n\nIf you need to enable different file type uploads, edit `authorized_extensions` in the [file settings](/admin/site_settings/category/files)." - - lounge_welcome: - title: "Welcome to the Lounge" - body: | - - Congratulations! :confetti_ball: - - If you can see this topic, you were recently promoted to **regular** (trust level 3). - - You can now … - - * Edit the title of any topic - * Change the category of any topic - * Have all your links followed ([automatic nofollow](http://en.wikipedia.org/wiki/Nofollow) is removed) - * Access a private Lounge category only visible to users at trust level 3 and higher - * Hide spam with a single flag - - Here's the [current list of fellow regulars](/badges/3/regular). Be sure to say hi. - - Thanks for being an important part of this community! - - (For more information on trust levels, [see this topic][trust]. Please note that only members who continue to meet the requirements over time will remain regulars.) - - [trust]: https://meta.discourse.org/t/what-do-user-trust-levels-do/4924 - - - category: - topic_prefix: "About the %{category} category" - replace_paragraph: "(Replace this first paragraph with a brief description of your new category. This guidance will appear in the category selection area, so try to keep it below 200 characters. **Until you edit this description or create topics, this category won't appear on the categories page.**)" - post_template: "%{replace_paragraph}\n\nUse the following paragraphs for a longer description, or to establish category guidelines or rules:\n\n- Why should people use this category? What is it for?\n\n- How exactly is this different than the other categories we already have?\n\n- What should topics in this category generally contain?\n\n- Do we need this category? Can we merge with another category, or subcategory?\n" - errors: - uncategorized_parent: "Uncategorized can't have a parent category" - self_parent: "A subcategory's parent cannot be itself" - depth: "You can't nest a subcategory under another" - invalid_email_in: "'%{email}' is not a valid email address." - email_already_used_in_group: "'%{email}' is already used by the group '%{group_name}'." - email_already_used_in_category: "'%{email}' is already used by the category '%{category_name}'." - cannot_delete: - uncategorized: "Can't delete Uncategorized" - has_subcategories: "Can't delete this category because it has sub-categories." - topic_exists: - one: "Can't delete this category because is has 1 topic. Oldest topic is %{topic_link}." - other: "Can't delete this category because it has %{count} topics. Oldest topic is %{topic_link}." - topic_exists_no_oldest: "Can't delete this category because topic count is %{count}." - uncategorized_description: "Topics that don't need a category, or don't fit into any other existing category." - trust_levels: - newuser: - title: "new user" - basic: - title: "basic user" - member: - title: "member" - regular: - title: "regular" - leader: - title: "leader" - change_failed_explanation: "You attempted to demote %{user_name} to '%{new_trust_level}'. However their trust level is already '%{current_trust_level}'. %{user_name} will remain at '%{current_trust_level}' - if you wish to demote user lock trust level first" - - - rate_limiter: - slow_down: "You have performed this action too many times, try again later." - too_many_requests: "We have a daily limit on how many times that action can be taken. Please wait %{time_left} before trying again." - by_type: - first_day_replies_per_day: "You've reached the maximum number of replies a new user can create on their first day. Please wait %{time_left} before trying again." - first_day_topics_per_day: "You've reached the maximum number of topics a new user can create on their first day. Please wait %{time_left} before trying again." - create_topic: "You're creating topics too quickly. Please wait %{time_left} before trying again." - create_post: "You're replying too quickly. Please wait %{time_left} before trying again." - delete_post: "You're deleting posts too quickly. Please wait %{time_left} before trying again." - topics_per_day: "You've reached the maximum number of new topics today. Please wait %{time_left} before trying again." - pms_per_day: "You've reached the maximum number of messages today. Please wait %{time_left} before trying again." - create_like: "You've reached the maximum number of likes today. Please wait %{time_left} before trying again." - create_bookmark: "You've reached the maximum number of bookmarks today. Please wait %{time_left} before trying again." - edit_post: "You've reached the maximun number of edits today. Please wait %{time_left} before trying again." - live_post_counts: "You're asking for live post counts too quickly. Please wait %{time_left} before trying again." - unsubscribe_via_email: "You've reached the maximum number of unsubscribe via email today. Please wait %{time_left} before trying again." - topic_invitations_per_day: "You've reached the maximum number of topic invitations today. Please wait %{time_left} before trying again." - - hours: - one: "1 hour" - other: "%{count} hours" - minutes: - one: "1 minute" - other: "%{count} minutes" - seconds: - one: "1 second" - other: "%{count} seconds" - - datetime: - distance_in_words: - half_a_minute: "< 1m" - less_than_x_seconds: - one: "< 1s" - other: "< %{count}s" - x_seconds: - one: "1s" - other: "%{count}s" - less_than_x_minutes: - one: "< 1m" - other: "< %{count}m" - x_minutes: - one: "1m" - other: "%{count}m" - about_x_hours: - one: "1h" - other: "%{count}h" - x_days: - one: "1d" - other: "%{count}d" - about_x_months: - one: "1mon" - other: "%{count}mon" - x_months: - one: "1mon" - other: "%{count}mon" - about_x_years: - one: "1y" - other: "%{count}y" - over_x_years: - one: "> 1y" - other: "> %{count}y" - almost_x_years: - one: "1y" - other: "%{count}y" - - distance_in_words_verbose: - half_a_minute: "just now" - less_than_x_seconds: - one: "just now" - other: "just now" - x_seconds: - one: "1 second ago" - other: "%{count} seconds ago" - less_than_x_minutes: - one: "less than 1 minute ago" - other: "less than %{count} minutes ago" - x_minutes: - one: "1 minute ago" - other: "%{count} minutes ago" - about_x_hours: - one: "1 hour ago" - other: "%{count} hours ago" - x_days: - one: "1 day ago" - other: "%{count} days ago" - about_x_months: - one: "about 1 month ago" - other: "about %{count} months ago" - x_months: - one: "1 month ago" - other: "%{count} months ago" - about_x_years: - one: "about 1 year ago" - other: "about %{count} years ago" - over_x_years: - one: "over 1 year ago" - other: "over %{count} years ago" - almost_x_years: - one: "almost 1 year ago" - other: "almost %{count} years ago" - - password_reset: - no_token: "Sorry, that password change link is too old. Select the Log In button and use 'I forgot my password' to get a new link." - choose_new: "Please choose a new password" - choose: "Please choose a password" - update: 'Update Password' - save: 'Set Password' - title: 'Reset Password' - success: "You successfully changed your password and are now logged in." - success_unapproved: "You successfully changed your password." - continue: "Continue to %{site_name}" - - change_email: - confirmed: "Your email has been updated." - please_continue: "Continue to %{site_name}" - error: "There was an error changing your email address. Perhaps the address is already in use?" - error_staged: "There was an error changing your email address. The address is already in use by a staged user." - already_done: "Sorry, this confirmation link is no longer valid. Perhaps your email was already changed?" - authorizing_old: - title: "Thanks for confirming your current email address" - description: "We're now emailing your new address for confirmation." - - activation: - action: "Click here to activate your account" - already_done: "Sorry, this account confirmation link is no longer valid. Perhaps your account is already active?" - please_continue: "Your new account is confirmed; you will be redirected to the home page." - continue_button: "Continue to %{site_name}" - welcome_to: "Welcome to %{site_name}!" - approval_required: "A moderator must manually approve your new account before you can access this forum. You'll get an email when your account is approved!" - missing_session: "We cannot detect if your account was created, please ensure you have cookies enabled." - post_action_types: - off_topic: - title: 'Off-Topic' - description: 'This post is not relevant to the current discussion as defined by the title and first post, and should probably be moved elsewhere.' - long_form: 'flagged this as off-topic' - spam: - title: 'Spam' - description: 'This post is an advertisement. It is not useful or relevant to the current topic, but promotional in nature.' - long_form: 'flagged this as spam' - email_title: '"%{title}" was flagged as spam' - email_body: "%{link}\n\n%{message}" - inappropriate: - title: 'Inappropriate' - description: 'This post contains content that a reasonable person would consider offensive, abusive, or a violation of our community guidelines.' - long_form: 'flagged this as inappropriate' - notify_user: - title: 'Send @{{username}} a message' - description: 'I want to talk to this person directly and privately about their post.' - long_form: 'messaged user' - email_title: 'Your post in "%{title}"' - email_body: "%{link}\n\n%{message}" - notify_moderators: - title: "Something Else" - description: 'This post requires staff attention for another reason not listed above.' - long_form: 'flagged this for staff attention' - email_title: 'A post in "%{title}" requires staff attention' - email_body: "%{link}\n\n%{message}" - bookmark: - title: 'Bookmark' - description: 'Bookmark this post' - long_form: 'bookmarked this post' - like: - title: 'Like' - description: 'Like this post' - long_form: 'liked this' - vote: - title: 'Vote' - description: 'Vote for this post' - long_form: 'voted for this post' - - user_activity: - no_bookmarks: - self: "You have no bookmarked posts, bookmarking posts allows you to easily access them later on." - others: "No bookmarks." - no_likes_given: - self: "You have not liked any posts." - others: "No liked posts." - - topic_flag_types: - spam: - title: 'Spam' - description: 'This topic is an advertisement. It is not useful or relevant to this site, but promotional in nature.' - long_form: 'flagged this as spam' - inappropriate: - title: 'Inappropriate' - description: 'This topic contains content that a reasonable person would consider offensive, abusive, or a violation of our community guidelines.' - long_form: 'flagged this as inappropriate' - notify_moderators: - title: "Something Else" - description: 'This topic requires general staff attention based on the guidelines, TOS, or for another reason not listed above.' - long_form: 'flagged this for moderator attention' - email_title: 'The topic "%{title}" requires moderator attention' - email_body: "%{link}\n\n%{message}" - - flagging: - you_must_edit: '

    Your post was flagged by the community. Please see your messages.

    ' - user_must_edit: '

    This post was flagged by the community and is temporarily hidden.

    ' - - archetypes: - regular: - title: "Regular Topic" - banner: - title: "Banner Topic" - message: - make: "This topic is now a banner. It will appear at the top of every page until it is dismissed by the user." - remove: "This topic is no longer a banner. It will no longer appear at the top of every page." - - unsubscribed: - title: "Unsubscribed!" - description: "You have been unsubscribed. To change your email settings visit your user preferences." - topic_description: "To re-subscribe to %{link}, use the notification control at the bottom or right of the topic." - - unsubscribe: - title: "Unsubscribe" - stop_watching_topic: "Stop watching this topic, %{link}" - mute_topic: "Mute all notifications for this topic, %{link}" - unwatch_category: "Stop watching all topics in %{category}" - mailing_list_mode: "Turn off mailing list mode" - disable_digest_emails: "Stop sending me summary emails" - all: "Don't send me any mail from %{sitename}" - different_user_description: "You are currently logged in as a different user than the one we emailed. Please log out, or enter anonymous mode, and try again." - not_found_description: "Sorry, we couldn't find this unsubscribe. It's possible the link in your email has expired?" - log_out: "Log Out" - - user_api_key: - title: "Authorize application access" - authorize: "Authorize" - read: "read" - read_write: "read/write" - description: "\"%{application_name}\" is requesting the following access to your account:" - no_trust_level: "Sorry, you do not have the required trust level to access the user API" - generic_error: "Sorry, we are unable to issue user API keys, this feature may be disabled by the site admin" - scopes: - message_bus: "Live updates" - notifications: "Read and clear notifications" - push: "Push notifications to external services" - session_info: "Read user session info" - read: "Read all" - write: "Write all" - - reports: - visits: - title: "User Visits" - xaxis: "Day" - yaxis: "Number of visits" - signups: - title: "New Users" - xaxis: "Day" - yaxis: "Number of new users" - profile_views: - title: "User Profile Views" - xaxis: "Day" - yaxis: "Number of user profiles viewed" - topics: - title: "Topics" - xaxis: "Day" - yaxis: "Number of new topics" - posts: - title: "Posts" - xaxis: "Day" - yaxis: "Number of new posts" - likes: - title: "Likes" - xaxis: "Day" - yaxis: "Number of new likes" - flags: - title: "Flags" - xaxis: "Day" - yaxis: "Number of flags" - bookmarks: - title: "Bookmarks" - xaxis: "Day" - yaxis: "Number of new bookmarks" - starred: - title: "Starred" - xaxis: "Day" - yaxis: "Number of new starred topics" - users_by_trust_level: - title: "Users per Trust Level" - xaxis: "Trust Level" - yaxis: "Number of Users" - emails: - title: "Emails Sent" - xaxis: "Day" - yaxis: "Number of Emails" - user_to_user_private_messages: - title: "User-to-User" - xaxis: "Day" - yaxis: "Number of messages" - system_private_messages: - title: "System" - xaxis: "Day" - yaxis: "Number of messages" - moderator_warning_private_messages: - title: "Moderator Warning" - xaxis: "Day" - yaxis: "Number of messages" - notify_moderators_private_messages: - title: "Notify Moderators" - xaxis: "Day" - yaxis: "Number of messages" - notify_user_private_messages: - title: "Notify User" - xaxis: "Day" - yaxis: "Number of messages" - top_referrers: - title: "Top Referrers" - xaxis: "User" - num_clicks: "Clicks" - num_topics: "Topics" - top_traffic_sources: - title: "Top Traffic Sources" - xaxis: "Domain" - num_clicks: "Clicks" - num_topics: "Topics" - num_users: "Users" - top_referred_topics: - title: "Top Referred Topics" - xaxis: "Topic" - num_clicks: "Clicks" - page_view_anon_reqs: - title: "Anonymous" - xaxis: "Day" - yaxis: "Anonymous Pageviews" - page_view_logged_in_reqs: - title: "Logged In" - xaxis: "Day" - yaxis: "Logged In Pageviews" - page_view_crawler_reqs: - title: "Web Crawlers" - xaxis: "Day" - yaxis: "Web Crawler Pageviews" - page_view_total_reqs: - title: "Total" - xaxis: "Day" - yaxis: "Total Pageviews" - page_view_logged_in_mobile_reqs: - title: "Logged In Pageviews" - xaxis: "Day" - yaxis: "Mobile Logged In Pageviews" - page_view_anon_mobile_reqs: - title: "Anon Pageviews" - xaxis: "Day" - yaxis: "Mobile Anon Pageviews" - http_background_reqs: - title: "Background" - xaxis: "Day" - yaxis: "Requests used for live update and tracking" - http_2xx_reqs: - title: "Status 2xx (OK)" - xaxis: "Day" - yaxis: "Successful requests (Status 2xx)" - http_3xx_reqs: - title: "HTTP 3xx (Redirect)" - xaxis: "Day" - yaxis: "Redirect requests (Status 3xx)" - http_4xx_reqs: - title: "HTTP 4xx (Client Error)" - xaxis: "Day" - yaxis: "Client Errors (Status 4xx)" - http_5xx_reqs: - title: "HTTP 5xx (Server Error)" - xaxis: "Day" - yaxis: "Server Errors (Status 5xx)" - http_total_reqs: - title: "Total" - xaxis: "Day" - yaxis: "Total requests" - time_to_first_response: - title: "Time to first response" - xaxis: "Day" - yaxis: "Average time (hours)" - topics_with_no_response: - title: "Topics with no response" - xaxis: "Day" - yaxis: "Total" - mobile_visits: - title: "User Visits" - xaxis: "Day" - yaxis: "Number of visits" - - dashboard: - rails_env_warning: "Your server is running in %{env} mode." - host_names_warning: "Your config/database.yml file is using the default localhost hostname. Update it to use your site's hostname." - gc_warning: 'Your server is using default ruby garbage collection parameters, which will not give you the best performance. Read this topic on performance tuning: Tuning Ruby and Rails for Discourse.' - sidekiq_warning: 'Sidekiq is not running. Many tasks, like sending emails, are executed asynchronously by sidekiq. Please ensure at least one sidekiq process is running. Learn about Sidekiq here.' - queue_size_warning: 'The number of queued jobs is %{queue_size}, which is high. This could indicate a problem with the Sidekiq process(es), or you may need to add more Sidekiq workers.' - memory_warning: 'Your server is running with less than 1 GB of total memory. At least 1 GB of memory is recommended.' - google_oauth2_config_warning: 'The server is configured to allow signup and log in with Google OAuth2 (enable_google_oauth2_logins), but the client id and client secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' - facebook_config_warning: 'The server is configured to allow signup and log in with Facebook (enable_facebook_logins), but the app id and app secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' - twitter_config_warning: 'The server is configured to allow signup and log in with Twitter (enable_twitter_logins), but the key and secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' - github_config_warning: 'The server is configured to allow signup and log in with GitHub (enable_github_logins), but the client id and secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' - s3_config_warning: 'The server is configured to upload files to s3, but at least one the following setting is not set: s3_access_key_id, s3_secret_access_key or s3_upload_bucket. Go to the Site Settings and update the settings. See "How to set up image uploads to S3?" to learn more.' - s3_backup_config_warning: 'The server is configured to upload backups to s3, but at least one the following setting is not set: s3_access_key_id, s3_secret_access_key or s3_backup_bucket. Go to the Site Settings and update the settings. See "How to set up image uploads to S3?" to learn more.' - image_magick_warning: 'The server is configured to create thumbnails of large images, but ImageMagick is not installed. Install ImageMagick using your favorite package manager or download the latest release.' - failing_emails_warning: 'There are %{num_failed_jobs} email jobs that failed. Check your app.yml and ensure that the mail server settings are correct. See the failed jobs in Sidekiq.' - subfolder_ends_in_slash: "Your subfolder setup is incorrect; the DISCOURSE_RELATIVE_URL_ROOT ends in a slash." - email_polling_errored_recently: - one: "Email polling has generated an error in the past 24 hours. Look at the logs for more details." - other: "Email polling has generated %{count} errors in the past 24 hours. Look at the logs for more details." - missing_mailgun_api_key: "The server is configured to send emails via mailgun but you haven't provided an API key used the verify the webhook messages." - bad_favicon_url: "The favicon is failing to load. Check your favicon_url setting in Site Settings." - poll_pop3_timeout: "Connection to the POP3 server is timing out. Incoming email could not be retrieved. Please check your POP3 settings and service provider." - poll_pop3_auth_error: "Connection to the POP3 server is failing with an authentication error. Please check your POP3 settings." - - site_settings: - censored_words: "Words that will be automatically replaced with ■■■■" - censored_pattern: "Regex pattern that will be automatically replaced with ■■■■" - delete_old_hidden_posts: "Auto-delete any hidden posts that stay hidden for more than 30 days." - default_locale: "The default language of this Discourse instance (ISO 639-1 Code)" - allow_user_locale: "Allow users to choose their own language interface preference" - set_locale_from_accept_language_header: "set interface language for anonymous users from their web browser's language headers. (EXPERIMENTAL, does not work with anonymous cache)" - min_post_length: "Minimum allowed post length in characters" - min_first_post_length: "Minimum allowed first post (topic body) length in characters" - min_private_message_post_length: "Minimum allowed post length in characters for messages" - max_post_length: "Maximum allowed post length in characters" - min_topic_title_length: "Minimum allowed topic title length in characters" - max_topic_title_length: "Maximum allowed topic title length in characters" - min_private_message_title_length: "Minimum allowed title length for a message in characters" - min_search_term_length: "Minimum valid search term length in characters" - search_tokenize_chinese_japanese_korean: "Force search to tokenize Chinese/Japanese/Korean even on non CJK sites" - search_prefer_recent_posts: "If searching your large forum is slow, this option tries an index of more recent posts first" - search_recent_posts_size: "How many recent posts to keep in the index" - allow_uncategorized_topics: "Allow topics to be created without a category. WARNING: If there are any uncategorized topics, you must recategorize them before turning this off." - allow_duplicate_topic_titles: "Allow topics with identical, duplicate titles." - unique_posts_mins: "How many minutes before a user can make a post with the same content again" - educate_until_posts: "When the user starts typing their first (n) new posts, show the pop-up new user education panel in the composer." - title: "The name of this site, as used in the title tag." - site_description: "Describe this site in one sentence, as used in the meta description tag." - contact_email: "Email address of key contact responsible for this site. Used for critical notifications such as unhandled flags, as well as on the /about contact form for urgent matters." - contact_url: "Contact URL for this site. Used on the /about contact form for urgent matters." - queue_jobs: "DEVELOPER ONLY! WARNING! By default, queue jobs in sidekiq. If disabled, your site will be broken." - crawl_images: "Retrieve images from remote URLs to insert the correct width and height dimensions." - download_remote_images_to_local: "Convert remote images to local images by downloading them; this prevents broken images." - download_remote_images_threshold: "Minimum disk space necessary to download remote images locally (in percent)" - download_remote_images_max_days_old: "Don't download remote images for posts that are more than n days old." - disabled_image_download_domains: "Remote images will never be downloaded from these domains. Pipe-delimited list." - editing_grace_period: "For (n) seconds after posting, editing will not create a new version in the post history." - post_edit_time_limit: "The author can edit or delete 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" - max_image_height: "Maximum thumbnail height of images in a post" - category_featured_topics: "Number of topics displayed per category on the /categories page. After changing this value, it takes up to 15 minutes for the categories page to update." - show_subcategory_list: "Show subcategory list instead of topic list when entering a category." - fixed_category_positions: "If checked, you will be able to arrange categories into a fixed order. If unchecked, categories are listed in order of activity." - fixed_category_positions_on_create: "If checked, category ordering will be maintained on topic creation dialog (requires fixed_category_positions)." - add_rel_nofollow_to_user_content: "Add rel nofollow to all submitted user content, except for internal links (including parent domains). If you change this, you must rebake all posts with: \"rake posts:rebake\"" - exclude_rel_nofollow_domains: "A list of domains where nofollow should not be added to links. tld.com will automatically allow sub.tld.com as well. As a minimum, you should add the top-level domain of this site to help web crawlers find all content. If other parts of your website are at other domains, add those too." - - post_excerpt_maxlength: "Maximum length of a post excerpt / summary." - show_pinned_excerpt_mobile: "Show excerpt on pinned topics in mobile view." - show_pinned_excerpt_desktop: "Show excerpt on pinned topics in desktop view." - post_onebox_maxlength: "Maximum length of a oneboxed Discourse post in characters." - onebox_domains_blacklist: "A list of domains that will never be oneboxed." - max_oneboxes_per_post: "Maximum number of oneboxes in a post." - - logo_url: "The logo image at the top left of your site, should be a wide rectangle shape. If left blank site title text will be shown." - digest_logo_url: "The alternate logo image used at the top of your site's email summary. Should be a wide rectangle shape. Should not be an SVG image. If left blank `logo_url` will be used." - logo_small_url: "The small logo image at the top left of your site, should be a square shape, seen when scrolling down. If left blank a home glyph will be shown." - favicon_url: "A favicon for your site, see http://en.wikipedia.org/wiki/Favicon, to work correctly over a CDN it must be a png" - mobile_logo_url: "The fixed position logo image used at the top left of your mobile site. Should be a square shape. If left blank, `logo_url` will be used. eg: http://example.com/uploads/default/logo.png" - apple_touch_icon_url: "Icon used for Apple touch devices. Recommended size is 144px by 144px." - - notification_email: "The from: email address used when sending all essential system emails. The domain specified here must have SPF, DKIM and reverse PTR records set correctly for email to arrive." - email_custom_headers: "A pipe-delimited list of custom email headers" - email_subject: "Customizable subject format for standard emails. See https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801" - force_https: "Force your site to use HTTPS only. WARNING: do NOT enable this until you verify HTTPS is fully set up and working absolutely everywhere! Did you check your CDN, all social logins, and any external logos / dependencies to make sure they are all HTTPS compatible, too?" - summary_score_threshold: "The minimum score required for a post to be included in 'Summarize This Topic'" - summary_posts_required: "Minimum posts in a topic before 'Summarize This Topic' is enabled" - summary_likes_required: "Minimum likes in a topic before 'Summarize This Topic' is enabled" - summary_percent_filter: "When a user clicks 'Summarize This Topic', show the top % of posts" - summary_max_results: "Maximum posts returned by 'Summary This Topic'" - - enable_private_messages: "Allow trust level 1 (configurable via min trust level to send messages) users to create messages and reply to messages. Note that staff can always send messages no matter what." - - enable_long_polling: "Message bus used for notification can use long polling" - long_polling_base_url: "Base URL used for long polling (when a CDN is serving dynamic content, be sure to set this to origin pull) eg: http://origin.site.com" - long_polling_interval: "Amount of time the server should wait before responding to clients when there is no data to send (logged on users only)" - polling_interval: "When not long polling, how often should logged on clients poll in milliseconds" - anon_polling_interval: "How often should anonymous clients poll in milliseconds" - background_polling_interval: "How often should the clients poll in milliseconds (when the window is in the background)" - - flags_required_to_hide_post: "Number of flags that cause a post to be automatically hidden and message sent to the user (0 for never)" - cooldown_minutes_after_hiding_posts: "Number of minutes a user must wait before they can edit a post hidden via community flagging" - - max_topics_in_first_day: "The maximum number of topics a user is allowed to create in the 24 hour period after creating their first post" - max_replies_in_first_day: "The maximum number of replies a user is allowed to create in the 24 hour period after creating their first post" - - tl2_additional_likes_per_day_multiplier: "Increase limit of likes per day for tl2 (member) by multiplying with this number" - tl3_additional_likes_per_day_multiplier: "Increase limit of likes per day for tl3 (regular) by multiplying with this number" - tl4_additional_likes_per_day_multiplier: "Increase limit of likes per day for tl4 (leader) by multiplying with this number" - - num_spam_flags_to_block_new_user: "If a new user's posts get this many spam flags from num_users_to_block_new_user different users, hide all their posts and prevent future posting. 0 to disable." - num_users_to_block_new_user: "If a new user's posts get num_spam_flags_to_block_new_user spam flags from this many different users, hide all their posts and prevent future posting. 0 to disable." - num_tl3_flags_to_block_new_user: "If a new user's posts get this many flags from num_tl3_users_to_block_new_user different trust level 3 users, hide all their posts and prevent future posting. 0 to disable." - num_tl3_users_to_block_new_user: "If a new user's posts get num_tl3_flags_to_block_new_user flags from this many different trust level 3 users, hide all their posts and prevent future posting. 0 to disable." - notify_mods_when_user_blocked: "If a user is automatically blocked, send a message to all moderators." - flag_sockpuppets: "If a new user replies to a topic from the same IP address as the new user who started the topic, flag both of their posts as potential spam." - - traditional_markdown_linebreaks: "Use traditional linebreaks in Markdown, which require two trailing spaces for a linebreak." - allow_html_tables: "Allow tables to be entered in Markdown using HTML tags. TABLE, THEAD, TD, TR, TH will be whitelisted (requires full rebake on all old posts containing tables)" - post_undo_action_window_mins: "Number of minutes users are allowed to undo recent actions on a post (like, flag, etc)." - must_approve_users: "Staff must approve all new user accounts before they are allowed to access the site. WARNING: enabling this for a live site will revoke access for existing non-staff users!" - pending_users_reminder_delay: "Notify moderators if new users have been waiting for approval for longer than this many hours. Set to -1 to disable notifications." - maximum_session_age: "User will remain logged in for n hours since last visit" - ga_tracking_code: "OBSOLETE: Google analytics (ga.js) tracking code code, eg: UA-12345678-9; see http://google.com/analytics" - ga_domain_name: "OBSOLETE: Google analytics (ga.js) domain name, eg: mysite.com; see http://google.com/analytics" - ga_universal_tracking_code: "Google Universal Analytics (analytics.js) tracking code code, eg: UA-12345678-9; see http://google.com/analytics" - ga_universal_domain_name: "Google Universal Analytics (analytics.js) domain name, eg: mysite.com; see http://google.com/analytics" - gtm_container_id: "Google Tag Manager container id. eg: GTM-ABCDEF" - enable_escaped_fragments: "Fall back to Google's Ajax-Crawling API if no webcrawler is detected. See https://developers.google.com/webmasters/ajax-crawling/docs/learn-more" - enable_noscript_support: "Enable standard webcrawler search engine support via the noscript tag" - allow_moderators_to_create_categories: "Allow moderators to create new categories" - cors_origins: "Allowed origins for cross-origin requests (CORS). Each origin must include http:// or https://. The DISCOURSE_ENABLE_CORS env variable must be set to true to enable CORS." - use_admin_ip_whitelist: "Admins can only log in if they are at an IP address defined in the Screened IPs list (Admin > Logs > Screened Ips)." - top_menu: "Determine which items appear in the homepage navigation, and in what order. Example latest|new|unread|categories|top|read|posted|bookmarks" - post_menu: "Determine which items appear on the post menu, and in what order. Example like|edit|flag|delete|share|bookmark|reply" - post_menu_hidden_items: "The menu items to hide by default in the post menu unless an expansion ellipsis is clicked on." - share_links: "Determine which items appear on the share dialog, and in what order." - track_external_right_clicks: "Track external links that are right clicked (eg: open in new tab) disabled by default because it rewrites URLs" - site_contact_username: "A valid staff username to send all automated messages from. If left blank the default System account will be used." - send_welcome_message: "Send all new users a welcome message with a quick start guide." - suppress_reply_directly_below: "Don't show the expandable reply count on a post when there is only a single reply directly below this post." - suppress_reply_directly_above: "Don't show the expandable in-reply-to on a post when there is only a single reply directly above this post." - suppress_reply_when_quoting: "Don't show the expandable in-reply-to on a post when post quotes reply." - max_reply_history: "Maximum number of replies to expand when expanding in-reply-to" - topics_per_period_in_top_summary: "Number of top topics shown in the default top topics summary." - topics_per_period_in_top_page: "Number of top topics shown on the expanded 'Show More' top topics." - redirect_users_to_top_page: "Automatically redirect new and long absent users to the top page." - top_page_default_timeframe: "Default timeframe for the top view page." - show_email_on_profile: "Show a user's email on their profile (only visible to themselves and staff)" - prioritize_username_in_ux: "Show username first on user page, user card and posts (when disabled name is shown first)" - - email_token_valid_hours: "Forgot password / activate account tokens are valid for (n) hours." - email_token_grace_period_hours: "Forgot password / activate account tokens are still valid for a grace period of (n) hours after being redeemed." - - enable_badges: "Enable the badge system" - enable_whispers: "Allow staff private communication within topic. (experimental)" - - allow_index_in_robots_txt: "Specify in robots.txt that this site is allowed to be indexed by web search engines." - email_domains_blacklist: "A pipe-delimited list of email domains that users are not allowed to register accounts with. Example: mailinator.com|trashmail.net" - email_domains_whitelist: "A pipe-delimited list of email domains that users MUST register accounts with. WARNING: Users with email domains other than those listed will not be allowed!" - forgot_password_strict: "Don't inform users of an account's existence when they use the forgot password dialog." - log_out_strict: "When logging out, log out ALL sessions for the user on all devices" - version_checks: "Ping the Discourse Hub for version updates and show new version messages on the /admin dashboard" - new_version_emails: "Send an email to the contact_email address when a new version of Discourse is available." - - port: "DEVELOPER ONLY! WARNING! Use this HTTP port rather than the default of port 80. Leave blank for default of 80." - force_hostname: "DEVELOPER ONLY! WARNING! Specify a hostname in the URL. Leave blank for default." - - invite_expiry_days: "How long user invitation keys are valid, in days" - invite_passthrough_hours: "How long a user can use a previously redeemed invitation key to log in, in hours" - - invite_only: "Public registration is disabled, all new users must be explicitly invited by other members or staff." - - login_required: "Require authentication to read content on this site, disallow anonymous access." - - min_username_length: "Minimum username length in characters." - max_username_length: "Maximum username length in characters." - - reserved_usernames: "Usernames for which signup is not allowed." - - min_password_length: "Minimum password length." - min_admin_password_length: "Minimum password length for Admin." - block_common_passwords: "Don't allow passwords that are in the 10,000 most common passwords." - - enable_sso: "Enable single sign on via an external site (WARNING: USERS' EMAIL ADDRESSES *MUST* BE VALIDATED BY THE EXTERNAL SITE!)" - verbose_sso_logging: "Log verbose SSO related diagnostics to /logs" - enable_sso_provider: "Implement Discourse SSO provider protocol at the /session/sso_provider endpoint, requires sso_secret to be set" - sso_url: "URL of single sign on endpoint (must include http:// or https://)" - sso_secret: "Secret string used to cryptographically authenticate SSO information, be sure it is 10 characters or longer" - sso_overrides_bio: "Overrides user bio in user profile and prevents user from changing it" - sso_overrides_email: "Overrides local email with external site email from SSO payload on every login, and prevent local changes. (WARNING: discrepancies can occur due to normalization of local emails)" - sso_overrides_username: "Overrides local username with external site username from SSO payload on every login, and prevent local changes. (WARNING: discrepancies can occur due to differences in username length/requirements)" - sso_overrides_name: "Overrides local full name with external site full name from SSO payload on every login, and prevent local changes." - sso_overrides_avatar: "Overrides user avatar with external site avatar from SSO payload. If enabled, disabling allow_uploaded_avatars is highly recommended" - sso_not_approved_url: "Redirect unapproved SSO accounts to this URL" - - enable_local_logins: "Enable local username and password login based accounts. (Note: this must be enabled for invites to work)" - allow_new_registrations: "Allow new user registrations. Uncheck this to prevent anyone from creating a new account." - enable_signup_cta: "Show a notice to returning anonymous users prompting them to sign up for an account." - enable_yahoo_logins: "Enable Yahoo authentication" - - enable_google_oauth2_logins: "Enable Google Oauth2 authentication. This is the method of authentication that Google currently supports. Requires key and secret." - google_oauth2_client_id: "Client ID of your Google application." - google_oauth2_client_secret: "Client secret of your Google application." - - enable_twitter_logins: "Enable Twitter authentication, requires twitter_consumer_key and twitter_consumer_secret" - twitter_consumer_key: "Consumer key for Twitter authentication, registered at http://dev.twitter.com" - twitter_consumer_secret: "Consumer secret for Twitter authentication, registered at http://dev.twitter.com" - - enable_instagram_logins: "Enable Instagram authentication, requires instagram_consumer_key and instagram_consumer_secret" - instagram_consumer_key: "Consumer key for Instagram authentication" - instagram_consumer_secret: "Consumer secret Instagram authentication" - - enable_facebook_logins: "Enable Facebook authentication, requires facebook_app_id and facebook_app_secret" - facebook_app_id: "App id for Facebook authentication, registered at https://developers.facebook.com/apps" - facebook_app_secret: "App secret for Facebook authentication, registered at https://developers.facebook.com/apps" - facebook_request_extra_profile_details: "Request about me, location and website from facebook. (requires that your auth application be approved by facebook)" - - enable_github_logins: "Enable Github authentication, requires github_client_id and github_client_secret" - github_client_id: "Client id for Github authentication, registered at https://github.com/settings/applications" - github_client_secret: "Client secret for Github authentication, registered at https://github.com/settings/applications" - - readonly_mode_during_backup: "Enable read only mode while taking a backup" - allow_restore: "Allow restore, which can replace ALL site data! Leave false unless you plan to restore a backup" - maximum_backups: "The maximum amount of backups to keep on disk. Older backups are automatically deleted" - automatic_backups_enabled: "Run automatic backups as defined in backup frequency" - backup_frequency: "How frequently we create a site backup, in days." - enable_s3_backups: "Upload backups to S3 when complete. IMPORTANT: requires valid S3 credentials entered in Files settings." - s3_backup_bucket: "The remote bucket to hold backups. WARNING: Make sure it is a private bucket." - s3_disable_cleanup: "Disable the removal of backups from S3 when removed locally." - backup_time_of_day: "Time of day UTC when the backup should occur." - backup_with_uploads: "Include uploads in scheduled backups. Disabling this will only backup the database." - - active_user_rate_limit_secs: "How frequently we update the 'last_seen_at' field, in seconds" - verbose_localization: "Show extended localization tips in the UI" - previous_visit_timeout_hours: "How long a visit lasts before we consider it the 'previous' visit, in hours" - - top_topics_formula_log_views_multiplier: "value of log views multiplier (n) in top topics formula: `log(views_count) * (n) + op_likes_count * 0.5 + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" - top_topics_formula_first_post_likes_multiplier: "value of first post likes multiplier (n) in top topics formula: `log(views_count) * 2 + op_likes_count * (n) + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" - top_topics_formula_least_likes_per_post_multiplier: "value of least likes per post multiplier (n) in top topics formula: `log(views_count) * 2 + op_likes_count * 0.5 + LEAST(likes_count / posts_count, (n)) + 10 + log(posts_count)`" - - rebake_old_posts_count: "Number of old posts to be rebaked every 15 minutes." - - rate_limit_create_topic: "After creating a topic, users must wait (n) seconds before creating another topic." - rate_limit_create_post: "After posting, users must wait (n) seconds before creating another post." - rate_limit_new_user_create_topic: "After creating a topic, new users must wait (n) seconds before creating another topic." - rate_limit_new_user_create_post: "After posting, new users must wait (n) seconds before creating another post." - - max_likes_per_day: "Maximum number of likes per user per day." - max_flags_per_day: "Maximum number of flags per user per day." - max_bookmarks_per_day: "Maximum number of bookmarks per user per day." - max_edits_per_day: "Maximum number of edits per user per day." - max_topics_per_day: "Maximum number of topics a user can create per day." - max_private_messages_per_day: "Maximum number of messages users can create per day." - max_invites_per_day: "Maximum number of invites a user can send per day." - max_topic_invitations_per_day: "Maximum number of topic invitations a user can send per day." - - alert_admins_if_errors_per_minute: "Number of errors per minute in order to trigger an admin alert. A value of 0 disables this feature. NOTE: requires restart." - alert_admins_if_errors_per_hour: "Number of errors per hour in order to trigger an admin alert. A value of 0 disables this feature. NOTE: requires restart." - - categories_topics: "Number of topics to show in /categories page." - suggested_topics: "Number of suggested topics shown at the bottom of a topic." - limit_suggested_to_category: "Only show topics from the current category in suggested topics." - suggested_topics_max_days_old: "Suggested topics should not be more than n days old." - - clean_up_uploads: "Remove orphan unreferenced uploads to prevent illegal hosting. WARNING: you may want to back up of your /uploads directory before enabling this setting." - clean_orphan_uploads_grace_period_hours: "Grace period (in hours) before an orphan upload is removed." - purge_deleted_uploads_grace_period_days: "Grace period (in days) before a deleted upload is erased." - purge_unactivated_users_grace_period_days: "Grace period (in days) before a user who has not activated their account is deleted." - enable_s3_uploads: "Place uploads on Amazon S3 storage. IMPORTANT: requires valid S3 credentials (both access key id & secret access key)." - s3_use_iam_profile: 'Use AWS EC2 IAM role to retrieve keys. NOTE: enabling will override "s3 access key id" and "s3 secret access key" settings.' - s3_upload_bucket: "The Amazon S3 bucket name that files will be uploaded into. WARNING: must be lowercase, no periods, no underscores." - s3_access_key_id: "The Amazon S3 access key id that will be used to upload images." - s3_secret_access_key: "The Amazon S3 secret access key that will be used to upload images." - s3_region: "The Amazon S3 region name that will be used to upload images." - s3_cdn_url: "The CDN URL to use for all s3 assets (for example: https://cdn.somewhere.com). WARNING: after changing this setting you must rebake all old posts." - - avatar_sizes: "List of automatically generated avatar sizes." - - external_system_avatars_enabled: "Use external system avatars service." - external_system_avatars_url: "URL of the external system avatars service. Allowed substitutions are {username} {first_letter} {color} {size}" - - default_opengraph_image_url: "URL of the default opengraph image." - twitter_summary_large_image_url: "URL of the default Twitter summary card image (should be at least 280px in width, and at least 150px in height)." - - allow_all_attachments_for_group_messages: "Allow all email attachments for group messages." - - convert_pasted_images_to_hq_jpg: "Convert pasted images to high-quality JPG files." - convert_pasted_images_quality: "Quality of the converted JPG file (1 is lowest quality, 100 is best quality)." - - enable_flash_video_onebox: "Enable embedding of swf and flv (Adobe Flash) links in oneboxes. WARNING: may introduce security risks." - - default_invitee_trust_level: "Default trust level (0-4) for invited users." - default_trust_level: "Default trust level (0-4) for all new users. WARNING! Changing this will put you at serious risk for spam." - - tl1_requires_topics_entered: "How many topics a new user must enter before promotion to trust level 1." - tl1_requires_read_posts: "How many posts a new user must read before promotion to trust level 1." - tl1_requires_time_spent_mins: "How many minutes a new user must read posts before promotion to trust level 1." - - tl2_requires_topics_entered: "How many topics a user must enter before promotion to trust level 2." - tl2_requires_read_posts: "How many posts a user must read before promotion to trust level 2." - tl2_requires_time_spent_mins: "How many minutes a user must read posts before promotion to trust level 2." - tl2_requires_days_visited: "How many days a user must visit the site before promotion to trust level 2." - tl2_requires_likes_received: "How many likes a user must receive before promotion to trust level 2." - tl2_requires_likes_given: "How many likes a user must cast before promotion to trust level 2." - tl2_requires_topic_reply_count: "How many topics user must reply to before promotion to trust level 2." - - tl3_time_period: "Trust Level 3 requirements time period (in days)" - tl3_requires_days_visited: "Minimum number of days that a user needs to have visited the site in the last (tl3 time period) days to qualify for promotion to trust level 3. Set higher than tl3 time period to disable promotions to tl3. (0 or higher)" - tl3_requires_topics_replied_to: "Minimum number of topics a user needs to have replied to in the last (tl3 time period) days to qualify for promotion to trust level 3. (0 or higher)" - tl3_requires_topics_viewed: "The percentage of topics created in the last (tl3 time period) days that a user needs to have viewed to qualify for promotion to trust level 3. (0 to 100)" - tl3_requires_topics_viewed_cap: "The maximum required number of topics viewed in the last (tl3 time period) days." - tl3_requires_posts_read: "The percentage of posts created in the last (tl3 time period) days that a user needs to have viewed to qualify for promotion to trust level 3. (0 to 100)" - tl3_requires_posts_read_cap: "The maximum required number of posts read in the last (tl3 time period) days." - tl3_requires_topics_viewed_all_time: "The minimum total number of topics a user must have viewed to qualify for trust level 3." - tl3_requires_posts_read_all_time: "The minimum total number of posts a user must have read to qualify for trust level 3." - tl3_requires_max_flagged: "User must not have had more than x posts flagged by x different users in the last (tl3 time period) days to qualify for promotion to trust level 3, where x is this setting's value. (0 or higher)" - tl3_promotion_min_duration: "The minimum number of days that a promotion to trust level 3 lasts before a user can be demoted back to trust level 2." - tl3_requires_likes_given: "The minimum number of likes that must be given in the last (tl3 time period) days to qualify for promotion to trust level 3." - tl3_requires_likes_received: "The minimum number of likes that must be received in the last (tl3 time period) days to qualify for promotion to trust level 3." - tl3_links_no_follow: "Do not remove rel=nofollow from links posted by trust level 3 users." - - min_trust_to_create_topic: "The minimum trust level required to create a new topic." - - min_trust_to_edit_wiki_post: "The minimum trust level required to edit post marked as wiki." - - min_trust_to_edit_post: "The minimum trust level required to edit posts." - - min_trust_to_allow_self_wiki: "The minimum trust level required to make user's own post wiki." - - min_trust_to_send_messages: "The minimum trust level required to create new private messages." - - newuser_max_links: "How many links a new user can add to a post." - newuser_max_images: "How many images a new user can add to a post." - newuser_max_attachments: "How many attachments a new user can add to a post." - newuser_max_mentions_per_post: "Maximum number of @name notifications a new user can use in a post." - newuser_max_replies_per_topic: "Maximum number of replies a new user can make in a single topic until someone replies to them." - max_mentions_per_post: "Maximum number of @name notifications anyone can use in a post." - max_users_notified_per_group_mention: "Maximum number of users that may receive a notification if a group is mentioned (if threshold is met no notifications will be raised)" - - create_thumbnails: "Create thumbnails and lightbox images that are too large to fit in a post." - - email_time_window_mins: "Wait (n) minutes before sending any notification emails, to give users a chance to edit and finalize their posts." - private_email_time_window_seconds: "Wait (n) seconds before sending any private notification emails, to give users a chance to edit and finalize their messages." - email_posts_context: "How many prior replies to include as context in notification emails." - flush_timings_secs: "How frequently we flush timing data to the server, in seconds." - title_max_word_length: "The maximum allowed word length, in characters, in a topic title." - title_min_entropy: "The minimum entropy (unique characters, non-english count for more) required for a topic title." - body_min_entropy: "The minimum entropy (unique characters, non-english count for more) required for a post body." - allow_uppercase_posts: "Allow all caps in a topic title or a post body." - - title_fancy_entities: "Convert common ASCII characters to fancy HTML entities in topic titles, ala SmartyPants http://daringfireball.net/projects/smartypants/" - - min_title_similar_length: "The minimum length of a title before it will be checked for similar topics." - min_body_similar_length: "The minimum length of a post's body before it will be checked for similar topics." - - desktop_category_page_style: "Visual style for the /categories page." - category_colors: "A list of hexadecimal color values allowed for categories." - category_style: "Visual style for category badges." - - max_image_size_kb: "The maximum image upload size in kB. This must be configured in nginx (client_max_body_size) / apache or proxy as well." - max_attachment_size_kb: "The maximum attachment files upload size in kB. This must be configured in nginx (client_max_body_size) / apache or proxy as well." - authorized_extensions: "A list of file extensions allowed for upload (use '*' to enable all file types)" - max_similar_results: "How many similar topics to show above the editor when composing a new topic. Comparison is based on title and body." - - title_prettify: "Prevent common title typos and errors, including all caps, lowercase first character, multiple ! and ?, extra . at end, etc." - - topic_views_heat_low: "After this many views, the views field is slightly highlighted." - topic_views_heat_medium: "After this many views, the views field is moderately highlighted." - topic_views_heat_high: "After this many views, the views field is strongly highlighted." - - cold_age_days_low: "After this many days of conversation, the last activity date is slightly dimmed." - cold_age_days_medium: "After this many days of conversation, the last activity date is moderately dimmed." - cold_age_days_high: "After this many days of conversation, the last activity date is strongly dimmed." - - history_hours_low: "A post edited within this many hours has the edit indicator slightly highlighted" - history_hours_medium: "A post edited within this many hours has the edit indicator moderately highlighted." - history_hours_high: "A post edited within this many hours has the edit indicator strongly highlighted." - - topic_post_like_heat_low: "After the likes:post ratio exceeds this ratio, the post count field is slightly highlighted." - topic_post_like_heat_medium: "After the likes:post ratio exceeds this ratio, the post count field is moderately highlighted." - topic_post_like_heat_high: "After the likes:post ratio exceeds this ratio, the post count field is strongly highlighted." - - faq_url: "If you have a FAQ hosted elsewhere that you want to use, provide the full URL here." - tos_url: "If you have a Terms of Service document hosted elsewhere that you want to use, provide the full URL here." - privacy_policy_url: "If you have a Privacy Policy document hosted elsewhere that you want to use, provide the full URL here." - - newuser_spam_host_threshold: "How many times a new user can post a link to the same host within their `newuser_spam_host_threshold` posts before being considered spam." - - white_listed_spam_host_domains: "A list of domains excluded from spam host testing. New users will never be restricted from creating posts with links to these domains." - staff_like_weight: "How much extra weighting factor to give staff likes." - topic_view_duration_hours: "Count a new topic view once per IP/User every N hours" - user_profile_view_duration_hours: "Count a new user profile view once per IP/User every N hours" - - levenshtein_distance_spammer_emails: "When matching spammer emails, number of characters difference that will still allow a fuzzy match." - max_new_accounts_per_registration_ip: "If there are already (n) trust level 0 accounts from this IP (and none is a staff member or at TL2 or higher), stop accepting new signups from that IP." - min_ban_entries_for_roll_up: "When clicking the Roll up button, will create a new subnet ban entry if there are at least (N) entries." - - max_age_unmatched_emails: "Delete unmatched screened email entries after (N) days." - max_age_unmatched_ips: "Delete unmatched screened IP entries after (N) days." - - num_flaggers_to_close_topic: "Minimum number of unique flaggers that is required to automatically pause a topic for intervention" - num_flags_to_close_topic: "Minimum number of active flags that is required to automatically pause a topic for intervention" - - auto_respond_to_flag_actions: "Enable automatic reply when disposing a flag." - min_first_post_typing_time: "Minimum amount of time in milliseconds a user must type during first post, if threshold is not met post will automatically enter the needs approval queue. Set to 0 to disable (not recommended)" - auto_block_fast_typers_on_first_post: "Automatically block users that do not meet min_first_post_typing_time" - auto_block_fast_typers_max_trust_level: "Maximum trust level to auto block fast typers" - auto_block_first_post_regex: "Case insensitive regex that if passed will cause first post by user to be blocked and sent to approval queue. Example: raging|a[bc]a , will cause all posts containing raging or aba or aca to be blocked on first. Only applies to first post." - - reply_by_email_enabled: "Enable replying to topics via email." - reply_by_email_address: "Template for reply by email incoming email address, for example: %{reply_key}@reply.example.com or replies+%{reply_key}@example.com" - alternative_reply_by_email_addresses: "List of alternative templates for reply by email incoming email addresses. Example: %{reply_key}@reply.example.com|replies+%{reply_key}@example.com" - incoming_email_prefer_html: "Use the HTML instead of the text for incoming email. May cause unexpected formatting issues!" - - disable_emails: "Prevent Discourse from sending any kind of emails" - - strip_images_from_short_emails: "Strip images from emails having size less than 2800 Bytes" - short_email_length: "Short email length in Bytes" - display_name_on_email_from: "Display full names on email from fields" - - unsubscribe_via_email: "Allow users to unsubscribe from emails by sending an email with 'unsubscribe' in the subject or body" - unsubscribe_via_email_footer: "Attach an unsubscribe via email mailto: link to the footer of sent emails" - - delete_email_logs_after_days: "Delete email logs after (N) days. 0 to keep indefinitely" - max_emails_per_day_per_user: "Maximum number of emails to send users per day. 0 to disable the limit" - enable_staged_users: "Automatically create staged users when processing incoming emails." - maximum_staged_users_per_email: "Maximum number of staged users created when processing an incoming email." - auto_generated_whitelist: "List of email addresses that won't be checked for auto-generated content. Example: foo@bar.com|discourse@bar.com" - block_auto_generated_emails: "Block incoming emails identified as being auto generated." - ignore_by_title: "Ignore incoming emails based on their title." - mailgun_api_key: "Mailgun Secret API key used to verify webhook messages." - - soft_bounce_score: "Bounce score added to the user when a temporary bounce happens." - hard_bounce_score: "Bounce score added to the user when a permanent bounce happens." - bounce_score_threshold: "Max bounce score before we will stop emailing a user." - bounce_score_threshold_deactivate: "Max bounce score before we will deactivate a user." - reset_bounce_score_after_days: "Automatically reset bounce score after X days." - - attachment_content_type_blacklist: "List of keywords used to blacklist attachments based on the content type." - attachment_filename_blacklist: "List of keywords used to blacklist attachments based on the filename." - - enable_forwarded_emails: "[BETA] Allow users to create a topic by forwarding an email in." - always_show_trimmed_content: "Always show trimmed part of incoming emails. WARNING: might reveal email addresses." - - manual_polling_enabled: "Push emails using the API for email replies." - pop3_polling_enabled: "Poll via POP3 for email replies." - pop3_polling_ssl: "Use SSL while connecting to the POP3 server. (Recommended)" - pop3_polling_openssl_verify: "Verify TLS server certificate (Default: enabled)" - pop3_polling_period_mins: "The period in minutes between checking the POP3 account for email. NOTE: requires restart." - pop3_polling_port: "The port to poll a POP3 account on." - pop3_polling_host: "The host to poll for email via POP3." - pop3_polling_username: "The username for the POP3 account to poll for email." - pop3_polling_password: "The password for the POP3 account to poll for email." - log_mail_processing_failures: "Log all email processing failures to http://yoursitename.com/logs" - email_in: "Allow users to post new topics via email (requires pop3 polling). Configure the addresses in the \"Settings\" tab of each category." - email_in_min_trust: "The minimum trust level a user needs to have to be allowed to post new topics via email." - email_prefix: "The [label] used in the subject of emails. It will default to 'title' if not set." - email_site_title: "The title of the site used as the sender of emails from the site. Default to 'title' if not set. If your 'title' contains characters that are not allowed in email sender strings, use this setting." - - minimum_topics_similar: "How many topics need to exist before similar topics are presented when composing new topics." - - relative_date_duration: "Number of days after posting where post dates will be shown as relative (7d) instead of absolute (20 Feb)." - delete_user_max_post_age: "Don't allow deleting users whose first post is older than (x) days." - delete_all_posts_max: "The maximum number of posts that can be deleted at once with the Delete All Posts button. If a user has more than this many posts, the posts cannot all be deleted at once and the user can't be deleted." - username_change_period: "The number of days after registration that accounts can change their username (0 to disallow username change)." - email_editable: "Allow users to change their e-mail address after registration." - logout_redirect: "Location to redirect browser to after logout (eg: http://somesite.com/logout)" - - allow_uploaded_avatars: "Allow users to upload custom profile pictures." - allow_animated_avatars: "Allow users to use animated gif profile pictures. WARNING: run the avatars:refresh rake task after changing this setting." - allow_animated_thumbnails: "Generates animated thumbnails of animated gifs." - default_avatars: "URLs to avatars that will be used by default for new users until they change them." - automatically_download_gravatars: "Download Gravatars for users upon account creation or email change." - digest_topics: "The maximum number of popular topics to display in the email summary." - digest_posts: "The maximum number of popular posts to display in the email summary." - digest_other_topics: "The maximum number of topics to show in the 'New in topics and categories you follow' section of the email summary." - digest_min_excerpt_length: "Minimum post excerpt in the email summary, in characters." - delete_digest_email_after_days: "Suppress summary emails for users not seen on the site for more than (n) days." - digest_suppress_categories: "Suppress these categories from summary emails." - disable_digest_emails: "Disable summary emails for all users." - - detect_custom_avatars: "Whether or not to check that users have uploaded custom profile pictures." - max_daily_gravatar_crawls: "Maximum number of times Discourse will check Gravatar for custom avatars in a day" - public_user_custom_fields: "A whitelist of custom fields for a user that can be shown publicly." - staff_user_custom_fields: "A whitelist of custom fields for a user that can be shown to staff." - enable_user_directory: "Provide a directory of users for browsing" - allow_anonymous_posting: "Allow users to switch to anonymous mode" - anonymous_posting_min_trust_level: "Minimum trust level required to enable anonymous posting" - anonymous_account_duration_minutes: "To protect anonymity create a new anonymous account every N minutes for each user. Example: if set to 600, as soon as 600 minutes elapse from last post AND user switches to anon, a new anonymous account is created." - - hide_user_profiles_from_public: "Disable user cards, user profiles and user directory for anonymous users." - - allow_profile_backgrounds: "Allow users to upload profile backgrounds." - - sequential_replies_threshold: "Number of posts a user has to make in a row in a topic before being reminded about too many sequential replies." - - enable_mobile_theme: "Mobile devices use a mobile-friendly theme, with the ability to switch to the full site. Disable this if you want to use a custom stylesheet that is fully responsive." - - dominating_topic_minimum_percent: "What percentage of posts a user has to make in a topic before being reminded about overly dominating a topic." - - disable_avatar_education_message: "Disable education message for changing avatar." - - suppress_uncategorized_badge: "Don't show the badge for uncategorized topics in topic lists." - - permalink_normalizations: "Apply the following regex before matching permalinks, for example: /(topic.*)\\?.*/\\1 will strip query strings from topic routes. Format is regex+string use \\1 etc. to access captures" - - global_notice: "Display an URGENT, EMERGENCY global banner notice to all visitors, change to blank to hide it (HTML allowed)." - - disable_edit_notifications: "Disables edit notifications by the system user when 'download_remote_images_to_local' is active." - - automatically_unpin_topics: "Automatically unpin topics when the user reaches the bottom." - - read_time_word_count: "Word count per minute for calculating estimated reading time." - - topic_page_title_includes_category: "Topic page title includes the category name." - - max_prints_per_hour_per_user: "Maximum number of /print page impressions (set to 0 to disable)" - - full_name_required: "Full name is a required field of a user's profile." - enable_names: "Show the user's full name on their profile, user card, and emails. Disable to hide full name everywhere." - display_name_on_posts: "Show a user's full name on their posts in addition to their @username." - show_time_gap_days: "If two posts are made this many days apart, display the time gap in the topic." - invites_per_page: "Default invites shown on the user page." - short_progress_text_threshold: "After the number of posts in a topic goes above this number, the progress bar will only show the current post number. If you change the progress bar's width, you may need to change this value." - default_code_lang: "Default programming language syntax highlighting applied to GitHub code blocks (lang-auto, ruby, python etc.)" - warn_reviving_old_topic_age: "When someone starts replying to a topic where the last reply is older than this many days, a warning will be displayed. Disable by setting to 0." - autohighlight_all_code: "Force apply code highlighting to all preformatted code blocks even when they didn't explicitly specify the language." - highlighted_languages: "Included syntax highlighting rules. (Warning: including too many languages may impact performance) see: https://highlightjs.org/static/demo/ for a demo" - - feed_polling_enabled: "EMBEDDING ONLY: Whether to embed a RSS/ATOM feed as posts." - feed_polling_url: "EMBEDDING ONLY: URL of RSS/ATOM feed to embed." - embed_by_username: "Discourse username of the user who creates the embedded topics." - embed_username_key_from_feed: "Key to pull discourse username from feed." - embed_title_scrubber: "Regular expression for scrubbing embeddable titles." - embed_truncate: "Truncate the embedded posts." - allowed_href_schemes: "Schemes allowed in links in addition to http and https." - embed_post_limit: "Maximum number of posts to embed." - embed_username_required: "The username for topic creation is required." - embed_whitelist_selector: "CSS selector for elements that are allowed in embeds." - embed_blacklist_selector: "CSS selector for elements that are removed from embeds." - notify_about_flags_after: "If there are flags that haven't been handled after this many hours, send an email to the contact_email. Set to 0 to disable." - enable_cdn_js_debugging: "Allow /logs to display proper errors by adding crossorigin permissions on all js includes." - show_create_topics_notice: "If the site has fewer than 5 public topics, show a notice asking admins to create some topics." - - delete_drafts_older_than_n_days: Delete drafts older than (n) days. - - bootstrap_mode_min_users: "Minimum number of users required to disable bootstrap mode (set to 0 to disable)" - - vacuum_db_days: "Run VACUUM ANALYZE to reclaim DB space after migrations (set to 0 to disable)" - - prevent_anons_from_downloading_files: "Prevent anonymous users from downloading attachments. WARNING: this will prevent any non-image site assets posted as attachments from working." - - slug_generation_method: "Choose a slug generation method. 'encoded' will generate percent encoding string. 'none' will disable slug at all." - - enable_emoji: "Enable emoji" - emoji_set: "How would you like your emoji?" - enforce_square_emoji: "Force a square aspect ratio to all emojis." - - approve_post_count: "The amount of posts from a new or basic user that must be approved" - approve_unless_trust_level: "Posts for users below this trust level must be approved" - approve_new_topics_unless_trust_level: "New topics for users below this trust level must be approved" - notify_about_queued_posts_after: "If there are posts that have been waiting to be reviewed for more than this many hours, an email will be sent to the contact_email. Set to 0 to disable these emails." - auto_close_messages_post_count: "Maximum number of posts allowed in a message before it is automatically closed (0 to disable)" - auto_close_topics_post_count: "Maximum number of posts allowed in a topic before it is automatically closed (0 to disable)" - - code_formatting_style: "Code button in composer will default to this code formatting style" - - default_email_digest_frequency: "How often users receive summary emails by default." - default_include_tl0_in_digests: "Include posts from new users in summary emails by default. Users can change this in their preferences." - default_email_private_messages: "Send an email when someone messages the user by default." - default_email_direct: "Send an email when someone quotes/replies to/mentions or invites the user by default." - default_email_mailing_list_mode: "Send an email for every new post by default." - default_email_mailing_list_mode_frequency: "Users who enable mailing list mode will receive emails this often by default." - disable_mailing_list_mode: "Disallow users from enabling mailing list mode." - default_email_always: "Send an email notification even when the user is active by default." - default_email_previous_replies: "Include previous replies in emails by default." - - default_email_in_reply_to: "Include excerpt of replied to post in emails by default." - - default_other_new_topic_duration_minutes: "Global default condition for which a topic is considered new." - default_other_auto_track_topics_after_msecs: "Global default time before a topic is automatically tracked." - default_other_notification_level_when_replying: "Global default notification level when the user replies to a topic." - default_other_external_links_in_new_tab: "Open external links in a new tab by default." - default_other_enable_quoting: "Enable quote reply for highlighted text by default." - default_other_dynamic_favicon: "Show new/updated topic count on browser icon by default." - default_other_disable_jump_reply: "Don't jump to user's post after they reply by default." - - default_other_like_notification_frequency: "Notify users on likes by default" - - default_topics_automatic_unpin: "Automatically unpin topics when the user reaches the bottom by default." - - default_categories_watching: "List of categories that are watched by default." - default_categories_tracking: "List of categories that are tracked by default." - default_categories_muted: "List of categories that are muted by default." - default_categories_watching_first_post: "List of categories in which first post in each new topic will be watched by default." - - max_user_api_reqs_per_day: "Maximum number of user API requests per key per day" - max_user_api_reqs_per_minute: "Maximum number of user API requests per key per minute" - allow_user_api_keys: "Allow generation of user API keys" - allow_user_api_key_scopes: "List of scopes allowed for user API keys" - max_api_keys_per_user: "Maximum number of user API keys per user" - min_trust_level_for_user_api_key: "Trust level required for generation of user API keys" - allowed_user_api_auth_redirects: "Allowed URL for authentication redirect for user API keys" - allowed_user_api_push_urls: "Allowed URLs for server push to user API" - - tagging_enabled: "Enable tags on topics?" - min_trust_to_create_tag: "The minimum trust level required to create a tag." - max_tags_per_topic: "The maximum tags that can be applied to a topic." - max_tag_length: "The maximum amount of characters that can be used in a tag." - max_tag_search_results: "When searching for tags, the maximum number of results to show." - show_filter_by_tag: "Show a dropdown to filter a topic list by tag." - max_tags_in_filter_list: "Maximum number of tags to show in the filter dropdown. The most used tags will be shown." - tags_sort_alphabetically: "Show tags in alphabetical order. Default is to show in order of popularity." - tag_style: "Visual style for tag badges." - staff_tags: "A list of tags that can only be applied by staff members" - min_trust_level_to_tag_topics: "Minimum trust level required to tag topics" - suppress_overlapping_tags_in_list: "If tags match exact words in topic titles, don't show the tag" - remove_muted_tags_from_latest: "Don't show topics tagged with muted tags in the latest topic list." - - company_short_name: "Company Name (short)" - company_full_name: "Company Name (full)" - company_domain: "Company Domain" - - errors: - invalid_email: "Invalid email address." - invalid_username: "There's no user with that username." - invalid_integer_min_max: "Value must be between %{min} and %{max}." - invalid_integer_min: "Value must be %{min} or greater." - invalid_integer_max: "Value cannot be higher than %{max}." - invalid_integer: "Value must be an integer." - regex_mismatch: "Value doesn't match the required format." - must_include_latest: "Top menu must include the 'latest' tab." - invalid_string: "Invalid value." - invalid_string_min_max: "Must be between %{min} and %{max} characters." - invalid_string_min: "Must be at least %{min} characters." - invalid_string_max: "Must be no more than %{max} characters." - invalid_reply_by_email_address: "Value must contain '%{reply_key}' and be different from the notification email." - invalid_alternative_reply_by_email_addresses: "All values must contain '%{reply_key}' and be different from the notification email." - pop3_polling_host_is_empty: "You must set a 'pop3 polling host' before enabling POP3 polling." - pop3_polling_username_is_empty: "You must set a 'pop3 polling username' before enabling POP3 polling." - pop3_polling_password_is_empty: "You must set a 'pop3 polling password' before enabling POP3 polling." - pop3_polling_authentication_failed: "POP3 authentication failed. Please verify your pop3 credentials." - reply_by_email_address_is_empty: "You must set a 'reply by email address' before enabling reply by email." - email_polling_disabled: "You must enable either manual or POP3 polling before enabling reply by email." - user_locale_not_enabled: "You must first enable 'allow user locale' before enabling this setting." - invalid_regex: "Regex is invalid or not allowed." - - search: - within_post: "#%{post_number} by %{username}" - types: - category: 'Categories' - topic: 'Results' - user: 'Users' - - sso: - not_found: "Your account couldn't be found. Please contact the site's administrator." - account_not_approved: "Your account is pending approval. You will receive an email notification when you are approved." - unknown_error: "There is a problem with your account. Please contact the site's administrator." - timeout_expired: "Account login timed out, please try logging in again." - - original_poster: "Original Poster" - most_posts: "Most Posts" - most_recent_poster: "Most Recent Poster" - frequent_poster: "Frequent Poster" - - redirected_to_top_reasons: - new_user: "Welcome to our community! These are the most popular recent topics." - not_seen_in_a_month: "Welcome back! We haven't seen you in a while. These are the most popular topics since you've been away." - - merge_posts: - edit_reason: - one: "A post was merged in by %{username}" - other: "%{count} posts were merged in by %{username}" - errors: - different_topics: "Posts belonging to different topics cannot be merged." - different_users: "Posts belonging to different users cannot be merged." - - move_posts: - new_topic_moderator_post: - one: "A post was split to a new topic: %{topic_link}" - other: "%{count} posts were split to a new topic: %{topic_link}" - existing_topic_moderator_post: - one: "A post was merged into an existing topic: %{topic_link}" - other: "%{count} posts were merged into an existing topic: %{topic_link}" - - change_owner: - post_revision_text: "Ownership transferred from %{old_user} to %{new_user}" - deleted_user: "a deleted user" - - emoji: - errors: - name_already_exists: "Sorry, the name '%{name}' is already used by another emoji." - error_while_storing_emoji: "Sorry, there has been an error while storing the emoji." - - topic_statuses: - archived_enabled: "This topic is now archived. It is frozen and cannot be changed in any way." - archived_disabled: "This topic is now unarchived. It is no longer frozen, and can be changed." - closed_enabled: "This topic is now closed. New replies are no longer allowed." - closed_disabled: "This topic is now opened. New replies are allowed." - autoclosed_message_max_posts: - one: "This message was automatically closed after reaching the maximum limit of 1 reply." - other: "This message was automatically closed after reaching the maximum limit of %{count} replies." - autoclosed_topic_max_posts: - one: "This topic was automatically closed after reaching the maximum limit of 1 reply." - other: "This topic was automatically closed after reaching the maximum limit of %{count} replies." - autoclosed_enabled_days: - one: "This topic was automatically closed after 1 day. New replies are no longer allowed." - other: "This topic was automatically closed after %{count} days. New replies are no longer allowed." - autoclosed_enabled_hours: - one: "This topic was automatically closed after 1 hour. New replies are no longer allowed." - other: "This topic was automatically closed after %{count} hours. New replies are no longer allowed." - autoclosed_enabled_minutes: - one: "This topic was automatically closed after 1 minute. New replies are no longer allowed." - other: "This topic was automatically closed after %{count} minutes. New replies are no longer allowed." - autoclosed_enabled_lastpost_days: - one: "This topic was automatically closed 1 day after the last reply. New replies are no longer allowed." - other: "This topic was automatically closed %{count} days after the last reply. New replies are no longer allowed." - autoclosed_enabled_lastpost_hours: - one: "This topic was automatically closed 1 hour after the last reply. New replies are no longer allowed." - other: "This topic was automatically closed %{count} hours after the last reply. New replies are no longer allowed." - autoclosed_enabled_lastpost_minutes: - one: "This topic was automatically closed 1 minute after the last reply. New replies are no longer allowed." - other: "This topic was automatically closed %{count} minutes after the last reply. New replies are no longer allowed." - autoclosed_disabled: "This topic is now opened. New replies are allowed." - autoclosed_disabled_lastpost: "This topic is now opened. New replies are allowed." - pinned_enabled: "This topic is now pinned. It will appear at the top of its category until it is unpinned by staff for everyone, or by individual users for themselves." - pinned_disabled: "This topic is now unpinned. It will no longer appear at the top of its category." - pinned_globally_enabled: "This topic is now pinned globally. It will appear at the top of its category and all topic lists until it is unpinned by staff for everyone, or by individual users for themselves." - pinned_globally_disabled: "This topic is now unpinned. It will no longer appear at the top of its category." - visible_enabled: "This topic is now listed. It will be displayed in topic lists." - visible_disabled: "This topic is now unlisted. It will no longer be displayed in any topic lists. The only way to access this topic is via direct link." - - login: - not_approved: "Your account hasn't been approved yet. You will be notified by email when you are ready to log in." - incorrect_username_email_or_password: "Incorrect username, email or password" - wait_approval: "Thanks for signing up. We will notify you when your account has been approved." - active: "Your account is activated and ready to use." - activate_email: "

    You're almost done! We sent an activation mail to %{email}. Please follow the instructions in the email to activate your account.

    If it doesn't arrive, check your spam folder, or try to log in again to send another activation mail.

    " - not_activated: "You can't log in yet. We sent an activation email to you. Please follow the instructions in the email to activate your account." - not_allowed_from_ip_address: "You can't log in as %{username} from that IP address." - admin_not_allowed_from_ip_address: "You can't log in as admin from that IP address." - suspended: "You can't log in until %{date}." - suspended_with_reason: "Account suspended until %{date}: %{reason}" - errors: "%{errors}" - not_available: "Not available. Try %{suggestion}?" - something_already_taken: "Something went wrong, perhaps the username or email is already registered. Try the forgot password link." - omniauth_error: "Sorry, there was an error authorizing your account. Perhaps you did not approve authorization?" - omniauth_error_unknown: "Something went wrong processing your log in, please try again." - authenticator_error_no_valid_email: "No email addresses associated with %{account} are allowed. You may need to configure your account with a different email address." - new_registrations_disabled: "New account registrations are not allowed at this time." - password_too_long: "Passwords are limited to 200 characters." - email_too_long: "The email you provided is too long. Mailbox names must be no more than 254 characters, and domain names must be no more than 253 characters." - reserved_username: "That username is not allowed." - missing_user_field: "You have not completed all the user fields" - close_window: "Authentication is complete. Close this window to continue." - already_logged_in: "Oops, looks like you are attempting to accept an invitation for another user. If you are not %{current_user}, please log out and try again." - - user: - no_accounts_associated: "No accounts associated" - deactivated: "Was deactivated due to too many bounced emails to '%{email}'." - username: - short: "must be at least %{min} characters" - long: "must be no more than %{max} characters" - characters: "must only include numbers, letters and underscores" - unique: "must be unique" - blank: "must be present" - must_begin_with_alphanumeric_or_underscore: "must begin with a letter, a number or an underscore" - must_end_with_alphanumeric: "must end with a letter or a number" - must_not_contain_two_special_chars_in_seq: "must not contain a sequence of 2 or more special chars (.-_)" - must_not_end_with_confusing_suffix: "must not end with a confusing suffix like .json or .png etc." - email: - not_allowed: "is not allowed from that email provider. Please use another email address." - blocked: "is not allowed." - revoked: "Won't be sending emails to '%{email}' until %{date}." - ip_address: - blocked: "New registrations are not allowed from your IP address." - max_new_accounts_per_registration_ip: "New registrations are not allowed from your IP address (maximum limit reached). Contact a staff member." - - flags_reminder: - flags_were_submitted: - one: "Flags were submitted over 1 hour ago. Please review them." - other: "Flags were submitted over %{count} hours ago. Please review them." - subject_template: - one: "1 flag waiting to be handled" - other: "%{count} flags waiting to be handled" - - unsubscribe_mailer: - subject_template: "Confirm you no longer want to receive email updates from %{site_title}" - text_body_template: | - Someone (possibly you?) requested to no longer send email updates from %{site_domain_name} to this address. - If you with to confirm this, please click this link: - - %{confirm_unsubscribe_link} - - - If you want to continue receiving email updates, you may ignore this email. - - invite_mailer: - subject_template: "%{invitee_name} invited you to '%{topic_title}' on %{site_domain_name}" - text_body_template: | - %{invitee_name} invited you to a discussion - - > **%{topic_title}** - > - > %{topic_excerpt} - - at - - > %{site_title} -- %{site_description} - - If you're interested, click the link below: - - %{invite_link} - - This invitation is from a trusted user, so you can reply to the discussion immediately. - - custom_invite_mailer: - subject_template: "%{invitee_name} invited you to '%{topic_title}' on %{site_domain_name}" - text_body_template: | - %{invitee_name} invited you to a discussion - - > **%{topic_title}** - > - > %{topic_excerpt} - - at - - > %{site_title} -- %{site_description} - - Message from %{invitee_name}: - - %{user_custom_message} - - If you're interested, click the link below: - - %{invite_link} - - This invitation is from a trusted user, so you can reply to the discussion immediately. - - invite_forum_mailer: - subject_template: "%{invitee_name} invited you to join %{site_domain_name}" - text_body_template: | - %{invitee_name} invited you to join - - > **%{site_title}** - > - > %{site_description} - - If you're interested, click the link below: - - %{invite_link} - - This invitation is from a trusted user, so an account will be created for you automatically. - - custom_invite_forum_mailer: - subject_template: "%{invitee_name} invited you to join %{site_domain_name}" - text_body_template: | - %{invitee_name} invited you to join - - > **%{site_title}** - > - > %{site_description} - - Message from %{invitee_name}: - - %{user_custom_message} - - If you're interested, click the link below: - - %{invite_link} - - This invitation is from a trusted user, so an account will be created for you automatically. - - invite_password_instructions: - subject_template: "Set password for your %{site_name} account" - text_body_template: | - Thanks for accepting your invitation to %{site_name} -- welcome! - - Click this link to choose a password now: - %{base_url}/users/password-reset/%{email_token} - - (If the link above has expired, choose "I forgot my password" when logging in with your email address.) - - test_mailer: - subject_template: "[%{site_name}] Email Deliverability Test" - text_body_template: | - This is a test email from - - [**%{base_url}**][0] - - Email deliverability is complicated. Here are a few important things you should check first: - - - Be *sure* to set the `notification email` from: address correctly in your site settings. **The domain specified in the "from" address of the emails you send is the domain your email will be validated against**. - - - Know how to view the raw source of the email in your mail client, so you can examine email headers for important clues. in Gmail, it is the "show original" option in the drop-down menu at the top right of each mail. - - - **IMPORTANT:** Does your ISP have a reverse DNS record entered to associate the domain names and IP addresses you send mail from? [Test your Reverse PTR record][2] here. If your ISP does not enter the proper reverse DNS pointer record, it's very unlikely any of your email will be delivered. - - - Is your domain's [SPF record][8] correct? [Test your SPF record][1] here. Note that TXT is the correct official record type for SPF. - - - Is your domain's [DKIM record][3] correct? This will significantly improve email deliverability. [Test your DKIM record][7] here. - - - If you run your own mail server, check to make sure the IPs of your mail server are [not on any email blacklists][4]. Also verify that it is definitely sending a fully-qualified hostname that resolves in DNS in its HELO message. If not, this will cause your email to be rejected by many mail services. - - - We highly recommend you **send a test email to [mail-tester.com][mt]** to verify that all the above is working correctly. - - (The *easy* way is to create a free account on [SendGrid][sg], [SparkPost][sp], [Mailgun][mg] or [Mailjet][mj], which have generous free mailing plans and will be fine for small communities. You'll still need to set up the SPF and DKIM records in your DNS, though!) - - We hope you received this email deliverability test OK! - - Good luck, - - Your friends at [Discourse](http://www.discourse.org) - - [0]: %{base_url} - [1]: http://www.kitterman.com/spf/validate.html - [2]: http://mxtoolbox.com/ReverseLookup.aspx - [3]: http://www.dkim.org/ - [4]: http://whatismyipaddress.com/blacklist-check - [7]: https://www.mail-tester.com/spf-dkim-check - [8]: http://www.openspf.org/SPF_Record_Syntax - [sg]: https://goo.gl/r1WMF6 - [sp]: https://www.sparkpost.com/ - [mg]: http://www.mailgun.com/ - [mj]: https://www.mailjet.com/pricing - [mt]: http://www.mail-tester.com/ - - new_version_mailer: - subject_template: "[%{site_name}] New Discourse version, update available" - text_body_template: | - Hooray, a new version of [Discourse](http://www.discourse.org) is available! - - Your version: %{installed_version} - New version: **%{new_version}** - - - Upgrade using our easy **[one-click browser upgrade](%{base_url}/admin/upgrade)** - - - See what's new in the [GitHub changelog](https://github.com/discourse/discourse/commits/master) - - - Visit [meta.discourse.org](https://meta.discourse.org) for news, discussion, and support for Discourse - - new_version_mailer_with_notes: - subject_template: "[%{site_name}] update available" - text_body_template: | - Hooray, a new version of [Discourse](http://www.discourse.org) is available! - - Your version: %{installed_version} - New version: **%{new_version}** - - - Upgrade using our easy **[one-click browser upgrade](%{base_url}/admin/upgrade)** - - - See what's new in the [GitHub changelog](https://github.com/discourse/discourse/commits/master) - - - Visit [meta.discourse.org](https://meta.discourse.org) for news, discussion, and support for Discourse - - ### Release notes - - %{notes} - - queued_posts_reminder: - subject_template: - one: "[%{site_name}] 1 post waiting to be reviewed" - other: "[%{site_name}] %{count} posts waiting to be reviewed" - text_body_template: | - Hello, - - Posts from new users were held for moderation and are currently waiting to be reviewed. [Approve or reject them here](%{base_url}/queued-posts). - - flag_reasons: - off_topic: "Your post was flagged as **off-topic**: the community feels it is not a good fit for the topic, as currently defined by the title and the first post." - inappropriate: "Your post was flagged as **inappropriate**: the community feels it is offensive, abusive, or a violation of [our community guidelines](/guidelines)." - spam: "Your post was flagged as **spam**: the community feels it is an advertisement, something that is overly promotional in nature instead of being useful or relevant to the topic as expected." - notify_moderators: "Your post was flagged **for moderator attention**: the community feels something about the post requires manual intervention by a staff member." - - flags_dispositions: - agreed: "Thanks for letting us know. We agree there is an issue and we're looking into it." - agreed_and_deleted: "Thanks for letting us know. We agree there is an issue and we've removed the post." - disagreed: "Thanks for letting us know. We're looking into it." - deferred: "Thanks for letting us know. We're looking into it." - deferred_and_deleted: "Thanks for letting us know. We've removed the post." - - temporarily_closed_due_to_flags: "This topic is temporarily closed due to a large number of community flags." - - system_messages: - post_hidden: - subject_template: "Post hidden by community flags" - text_body_template: | - Hello, - - This is an automated message from %{site_name} to let you know that your post was hidden. - - %{base_url}%{url} - - %{flag_reason} - - Multiple community members flagged this post before it was hidden, so please consider how you might revise your post to reflect their feedback. **You can edit your post after %{edit_delay} minutes, and it will be automatically unhidden.** - - However, if the post is hidden by the community a second time, it will remain hidden until handled by staff – and there may be further action, including the possible suspension of your account. - - For additional guidance, please refer to our [community guidelines](%{base_url}/guidelines). - - usage_tips: - text_body_template: | - Here are a few quick tips to get you started: - - ## Reading - - To read more, **just keep scrolling down!** - - As new replies or new topics arrive, they will appear automatically – no need to refresh the page. - - ## Navigation - - - For search, your user page, or the menu, use the **icon buttons at upper right**. - - - Selecting a topic title will always take you to your **next unread reply** in the topic. To enter at the top or bottom instead, select the reply count or last reply date. - - - - - While reading a topic, use the timeline on the right to jump to the top, bottom, or your last read position. On smaller screens, select the progress bar at bottom right to expand it: - - - - You can also press ? on your keyboard for a list of super-speedy keyboard shortcuts. - - ## Replying - - To insert a quote, select the text you wish to quote, then press any Reply button to open the editor. Repeat for multiple quotes. - - - - You can always continue reading while you compose your reply, and we automatically save drafts as you write. - - To notify someone about your reply, mention their name. Type `@` to begin selecting a username. - - - - To use [standard Emoji](http://www.emoji.codes/), just type `:` to match by name, or use the traditional smileys `;)` - - - - To generate a summary for a link, paste it on a line by itself: - - - - Your reply can be formatted using simple HTML, BBCode, or [Markdown](http://commonmark.org/help/): - - This is bold. - This is [b]bold[/b]. - This is **bold**. - - For more formatting tips, [try our fun 10 minute interactive tutorial!](http://commonmark.org/help/tutorial/) - - ## Actions - - There are action buttons at the bottom of each post: - - - - - To let someone know that you enjoyed and appreciated their post, use the **like** button. Share the love! - - - Grab a copy-pasteable link to any reply or topic via the **link** button. - - - Use the show more button to reveal more actions. **Flag** to privately let the author, or [our staff](%{base_url}/about), know about a problem. **Bookmark** to find this post later on your profile page. - - ## Notifications - - When someone replies to you, quotes your post, mentions your `@username`, or even links to your post, a number will immediately appear at the top right of the page. Select it to access your **notifications**. - - - - Don't worry about missing a reply – you'll be emailed any notifications that arrive when you are away. - - ## Preferences - - - All topics less than **two days old** are considered new. - - - Any topic you've **actively participated in** (by creating it, replying to it, or reading it for an extended period) will be automatically tracked on your behalf. - - You will see the new and unread number indicators next to these topics: - - - - You can change your notifications for any topic via the notification control at the bottom, and right hand side, of each topic. - - - - You can also set notification state per category, if you want to watch or mute every new topic in a specific category. - - To change any of these settings, see [your user preferences](%{base_url}/my/preferences). - - ## Community Trust - - It's great to meet you! As you participate here, over time we'll get to know you, and your temporary new user limitations will be lifted. Keep participating, and over time you'll gain new [trust levels](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924) that include special abilities to help us manage our community together. - - welcome_user: - subject_template: "Welcome to %{site_name}!" - text_body_template: | - Thanks for joining %{site_name}, and welcome! - - %{new_user_tips} - - We believe in [civilized community behavior](%{base_url}/guidelines) at all times. - - Enjoy your stay! - - (If you need to communicate with [staff members](%{base_url}/about) as a new user, just reply to this message.) - - welcome_invite: - subject_template: "Welcome to %{site_name}!" - text_body_template: | - Thanks for accepting your invitation to %{site_name} -- welcome! - - We've created a new account **%{username}** for you, and you are logged in. You can change your name by visiting [your user profile][prefs]. - - To log in again later: - - 1. Always **use the same email address from your original invitation** when logging in. Otherwise we won't be able to tell it's you! - - 2. Create a unique password for [your user profile][prefs], and use it to log in. - - %{new_user_tips} - - We believe in [civilized community behavior](%{base_url}/guidelines) at all times. - - Enjoy your stay! - - (If you need to communicate with [staff members](%{base_url}/about) as a new user, just reply to this message.) - - [prefs]: %{user_preferences_url} - - backup_succeeded: - subject_template: "Backup completed successfully" - text_body_template: | - The backup was successful. - - Visit the [admin > backup section](%{base_url}/admin/backups) to download your new backup. - - Here's the log: - - ```text - %{logs} - ``` - - backup_failed: - subject_template: "Backup failed" - text_body_template: | - The backup has failed. - - Here's the log: - - ```text - %{logs} - ``` - - restore_succeeded: - subject_template: "Restore completed successfully" - text_body_template: | - The restore was successful. - - Here's the log: - - ```text - %{logs} - ``` - - restore_failed: - subject_template: "Restore failed" - text_body_template: | - The restore has failed. - - Here's the log: - - ```text - %{logs} - ``` - - bulk_invite_succeeded: - subject_template: "Bulk user invite processed successfully" - text_body_template: "Your bulk user invite file was processed, %{sent} invites mailed." - - bulk_invite_failed: - subject_template: "Bulk user invite processed with errors" - text_body_template: | - Your bulk user invite file was processed, %{sent} invites mailed with %{failed} error(s). - - Here's the log: - - ``` - %{logs} - ``` - - csv_export_succeeded: - subject_template: "Data export complete" - text_body_template: | - Your data export was successful! :dvd: - - %{file_name} (%{file_size}) - - The above download link will be valid for 48 hours. - - csv_export_failed: - subject_template: "Data export failed" - text_body_template: "We're sorry, but your data export failed. Please check the logs or contact a staff member." - - email_reject_insufficient_trust_level: - subject_template: "[%{site_name}] Email issue -- Insufficient Trust Level" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - Your account does not have the required trust level to post new topics to this email address. If you believe this is an error, contact a staff member. - - email_reject_user_not_found: - subject_template: "[%{site_name}] Email issue -- User Not Found" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - Your reply was sent from an unknown email address. Try sending from another email address, or contact a staff member. - - email_reject_screened_email: - subject_template: "[%{site_name}] Email issue -- Blocked Email" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - Your reply was sent from a blocked email address. Try sending from another email address, or contact a staff member. - - email_reject_inactive_user: - subject_template: "[%{site_name}] Email issue -- Inactive User" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - Your account associated with this email address is not activated. Please activate your account before sending emails in. - - email_reject_blocked_user: - subject_template: "[%{site_name}] Email issue -- Blocked User" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - Your account associated with this email address has been blocked. - - email_reject_reply_user_not_matching: - subject_template: "[%{site_name}] Email issue -- Unexpected Reply Address" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - Your reply was sent from a different email address than the one we expected, so we're not sure if this is the same person. Try sending from another email address, or contact a staff member. - - email_reject_no_account: - subject_template: "[%{site_name}] Email issue -- Unknown Account" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - We can't find any accounts that match your email address. Try sending from a different email address, or contact a staff member. - - email_reject_empty: - subject_template: "[%{site_name}] Email issue -- No Content" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - We couldn't find any reply content in your email. - - If you're getting this and you _did_ include a reply, try again with simpler formatting. - - email_reject_parsing: - subject_template: "[%{site_name}] Email issue -- Content Unrecognized" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - We couldn't find your reply in the email. **Make sure your reply is at the top of the email** -- we can't process inline replies. - - email_reject_invalid_access: - subject_template: "[%{site_name}] Email issue -- Invalid Access" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - Your account does not have the privileges to post new topics in that category. If you believe this is an error, contact a staff member. - - email_reject_strangers_not_allowed: - subject_template: "[%{site_name}] Email issue -- Invalid Access" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - The category you sent this email to only allows replies from users with valid accounts and known email addresses. If you believe this is an error, contact a staff member. - - email_reject_invalid_post: - subject_template: "[%{site_name}] Email issue -- Posting error" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - Some possible causes are: complex formatting, message too large, message too small. Please try again, or post via the website if this continues. - - email_reject_invalid_post_specified: - subject_template: "[%{site_name}] Email issue -- Posting error" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - Reason: - - %{post_error} - - If you can correct the problem, please try again. - - email_reject_invalid_post_action: - subject_template: "[%{site_name}] Email issue -- Invalid Post Action" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - The Post Action was not recognized. Please try again, or post via the website if this continues. - - - email_reject_reply_key: - subject_template: "[%{site_name}] Email issue -- Unknown Reply Key" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - The reply key in the email is invalid or unknown, so we can't figure out what this email is in reply to. Contact a staff member. - - email_reject_bad_destination_address: - subject_template: "[%{site_name}] Email issue -- Unknown To: Address" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - None of the destination email addresses are recognized. Please make sure that you are sending to the correct email address provided by staff. - - email_reject_topic_not_found: - subject_template: "[%{site_name}] Email issue -- Topic Not Found" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - The topic you are replying to no longer exists -- perhaps it was deleted? If you believe this is an error, contact a staff member. - - email_reject_topic_closed: - subject_template: "[%{site_name}] Email issue -- Topic Closed" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - The topic you are replying to is currently closed and no longer accepting replies. If you believe this is an error, contact a staff member. - - email_reject_auto_generated: - subject_template: "[%{site_name}] Email issue -- Auto Generated Reply" - text_body_template: | - We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. - - Your email was marked as "auto generated", which means it was automatically created by a computer instead of being typed by a human; we can't accept those kinds of emails. If you believe this is an error, contact a staff member. - - email_error_notification: - subject_template: "[%{site_name}] Email issue -- POP authentication error" - text_body_template: | - Unfortunately, there was an authentication error while polling mails from the POP server. - - Please make sure you have properly configured the POP credentials in [the site settings](%{base_url}/admin/site_settings/category/email). - - If there is a web UI for the POP email account, you may need to log in on the web and check your settings there. - too_many_spam_flags: - subject_template: "New account on hold" - text_body_template: | - Hello, - - This is an automated message from %{site_name} to let you know that your posts have been temporarily hidden because they were flagged by the community. - - As a precautionary measure, your new account has been blocked from creating new replies or topics until a staff member can review your account. We apologize for the inconvenience. - - For additional guidance, please refer to our [community guidelines](%{base_url}/guidelines). - too_many_tl3_flags: - subject_template: "New account on hold" - text_body_template: | - Hello, - - This is an automated message from %{site_name} to let you know you that your account has been placed on hold due to a large number of community flags. - - As a precautionary measure, your new account has been blocked from creating new replies or topics until a staff member can review your account. We apologize for the inconvenience. - - For additional guidance, please refer to our [community guidelines](%{base_url}/guidelines). - blocked_by_staff: - subject_template: "Account temporarily on hold" - text_body_template: | - Hello, - - This is an automated message from %{site_name} to let you know that your account has been temporarily placed on hold as a precautionary measure. - - Please do continue to browse, but you won't be able to reply or create topics until a [staff member](%{base_url}/about) reviews your most recent posts. We apologize for the inconvenience. - - For additional guidance, refer to our [community guidelines](%{base_url}/guidelines). - - user_automatically_blocked: - subject_template: "New user %{username} blocked by community flags" - text_body_template: | - This is an automated message. - - The new user [%{username}](%{user_url}) was automatically blocked because multiple users flagged %{username}'s post(s). - - Please [review the flags](%{base_url}/admin/flags). If %{username} was incorrectly blocked from posting, click the unblock button on [the admin page for this user](%{user_url}). - - This threshold can be changed via the `block_new_user` site settings. - - spam_post_blocked: - subject_template: "New user %{username} posts blocked due to repeated links" - text_body_template: | - This is an automated message. - - The new user [%{username}](%{user_url}) tried to create multiple posts with links to %{domains}, but those posts were blocked to avoid spam. The user is still able to create new posts that do not link to %{domains}. - - Please [review the user](%{user_url}). - - This can be modified via the `newuser_spam_host_threshold` and `white_listed_spam_host_domains` site settings. - - unblocked: - subject_template: "Account no longer on hold" - text_body_template: | - Hello, - - This is an automated message from %{site_name} to let you know that your account is no longer on hold after staff review. - - You can now create new replies and topics again. Thank you for your patience. - - pending_users_reminder: - subject_template: - one: "1 user waiting for approval" - other: "%{count} users waiting for approval" - text_body_template: | - There are new user signups waiting to be approved (or rejected) before they can access this forum. - - [Please review them in the admin section](%{base_url}/admin/users/list/pending). - - download_remote_images_disabled: - subject_template: "Downloading remote images disabled" - text_body_template: "The `download_remote_images_to_local` setting was disabled because the disk space limit at `download_remote_images_threshold` was reached." - - dashboard_problems: - subject_template: "Problems have been found" - text_body_template: | - Some problems are being reported on your admin dashboard. - - [Please review and fix them](%{base_url}/admin). - - unsubscribe_link: | - To unsubscribe from these emails, [click here](%{unsubscribe_url}). - - unsubscribe_link_and_mail: | - To unsubscribe from these emails, [click here](%{unsubscribe_url}). - - unsubscribe_mailing_list: | - You are receiving this because you enabled mailing list mode. - - To unsubscribe from these emails, [click here](%{unsubscribe_url}). - - subject_re: "Re: " - subject_pm: "[PM] " - - user_notifications: - previous_discussion: "Previous Replies" - reached_limit: - one: "WARNING: you reached the limit of daily emails. Further email notifications will be suppressed." - other: "WARNING: you reached the limit of %{count} daily emails. Further email notifications will be suppressed." - in_reply_to: "In Reply To" - unsubscribe: - title: "Unsubscribe" - description: "Not interested in getting these emails? No problem! Click below to unsubscribe instantly:" - - header_instructions: '' - reply_by_email: "[Visit Topic](%{base_url}%{url}) or reply to this email to respond." - reply_by_email_pm: "[Visit Message](%{base_url}%{url}) or reply to this email to respond." - only_reply_by_email: "Reply to this email to respond." - visit_link_to_respond: "[Visit Topic](%{base_url}%{url}) to respond." - visit_link_to_respond_pm: "[Visit Message](%{base_url}%{url}) to respond." - - posted_by: "Posted by %{username} on %{post_date}" - - invited_to_private_message_body: | - %{username} invited you to a message - - > **%{topic_title}** - > - > %{topic_excerpt} - - at - - > %{site_title} -- %{site_description} - - invited_to_topic_body: | - %{username} invited you to a discussion - - > **%{topic_title}** - > - > %{topic_excerpt} - - at - - > %{site_title} -- %{site_description} - - user_invited_to_private_message_pm: - subject_template: "[%{site_name}] %{username} invited you to a message '%{topic_title}'" - text_body_template: | - %{header_instructions} - - %{message} - - %{respond_instructions} - - user_invited_to_private_message_pm_staged: - subject_template: "[%{site_name}] %{username} invited you to a message '%{topic_title}'" - text_body_template: | - %{header_instructions} - - %{message} - - %{respond_instructions} - - user_invited_to_topic: - subject_template: "[%{site_name}] %{username} invited you to '%{topic_title}'" - text_body_template: | - %{header_instructions} - - %{message} - - %{respond_instructions} - - user_replied: - subject_template: "[%{site_name}] %{topic_title}" - text_body_template: | - %{header_instructions} - - %{message} - - %{context} - - %{respond_instructions} - - user_replied_pm: - subject_template: "[%{site_name}] [PM] %{topic_title}" - text_body_template: | - %{header_instructions} - - %{message} - - %{context} - - %{respond_instructions} - - user_quoted: - subject_template: "[%{site_name}] %{topic_title}" - text_body_template: | - %{header_instructions} - - %{message} - - %{context} - - %{respond_instructions} - - user_linked: - subject_template: "[%{site_name}] %{topic_title}" - text_body_template: | - %{header_instructions} - - %{message} - - %{context} - - %{respond_instructions} - - user_mentioned: - subject_template: "[%{site_name}] %{topic_title}" - text_body_template: | - %{header_instructions} - - %{message} - - %{context} - - %{respond_instructions} - - user_group_mentioned: - subject_template: "[%{site_name}] %{topic_title}" - text_body_template: | - %{header_instructions} - - %{message} - - %{context} - - %{respond_instructions} - - user_posted: - subject_template: "[%{site_name}] %{topic_title}" - text_body_template: | - %{header_instructions} - - %{message} - - %{context} - - %{respond_instructions} - - user_watching_first_post: - subject_template: "[%{site_name}] %{topic_title}" - text_body_template: | - %{header_instructions} - - %{message} - - %{context} - - %{respond_instructions} - - user_posted_pm: - subject_template: "[%{site_name}] [PM] %{topic_title}" - text_body_template: | - %{header_instructions} - - %{message} - - %{context} - - %{respond_instructions} - - user_posted_pm_staged: - subject_template: "%{optional_re}%{topic_title}" - text_body_template: | - - %{message} - - digest: - why: "A brief summary of %{site_link} since your last visit on %{last_seen_at}" - since_last_visit: "Since your last visit" - new_topics: "New Topics" - unread_messages: "Unread Messages" - unread_notifications: "Unread Notifications" - new_posts: "New Posts" - new_users: "New Users" - popular_topics: "Popular Topics" - follow_topic: "Follow this topic" - join_the_discussion: "Read More" - popular_posts: "Popular Posts" - from_topic_label: "From" - more_new: "New in topics and categories you follow" - subject_template: "[%{site_name}] Summary" - unsubscribe: "This summary is sent from %{site_link} when we haven't seen you in a while. To unsubscribe %{unsubscribe_link}." - click_here: "click here" - from: "%{site_name} summary" - preheader: "A brief summary since your last visit on %{last_seen_at}" - custom: - html: - header: '' - below_post_1: '' - below_post_2: '' - below_post_3: '' - below_post_4: '' - below_post_5: '' - above_popular_topics: '' - below_popular_topics: '' - above_footer: '' - below_footer: '' - text: - below_post_1: '' - below_post_2: '' - below_post_3: '' - below_post_4: '' - below_post_5: '' - above_popular_topics: '' - below_popular_topics: '' - above_footer: '' - below_footer: '' - - mailing_list: - why: "All activity on %{site_link} for %{date}" - subject_template: "[%{site_name}] Summary for %{date}" - unsubscribe: "This summary is sent daily due to mailing list mode being enabled. To unsubscribe %{unsubscribe_link}." - from: "%{site_name} summary" - new_topics: "New topics" - topic_updates: "Topic updates" - view_this_topic: "View this topic" - back_to_top: "Back to top" - forgot_password: - subject_template: "[%{site_name}] Password reset" - text_body_template: | - Somebody asked to reset your password on [%{site_name}](%{base_url}). - - If it was not you, you can safely ignore this email. - - Click the following link to choose a new password: - %{base_url}/users/password-reset/%{email_token} - - set_password: - subject_template: "[%{site_name}] Set Password" - text_body_template: | - Somebody asked to add a password to your account on [%{site_name}](%{base_url}). Alternatively, you can log in using any supported online service (Google, Facebook, etc) that is associated with this validated email address. - - If you did not make this request, you can safely ignore this email. - - Click the following link to choose a password: - %{base_url}/users/password-reset/%{email_token} - - admin_login: - subject_template: "[%{site_name}] Login" - text_body_template: | - Somebody asked to login to your account on [%{site_name}](%{base_url}). - - If you did not make this request, you can safely ignore this email. - - Click the following link to login: - %{base_url}/users/admin-login/%{email_token} - - account_created: - subject_template: "[%{site_name}] Your New Account" - text_body_template: | - A new account was created for you at %{site_name} - - Click the following link to choose a password for your new account: - %{base_url}/users/password-reset/%{email_token} - - confirm_new_email: - subject_template: "[%{site_name}] Confirm your new email address" - text_body_template: | - Confirm your new email address for %{site_name} by clicking on the following link: - - %{base_url}/users/authorize-email/%{email_token} - - confirm_old_email: - subject_template: "[%{site_name}] Confirm your current email address" - text_body_template: | - Before we can change your email address, we need you to confirm that you control - the current email account. After you complete this step, we will have you confirm - the new email address. - - Confirm your current email address for %{site_name} by clicking on the following link: - - %{base_url}/users/authorize-email/%{email_token} - - notify_old_email: - subject_template: "[%{site_name}] Your email address has been changed" - text_body_template: | - This is an automated message to let you know that your email address for - %{site_name} has been changed. If this was done in error, please contact - a site administrator. - - Your email address has been changed to: - - %{new_email} - - signup_after_approval: - subject_template: "You've been approved on %{site_name}!" - text_body_template: | - Welcome to %{site_name}! - - A staff member approved your account on %{site_name}. - - Click the following link to confirm and activate your new account: - %{base_url}/users/activate-account/%{email_token} - - If the above link is not clickable, try copying and pasting it into the address bar of your web browser. - - %{new_user_tips} - - We believe in [civilized community behavior](%{base_url}/guidelines) at all times. - - Enjoy your stay! - - (If you need to communicate with [staff members](%{base_url}/about) as a new user, just reply to this message.) - - signup: - subject_template: "[%{site_name}] Confirm your new account" - text_body_template: | - Welcome to %{site_name}! - - Click the following link to confirm and activate your new account: - %{base_url}/users/activate-account/%{email_token} - - If the above link is not clickable, try copying and pasting it into the address bar of your web browser. - - page_not_found: - title: "Oops! That page doesn’t exist or is private." - popular_topics: "Popular" - recent_topics: "Recent" - see_more: "More" - search_title: "Search this site" - search_google: "Google" - - login_required: - welcome_message: | - #[Welcome to %{title}](#welcome) - An account is required. Please create an account or log in to continue. - - terms_of_service: - title: "Terms of Service" - signup_form_message: 'I have read and accept the Terms of Service.' - - deleted: 'deleted' - - upload: - edit_reason: "downloaded local copies of images" - unauthorized: "Sorry, the file you are trying to upload is not authorized (authorized extensions: %{authorized_extensions})." - pasted_image_filename: "Pasted image" - store_failure: "Failed to store upload #%{upload_id} for user #%{user_id}." - file_missing: "Sorry, you must provide a file to upload." - attachments: - too_large: "Sorry, the file you are trying to upload is too big (maximum size is %{max_size_kb}KB)." - images: - too_large: "Sorry, the image you are trying to upload is too big (maximum size is %{max_size_kb}KB), please resize it and try again." - size_not_found: "Sorry, but we couldn't determine the size of the image. Maybe your image is corrupted?" - - avatar: - missing: "Sorry, we can't find any avatar associated with that email address. Can you try uploading it again?" - - flag_reason: - sockpuppet: "A new user created a topic, and another new user at the same IP address (%{ip_address}) replied. See the `flag_sockpuppets` site setting." - spam_hosts: "This new user tried to create multiple posts with links to the same domain (%{domain}). See the `newuser_spam_host_threshold` site setting." - - email_log: - post_user_deleted: "User of the post has been deleted." - no_user: "Can't find user with id %{user_id}" - anonymous_user: "User is anonymous" - suspended_not_pm: "User is suspended, not a message" - seen_recently: "User was seen recently" - post_not_found: "Can't find a post with id %{post_id}" - notification_already_read: "The notification this email is about has already been read" - topic_nil: "post.topic is nil" - post_deleted: "post was deleted by the author" - user_suspended: "user was suspended" - already_read: "user has already read this post" - exceeded_emails_limit: "Exceeded max_emails_per_day_per_user" - exceeded_bounces_limit: "Exceeded bounce_score_threshold" - message_blank: "message is blank" - message_to_blank: "message.to is blank" - text_part_body_blank: "text_part.body is blank" - body_blank: "body is blank" - no_echo_mailing_list_mode: "Mailing list notifications disabled for user's own posts" - - color_schemes: - base_theme_name: "Base" - - about: "About" - guidelines: "Guidelines" - privacy: "Privacy" - - edit_this_page: "Edit this page" - - csv_export: - boolean_yes: "Yes" - boolean_no: "No" - - static_topic_first_reply: | - Edit the first post in this topic to change the contents of the %{page_name} page. - - guidelines_topic: - title: "FAQ/Guidelines" - body: | - - - ## [This is a Civilized Place for Public Discussion](#civilized) - - Please treat this discussion forum with the same respect you would a public park. We, too, are a shared community resource — a place to share skills, knowledge and interests through ongoing conversation. - - These are not hard and fast rules, merely aids to the human judgment of our community. Use these guidelines to keep this a clean, well-lighted place for civilized public discourse. - - - - ## [Improve the Discussion](#improve) - - Help us make this a great place for discussion by always working to improve the discussion in some way, however small. If you are not sure your post adds to the conversation, think over what you want to say and try again later. - - The topics discussed here matter to us, and we want you to act as if they matter to you, too. Be respectful of the topics and the people discussing them, even if you disagree with some of what is being said. - - One way to improve the discussion is by discovering ones that are already happening. Please spend some time browsing the topics here before replying or starting your own, and you’ll have a better chance of meeting others who share your interests. - - - - ## [Be Agreeable, Even When You Disagree](#agreeable) - - You may wish to respond to something by disagreeing with it. That’s fine. But, remember to _criticize ideas, not people_. Please avoid: - - * Name-calling. - * Ad hominem attacks. - * Responding to a post’s tone instead of its actual content. - * Knee-jerk contradiction. - - Instead, provide reasoned counter-arguments that improve the conversation. - - - - ## [Your Participation Counts](#participate) - - The conversations we have here set the tone for everyone. Help us influence the future of this community by choosing to engage in discussions that make this forum an interesting place to be — and avoiding those that do not. - - Discourse provides tools that enable the community to collectively identify the best (and worst) contributions: favorites, bookmarks, likes, flags, replies, edits, and so forth. Use these tools to improve your own experience, and everyone else’s, too. - - Let’s try to leave our park better than we found it. - - - - ## [If You See a Problem, Flag It](#flag-problems) - - Moderators have special authority; they are responsible for this forum. But so are you. With your help, moderators can be community facilitators, not just janitors or police. - - When you see bad behavior, don’t reply. It encourages the bad behavior by acknowledging it, consumes your energy, and wastes everyone’s time. _Just flag it_. If enough flags accrue, action will be taken, either automatically or by moderator intervention. - - In order to maintain our community, moderators reserve the right to remove any content and any user account for any reason at any time. Moderators do not preview new posts in any way; the moderators and site operators take no responsibility for any content posted by the community. - - - - ## [Always Be Civil](#be-civil) - - Nothing sabotages a healthy conversation like rudeness: - - * Be civil. Don’t post anything that a reasonable person would consider offensive, abusive, or hate speech. - * Keep it clean. Don’t post anything obscene or sexually explicit. - * Respect each other. Don’t harass or grief anyone, impersonate people, or expose their private information. - * Respect our forum. Don’t post spam or otherwise vandalize the forum. - - These are not concrete terms with precise definitions — avoid even the _appearance_ of any of these things. If you’re unsure, ask yourself how you would feel if your post was featured on the front page of the New York Times. - - This is a public forum, and search engines index these discussions. Keep the language, links, and images safe for family and friends. - - - - ## [Keep It Tidy](#keep-tidy) - - Make the effort to put things in the right place, so that we can spend more time discussing and less cleaning up. So: - - * Don’t start a topic in the wrong category. - * Don’t cross-post the same thing in multiple topics. - * Don’t post no-content replies. - * Don’t divert a topic by changing it midstream. - * Don’t sign your posts — every post has your profile information attached to it. - - Rather than posting “+1” or “Agreed”, use the Like button. Rather than taking an existing topic in a radically different direction, use Reply as a Linked Topic. - - - - ## [Post Only Your Own Stuff](#stealing) - - You may not post anything digital that belongs to someone else without permission. You may not post descriptions of, links to, or methods for stealing someone’s intellectual property (software, video, audio, images), or for breaking any other law. - - - - ## [Powered by You](#power) - - This site is operated by your [friendly local staff](/about) and *you*, the community. If you have any further questions about how things should work here, open a new topic in the [site feedback category](/c/site-feedback) and let's discuss! If there's a critical or urgent issue that can't be handled by a meta topic or flag, contact us via the [staff page](/about). - - - - ## [Terms of Service](#tos) - - Yes, legalese is boring, but we must protect ourselves – and by extension, you and your data – against unfriendly folks. We have a [Terms of Service](/tos) describing your (and our) behavior and rights related to content, privacy, and laws. To use this service, you must agree to abide by our [TOS](/tos). - - - tos_topic: - title: "Terms of Service" - body: | - The following terms and conditions govern all use of the %{company_domain} website and all content, services and products available at or through the website, including, but not limited to, %{company_domain} Forum Software, %{company_domain} Support Forums and the %{company_domain} Hosting service ("Hosting"), (taken together, the Website). The Website is owned and operated by %{company_full_name} ("%{company_name}"). The Website is offered subject to your acceptance without modification of all of the terms and conditions contained herein and all other operating rules, policies (including, without limitation, %{company_domain}’s [Privacy Policy](/privacy) and [Community Guidelines](/faq)) and procedures that may be published from time to time on this Site by %{company_name} (collectively, the "Agreement"). - - Please read this Agreement carefully before accessing or using the Website. By accessing or using any part of the web site, you agree to become bound by the terms and conditions of this agreement. If you do not agree to all the terms and conditions of this agreement, then you may not access the Website or use any services. If these terms and conditions are considered an offer by %{company_name}, acceptance is expressly limited to these terms. The Website is available only to individuals who are at least 13 years old. - - - - ## [1. Your %{company_domain} Account](#1) - - If you create an account on the Website, you are responsible for maintaining the security of your account and you are fully responsible for all activities that occur under the account. You must immediately notify %{company_name} of any unauthorized uses of your account or any other breaches of security. %{company_name} will not be liable for any acts or omissions by you, including any damages of any kind incurred as a result of such acts or omissions. - - - - ## [2. Responsibility of Contributors](#2) - - If you post material to the Website, post links on the Website, or otherwise make (or allow any third party to make) material available by means of the Website (any such material, "Content"), You are entirely responsible for the content of, and any harm resulting from, that Content. That is the case regardless of whether the Content in question constitutes text, graphics, an audio file, or computer software. By making Content available, you represent and warrant that: - - * the downloading, copying and use of the Content will not infringe the proprietary rights, including but not limited to the copyright, patent, trademark or trade secret rights, of any third party; - * if your employer has rights to intellectual property you create, you have either (i) received permission from your employer to post or make available the Content, including but not limited to any software, or (ii) secured from your employer a waiver as to all rights in or to the Content; - * you have fully complied with any third-party licenses relating to the Content, and have done all things necessary to successfully pass through to end users any required terms; - * the Content does not contain or install any viruses, worms, malware, Trojan horses or other harmful or destructive content; - * the Content is not spam, is not machine- or randomly-generated, and does not contain unethical or unwanted commercial content designed to drive traffic to third party sites or boost the search engine rankings of third party sites, or to further unlawful acts (such as phishing) or mislead recipients as to the source of the material (such as spoofing); - * the Content is not pornographic, does not contain threats or incite violence, and does not violate the privacy or publicity rights of any third party; - * your content is not getting advertised via unwanted electronic messages such as spam links on newsgroups, email lists, blogs and web sites, and similar unsolicited promotional methods; - * your content is not named in a manner that misleads your readers into thinking that you are another person or company; and - * you have, in the case of Content that includes computer code, accurately categorized and/or described the type, nature, uses and effects of the materials, whether requested to do so by %{company_name} or otherwise. - - - - ## [3. User Content License](#3) - - User contributions are licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US). Without limiting any of those representations or warranties, %{company_name} has the right (though not the obligation) to, in %{company_name}’s sole discretion (i) refuse or remove any content that, in %{company_name}’s reasonable opinion, violates any %{company_name} policy or is in any way harmful or objectionable, or (ii) terminate or deny access to and use of the Website to any individual or entity for any reason, in %{company_name}’s sole discretion. %{company_name} will have no obligation to provide a refund of any amounts previously paid. - - - - - ## [4. Payment and Renewal](#4) - - ### General Terms - - Optional paid services or upgrades may be available on the Website. When utilizing an optional paid service or upgrade, you agree to pay %{company_name} the monthly or annual subscription fees indicated. Payments will be charged on a pre-pay basis on the day you begin utilizing the service or upgrade and will cover the use of that service or upgrade for a monthly or annual subscription period as indicated. These fees are not refundable. - - ### Automatic Renewal - - Unless you notify %{company_name} before the end of the applicable subscription period that you want to cancel a service or upgrade, your subscription will automatically renew and you authorize us to collect the then-applicable annual or monthly subscription fee (as well as any taxes) using any credit card or other payment mechanism we have on record for you. Subscriptions can be canceled at any time. - - - - ## [5. Services](#5) - - ### Hosting, Support Services - - Optional Hosting and Support services may be provided by %{company_name} under the terms and conditions for each such service. By signing up for a Hosting/Support or Support services account, you agree to abide by such terms and conditions. - - - - ## [6. Responsibility of Website Visitors](#6) - - %{company_name} has not reviewed, and cannot review, all of the material, including computer software, posted to the Website, and cannot therefore be responsible for that material’s content, use or effects. By operating the Website, %{company_name} does not represent or imply that it endorses the material there posted, or that it believes such material to be accurate, useful or non-harmful. You are responsible for taking precautions as necessary to protect yourself and your computer systems from viruses, worms, Trojan horses, and other harmful or destructive content. The Website may contain content that is offensive, indecent, or otherwise objectionable, as well as content containing technical inaccuracies, typographical mistakes, and other errors. The Website may also contain material that violates the privacy or publicity rights, or infringes the intellectual property and other proprietary rights, of third parties, or the downloading, copying or use of which is subject to additional terms and conditions, stated or unstated. %{company_name} disclaims any responsibility for any harm resulting from the use by visitors of the Website, or from any downloading by those visitors of content there posted. - - - - ## [7. Content Posted on Other Websites](#7) - - We have not reviewed, and cannot review, all of the material, including computer software, made available through the websites and webpages to which %{company_domain} links, and that link to %{company_domain}. %{company_name} does not have any control over those non-%{company_domain} websites and webpages, and is not responsible for their contents or their use. By linking to a non-%{company_domain} website or webpage, %{company_name} does not represent or imply that it endorses such website or webpage. You are responsible for taking precautions as necessary to protect yourself and your computer systems from viruses, worms, Trojan horses, and other harmful or destructive content. %{company_name} disclaims any responsibility for any harm resulting from your use of non-%{company_domain} websites and webpages. - - - - ## [8. Copyright Infringement and DMCA Policy](#8) - - As %{company_name} asks others to respect its intellectual property rights, it respects the intellectual property rights of others. If you believe that material located on or linked to by %{company_domain} violates your copyright, and if this website resides in the USA, you are encouraged to notify %{company_name} in accordance with %{company_name}’s [Digital Millennium Copyright Act](http://en.wikipedia.org/wiki/Digital_Millennium_Copyright_Act) ("DMCA") Policy. %{company_name} will respond to all such notices, including as required or appropriate by removing the infringing material or disabling all links to the infringing material. %{company_name} will terminate a visitor’s access to and use of the Website if, under appropriate circumstances, the visitor is determined to be a repeat infringer of the copyrights or other intellectual property rights of %{company_name} or others. In the case of such termination, %{company_name} will have no obligation to provide a refund of any amounts previously paid to %{company_name}. - - - - ## [9. Intellectual Property](#9) - - This Agreement does not transfer from %{company_name} to you any %{company_name} or third party intellectual property, and all right, title and interest in and to such property will remain (as between the parties) solely with %{company_name}. %{company_name}, %{company_domain}, the %{company_domain} logo, and all other trademarks, service marks, graphics and logos used in connection with %{company_domain}, or the Website are trademarks or registered trademarks of %{company_name} or %{company_name}’s licensors. Other trademarks, service marks, graphics and logos used in connection with the Website may be the trademarks of other third parties. Your use of the Website grants you no right or license to reproduce or otherwise use any %{company_name} or third-party trademarks. - - - - ## [10. Advertisements](#10) - - %{company_name} reserves the right to display advertisements on your content unless you have purchased an Ad-free Upgrade or a Services account. - - - - ## [11. Attribution](#11) - - %{company_name} reserves the right to display attribution links such as ‘Powered by %{company_domain},’ theme author, and font attribution in your content footer or toolbar. Footer credits and the %{company_domain} toolbar may not be removed regardless of upgrades purchased. - - - - ## [12. Changes](#12) - - %{company_name} reserves the right, at its sole discretion, to modify or replace any part of this Agreement. It is your responsibility to check this Agreement periodically for changes. Your continued use of or access to the Website following the posting of any changes to this Agreement constitutes acceptance of those changes. %{company_name} may also, in the future, offer new services and/or features through the Website (including, the release of new tools and resources). Such new features and/or services shall be subject to the terms and conditions of this Agreement. - - - - ## [13. Termination](#13) - - %{company_name} may terminate your access to all or any part of the Website at any time, with or without cause, with or without notice, effective immediately. If you wish to terminate this Agreement or your %{company_domain} account (if you have one), you may simply discontinue using the Website. All provisions of this Agreement which by their nature should survive termination shall survive termination, including, without limitation, ownership provisions, warranty disclaimers, indemnity and limitations of liability. - - - - ## [14. Disclaimer of Warranties](#14) - - The Website is provided "as is". %{company_name} and its suppliers and licensors hereby disclaim all warranties of any kind, express or implied, including, without limitation, the warranties of merchantability, fitness for a particular purpose and non-infringement. Neither %{company_name} nor its suppliers and licensors, makes any warranty that the Website will be error free or that access thereto will be continuous or uninterrupted. If you’re actually reading this, here’s [a treat](http://www.newyorker.com/online/blogs/shouts/2012/12/the-hundred-best-lists-of-all-time.html). You understand that you download from, or otherwise obtain content or services through, the Website at your own discretion and risk. - - - - ## [15. Limitation of Liability](#15) - - In no event will %{company_name}, or its suppliers or licensors, be liable with respect to any subject matter of this agreement under any contract, negligence, strict liability or other legal or equitable theory for: (i) any special, incidental or consequential damages; (ii) the cost of procurement for substitute products or services; (iii) for interruption of use or loss or corruption of data; or (iv) for any amounts that exceed the fees paid by you to %{company_name} under this agreement during the twelve (12) month period prior to the cause of action. %{company_name} shall have no liability for any failure or delay due to matters beyond their reasonable control. The foregoing shall not apply to the extent prohibited by applicable law. - - - - ## [16. General Representation and Warranty](#16) - - You represent and warrant that (i) your use of the Website will be in strict accordance with the %{company_name} [Privacy Policy](/privacy), [Community Guidelines](/guidelines), with this Agreement and with all applicable laws and regulations (including without limitation any local laws or regulations in your country, state, city, or other governmental area, regarding online conduct and acceptable content, and including all applicable laws regarding the transmission of technical data exported from the country in which this website resides or the country in which you reside) and (ii) your use of the Website will not infringe or misappropriate the intellectual property rights of any third party. - - - - ## [17. Indemnification](#17) - - You agree to indemnify and hold harmless %{company_name}, its contractors, and its licensors, and their respective directors, officers, employees and agents from and against any and all claims and expenses, including attorneys’ fees, arising out of your use of the Website, including but not limited to your violation of this Agreement. - - - - ## [18. Miscellaneous](#18) - - This Agreement constitutes the entire agreement between %{company_name} and you concerning the subject matter hereof, and they may only be modified by a written amendment signed by an authorized executive of %{company_name}, or by the posting by %{company_name} of a revised version. Except to the extent applicable law, if any, provides otherwise, this Agreement, any access to or use of the Website will be governed by the laws of the state of California, U.S.A., excluding its conflict of law provisions, and the proper venue for any disputes arising out of or relating to any of the same will be the state and federal courts located in San Francisco County, California. Except for claims for injunctive or equitable relief or claims regarding intellectual property rights (which may be brought in any competent court without the posting of a bond), any dispute arising under this Agreement shall be finally settled in accordance with the Comprehensive Arbitration Rules of the Judicial Arbitration and Mediation Service, Inc. (“JAMS”) by three arbitrators appointed in accordance with such Rules. The arbitration shall take place in San Francisco, California, in the English language and the arbitral decision may be enforced in any court. The prevailing party in any action or proceeding to enforce this Agreement shall be entitled to costs and attorneys’ fees. If any part of this Agreement is held invalid or unenforceable, that part will be construed to reflect the parties’ original intent, and the remaining portions will remain in full force and effect. A waiver by either party of any term or condition of this Agreement or any breach thereof, in any one instance, will not waive such term or condition or any subsequent breach thereof. You may assign your rights under this Agreement to any party that consents to, and agrees to be bound by, its terms and conditions; %{company_name} may assign its rights under this Agreement without condition. This Agreement will be binding upon and will inure to the benefit of the parties, their successors and permitted assigns. - - This document is CC-BY-SA. It was last updated May 31, 2013. - - Originally adapted from the [WordPress Terms of Service](http://en.wordpress.com/tos/). - - privacy_topic: - title: "Privacy Policy" - body: | - - - ## [What information do we collect?](#collect) - - We collect information from you when you register on our site and gather data when you participate in the forum by reading, writing, and evaluating the content shared here. - - When registering on our site, you may be asked to enter your name and e-mail address. You may, however, visit our site without registering. Your e-mail address will be verified by an email containing a unique link. If that link is visited, we know that you control the e-mail address. - - When registered and posting, we record the IP address that the post originated from. We also may retain server logs which include the IP address of every request to our server. - - - - ## [What do we use your information for?](#use) - - Any of the information we collect from you may be used in one of the following ways: - - * To personalize your experience — your information helps us to better respond to your individual needs. - * To improve our site — we continually strive to improve our site offerings based on the information and feedback we receive from you. - * To improve customer service — your information helps us to more effectively respond to your customer service requests and support needs. - * To send periodic emails — The email address you provide may be used to send you information, notifications that you request about changes to topics or in response to your user name, respond to inquiries, and/or other requests or questions. - - - - ## [How do we protect your information?](#protect) - - We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. - - - - ## [What is your data retention policy?](#data-retention) - - We will make a good faith effort to: - - * Retain server logs containing the IP address of all requests to this server no more than 90 days. - * Retain the IP addresses associated with registered users and their posts no more than 5 years. - - - - ## [Do we use cookies?](#cookies) - - Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account. - - We use cookies to understand and save your preferences for future visits and compile aggregate data about site traffic and site interaction so that we can offer better site experiences and tools in the future. We may contract with third-party service providers to assist us in better understanding our site visitors. These service providers are not permitted to use the information collected on our behalf except to help us conduct and improve our business. - - - - ## [Do we disclose any information to outside parties?](#disclose) - - We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety. However, non-personally identifiable visitor information may be provided to other parties for marketing, advertising, or other uses. - - - - ## [Third party links](#third-party) - - Occasionally, at our discretion, we may include or offer third party products or services on our site. These third party sites have separate and independent privacy policies. We therefore have no responsibility or liability for the content and activities of these linked sites. Nonetheless, we seek to protect the integrity of our site and welcome any feedback about these sites. - - - - ## [Children's Online Privacy Protection Act Compliance](#coppa) - - Our site, products and services are all directed to people who are at least 13 years old or older. If this server is in the USA, and you are under the age of 13, per the requirements of COPPA ([Children's Online Privacy Protection Act](https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act)), do not use this site. - - - - ## [Online Privacy Policy Only](#online) - - This online privacy policy applies only to information collected through our site and not to information collected offline. - - - - ## [Your Consent](#consent) - - By using our site, you consent to our web site privacy policy. - - - - ## [Changes to our Privacy Policy](#changes) - - If we decide to change our privacy policy, we will post those changes on this page. - - This document is CC-BY-SA. It was last updated May 31, 2013. - - badges: - editor: - name: Editor - description: First post edit - long_description: | - This badge is granted the first time you edit one of your posts. While you won't be able to edit your posts forever, editing is always a good idea — you can improve your posts, fix small mistakes, or add anything you missed when you originally posted. Edit to make your posts even better! - basic_user: - name: Basic - description: Granted all essential community functions - long_description: | - This badge is granted when you reach trust level 1. Thanks for sticking around a little while and reading a few topics to learn what our community is about. Your new user restrictions have been lifted; you've been granted all essential community abilities, such as personal messaging, flagging, wiki editing, and the ability to post multiple images and links. - member: - name: Member - description: Granted invitations, group messaging, more likes - long_description: | - This badge is granted when you reach trust level 2. Thanks for participating over a period of weeks to truly join our community. You can now send invitations from your user page or individual topics, create group personal messages, and have a few more likes per day. - regular: - name: Regular - description: Granted recategorize, rename, followed links, wiki, more likes - long_description: | - This badge is granted when you reach trust level 3. Thanks for being a regular part of our community over a period of months. You're now one of the most active readers, and a reliable contributor that makes our community great. You can now recategorize and rename topics, take advantage of more powerful spam flags, access a private lounge area, and you'll also get lots more likes per day. - leader: - name: Leader - description: Granted global edit, pin, close, archive, split and merge, more likes - long_description: | - This badge is granted when you reach trust level 4. You're a leader in this community as selected by staff, and you set a positive example for the rest of the community in your actions and words here. You have the ability to edit all posts, take common topic moderator actions such as pin, close, unlist, archive, split, and merge, and you have tons of likes per day. - welcome: - name: Welcome - description: Received a like - long_description: | - This badge is granted when you receive your first like on a post. Congratulations, you've posted something that your fellow community members found interesting, cool, or useful! - autobiographer: - name: Autobiographer - description: Filled out profile information - long_description: | - This badge is granted for filling out your user profile and selecting a profile picture. Letting the community know a bit more about who you are and what you're interested in makes for a better, more connected community. Join us! - anniversary: - name: Anniversary - description: Active member for a year, posted at least once - long_description: | - This badge is granted when you've been a member for a year with at least one post in that year. Thank you for sticking around and contributing to our community. We couldn't do it without you. - nice_post: - name: Nice Reply - description: Received 10 likes on a reply - long_description: | - This badge is granted when your reply gets 10 likes. Your reply really made an impression on the community and helped move the conversation forward! - good_post: - name: Good Reply - description: Received 25 likes on a reply - long_description: | - This badge is granted when your reply gets 25 likes. Your reply was exceptional and made the conversation a whole lot better for everyone! - great_post: - name: Great Reply - description: Received 50 likes on a reply - long_description: | - This badge is granted when your reply gets 50 likes. Wow! Your reply was inspiring, fascinating, hilarious, or insightful and the community loved it. - nice_topic: - name: Nice Topic - description: Received 10 likes on a topic - long_description: | - This badge is granted when your topic gets 10 likes. Hey, you started an interesting conversation that the community enjoyed! - good_topic: - name: Good Topic - description: Received 25 likes on a topic - long_description: | - This badge is granted when your topic gets 25 likes. You launched a vibrant conversation that the community rallied around and loved! - great_topic: - name: Great Topic - description: Received 50 likes on a topic - long_description: | - This badge is granted when your topic gets 50 likes. You kicked off a fascinating conversation and the community enjoyed the dynamic discussion that resulted! - nice_share: - name: Nice Share - description: Shared a post with 25 unique visitors - long_description: | - This badge is granted for sharing a link that was clicked by 25 outside visitors. Thanks for spreading the word about our discussions, and this community. - good_share: - name: Good Share - description: Shared a post with 300 unique visitors - long_description: | - This badge is granted for sharing a link that was clicked by 300 outside visitors. Good work! You've shown off a great discussion to a bunch of new people and helped this community grow. - great_share: - name: Great Share - description: Shared a post with 1000 unique visitors - long_description: | - This badge is granted for sharing a link that was clicked by 1000 outside visitors. Wow! You've promoted an interesting discussion to a huge new audience, and helped us grow our community in a big way! - first_like: - name: First Like - description: Liked a post - long_description: | - This badge is granted the first time you like a post using the :heart: button. Liking posts is a great way to let your fellow community members know that what they posted was interesting, useful, cool, or fun. Share the love! - first_flag: - name: First Flag - description: Flagged a post - long_description: | - This badge is granted the first time you flag a post. Flagging is how we all help keep this a clean, well lit place for everyone. If you notice any posts that require moderator attention for any reason please don't hesitate to flag. You can also flag to send personal messages to fellow users if you see an issue with their post. If you see a problem, :flag_black: flag it! - promoter: - name: Promoter - description: Invited a user - long_description: | - This badge is granted when you invite someone to join the community via the invite button on your user page, or at the bottom of a topic. Inviting friends who might be interested in specific discussions is an great way to introduce new people to our community, so thanks! - campaigner: - name: Campaigner - description: Invited 3 basic users - long_description: | - This badge is granted when you've invited 3 people who subsequently spent enough time on the site to become basic users. A vibrant community needs a regular infusion of newcomers who regularly participate and add new voices to the conversations. - champion: - name: Champion - description: Invited 5 members - long_description: | - This badge is granted when you've invited 5 people who subsequently spent enough time on the site to become full members. Wow! Thanks for expanding the diversity of our community with new members! - first_share: - name: First Share - description: Shared a post - long_description: | - This badge is granted the first time you share a link to a reply or topic using the share button. Sharing links is a great way to show off interesting discussions with the rest of the world and grow your community. - first_link: - name: First Link - description: Added a link to another topic - long_description: | - This badge is granted the first time you add a link to another topic. Linking topics helps fellow readers find interesting related conversations, by showing the connections between topics in both directions. Link freely! - first_quote: - name: First Quote - description: Quoted a post - long_description: | - This badge is granted the first time you quote a post in your reply. Quoting relevant sections of earlier posts in your reply helps keep discussions connected together and on topic. The easiest way to quote is to highlight a section of a post, and then press any reply button. Quote generously! - read_guidelines: - name: Read Guidelines - description: Read the community guidelines - long_description: | - This badge is granted for reading the community guidelines. Following and sharing these simple guidelines helps build a safe, fun, and sustainable community for everyone. Always remember there's another human being, one very much like yourself, on the other side of that screen. Be nice! - reader: - name: Reader - description: Read every reply in a topic with more than 100 replies - long_description: | - This badge is granted the first time you read a long topic with more than 100 replies. Reading a conversation closely helps you follow the discussion, understand different viewpoints, and leads to more interesting conversations. The more you read, the better the conversation gets. As we like to say, Reading is Fundamental! :slight_smile: - popular_link: - name: Popular Link - description: Posted an external link with 50 clicks - long_description: | - This badge is granted when a link you shared gets 50 clicks. Thanks for posting a useful link that added interesting context to the conversation! - hot_link: - name: Hot Link - description: Posted an external link with 300 clicks - long_description: | - This badge is granted when a link you shared gets 300 clicks. Thanks for posting a fascinating link that drove the conversation forward and illuminated the discussion! - famous_link: - name: Famous Link - description: Posted an external link with 1000 clicks - long_description: | - This badge is granted when a link you shared gets 1000 clicks. Wow! You posted a link that significantly improved the conversation by adding essential detail, context, and information. Great work! - appreciated: - name: Appreciated - description: Received 1 like on 20 posts - long_description: | - This badge is granted when you receive at least one like on 20 different posts. The community is enjoying your contributions to the conversations here! - respected: - name: Respected - description: Received 2 likes on 100 posts - long_description: | - This badge is granted when you receive at least 2 likes on 100 different posts. The community is growing to respect your many contributions to the conversations here. - admired: - name: Admired - description: Received 5 likes on 300 posts - long_description: | - This badge is granted when you receive at least 5 likes on 300 different posts. Wow! The community admires your frequent, high quality contributions to the conversations here. - out_of_love: - name: Out of Love - description: Used 50 likes in a day - long_description: | - This badge is granted when you use all 50 of your daily likes. Remembering to take a moment and like the posts you enjoy and appreciate encourages your fellow community members to create even more great discussions in the future. - higher_love: - name: Higher Love - description: Used 50 likes in a day 5 times - long_description: | - This badge is granted when you use all 50 of your daily likes for 5 days. Thanks for taking the time actively encouraging the best conversations every day! - crazy_in_love: - name: Crazy in Love - description: Used 50 likes in a day 20 times - long_description: | - This badge is granted when you use all 50 of your daily likes for 20 days. Wow! You're a model of regularly encouraging your fellow community members! - thank_you: - name: Thank You - description: Has 20 liked posts and gave 10 likes - long_description: | - This badge is granted when you have 20 liked posts and give 10 or more likes in return. When someone likes your posts, you find the time to like what others are posting, too. - gives_back: - name: Gives Back - description: Has 100 liked posts and gave 100 likes - long_description: | - This badge is granted when you have 100 liked posts and give 100 or more likes in return. Thanks for paying it forward! - empathetic: - name: Empathetic - description: Has 500 liked posts and gave 1000 likes - long_description: | - This badge is granted when you have 500 liked posts and give 1000 or more likes in return. Wow! You're a model of generosity and mutual appreciation :two_hearts:. - first_emoji: - name: First Emoji - description: Used an Emoji in a Post - long_description: | - This badge is granted the first time you add an Emoji to your post :thumbsup:. Emoji let you convey emotion in your posts, from happiness :smiley: to sadness :anguished: to anger :angry: and everything in between :sunglasses: . Just type a : (colon) or press the Emoji toolbar button in the editor to select from hundreds of choices :ok_hand: - first_mention: - name: First Mention - description: Mentioned a user in a Post - long_description: This badge is granted the first time you mention someone's @username in your post. Each mention generates a notification to that person, so they know about your post. Just begin typing @ (at symbol) to mention any user or, if allowed, group – it's a convenient way to bring something to their attention. - first_onebox: - name: First Onebox - description: Posted a link that was oneboxed - long_description: This badge is granted the first time you post a link on a line by itself, which was then automatically expanded into a onebox with a brief summary of the link, a title, and (when available) a picture. - first_reply_by_email: - name: First Reply By Email - description: Replied to a Post via email - long_description: | - This badge is granted the first time you reply to a post via email :e-mail:. - - admin_login: - success: "Email Sent" - error: "Error!" - email_input: "Admin Email" - submit_button: "Send Email" - - discourse_hub: - access_token_problem: "Tell an admin: Please update the site settings to include the correct discourse_org_access_key." - - performance_report: - initial_post_raw: This topic includes daily performance reports for your site. - initial_topic_title: Website performance reports - - topic_invite: - user_exists: "Sorry, that user has already been invited. You may only invite a user to a topic once." - - tags: - title: "Tags" - staff_tag_disallowed: "The tag \"%{tag}\" may only be applied by staff." - staff_tag_remove_disallowed: "The tag \"%{tag}\" may only be removed by staff." - rss_by_tag: "Topics tagged %{tag}" - - finish_installation: - congratulations: "Congratulations, you installed Discourse!" - register: - button: "Register" - title: "Register Admin Account" - help: "register a new account to get started" - no_emails: "Unfortunately, no administrator emails were defined during setup, so finalizing the configuration may be difficult." - confirm_email: - title: "Confirm your Email" - message: "

    We sent an activation mail to %{email}. Please follow the instructions in the email to activate your account.

    If it doesn't arrive, ensure you have set up email correctly for your Discourse and check your spam folder.

    " - resend_email: - title: "Resend Activation Email" - message: "

    We've re-sent the activation email to %{email}" - - safe_mode: - title: "Enter safe mode" - description: "Safe mode allows you to test your site without loading plugins or site customizations." - no_customizations: "Disable all site customizations" - only_official: "Disable unofficial plugins" - no_plugins: "Disable all plugins" - enter: "Enter Safe Mode" - wizard: - title: "Discourse Setup" - step: - locale: - title: "Welcome to your Discourse!" - fields: - default_locale: - description: "What’s the default language for your community?" - - forum_title: - title: "Name" - description: "Your name is a sign visible in the distance, the first thing potential visitors will notice about your community. What does your name and title say about your community?" - - fields: - title: - label: "Your community’s name" - placeholder: "Jane’s Hangout" - site_description: - label: "Describe your community in one short sentence" - placeholder: "A place for Jane and her friends to discuss cool stuff" - - introduction: - title: "Introduction" - - fields: - welcome: - label: "Welcome Topic" - description: "

    How would you describe your community to a stranger on an elevator in about 1 minute?

    -
      -
    • Who are these discussions for?
    • -
    • What can I find here?
    • -
    • Why should I visit?
    • -
    -

    Your welcome topic is the first thing new visitors will see. Think of it as your one paragraph 'elevator pitch' or 'mission statement'.

    " - one_paragraph: "Please restrict your welcome message to one paragraph." - - privacy: - title: "Access" - description: "

    Is your community open to everyone, or is it restricted by membership, invitation, or approval? If you prefer, you can set things up privately, then switch over to public later.

    -

    Remember you can always send invites from topics, or from your user profile page, too.

    " - - fields: - privacy: - choices: - open: - label: "Public" - description: "Anyone can access this community and sign up for an account" - restricted: - label: "Private" - description: "Only people I have invited or approved can access this community" - - contact: - title: "Contact" - fields: - contact_email: - label: "Mail" - placeholder: "name@example.com" - description: "Email address for the person or group responsible for this community. Used for critical notifications such as unhandled flags, security updates, and on your about page for urgent community contact." - contact_url: - label: "Web Page" - placeholder: "http://www.example.com/contact-us" - description: "General contact web page for you or your organization. Will be displayed on your about page." - site_contact: - label: "Automated Messages" - description: "All automated Discourse personal messages will be sent from this user. Most importantly, this user will be the designated sender of every welcome message automatically sent to new users." - - corporate: - title: "Organization" - description: "These names will be entered in your Privacy Policy and Terms of Service, which you can edit any time in the Staff category. If you don’t have a company, feel free to skip this step for now." - - fields: - company_short_name: - label: "Company Name (short)" - placeholder: "Initech" - company_full_name: - label: "Company Name (full)" - placeholder: "Initech, Inc." - company_domain: - label: "Company Domain Name" - placeholder: "initech.com" - - colors: - title: "Theme" - fields: - theme_id: - description: "Do you prefer a light or dark color scheme to start with? You can always further customize the look and feel of your site via Admin, Customize." - choices: - default: - label: "Simple Light" - dark: - label: "Simple Dark" - - logos: - title: "Logos" - fields: - logo_url: - label: "Primary Logo" - description: "The logo image at the top left of your site. Use a wide rectangle shape." - logo_small_url: - label: "Compact Logo" - description: "A compact version of your logo, shown at the top left of your site when scrolling down. Use a square shape." - - icons: - title: "Icons" - fields: - favicon_url: - label: "Small Icon" - description: "Icon image used to represent your site in web browsers that looks good at small sizes such as 32px by 32px." - apple_touch_icon_url: - label: "Large Icon" - description: "Icon image used to represent your site on modern devices that looks good at larger sizes. Recommended size is at least 144px by 144px." - - homepage: - description: "We recommend showing the latest topics on your homepage, but you can choose to show categories (groups of topics) on the homepage if you prefer." - title: "Homepage" - - fields: - homepage_style: - choices: - latest: - label: "Latest Topics" - categories: - label: "Categories" - - emoji: - title: "Emoji" - description: "Which Emoji style do you prefer for your community? You can always add more custom Emoji later via Admin, Customize, Emoji." - - invites: - title: "Invite Staff" - description: "You’re almost done! Let’s invite some staff members to help seed your discussions with interesting topics and replies to get your community started." - - finished: - title: "Your Discourse is Ready!" - description: | -

    If you ever feel like changing these settings, visit your admin section; find it next to the wrench icon in the site menu.

    -

    Have fun, and good luck building your new community!

    diff --git a/config/locales/server.vi.yml b/config/locales/server.vi.yml index 4f13cb35502..7d9ad039350 100644 --- a/config/locales/server.vi.yml +++ b/config/locales/server.vi.yml @@ -94,8 +94,6 @@ vi: max_username_length_range: "Bạn không thể thiết lập số tối đa nhỏ hơn số tối thiểu" default_categories_already_selected: "Bạn không thể chọn một danh mục được sử dụng trong danh sách khác." s3_upload_bucket_is_required: "Bạn không thể tải lên S3 mà chưa thiết lập 's3_upload_bucket'." - bulk_invite: - file_should_be_csv: "Tập tin tải lên nên ở dạng csv hoặc txt." backup: operation_already_running: "Một tiến trình đang được thực hiện. Không thể bắt đầu một tiến trình mới ngay bây giờ." backup_file_should_be_tar_gz: "Tập tin sao lưu nên nên ở dạng .tar.gz." @@ -755,9 +753,7 @@ vi: top_page_default_timeframe: "Khung thời gian mặc định cho trang xem trên cùng." show_email_on_profile: "Hiển thị email thành viên trên trang hồ hơ (chỉ cho họ và quản trị viên)" email_token_valid_hours: "Token quyên mật khẩu / kích hoạt tài khoản có giá trị trong (n) giờ." - email_token_grace_period_hours: "Token quyên mật khẩu / kích hoạt tài khoản vẫn còn giá trị (n) giờ sau khi được gia hạn" enable_badges: "Kích hoạt hệ thống huy hiệu" - enable_whispers: "Cho phép quản trị viên giao tiếp riêng trong chủ đề. (thực nghiệm)" allow_index_in_robots_txt: "Chỉ rõ trong robots.txt trang web này cho phép tạo chỉ mục bởi web search engines." email_domains_blacklist: "Một danh sách đuôi email mà người dùng không được phép dùng để đăng ký tài khoản. Ví dụ: maillinator.com|trashmail.net. Lưu ý mỗi tên miền cách nhau bởi dấu \"|\"." email_domains_whitelist: "Danh sách tên miền người dùng ĐƯỢC PHÉP đăng ký tài khoản. CẢNH BÁO: người dùng với tên miền email khác trong danh sách sẽ không được phép đăng ký!" @@ -1009,7 +1005,6 @@ vi: embed_whitelist_selector: "Bộ chọn các thành phần CSS được hỗ trợ khi nhúng." embed_blacklist_selector: "Bộ chọn các thành phần CSS được loại bỏ khi nhúng." notify_about_flags_after: "Nếu có các đánh dấu chưa được xử lý sau số giờ được thiết lập ở đây, gửi email đến contact_email. Đặt là 0 để vô hiệu hóa." - enable_cdn_js_debugging: "Cho phép /logs hiển thị lỗi thích hợp bằng cách thêm quyền cross-origin trên tất cả js kèm theo." show_create_topics_notice: "Nếu trang có ít hơn 5 chủ đề công khai, hiển thị một thông báo yêu cầu quản trị tạo thêm các chủ đề mới" delete_drafts_older_than_n_days: Xóa các bản nháp cũ hơn (n) ngày. vacuum_db_days: "Chạy VACUUM ANALYZE để lấy lại khoảng trống DB sau khi migration (đặt là 0 để tắt)" @@ -1203,7 +1198,7 @@ vi: test_mailer: subject_template: "[%{site_name}] Email Thử Nghiệm" new_version_mailer: - subject_template: "[%{site_name}] Phiên bạn Discourse mới, cập nhật đã sẵn sàng" + subject_template: "[%{site_name}] Phiên bản Discourse mới, cập nhật đã sẵn sàng" new_version_mailer_with_notes: subject_template: "[%{site_name}] cập nhật đã sẵn sàng" queued_posts_reminder: @@ -1236,26 +1231,6 @@ vi: (Nếu bạn cần giao tiếp với BQT [thành viên quản trị](%{base_url}/about), bạn có thể gửi trả lời email này). welcome_invite: subject_template: "Chào mừng đến với %{site_name}!" - text_body_template: | - Chào mừng bạn gia nhập %{site_name}! - - Chúng tôi đã tạo một tài khoản mới **%{username}** cho bạn, bạn có thể thay đổi tên của mình bằng cách truy cập [your user profile][prefs]. - - Cho lần đăng nhập sau: - - 1. Luôn **sử dụng cùng một địa chỉ email từ lời mời ban đầu của bạn** khi đăng nhập. Nếu không chúng ta sẽ không thể biết đó là bạn! - - 2. Tạo một mật khẩu cho [your user profile][prefs], và sử dụng nó để đăng nhập. - - %{new_user_tips} - - Chúng tôi tin rằng bạn sẽ cùng chúng tôi phát triển một cộng đồng văn minh [hành vi ứng xử](%{base_url}/guidelines). - - Chúc vui vẻ! - - (Nếu bạn cần giao tiếp với BQT [thành viên quản trị](%{base_url}/about), bạn có thể gửi trả lời email này). - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "Sản sao lưu hoàn tất thành công" backup_failed: diff --git a/config/locales/server.zh_CN.yml b/config/locales/server.zh_CN.yml index d398fa1b11a..85ff3f24596 100644 --- a/config/locales/server.zh_CN.yml +++ b/config/locales/server.zh_CN.yml @@ -71,7 +71,7 @@ zh_CN: has_already_been_used: "不能和其他%{attribute}重复" inclusion: 不包括在列表中 invalid: 无效 - is_invalid: "似乎不清晰,这是个完整的句子吗?" + is_invalid: "似乎不清楚,这是一个完整的句子?" less_than: 必须小于 %{count} less_than_or_equal_to: 必须小于等于 %{count} not_a_number: 不是数字 @@ -102,7 +102,8 @@ zh_CN: default_categories_already_selected: "不能选择一个已经用于另一个列表的分类。" s3_upload_bucket_is_required: "你没有填写“s3_upload_bucket”,不能开启上传至 S3。" bulk_invite: - file_should_be_csv: "上传的文件应为 csv 或 txt 格式。" + file_should_be_csv: "上传的文件应为 csv 格式。" + error: "上传文件的时候出错了。请重试。" backup: operation_already_running: "有操作正在运行。目前无法开始新的操作。" backup_file_should_be_tar_gz: "备份文件应为 .tar.gz 存档文件。" @@ -119,6 +120,11 @@ zh_CN: embed: start_discussion: "开始讨论" continue: "继续讨论" + error: "嵌入故障" + referer: "来源:" + mismatch: "来源(referer)不符合下列主机地址:" + no_hosts: "嵌入没有设置任何主机地址。" + configure: "配置嵌入" more_replies: other: "%{count} 个更多回复" loading: "正在载入讨论中..." @@ -145,9 +151,10 @@ zh_CN: spamming_host: "抱歉,你不能添加一个链接到那个地址的链接。" user_is_suspended: "被封禁的用户不允许发贴。" topic_not_found: "出现问题。也许这个话题被关闭或删除。" + not_accepting_pms: "对不起,%{username} 目前不接收讯息。" just_posted_that: "太类似于你最近发表的内容" invalid_characters: "包含无效字符" - is_invalid: "似乎不清晰,这是个完整的句子吗?" + is_invalid: "似乎不清楚,这是一个完整的句子? " next_page: "下一页 →" prev_page: "← 上一页" page_num: "第%{num}页" @@ -257,6 +264,7 @@ zh_CN: name: "分类名称" topic: title: '标题' + featured_link: '特色链接' post: raw: "内容" user_profile: @@ -270,6 +278,9 @@ zh_CN: too_many_users: "一次只能发送警告给一个用户。" cant_send_pm: "抱歉,不能向该用户发送私信。" no_user_selected: "必须选择一个有效的用户。" + featured_link: + invalid: "不合法。URL 应包括 http:// 或 https://。" + invalid_category: "无法编辑该分类。" user: attributes: password: @@ -300,7 +311,24 @@ zh_CN: meta_category_description: "讨论该站点的站务、组织、如何运作和如何改善它。" staff_category_name: "管理人员" staff_category_description: "管理人员可见的分类。只有管理员和版主才能阅览主题。" + assets_topic_title: "站点设计资料" assets_topic_body: "这是一个永久主题,仅对管理人员可见,用于存储论坛设计使用的图像和文件。不要删除它!\n\n\n详细教程:\n\n\n1. 回复到这个主题。\n2. 上传你想用作站点标志、图标和其他所有图片到这儿。(使用帖子编辑器工具栏中的上传图标,或者拖拽或者粘贴图像。)\n3. 提交你的回复添加帖子。\n4. 在你的新帖子里右键点击图片获得这些已上传图片的链接,或者点击编辑按钮来编辑帖子,获得到图片的相对地址。复制这些相对地址。\n5. 粘贴这些图像的路径到[基础设置](/admin/site_settings/category/required)。\n\n\n如果你需要运行额外的上传文件类型,在[文件设置](/admin/site_settings/category/files)中编辑 `authorized_extensions`。" + discourse_welcome_topic: + title: "欢迎来到 Discourse" + body: |2 + + 置顶主题的第一段是访客在主页看到的欢迎消息。这很重要! + + **编辑**它作为社群的简要介绍: + + - 什么人想参与? + - 他们能在这找到什么? + - 为什么他们要来这? + - 他们能在哪里阅读更多的内容(链接、资源等)? + + + + 你可能想要在管理 :wrench: (右上角)中关闭这个主题,这样回复就不会积压在这个通告下。 lounge_welcome: title: "欢迎来到贵宾室" body: |2 @@ -363,6 +391,7 @@ zh_CN: create_topic: "你创建新主题的速度太快了,请等待%{time_left}之后再试。" create_post: "你回帖太快了,请等待%{time_left}之后再试。" delete_post: "你正在快速地删除帖子。请等 %{time_left}之后再试。" + public_group_membership: "你加入/离开群组的速度太快了,请等待%{time_left}之后再试。" topics_per_day: "你今天新主题的数量已经到达上限,请等待%{time_left}之后再试。" pms_per_day: "你今天的消息数量已经到达上限,请等待%{time_left}之后再试。" create_like: "你今天的“赞”数量已经到达上限,请等待%{time_left}之后再试。" @@ -728,6 +757,8 @@ zh_CN: min_first_post_length: "第一帖(主题内容)允许的最少字符数" min_private_message_post_length: "消息允许的最小字符数" max_post_length: "帖子允许的最大字符数" + topic_featured_link_enabled: "允许发链接帖。" + show_topic_featured_link_in_digest: "在摘要邮件中显示主题特色链接。" min_topic_title_length: "标题允许的最少字符数" max_topic_title_length: "标题允许的最大字符数" min_private_message_title_length: "消息标题允许的最小字符数" @@ -836,9 +867,8 @@ zh_CN: show_email_on_profile: "在用户页面显示用户的邮件地址(只有用户和管理人员可见)" prioritize_username_in_ux: "在用户页、用户卡片和帖子上优先显示用户名(未选时,昵称将先显示)" email_token_valid_hours: "“忘记密码”/“激活账户”令牌有效的小时数(n)。" - email_token_grace_period_hours: "“忘记密码”/“激活账户”令牌在使用后仍旧有效的小时数(n)。" enable_badges: "启用徽章系统" - enable_whispers: "允许在主题中给管理人员密频。(experimental)" + enable_whispers: "允许工作人员在主题中私密交流。" allow_index_in_robots_txt: "在 robots.txt 中详细指出这个站点允许被网页搜索引擎检索。" email_domains_blacklist: "用管道符“|”分隔的邮箱域名黑名单列表,其中的域名将不能用来注册账户,例如:mailinator.com|trashmail.net" email_domains_whitelist: "用管道符“|”分隔的电子邮箱域名的列表,用户必须使用这些邮箱域名注册。警告:用户使用不包含在这个列表里的邮箱域名,将无法成功注册。" @@ -869,6 +899,7 @@ zh_CN: sso_overrides_name: "每一次登录时,用 SSO 信息中的外部站点的全名覆盖本地全名,并且阻止本地的全名修改。" sso_overrides_avatar: "用单点登录信息中的外部站点头像覆盖用户头像。如果启用,强烈建议禁用 allow_uploaded_avatars" sso_not_approved_url: "重定向未受许可的单点登录账号至这个 URL" + sso_allows_all_return_paths: "不限制 SSO 提供的 return_paths 中的域名(默认情况下返回地址必须位于当前站点)" enable_local_logins: "启用本地用户名和密码验证。(注意:邀请特性需要该选项)" allow_new_registrations: "允许新用户注册。取消选择将阻止任何人创建一个新账户。" enable_signup_cta: "显示推荐创建账户的提示给那些回访的未注册用户。" @@ -1089,19 +1120,25 @@ zh_CN: automatically_download_gravatars: "为注册或更改邮箱的用户下载 Gravatar 头像。" digest_topics: "邮件摘要中显示的流行主题的最大数目。" digest_posts: "邮件摘要中显示的最流行帖子的数量。" + digest_other_topics: "邮件摘要中“你关注的主题和分类中的新内容”栏目显示的主题数目上限。" digest_min_excerpt_length: "邮件摘要中显示的帖子摘要字符数下限。" delete_digest_email_after_days: "不发送摘要邮件给超过(n)天没访问的用户。" digest_suppress_categories: "不在摘要邮件中显示这些分类的内容。" disable_digest_emails: "禁用所有用户摘要邮件功能。" + email_accent_bg_color: "HTML 邮件中某些元素的背景使用的强调颜色。输入色彩名(“red”)或十六进制值(“#FF0000”)。" + email_accent_fg_color: "HTML 邮件中背景使用的字体颜色。输入色彩名(“white”)或十六进制值(“#FFFFFF”)。" + email_link_color: "HTML 邮件中的链接颜色。输入色彩名字(“blue”)或十六进制值(“#0000FF”)。" detect_custom_avatars: "检测用户是否上传了自定义个人头像。" max_daily_gravatar_crawls: "一天内 Discourse 将自动检查 gravatar 自定义头像的次数" public_user_custom_fields: "可公开显示的用户自定义属性白名单" staff_user_custom_fields: "可给管理人员公开显示的用户自定义属性白名单。" enable_user_directory: "提供可供浏览的用户目录" + enable_group_directory: "提供可供浏览的群组目录" allow_anonymous_posting: "允许用户切换至匿名模式" anonymous_posting_min_trust_level: "启用匿名发帖所需的最小信任等级" anonymous_account_duration_minutes: "为了匿名性,为每个用户每 N 分钟创建一个匿名账户。例如:如果设置为 600,只要发帖后 600 分钟到了,并且用户切换至了匿名模式,就会创建一个新的匿名账户。" hide_user_profiles_from_public: "不对来访用户显示用户信息卡、用户资料和用户目录。" + user_website_domains_whitelist: "用户网站要属于这些域名中。用 | 分割。" allow_profile_backgrounds: "允许用户上传个人资料背景图片。" sequential_replies_threshold: "在被提醒回复了太多连续的回复前,用户在主题中可以连续回复的帖子的数量。" enable_mobile_theme: "为移动设备启用移动友好的主题,但也能切换回完整站点。如果你想要使用自定义的响应式主题请禁用它。" @@ -1114,6 +1151,7 @@ zh_CN: automatically_unpin_topics: "当用户到达底部时自动解除主题置顶。" read_time_word_count: "一分钟阅读的词的数量,用于估计阅读时间。" topic_page_title_includes_category: "主题页面标题包含分类名。" + native_app_install_banner: "邀請常客安裝 Discourse 本机应用程序" max_prints_per_hour_per_user: "/print 页面的每小时最大展示量(设置为 0 禁用)" full_name_required: "全名是用户个人信息的必填项。" enable_names: "在用户的个人信息、用户卡片和邮件中显示全名。禁用将在所有地方隐藏全名。" @@ -1137,7 +1175,6 @@ zh_CN: embed_whitelist_selector: "在嵌入页面加入元素 CSS 选择器。" embed_blacklist_selector: "在嵌入页面移除元素 CSS 选择器。" notify_about_flags_after: "如果有标记没有在设定小时后处理,发送一封邮件给 contact_email。设为 0 将禁用。" - enable_cdn_js_debugging: "为包含的 js 启动跨源访问 /logs 权限以显示合适的错误。" show_create_topics_notice: "如果站点只有少于 5 篇的公开帖子时,显示一条请管理员创建帖子的提示。" delete_drafts_older_than_n_days: 删除超过 n 天得草稿。 bootstrap_mode_min_users: "禁用摘要模式的用户数下限(0 为禁用)。" @@ -1184,6 +1221,7 @@ zh_CN: max_api_keys_per_user: "每用户最多持有的用户 API 数" min_trust_level_for_user_api_key: "生成用户 API 密钥所需的信任等级" allowed_user_api_auth_redirects: "允许用户 API 密钥重定向授权至" + allowed_user_api_push_urls: "允许使用服务器推送至用户 API 的 URL" tagging_enabled: "启用标签功能,允许为主题设置标签?" min_trust_to_create_tag: "创建标签所需的最小信任等级。" max_tags_per_topic: "主题最多允许有多少个标签。" @@ -1332,6 +1370,8 @@ zh_CN: ip_address: blocked: "不允许从你的 IP 地址注册新用户。" max_new_accounts_per_registration_ip: "不允许从你的 IP 地址注册新用户(达到上限)。联系一个管理人员。" + website: + domain_not_allowed: "网站无效。允许的域名有:%{domains}" flags_reminder: flags_were_submitted: other: "这些标记在过去 %{count} 小时内被提交。请审核他们。" @@ -1389,36 +1429,8 @@ zh_CN: 这封邀请发自受信任的用户,所以你可以立即回复主题。 invite_forum_mailer: subject_template: "%{invitee_name} 邀请你加入 %{site_domain_name}" - text_body_template: | - %{invitee_name} 邀请你加入 - - > **%{site_title}** - > - > %{site_description} - - 如果你感兴趣,点击下面的链接: - - %{invite_link} - - 这封邀请发自受信任的用户,所以你的帐户将被自动创建。 custom_invite_forum_mailer: subject_template: "%{invitee_name}邀请你加入%{site_domain_name}" - text_body_template: | - %{invitee_name}邀请你加入 - - > **%{site_title}** - > - > %{site_description} - - %{invitee_name}的留言: - - %{user_custom_message} - - 如果你感兴趣,点击下面的链接: - - %{invite_link} - - 这封邀请发自受信任的用户,所以你的帐户将被自动创建。 invite_password_instructions: subject_template: "为 %{site_name} 账户设置密码" text_body_template: | @@ -1537,6 +1549,8 @@ zh_CN: 然而,如果帖子再次被社群成员标记并隐藏,它将被隐藏至版主处理后——并且可能导致进一步的措施,如封禁帐号。 想了解更多,请查看我们的[社群指引](%{base_url}/guidelines)。 + usage_tips: + text_body_template: "要查看给新用户的简要技巧,[(英文)看看这篇博客文章](http://blog.discourse.org/2016/12/discourse-new-user-tips-and-tricks/)。\n\n只要你参与,我们将更了解你,并且新用户的临时限制将被移除。\b随着时间,你将获得[信任等级](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924),这将提供一些特殊功能来帮助我们更好地管理社群。\n" welcome_user: subject_template: "欢迎来到 %{site_name}!" text_body_template: | @@ -1551,26 +1565,6 @@ zh_CN: (如果你在新用户级别需要和[管理人员](%{base_url}/about)沟通的话,直接回复这个消息。) welcome_invite: subject_template: "欢迎来到 %{site_name}!" - text_body_template: | - 感谢你接受邀请加入%{site_name} —— 欢迎! - - 我们为你创建了账号:**%{username}**,同时你已经登录了。你可以在任何时候访问[你的用户设置][prefs]来修改它。 - - 要再次登入,或者: - - 1. 永远 **使用收到邀请的邮箱地址**登录。否则我们就无法分辨是不是你本人! - - 2. 在 [你的用户设置][prefs]页面创建一个密码,然后使用该密码来登入。 - - %{new_user_tips} - - 我们始终相信[讨论应该文明](%{base_url}/guidelines)。 - - 好好享受你在论坛的时光吧! - - ( 如果你在新用户级别需要和[管理人员](%{base_url}/about)沟通的话,直接回复这个消息。) - - [prefs]: %{user_preferences_url} backup_succeeded: subject_template: "备份成功完成" text_body_template: | @@ -2009,12 +2003,15 @@ zh_CN: new_topics: "新主题" unread_messages: "未读私信" unread_notifications: "未读通知" + liked_received: "获得赞" + new_posts: "新帖子" + new_users: "新用户" popular_topics: "热门主题" follow_topic: "关注主题" join_the_discussion: "阅读更多" popular_posts: "流行帖子" from_topic_label: "来自" - more_new: "你关注的主题和分类中新内容" + more_new: "新内容" subject_template: "[%{site_name}] 摘要" unsubscribe: "这是封来自%{site_link}的摘要邮件,因为你长时间没有访问而发送。%{unsubscribe_link}取消订阅。" click_here: "点击此处" @@ -2757,14 +2754,45 @@ zh_CN: description: "你的社群主要使用什么语言?" forum_title: title: "名字" + description: "名字就像远方可见的路标一样,访客“首先”将看到这个社群的名字。你起的名字和标题怎样描述了你的社群?" fields: title: label: "你社群的名字" - contact: + placeholder: "小明的论坛" + site_description: + label: "用一句简短的话描述你的社群" + placeholder: "小明和他的朋友讨论酷东西的论坛" + introduction: + title: "介绍" fields: + welcome: + label: "欢迎主题" + one_paragraph: "请限制你的欢迎消息至一段话。" + privacy: + title: "访问" + fields: + privacy: + choices: + open: + label: "公开" + description: "任何人都可访问社群,可以创建账户" + restricted: + label: "私密" + description: "只有我邀请或审核通过的人可以访问社群" + contact: + title: "联系" + fields: + contact_email: + label: "邮件" + placeholder: "name@example.com" + description: "社群的负责人或小组的邮件地址。将用来接收关于未处理标记和安全更新的紧急通知,并显示在关于页面上作为紧急联系的方式。" contact_url: label: "网页" placeholder: "http://www.example.com/contact-us" + description: "你或者你的组织平时用于联络的网页。将被显示在关于页面中。" + site_contact: + label: "自动消息" + description: "所有自动发送自 Discourse 的私人消息将以该用户的名义发送。最重要的是,这个用户将被指定为发送给每个新用户的欢迎消息的发送人。" corporate: title: "组织" fields: @@ -2800,8 +2828,10 @@ zh_CN: fields: favicon_url: label: "小图标" + description: "浏览器中你站点显示的图标,要在小尺寸的情况下表现出色,例如 32px X 32px。" apple_touch_icon_url: label: "大图标" + description: "现代设备中你站点显示的图标,要在大一点尺寸的情况下表现出色。推荐的尺寸至少要达到144px X 144px。" homepage: title: "主页" fields: @@ -2815,6 +2845,7 @@ zh_CN: title: "Emoji" invites: title: "邀请工作人员" + description: "你快做完啦!让我们邀请一些工作人员来帮助你创建一些讨论主题以方便你发布社群。" finished: title: "你的 Discourse 已经准备就绪!" description: | diff --git a/config/locales/server.zh_TW.yml b/config/locales/server.zh_TW.yml index 57b5747e9c5..c0ca38caa78 100644 --- a/config/locales/server.zh_TW.yml +++ b/config/locales/server.zh_TW.yml @@ -14,17 +14,45 @@ zh_TW: formats: short: "%Y-%m-%d" short_no_year: "%B %-d" + date_only: "%Y年%m月%d日" + long: "%Y年%m月%d日%H:%M" date: month_names: [null, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月] <<: *datetime_formats + time: + am: "上午" + pm: "下午" + <<: *datetime_formats title: "論壇" topics: "討論話題" posts: "文章" loading: "載入中" powered_by_html: 'Powered by Discourse, 請啟用 Javascript 以獲得最佳瀏覽效果' log_in: "登入" + purge_reason: "自動當成遺棄、未啟動的帳戶刪除" disable_remote_images_download_reason: "磁盤空間不足,圖像下載已被禁用。" anonymous: "匿名" + remove_posts_deleted_by_author: "已由作者刪除" + emails: + incoming: + default_subject: "來自 %{email} 的電子郵件" + show_trimmed_content: "顯示刪減後的內容" + maximum_staged_user_per_email_reached: "以達成分期使用者能創造的最大數量信件" + errors: + empty_email_error: "當我們收到的原生郵件空白時發生。" + no_message_id_error: "當郵件沒有「Message-Id」標頭訊息時發生。" + auto_generated_email_error: "郵件頭部的“precedence”為:list、junk、bulk 或 auto_reply,或者頭部包含了:auto-submitted、auto-replied 或 auto-generated。" + no_body_detected_error: "無法解析正文並且沒有附件。" + inactive_user_error: "當寄件者處於非啟動狀態時發生。" + blocked_user_error: "當寄件者已被封鎖時發生。" + bad_destination_address: "發至/抄送/密送欄中的所有郵件都不匹配進站郵件地址。" + strangers_not_allowed_error: "當用戶試圖在尚未晉身為成員之一的分類中新建討論話題時發生。" + insufficient_trust_level_error: "用戶嘗試在用戶等級不滿足分類要求時發帖。" + reply_user_not_matching_error: "回覆郵箱地址與通知發送至的郵件地址不同。" + topic_not_found_error: "當得到回應,但相關討論話題已經刪除時發生。" + topic_closed_error: "當得到回應,但相關討論話題已經關閉時發生。" + bounced_email_error: "郵件是投遞失敗的錯誤報告。" + screened_email_error: "發件人郵箱已經被封禁。" errors: &errors format: '%{attribute} %{message}' messages: @@ -44,6 +72,7 @@ zh_TW: has_already_been_used: "已經被使用" inclusion: 不包括在這列表中 invalid: 無效的 + is_invalid: "似乎不清楚,這是完整的句子嗎?" less_than: 必須少於 %{count} less_than_or_equal_to: 必須少於或等於 %{count} not_a_number: 不是數字 @@ -71,21 +100,32 @@ zh_TW: min_username_length_range: "你不能設定「最小」大於「最大」。" max_username_length_exists: "您不能設置比現有用戶名短的「最大用戶名長度」。" max_username_length_range: "你不能設定「最大」小於「最小」。" + default_categories_already_selected: "不能選擇一個已經用於另一個列表的分類。" + s3_upload_bucket_is_required: "你沒有填寫“s3_upload_bucket”,不能開啟上傳至 S3。" bulk_invite: - file_should_be_csv: "上傳的文件應為 csv 或 txt 格式。" + file_should_be_csv: "上傳的檔案必須是 CSV 格式。" + error: "上傳檔案有錯誤,請再試一次。" backup: operation_already_running: "%{operation} 操作正在運行。 目前無法執行新的 %{operation} 操作。" backup_file_should_be_tar_gz: "備份檔案應使用 .tar.gz 歸檔" not_enough_space_on_disk: "沒有足夠的磁碟空間可供備份檔案上傳" + invalid_filename: "備份檔案名包含無效字元。有效字元為 a-z 0-9 . - _." not_logged_in: "你需要先登入才能那樣做。" not_found: "所請求的URL或資源無法找到。" invalid_access: "你不允許查看所請求的資源。" read_only_mode_enabled: "這個網站目前在唯讀模式,無法進行互動功能。" + reading_time: "閱讀時間" + likes: "個讚" too_many_replies: other: "我們非常抱歉,新用戶被臨時限制在同一個主題上,只能回覆 %{count} 次" embed: start_discussion: "開始討論" continue: "繼續討論" + error: "嵌入時遭遇錯誤" + referer: "Referer:" + mismatch: "referer 來源與下列任何主機不符:" + no_hosts: "未設置內嵌用的主機。" + configure: "配置嵌入" more_replies: other: "%{count} 個更多回覆" loading: "討論串載入中⋯" @@ -94,11 +134,28 @@ zh_TW: in_reply_to: "▶ %{username}" replies: other: "%{count} 個回覆" + no_mentions_allowed: "抱歉,您無法提及其他用戶。" + too_many_mentions: + other: "抱歉,您的貼文中只能提及 %{count} 位用戶。" + no_mentions_allowed_newuser: "抱歉,新用戶不能提及其他用戶。" + too_many_mentions_newuser: + other: "抱歉,新用戶只能在貼文中提及 %{count} 位用戶。" + no_images_allowed: "抱歉,新用戶不能在貼文中放置圖片。" + too_many_images: + other: "抱歉,新者用者只能在貼文中放置 %{count} 張圖片。" + no_attachments_allowed: "抱歉,新用戶不能在貼文中放置附件。" + too_many_attachments: + other: "抱歉,新用戶只能在貼文中放置 %{count} 個附件。" + no_links_allowed: "抱歉,新用戶不能在貼文中放置連結。" + too_many_links: + other: "抱歉,新用戶只能在貼文中放置 %{count} 個連結。" spamming_host: "抱歉,你不能張貼該網站之連結。" user_is_suspended: "被停權的用戶無法張貼文章。" topic_not_found: "出現問題。也許這個話題被關閉或刪除。" + not_accepting_pms: "對不起,%{username} 目前不接收訊息。" just_posted_that: "與你最近發表的內容太相似" invalid_characters: "包含無效字詞" + is_invalid: "似乎不清楚,這是完整的句子嗎?" next_page: "下一頁 →" prev_page: "← 上一頁" page_num: "%{num} 頁" @@ -114,13 +171,27 @@ zh_TW: rss_description: latest: "最新討論話題" hot: "熱門討論話題" + top: "熱門討論話題" posts: " 最近文章" + private_posts: "最新的私人訊息" + group_posts: "%{group_name} 的最新貼文" + group_mentions: "%{group_name} 的最近提及" + user_posts: "@%{username} 的最新貼文" + user_topics: "@%{username} 的的最新討論話題" + tag: "主題標籤" too_late_to_edit: "這文章建立很久了,它已經無法被編輯或刪除" + revert_version_same: "您試圖回復的版本和當前版本相同。" excerpt_image: "圖片" + queue: + delete_reason: "通過帖子審核隊列刪除" groups: errors: + can_not_modify_automatic: "你不能修改自動組" member_already_exist: "'%{username}' 已經是群組成員了。" invalid_domain: "'%{domain}' 不是有效的域名." + invalid_incoming_email: "「%{email}」不是有效的電子郵件位址。" + email_already_used_in_group: "「%{email}」已經被「%{group_name}」群組使用。" + email_already_used_in_category: "「%{email}」已經被「%{category_name}」類別使用。" default_names: everyone: "所有人" admins: "管理員" @@ -134,6 +205,16 @@ zh_TW: education: until_posts: other: "%{count} 篇文章" + new-topic: | + 歡迎來到%{site_name} — **衷心感謝你參與討論!** + + - 標題是否清晰明了地描述了主題?看起來有意思麼? + + - 誰會感興趣?它為什麼重要?你期望從社區中獲得什麼樣的回應? + + - 選擇恰當的詞句以便別人能找到你的主題。若想要給主題分組,選擇一個分類。 + + 更多的幫助信息,[請查看我們的社群準則](/guidelines)。此信息面板只在你發佈前 %{education_posts_text}時顯示。 new-reply: | 歡迎來到%{site_name} — **感謝你的貢獻!** @@ -143,11 +224,48 @@ zh_TW: - 歡迎有建設性的評論,但是評論的應該是觀點,而不是人身攻擊。 - 欲查看更多,[請查看我們的社群准則](/guidelines)。此訊息面板只會在你發表前 %{education_posts_text} 時顯示。 + 欲查看更多,[請查看我們的社群守則](/guidelines)。此訊息面板只會在你發表前 %{education_posts_text} 時顯示。 + avatar: | + ### 給你的賬戶設置頭像如何? + + 你已經發表了一些主題和回覆,但是你的個人頭像並不像你一樣獨特——只是一些字母而已。 + + 你考慮過**[訪問你的用戶頁面](%{profile_path})**,再上傳一個代表你的圖片? + + 當所有人都有獨特的頭像時,這會讓專注討論和找到有趣的人更加輕鬆。 + sequential_replies: | + ### 考慮一次性回覆多個帖子 + + 與其接連回覆主題幾次,不如在一個回覆中引用相關內容或者@用戶名引用前面的帖子。 + + 你可以編輯你之前的回覆以添加引用。添加引用需要選擇文字並且點擊出現的引用回覆按鈕。 + + 當主題中的帖子的內容不是多個小且獨立的回覆,而是更少的更有深度的帖子時,我們會更認真地閲讀這個主題。 + dominating_topic: | + ### 讓其他人加入討論 + + 很明顯這個主題對你很重要 – 你已經發表的帖子占該主題 %{percent}% 的回覆。 + + 你有讓其他人自由地表達他們的觀點了嗎? + too_many_replies: | + ### 你發表的回覆數量已經達到該主題的回覆上限。 + + 非常抱歉,但新用戶被臨時限制,只能在同一主題中回覆 %{newuser_max_replies_per_topic} 次。 + + 想要添加另一個回覆不如考慮編輯原先的回覆或訪問其他主題。 + reviving_old_topic: | + ### 復活這個主題? + + 這個主題的最後一個回覆距今已有 %{days} 天了。你的回覆將讓主題重新出現在列表的頂端並通知原先參與討論的人。 + + 你確定要繼續這個老的話題嗎? activerecord: attributes: category: name: "分類名稱" + topic: + title: '標題' + featured_link: '特選連結' post: raw: "內容" user_profile: @@ -161,41 +279,98 @@ zh_TW: too_many_users: "你只能同時傳送警告給一位用戶。" cant_send_pm: "抱歉,你不能向該用戶發送私人訊息。" no_user_selected: "你必須選擇有效用戶。" + featured_link: + invalid: "不合法。URL 應包括 http:// 或 https://。" + invalid_category: "無法在這個類別中編輯。" user: attributes: password: common: "這個密碼是 10000 個最常用密碼之一,請使用一個更安全的密碼" - same_as_username: "與你的使用者名稱相同。請使用其他更安全的密碼。" + same_as_username: "與你的用戶名稱相同。請使用其他更安全的密碼。" same_as_email: "與你的電郵相同。請使用其他更安全的密碼。" + same_as_current: "與您目前的密碼相同。" ip_address: signup_not_allowed: "不能使用這個帳戶進行登入" color_scheme_color: attributes: hex: invalid: "不是一個有效顏色" + post_reply: + base: + different_topic: "貼文和回覆都必須處在相同的討論話題下。" + web_hook: + attributes: + payload_url: + invalid: "URL 不合法。URL 應包括 http:// 或 https://。並且其中沒有空格。" <<: *errors user_profile: no_info_me: "
    你的自我簡介中,“關於我” 部分目前還沒有內容,不如來自我介紹一下?
    " no_info_other: "
    %{name} 尚未在他/她自我簡介中的“關於我”部分填寫任何資訊
    " vip_category_name: "貴賓室" vip_category_description: "信任等級高於 3 的用戶討論的分類" + meta_category_name: "站點反饋" meta_category_description: "討論這個網站、整體的組織規劃、社群的運作方式、以及我們該如何改善這些事務。" staff_category_name: "管理員" staff_category_description: "讓工作人員進行討論的私人分類。此分類下的討論話題只有管理員與板主才看得到。" + assets_topic_title: "站點設計資料" + assets_topic_body: "這是一個永久主題,僅對管理人員可見,用於存儲論壇設計使用的圖像和檔案。不要刪除它!\n\n\n詳細教程:\n\n\n1. 回覆到這個主題。\n2. 上傳你想用作站點標誌、表徵圖和其他所有圖片到這兒。(使用帖子編輯器工具欄中的上傳表徵圖,或者拖拽或者粘貼圖像。)\n3. 提交你的回覆添加帖子。\n4. 在你的新帖子裡右鍵點擊圖片獲得這些已上傳圖片的連結,或者點擊編輯按鈕來編輯帖子,獲得到圖片的相對地址。複製這些相對地址。\n5. 粘貼這些圖像的路徑到[基礎設置](/admin/site_settings/category/required)。\n\n\n如果你需要運行額外的上傳檔案類型,在[檔案設置](/admin/site_settings/category/files)中編輯 `authorized_extensions`。" + discourse_welcome_topic: + title: "歡迎來到 Discourse" + body: |2 + + 置頂主題的第一段是訪客在主頁看到的歡迎消息。這很重要! + + **編輯**它作為社群的簡要介紹: + + - 什麼人想參與? + - 他們能在這找到什麼? + - 為什麼他們要來這? + - 他們能在哪裡閲讀更多的內容(連結、資源等)? + + + + 你可能想要在管理 :wrench: (右上角)中關閉這個主題,這樣回覆就不會積壓在這個通告下。 lounge_welcome: title: "歡迎來到貴賓室" + body: |2 + + 恭喜! :confetti_ball: + + 如果你看到了這個主題,說明你已經被提升至**常規**(信任等級3)了。 + + 你現在可以… + + * 編輯任何主題的標題 + * 改變任何主題的分類 + * 讓你的連結設置為 follow 屬性([自動 nofollow](http://en.wikipedia.org/wiki/Nofollow)限制已經移除) + * 訪問一個只有信任等級3及更高才能見到的貴賓室分類 + * 一次標記即可隱藏垃圾信息 + + 這裡是[目前達到常規的用戶列表](/badges/3/regular)。一定要來問個好! + + 感謝成為社群的重要一員! + + (想瞭解關於信任等級的更多信息,[參見這個主題][trust]。請注意成員需要在將來也維持一定的選擇條件的成員才能保持在常規。) + + [trust]: https://meta.discourse.org/t/what-do-user-trust-levels-do/4924 category: topic_prefix: "對於分類:%{category} 的定義" + replace_paragraph: "(將第一段話修改成你的新分類的簡述。這段文字將出現在用戶選擇分類的地方,所以嘗試保持在 200 個字元內。 **除非你編輯了這段文字或者在這分類中創建了主題,這個分類不會出現在分類頁面中。**)" + post_template: "%{replace_paragraph}\n\n在接下來的這段話中多寫一些分類的用途,或者設定一個該分類的規則:\n\n- 為什麼我們要用這個分類?它用來做什麼?\n\n- 這個分類和我們已經有的分類究竟有什麼不同?\n\n- 這個分類中一般會包含哪些主題?\n\n- 我們需要這個分類麼?我們可以把它和別的分類、或者子分類合併嗎?\n\n" errors: uncategorized_parent: "未分類不能有一個父分類" self_parent: "一個子分類的上層不能是自己" depth: "你不能在子分類下再包含子分類" + invalid_email_in: "「%{email}」不是有效的電子郵件位址。" + email_already_used_in_group: "「%{email}」已被「%{group_name}」群組數用。" + email_already_used_in_category: "「%{email}」已被「%{category_name}」類別使用。" cannot_delete: uncategorized: "不能刪除該分類" has_subcategories: "不能刪除該分類,因為它有子分類" topic_exists: other: "不能刪除該分類,因為它有 %{count} 個話題,最老的話題是 %{topic_link}" topic_exists_no_oldest: "不能刪除該分類,因為有 %{count} 個話題" + uncategorized_description: "不需要分類或者不適合放在現在的任何分類中的主題。" trust_levels: newuser: title: "新用戶" @@ -203,10 +378,29 @@ zh_TW: title: "初級用戶" member: title: "成員" + regular: + title: "活躍用戶" + leader: + title: "資深" + change_failed_explanation: "你嘗試將%{user_name}降至%{new_trust_level}。然而他們的信任等級已經是%{current_trust_level}。%{user_name}將仍處于%{current_trust_level}——如果你想要降級用戶,先鎖定信任等級。" rate_limiter: + slow_down: "您這個動作重複太多次,請稍後再試。" too_many_requests: "你的瀏覽速度過於頻繁,請等待 %{time_left} 後再試。" by_type: + first_day_replies_per_day: "你回帖的數量已經超出身為新用戶當天允許的上限,請等待%{time_left}之後再試。" + first_day_topics_per_day: "你創建新主題的數量已經超出身為新用戶當天允許的上限,請等待%{time_left}之後再試。" + create_topic: "您創建討論話題過於倉猝。請稍等 %{time_left} 再試一次。" create_post: "你的回覆過快。請等待%{time_left}再重試。" + delete_post: "您刪除討論話題過於倉猝。請稍待 %{time_left} 後再試一次。" + public_group_membership: "您加入/離開群組過於頻繁。請稍等 %{time_left} 後再試一次。" + topics_per_day: "您今天新發佈的討論話題已經達到上限。請稍待 %{time_left} 後再試一次。" + pms_per_day: "您今天發表的訊息數已經達到上限。請等待 %{time_left} 後再行嘗試。" + create_like: "您今天給予讚的次數已經達到上限。請等待 %{time_left} 再行嘗試。" + create_bookmark: "您今天加入書籤的數目已經達到上限。請等待 %{time_left} 再行嘗試。" + edit_post: "您今天編輯的次數已達到上限。請等待 %{time_left} 再行嘗試。" + live_post_counts: "您要求的即時文章計數過於快速。請等待 %{time_left} 再行嘗試。" + unsubscribe_via_email: "你已經達到了今日用郵件解除訂閲的最大數量限制。請等待%{time_left}之後再試。" + topic_invitations_per_day: "你已經達到了今日主題邀請的最大數量限制。請等待%{time_left}之後再試。" hours: other: "%{count} 小時" minutes: @@ -263,6 +457,7 @@ zh_TW: almost_x_years: other: "約 %{count} 年前" password_reset: + no_token: "抱歉,密碼修改連結已過期。選擇登錄按鈕再使用“我忘記了密碼”獲得一個新連結。" choose_new: "請選擇一個新密碼" choose: "請選擇一個密碼" update: '更新密碼' @@ -275,6 +470,11 @@ zh_TW: confirmed: "你的電子郵箱已更新。" please_continue: "繼續連接至 %{site_name}" error: "修改你的電郵位址時發生錯誤,可能此郵箱已有人使用了。" + error_staged: "在修改你的電子郵箱地址時出現了錯誤。這個郵箱已經被一個暫存用戶占用了。" + already_done: "抱歉,此激活連結已經失效。可能你已經修改了郵箱?" + authorizing_old: + title: "感謝你確認你目前的郵箱地址" + description: "我們正向你的新地址發送確認郵件。" activation: action: "點擊此處啟用你的帳戶" already_done: "抱歉,此帳號啟用連結已經失效。可能你的帳號已經啟用了。" @@ -282,6 +482,7 @@ zh_TW: continue_button: "繼續連接至 %{site_name}" welcome_to: "歡迎來到%{site_name}!" approval_required: "你的論壇帳號需要由板主手動審核後才可使用。當你的帳號獲得批准,你將收到電子郵件通知。" + missing_session: "無法確認你是否註冊了帳戶,請確定你已經啟用了 cookie。" post_action_types: off_topic: title: '離題內容' @@ -295,14 +496,19 @@ zh_TW: email_body: "%{link}\n\n%{message}" inappropriate: title: '不當內容' - description: '此帖內容包含對他人的攻擊、侮辱、仇視語言或違反了我們的社群准則。' + description: '此帖內容包含對他人的攻擊、侮辱、仇視語言或違反了我們的社群守則。' long_form: '投訴為不當內容' notify_user: title: '給 @{{username}} 送出一則訊息' + description: '我想要直接且私下地和這位朋友討論其文章。' + long_form: '傳訊給用戶' email_title: '你的文章在"%{title}"' email_body: "%{link}\n\n%{message}" notify_moderators: title: "其他" + description: '這個帖子需要版主的注意,但是原因沒有包括在上述選項中。' + long_form: '標記為需版主注意' + email_title: '"%{title}" 主題需要版主的注意' email_body: "%{link}\n\n%{message}" bookmark: title: '書籤' @@ -316,6 +522,13 @@ zh_TW: title: '投票' description: '投票給此文章' long_form: '已投票給此文章' + user_activity: + no_bookmarks: + self: "你沒有收藏帖子,收藏帖子能讓你之後輕鬆找到他們。" + others: "沒有書籤。" + no_likes_given: + self: "你沒有對任何文章按讚。" + others: "沒有被讚的帖子。" topic_flag_types: spam: title: '垃圾內容' @@ -323,14 +536,16 @@ zh_TW: long_form: '投訴為垃圾內容' inappropriate: title: '不當內容' - description: '此主題內容包含對他人的攻擊、侮辱、仇視語言或違反了我們的社群准則。' + description: '此主題內容包含對他人的攻擊、侮辱、仇視語言或違反了我們的社群守則。' long_form: '投訴為不當內容' notify_moderators: title: "其他" + description: '此帖需要版主依據社群準則服務條款(TOS)或其它未列出的原因來給予關注。' long_form: '標記為需版主注意' email_title: '此討論話題 "%{title}" 需要板主注意' email_body: "%{link}\n\n%{message}" flagging: + you_must_edit: '

    你的帖子被社群成員標記了。請查看你的消息

    ' user_must_edit: '

    你的帖子已經被社群標記並被臨時隱藏。

    ' archetypes: regular: @@ -340,6 +555,36 @@ zh_TW: message: make: "本主題現在是橫幅主題。它將出現在每頁的頂部,除非用戶將其隱藏。" remove: "本主題已經不再是橫幅主題。它將不在每個頁面的頂部顯示。" + unsubscribed: + title: "退訂!" + description: "你已經退訂。要更改你的郵件設置,訪問你的用戶設置頁面。" + topic_description: "點擊連結 %{link} 重新訂閲,或是使用主題底部或右側的通知控制。" + unsubscribe: + title: "退訂" + stop_watching_topic: "停止關注這個討論話題,%{link}" + mute_topic: "關閉此主題的所有通知,%{link}" + unwatch_category: "停止監看%{category}分類中的所有主題" + mailing_list_mode: "停用郵件列表模式" + disable_digest_emails: "不要給我發送摘要郵件" + all: "不要從%{sitename}給我發送任何郵件" + different_user_description: "你登錄的帳戶與郵件不符。請登出,或進入隱私模式,然後再重試。" + not_found_description: "對不起,我們找不到這個退訂連結。有可能你的郵件中的連結已經過期?" + log_out: "退出" + user_api_key: + title: "授權應用訪問" + authorize: "授權" + read: "閲讀" + read_write: "讀/寫" + description: "“%{application_name}”正在請求訪問你的賬戶中的以下權限:" + no_trust_level: "抱歉,你沒有使用用戶 API 所需要的信任等級" + generic_error: "抱歉,我們不能分發用戶 API 密鑰,該特性已經被站點管理員禁用" + scopes: + message_bus: "實時更新" + notifications: "讀取並清除通知" + push: "推送通知到外部服務" + session_info: "讀取用戶會話信息" + read: "讀取所有" + write: "寫入所有" reports: visits: title: "用戶瀏覽量" @@ -350,7 +595,9 @@ zh_TW: xaxis: "天" yaxis: "新用戶數量" profile_views: + title: "查看用戶資料" xaxis: "天" + yaxis: "已看的用戶資料數量" topics: title: "討論話題" xaxis: "天" @@ -421,19 +668,27 @@ zh_TW: page_view_anon_reqs: title: "匿名" xaxis: "天" + yaxis: "未登錄頁面訪問" page_view_logged_in_reqs: title: "已登入" xaxis: "天" + yaxis: "已登錄頁面訪問" page_view_crawler_reqs: title: "網絡爬蟲" xaxis: "天" + yaxis: "Web 爬蟲頁面訪問" page_view_total_reqs: title: "總數" xaxis: "天" + yaxis: "總瀏覽量" page_view_logged_in_mobile_reqs: + title: "已登錄頁面訪問" xaxis: "天" + yaxis: "移動端已登錄頁面訪問" page_view_anon_mobile_reqs: + title: "未登錄頁面訪問" xaxis: "天" + yaxis: "移動端未登錄頁面訪問" http_background_reqs: title: "後台" xaxis: "天" @@ -459,16 +714,23 @@ zh_TW: xaxis: "天" yaxis: "請求總數" time_to_first_response: + title: "第一個回覆時間" xaxis: "天" + yaxis: "平均時間(小時)" topics_with_no_response: + title: "沒有回覆的帖子" xaxis: "天" + yaxis: "總量" mobile_visits: + title: "用戶訪問" xaxis: "天" + yaxis: "訪問次數" dashboard: rails_env_warning: "伺服器現在運行 %{env} 模式。" host_names_warning: "伺服器上 config/database.yml 的主機名稱為 localhost 。請更改成你的網站主機名稱。" gc_warning: '伺服器正在使用的 ruby 可能僅啟用了預設的 垃圾回收設定 (garbage collection), 這個設定無法提供最佳效能。請瀏覽此效能設定的資訊: Tuning Ruby and Rails for Discourse。' sidekiq_warning: 'Sidekiq 未有執行。很多程序, 如發送電子郵件, 需要 sidekiq 非同步 (asynchronous) 執行的。請確保至少運行一個 sidekiq 程序。瞭解 Sidekiq。' + queue_size_warning: '隊列中有較多任務,為 %{queue_size} 個。這可能是因為 Sidekiq 進程的問題導致,或者需要更多的 Sidekiq 進程。' memory_warning: '伺服器記憶體少於 1GB,建議配置至少 1GB 記憶體' google_oauth2_config_warning: '伺服器設定為允許使用 Google Oauth2 註冊以及登入 (enable_google_oauth2_logins),但未設定客戶端 id 和客戶端 secret 值。請至網站設定裡更改設定。參閱教學指南。' facebook_config_warning: '伺服器允許使用 Facebook 帳號登入 (enable_facebook_logins), 但未有設定 app id 及 app secret values 。 請在 網站設定 裡更改設定。 設定教學指南。' @@ -477,19 +739,35 @@ zh_TW: s3_config_warning: '伺服器被設定為上傳文件到 s3,但是至少有一個值未被設定: s3_access_key_id, s3_secret_access_key 或 s3_upload_bucket。到設定更新此設定。參考如何設置圖片上傳至 S3。' s3_backup_config_warning: '伺服器被設置為上傳備份到 s3,但是至少有一個值未被設定: s3_access_key_id, s3_secret_access_key 或 s3_upload_bucket。到設定更新此設定。參考如何設置圖片上傳至 S3。' image_magick_warning: '伺服器被設置為給大圖片創建縮略圖,但是 ImageMagick 沒有被安裝。使用你喜愛的包裝管理器安裝 ImageMagick 或下載最新版。' + failing_emails_warning: '有 %{num_failed_jobs} 個郵件任務失敗。請檢查 app.yml 檔案是否正確配置了郵件伺服器。查看 Sidekiq 中失敗的任務。' + subfolder_ends_in_slash: "你的子目錄設置不正確;DISCOURSE_RELATIVE_URL_ROOT以斜杠結尾。" + email_polling_errored_recently: + other: "郵件輪詢在過去的 24 小時內出現了 %{count} 個錯誤。看一看日誌尋找詳情。" + missing_mailgun_api_key: "伺服器設置使用 Mailgun 發送郵件,但並未設置驗證 webhook 消息的 API 密鑰。" + bad_favicon_url: "網站表徵圖無法載入。檢查站點設置中的 favicon_url。" + poll_pop3_timeout: "至 POP3 伺服器的連接超時。無法獲取進站郵件。請檢查POP3 設置和服務商。" + poll_pop3_auth_error: "至 POP3 伺服器的連接驗證失敗。請檢查POP3 設置。" site_settings: censored_words: "將被自動替換為 ■■■■" + censored_pattern: "正則表達式將自動被替換為■■■■" delete_old_hidden_posts: "自動刪除被隱藏超過 30 天的帖子。" default_locale: "Discourse 執行個體 (instance) 的預設語言編碼 (ISO 639-1)" allow_user_locale: "允許用戶選擇自己的語言介面" + set_locale_from_accept_language_header: "為未登錄用戶按照他們的瀏覽器發送的請求頭部設置界面語言。(實驗性,無法和匿名緩存共同使用)" min_post_length: "文章允許的最小文字數" min_first_post_length: "第一篇文章允許的最少文字數" min_private_message_post_length: "文章允許的最小文字數" max_post_length: "文章允許的最大文字數" + topic_featured_link_enabled: "允許發連結帖。" + show_topic_featured_link_in_digest: "在摘要郵件中顯示主題特色連結。" min_topic_title_length: "標題允許的最小文字數" max_topic_title_length: "標題允許的最大文字數" min_private_message_title_length: "標題允許的最小文字數" min_search_term_length: "搜尋條件允許的最小文字數" + search_tokenize_chinese_japanese_korean: "在非中/日/韓語站點強制切割中/日/韓語搜索分詞" + search_prefer_recent_posts: "如果搜索大型論壇較慢,這個選項將優先嘗試最新的帖子" + search_recent_posts_size: "索引多少最新的主題" + allow_uncategorized_topics: "允許發表沒有分類的帖子。警告:如果又任何未分類的帖子,你必須給他們重新分類後才能關閉該選項。" allow_duplicate_topic_titles: "允許話題有相同,重複的標題" unique_posts_mins: "使用者再次發表包含相同內容文章的間隔時間" educate_until_posts: "當用戶開始鍵入他們的前幾個 (n) 新帖子時,在編輯器上顯示教育面板視窗。" @@ -501,7 +779,9 @@ zh_TW: crawl_images: "允許從第三方 URL 取得圖片,來加入寬和高的數值" download_remote_images_to_local: "下載外部鏈接的圖片到本機;以防圖片損壞。" download_remote_images_threshold: "可用來下載外部圖片到本機最少的空間(百分比)" + download_remote_images_max_days_old: "不下載超過 n 天的帖子中的遠程圖片。" disabled_image_download_domains: "在此列表的網域名稱的遠端圖片將不會進行下載,用 | 分割多個域名" + editing_grace_period: "在 (n) 秒之內,對帖子的編輯不生成帖子歷史。" post_edit_time_limit: "作者可以在發表文章後的 ( n ) 分鐘內編輯或刪除他們的文章,設 0 為永遠" edit_history_visible_to_public: "允許任何人查看編輯過的帖子的舊版本。當禁用時,只有職員才能查看。" delete_removed_posts_after: "帖子被作者刪除,將在 (n) 小時後被自動刪除。如果設置為 0,帖子將被立即刪除。" @@ -510,39 +790,73 @@ zh_TW: category_featured_topics: "在分類 /categories 頁面每個分類顯示的討論話題數目。此數值的改變最多需要 15 分鐘才會反應在分類頁面上。" show_subcategory_list: "進入分類時顯示子分類列表,而非話題列表" fixed_category_positions: "若勾選,你將能調整並固定分類的順序。若不勾選,分類將會依照活躍程度來排序。" + fixed_category_positions_on_create: "如果選擇了,目錄排序將會在話題創建對話框中被包含(要求固定目錄位置選項)" add_rel_nofollow_to_user_content: "添加 rel nofollow 屬性到所有的用戶內容,除了內部鏈接(包括父域名)。如果你更改了這個,你必須重新調制所有帖子,而該命令為:“rake posts:rebake”" + exclude_rel_nofollow_domains: "不添加 nofollow 連結的域名列表。填寫 tld.com 將自動包括 sub.tld.com。最少你應該填寫頂級域名來讓爬蟲獲得所有內容。如果你的網站包含其他域名,增加他們。" post_excerpt_maxlength: "文章摘要的最大文字長度" + show_pinned_excerpt_mobile: "移動版顯示置頂主題剪輯。" + show_pinned_excerpt_desktop: "移動版顯示置頂主題剪輯。" post_onebox_maxlength: "Onebox 處理後的 Discourse 帖子的最大字符長度" + onebox_domains_blacklist: "不會被 Onebox 的域名列表。" + max_oneboxes_per_post: "帖子中最多的 Onebox 數量。" + logo_url: "在你站點左上角出現的小號標誌圖片,應為一個長方形。如果留空,將顯示站點標題文字。" + digest_logo_url: "郵件摘要中使用的標誌圖像。應為長方形。不能使用 SVG 圖片。如果留空,將使用 `logo_url`。" + logo_small_url: "在你站點左上角的小號標誌圖片,應為正方形,當滾動時才可見。如果留空,將顯示主頁表徵圖。" + favicon_url: "你的站點表徵圖(favicon),參考 http://zh.wikipedia.org/wiki/Favicon,如果要正確地通過 CDN 分發,它必須是 png 圖片" + mobile_logo_url: "移動站點左上角的固定標誌圖片。應為正方形。如果留空,`logo_url` 將被使用。如:http://example.com/uploads/default/logo.png" apple_touch_icon_url: "Apple 觸碰設備使用的圖示,建議 144 X 144px 大小" notification_email: "這個表格:被用於發送所有重要系統郵件的郵箱地址。指定的域名必須正確設置 SPF、DKIM 和反向 PTR 記錄以發送郵件。" email_custom_headers: "自定義的電子郵件標題的管道分隔列表" email_subject: "標準郵件的自定義主題格式。參見 https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801" + force_https: "強制使用 https。警告:開啟前必須確認 HTTPS 已經配置並能夠正常使用!你檢查了 CDN、第三方登錄和站外的 logo / 依賴是否支持 HTTPS 了嗎?" summary_score_threshold: "將一個帖子包含在“概括主題”中所需的最少分數" summary_posts_required: "如果使用了\"此話題的摘用\",話題顯示時需滿足最小的文章的數量" summary_likes_required: "如果使用了\"此話題的摘用\",話題顯示時需滿足最小得到\"讚\"的數量" summary_percent_filter: "當用戶點擊 \"此話題的摘要\",顯示前面多少 % 的文章" summary_max_results: "“概括主題”返回的最大帖子數量" + enable_private_messages: "允許信任等級1(可以另外選擇發送消息的信任等級)的用戶創建消息和回覆消息。注意:管理人員不受限制。" enable_long_polling: "啟用消息匯流排使通知功能可以使用長輪詢(long polling)" long_polling_base_url: "長輪詢的基本 URL(當用 CDN 分發動態內容,請設置此至原始拉取地址)例如:http://origin.site.com" long_polling_interval: "當沒有數據向客戶端發送時伺服器端應等待的時間(僅對已登錄用戶有效)" polling_interval: "當不再長輪詢時,已登錄的客戶端應該多久輪詢一次(單位 毫秒)" anon_polling_interval: "匿名使用者用戶端輪詢時間間隔(單位 毫秒)" background_polling_interval: "客戶端輪詢的間隔,以毫秒計(當視窗在後台時)" + flags_required_to_hide_post: "一個帖子累計多少個標記之後會被自動隱藏,並向帖子作者發送私信通知(0 為從不)" cooldown_minutes_after_hiding_posts: "如果一個文章因為標記而隱藏,用戶需要等待多少分鐘才能編輯該文章" + max_topics_in_first_day: "新用戶在24小時內在發表第一帖後允許創建的主題數" + max_replies_in_first_day: "新用戶在24小時內在發表第一帖後允許創建的回覆數" + tl2_additional_likes_per_day_multiplier: "增加信任等級2(成員)的贊限制,可提供一個乘數與原始值相乘" + tl3_additional_likes_per_day_multiplier: "增加信任等級3(常規)的每日贊限制,將此設置項與原始值相乘" + tl4_additional_likes_per_day_multiplier: "增加信任等級4(資深)的贊限制,可提供一個乘數與原始值相乘" + num_spam_flags_to_block_new_user: "如果新用戶的帖子被 num_users_to_block_new_user 個不同用戶標記,隱藏他們的所有帖子並不讓其繼續發表內容。0 為禁用。" + num_users_to_block_new_user: "如果新用戶的帖子被不同用戶 num_spam_flags_to_block_new_user 次標記為垃圾信息,隱藏他們的所有帖子並不讓其繼續發表內容。0 為禁用。" + num_tl3_flags_to_block_new_user: "如果新用戶的帖子被 num_tl3_users_to_block_new_user 個不同的信任等級3的用戶標記,隱藏他們的所有帖子並不讓其繼續發表內容。0 為禁用。" + num_tl3_users_to_block_new_user: "如果新用戶的帖子被不同的信任等級3的用戶標記 num_tl3_flags_to_block_new_user 次,隱藏他們的所有帖子並不讓其繼續發表內容。0 為禁用。" notify_mods_when_user_blocked: "若有用戶被自動封鎖,將發送訊息給所有板主。" flag_sockpuppets: "如果一個新用戶開始了一個主題,並且同時另一個新用戶以同一個 IP 在該主題回復,他們所有的帖子都將被自動標記為垃圾。" traditional_markdown_linebreaks: "在 Markdown 中使用傳統的換行符號,即用兩個行末空格來換行" + allow_html_tables: "允許在輸入 Markdown 文本時使用表格 HTML 標籤。標籤 TABLE、THEAD、TD、TR、TH 將被允許使用,即白名單這些標籤(需要重置所有包含表格的老帖子的 HTML)" post_undo_action_window_mins: "允許用戶在帖子上進行撤銷操作(讚、標記等)所需等待的時間分隔(分鐘)" + must_approve_users: "新用戶在被允許訪問站點前需要由管理人員批准。警告:在運行的站點中啟用將解除所有非管理人員用戶的訪問權限!" + pending_users_reminder_delay: "如果新用戶等待批准時間超過此小時設置則通知版主。設置 -1 關閉通知。" + maximum_session_age: "用戶自訪問後可維持登錄 n 小時" + ga_tracking_code: "廢棄:Google 分析追蹤代碼(ga.js),例如:UA-12345678-9。參考 http://google.com/analytics" + ga_domain_name: "廢棄:Google 分析域名(ga.js),例如:mysite.com;參考 http://google.com/analytics" ga_universal_tracking_code: "Google 通用 Analytics (分析) 追蹤代碼(analytics.js)追蹤代碼,例如:UA-12345678-9;參考 http://google.com/analytics" ga_universal_domain_name: "Google 通用 Analytics (分析) 域名(analytics.js)追踪代码,例如:mysite.com;参考 http://google.com/analytics" + gtm_container_id: "Google Tag Manager 容器 id。例如:GTM-ABCDEF" + enable_escaped_fragments: "如未偵測到爬蟲回退到使用 Google Ajax-Crawling API。參見 https://developers.google.com/webmasters/ajax-crawling/docs/learn-more" enable_noscript_support: "開啟noscript來對網路爬蟲來做標準的支援" allow_moderators_to_create_categories: "允許板主建立新分類" cors_origins: "允許跨來源資源共享(CORS)。每個來源必須包括 http:// 或 https://。DISCOURSE_ENABLE_CORS 環境選項必須設置為 true 才能啟用 CORS 。" + use_admin_ip_whitelist: "當目前的IP剛好處于IP段禁止名單(Admin > Logs > Screened Ips)中的時候,只有管理員才可登入。" top_menu: "選擇在主頁導航列包含哪些項目,以及排列次序。例如:latest|new|unread|categories|top|read|posted|bookmarks" post_menu: "確定在文章功能表條包含哪些條目,以及排列順序。例如:like|edit|flag|delete|share|bookmark|reply" post_menu_hidden_items: "帖子菜單中默認隱藏的按鈕,點擊省略號後顯示。" share_links: "決定在分享對話方塊裡顯示哪些項目、以什麼順序顯示。" track_external_right_clicks: "追蹤外部連結的右鍵點擊 ( 例如:開啟於瀏覽器的新頁面 ),預設是關閉的,因為它會重寫URLs" + site_contact_username: "論壇給用戶自動發送消息時使用的用戶名;如果留空將使用預設的系統賬戶。" + send_welcome_message: "給所有用戶發送快速開始指導的消息" suppress_reply_directly_below: "當帖子只有一個回覆時,不顯示帖子的回覆數量。" suppress_reply_directly_above: "當帖子只有一個回覆時,不顯示回覆到該帖的回覆。" suppress_reply_when_quoting: "當帖子引用回覆時,不顯示可展開的回覆到某帖的標記。" @@ -550,11 +864,16 @@ zh_TW: topics_per_period_in_top_summary: "預設推薦話題的顯示數量" topics_per_period_in_top_page: "在展開 \"顯示更多\" 推薦話題列表的顯示數量" redirect_users_to_top_page: "將新用戶或長時間未使用的用戶自動重新導向至熱門頁面" + top_page_default_timeframe: "頂部查看頁面的預設時間表" show_email_on_profile: "在用戶頁面顯示用戶的電郵地址(只有用戶自己和職員可見)" + prioritize_username_in_ux: "在用戶頁、用戶卡片和帖子上優先顯示用戶名(未選時,暱稱將先顯示)" email_token_valid_hours: "\"忘記密碼\" / \"重啟帳號\" token 有效的小時數 (n)" - email_token_grace_period_hours: "\"忘記密碼\" / \"重啟帳號\" 的 token 在使用後仍舊有效的小時數 (n)" enable_badges: "啟用勳章系統" + enable_whispers: "允許工作人員在主題中私密交流。" allow_index_in_robots_txt: "在 robots.txt 中記錄這個網站允許被搜尋引擎索引的部分" + email_domains_blacklist: "用管道符“|”分隔的郵箱域名黑名單列表,其中的域名將不能用來註冊賬戶,例如:mailinator.com|trashmail.net" + email_domains_whitelist: "用管道符“|”分隔的電子郵箱域名的列表,用戶必須使用這些郵箱域名註冊。警告:用戶使用不包含在這個列表裡的郵箱域名,將無法成功註冊。" + forgot_password_strict: "用戶找回密碼時不提示帳戶是否存在。" log_out_strict: "登出時,登出用戶所有設備上的所有時段" version_checks: "訪問 Discourse Hub 來檢查版本更新,並在管理面板 /admin 顯示新版本訊息" new_version_emails: "當新版本發佈時,將會發送一封新的 EMail 至 contact_email 設定的位址" @@ -566,13 +885,25 @@ zh_TW: login_required: "需要登入才能進入網站,不允許匿名操作" min_username_length: "最少用戶名長度" max_username_length: "最大用戶名長度" + reserved_usernames: "註冊時不可使用的用戶名。" min_password_length: "最小密碼長度" + min_admin_password_length: "管理員最短密碼長度" block_common_passwords: "不允許使用 10,000 個最常用的密碼" + enable_sso: "啟用通過外部站點單點登錄(警告:用戶的郵件地址必須被外部站點驗證!)" + verbose_sso_logging: "將 SSO 日誌詳情記錄至 /logs" enable_sso_provider: "在 /session/sso_provider endpoint 必須設定 sso_secret 以實現 Discourse SSO 提供方協定" + sso_url: "單點登錄 URL 入口點(必須包含 http:// 或 https://)" sso_secret: "秘密字符串,用於驗證秘密的 SSO 訊息,請確保由 10 個字或以上組成" + sso_overrides_bio: "在用戶頁面中覆蓋用戶的個人信息並禁止用戶修改" + sso_overrides_email: "每一次登錄時,用 SSO 信息中的外部站點的郵件地址覆蓋本地郵件地址,並且阻止本地的郵件地址修改。(警告:因格本地郵件的正規化,郵件地址可能會有所差異)" + sso_overrides_username: "每一次登錄時,用 SSO 信息中的外部站點的用戶名覆蓋本地用戶名,並且阻止本地的用戶名修改。(警告:因格本地用戶名的長度和其他要求,用戶名可能會有所差異)" + sso_overrides_name: "每一次登錄時,用 SSO 信息中的外部站點的全名覆蓋本地全名,並且阻止本地的全名修改。" sso_overrides_avatar: "用 SSO 訊息中的外部網站頭像覆蓋用戶頭像。如果啟用,建議禁用 allow_uploaded_avatars" + sso_not_approved_url: "重定向未受許可的單點登錄賬號至這個 URL" + sso_allows_all_return_paths: "不限制 SSO 提供的 return_paths 中的域名(預設情況下返回地址必須位於當前站點)" enable_local_logins: "啟用網站用戶名稱和密碼驗證 ( 注意:這必須啟用邀請才能有動作 )" allow_new_registrations: "允許新用戶註冊,如果取消選取,則沒有人能夠註冊" + enable_signup_cta: "顯示推薦創建賬戶的提示給那些回訪的未註冊用戶。" enable_yahoo_logins: "啟用雅虎(Yahoo)帳號驗證登入" enable_google_oauth2_logins: "啟用 Google Oauth2 認證。這是目前 Google 支援的認證方式,需要 key 以及 secret。" google_oauth2_client_id: "你的 Google 應用程式的客戶端 ID" @@ -580,19 +911,33 @@ zh_TW: enable_twitter_logins: "啟用推特(Twitter)帳號驗證登入,需要 twitter_consumer_key 和 twitter_consumer_secret" twitter_consumer_key: "推特帳號驗證的客戶密匙(Consumer key),到 http://dev.twitter.com 來註冊獲取" twitter_consumer_secret: "推特帳號驗證的客戶密碼(Consumer secret),到 http://dev.twitter.com 來註冊獲取" + enable_instagram_logins: "啟用 Instagram 驗證,需要 instagram_consumer_key 和 instagram_consumer_secret" + instagram_consumer_key: "Instagram 驗證的 Consumer key" + instagram_consumer_secret: "Instagram 驗證的 Consumer secret" enable_facebook_logins: "啟用臉書(Facebook)帳號驗證登入,需要 facebook_app_id 和 facebook_app_secret" facebook_app_id: "臉書帳號驗證的應用帳號(App id),到 https://developers.facebook.com/apps 來註冊獲取" facebook_app_secret: "臉書帳號驗證的應用密碼(App secret),到 https://developers.facebook.com/apps 來註冊獲取" + facebook_request_extra_profile_details: "從 Facebook 中請求關於我、地點和網站。(需要 Facebook 許可你的登錄應用)" enable_github_logins: "啟用 Github 帳號驗證登入,需要 github_client_id 和 github_client_secret" github_client_id: "Github 帳號驗證的用戶端帳號(Client id),到 https://github.com/settings/applications 來註冊獲取" github_client_secret: "Github 帳號驗證的用戶端密碼(Client secret),到 https://github.com/settings/applications 來註冊獲取" + readonly_mode_during_backup: "備份時啟用只讀模式" allow_restore: "允許還原資料,注意此動作可能覆蓋「所有」網站資料!除非你計畫還原備份檔,否則請保持此設定為 false" maximum_backups: "磁碟備份的最大數量,舊的將會自動刪除" + automatic_backups_enabled: "按照定義的備份頻率運行自動備份計劃" + backup_frequency: "自動創建站點備份的頻率,以天為單位。" enable_s3_backups: "當完成備份後上傳備份到 S3。重要:需要在文件設定中填寫有效的 S3 驗證資料。" s3_backup_bucket: "遠端備份 bucket ,注意:請確定是私有的 bucket" + s3_disable_cleanup: "當在本地刪除備份時不刪除 S3 上的備份。" + backup_time_of_day: "備份的 UTC 時間" + backup_with_uploads: "在備份日程中包括上傳。關閉此項僅備份資料庫。" active_user_rate_limit_secs: "更新“最後一次見到”資料的頻率,單位為秒" verbose_localization: "在界面上顯示詳細的本地化提示" previous_visit_timeout_hours: "系統判斷一次瀏覽之後多少小時後為“上一次”瀏覽" + top_topics_formula_log_views_multiplier: "熱門主題公式中訪問次數因子的值(n):`log(views_count) * (n) + op_likes_count * 0.5 + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" + top_topics_formula_first_post_likes_multiplier: "熱門主題公式中首貼讚的數量的因子的值(n):`log(views_count) * 2 + op_likes_count * (n) + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" + top_topics_formula_least_likes_per_post_multiplier: "熱門主題公式中贊和帖子數量的比例的最小值(n):`log(views_count) * (n) + op_likes_count * 0.5 + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" + rebake_old_posts_count: "每 15 分鐘重制老帖子的數量。" rate_limit_create_topic: "建立新討論話題之後,用戶必須間隔多少秒 (n) 才能再建立新討論話題" rate_limit_create_post: "建立新文章之後,用戶必須間隔多少秒 (n) 才能再建立新文章" rate_limit_new_user_create_topic: "建立一個話題後,新用戶必須等待 (n) 秒才能建立另一個新話題" @@ -604,8 +949,13 @@ zh_TW: max_topics_per_day: "每個用戶每天最多建立\"討論話題\"的數量" max_private_messages_per_day: "用戶每天能建立訊息的數量上限" max_invites_per_day: "每個用戶每天最多能邀請用戶的數量。" + max_topic_invitations_per_day: "每個用戶每天能創建的邀請至主題數量的最大值。" + alert_admins_if_errors_per_minute: "激活管理員警告的每分鐘錯誤的數量。0 會禁用這個特性。注意:需要重啟。" + alert_admins_if_errors_per_hour: "激活管理員警告的每小時錯誤的數量。0 會禁用這個特性。注意:需要重啟。" + categories_topics: "/categories 頁面中顯示的主題數。" suggested_topics: "討論話題下的推薦話題數量" limit_suggested_to_category: "目前的話題下只顯示同分類的推薦話題" + suggested_topics_max_days_old: "推薦主題創建時間不能大於 n 天。" clean_up_uploads: "移除孤立的已上傳檔案。警告:你可能想要在啟用這個設定前備份 /uploads 文件夾。" clean_orphan_uploads_grace_period_hours: "刪除孤立的上傳檔案的寬限期(單位:小時)" purge_deleted_uploads_grace_period_days: "徹底刪除孤立的上傳檔案的寬限期(單位:天)" @@ -616,8 +966,18 @@ zh_TW: s3_access_key_id: "上傳至 Amazon S3 的 access key id,將用於上傳圖片" s3_secret_access_key: "上傳至 Amazon S3 的 secret access key,將用於上傳圖片" s3_region: "上傳至 Amazon S3 的 region name,將用於上傳圖片" + s3_cdn_url: "用戶 S3 資料的 CDN URL(例如:https://cdn.somewhere.com)。警告:在改變該設置後你必須重制所有老帖子。" + avatar_sizes: "自動生成的頭像大小列表。" + external_system_avatars_enabled: "使用外部系統頭像服務。" + external_system_avatars_url: "外部系統頭像服務的 URL 地址。可選參數是 {username} {first_letter} {color} {size}" + default_opengraph_image_url: "opengraph圖像的預設URL。" + twitter_summary_large_image_url: "預設 Twitter summary 卡片的 URL(需要至少寬 280px 和高 150px)。" + allow_all_attachments_for_group_messages: "允許群組消息中包含任何郵件附件。" + convert_pasted_images_to_hq_jpg: "將粘貼圖片轉為高質量 JPG 檔案。" + convert_pasted_images_quality: "轉換過的 JPG 檔案質量(1 是最低,100 最高質量)。" enable_flash_video_onebox: "在 Onebox 啟用嵌入 swf 和 flv (Adobe Flash) 的鏈接。警告:可能增加安全風險。" default_invitee_trust_level: "預設的受邀用戶等級 (0-4)" + default_trust_level: "所有新用戶的預設信任等級(0-4)。警告!改變此項將提高廣告氾濫的風險。" tl1_requires_topics_entered: "新用戶升級到信任等級1所需要進入的主題數量。" tl1_requires_read_posts: "新用戶升級到信任等級1所需要閱讀的帖子數量。" tl1_requires_time_spent_mins: "新用戶升級到信任等級1所需要閱讀帖子消耗的時間(分鐘)。" @@ -628,37 +988,59 @@ zh_TW: tl2_requires_likes_received: "一個初級用戶升級到信任等級2所需要獲得的讚賞數。" tl2_requires_likes_given: "初級用戶升級到信任等級2所需要付出的讚賞數。" tl2_requires_topic_reply_count: "一個初級用戶升級到信任等級2所需要回覆的主題數量。" + tl3_time_period: "信任等級3考察期限(天數)" + tl3_requires_days_visited: "要升到信任等級3所需要的,在最近考察時間段內訪問的最低天數。將其設置為高於信任等級3的考察時間可禁用信任等級 3。(設置為 0 或比考察期更長)" + tl3_requires_topics_replied_to: "要升到信任等級3所需要的,在最近考察時間段內回覆的主題數量。(設置為 0 或更高)" + tl3_requires_topics_viewed: "要升到信任等級3所需要的,在最近考察時間段內所查看的新主題的百分比。將其設置為高於信任等級3的考察時間可禁用信任等級 3。(設置為 0 到 100)" + tl3_requires_topics_viewed_cap: "要升到信任等級3所需要的,在最近考察時間段內所需查看的主題數上限,與百分比計算後取最小。" + tl3_requires_posts_read: "要升到信任等級3所需要的,在最近考察時間段內所查看的新主題的百分比。將其設置為高於信任等級3的考察時間可禁用信任等級 3。(設置為 0 或比考察期更長)" + tl3_requires_posts_read_cap: "要升到信任等級3所需要的,在最近考察時間段內所需查看的帖子數上限,與百分比計算後取最小。" tl3_requires_topics_viewed_all_time: "用戶升至信任等級3所需查看的最少主題數量。" tl3_requires_posts_read_all_time: "用戶升至信任等級3所需查看的最少帖子數量。" + tl3_requires_max_flagged: "要升到信任等級3所需要的,在最近考察時間段內,用戶不得被 x 個不同用戶標記 x 篇帖子的 x 值。(設置為 0 或更高)" tl3_promotion_min_duration: "信任等級3的用戶可被降級至信任等級2前最少持續天數。" + tl3_requires_likes_given: "要升到信任等級3所需要的,在最近考察時間段內用戶必須要給出的贊(設置為 0 或更高)" + tl3_requires_likes_received: "要升到信任等級3所需要的,在最近考察時間段內用戶必須要收到的贊(設置為 0 或更高)" tl3_links_no_follow: "禁止從信任等級 3 之用戶所發表的連結中刪除 rel=nofollow 標籤" min_trust_to_create_topic: "建立話題最低所需的信任等級" min_trust_to_edit_wiki_post: "編輯被標示為維基的文章所需之最低信任等級。" + min_trust_to_edit_post: "能編輯帖子的最小信任等級。" + min_trust_to_allow_self_wiki: "用戶將自己的帖子設置為維基模式的最低信任等級。" + min_trust_to_send_messages: "發送消息所需的最低信任等級。" newuser_max_links: "新用戶可添加多少連結於一篇文章中" newuser_max_images: "新用戶可添加多少張圖片於一篇文章中" newuser_max_attachments: "新用戶可添加多少附件於一篇文章中" newuser_max_mentions_per_post: "新用戶可以在一個帖子裡使用@name提及的最大數量。" newuser_max_replies_per_topic: "直至有人回覆他們前,新用戶在一個帖子裡的最大回覆數量。" max_mentions_per_post: "你可以在一個帖子裡使用 @name 提及的最大數量。" + max_users_notified_per_group_mention: "當群組被提及時,接受提醒的最大用戶數 ( 超過閾值後將不發送提醒 )" create_thumbnails: "為太大而無法在帖子裡正常顯示的圖片創造縮略圖及 lightbox 圖片。" email_time_window_mins: "等待多少 (n) 分鐘才給用戶發送通知電子郵件,好讓他們有機會自己來編輯和完善他們的帖子。" + private_email_time_window_seconds: "等待多少(n)秒再給用戶發送通知電子郵件,這可以讓用戶有時間來編輯和完善他們的消息。" email_posts_context: "在通知電郵中包含的作為上下文的回覆數量。" flush_timings_secs: "刷新時間資料的頻率,以秒為單位" + title_max_word_length: "在主題的標題中,允許的詞語長度的最大字元數。" title_min_entropy: "在主題的標題中,允許的最低熵值(單字)。" body_min_entropy: "在一個帖子內文中,允許的最低熵值(單字)。" + allow_uppercase_posts: "允許標題和內容全大寫" title_fancy_entities: "轉換討論話題標題中的 HTML 實體" min_title_similar_length: "開始檢查相似主題的帖子標題的最少長度。" min_body_similar_length: "開始檢查相似主題的帖子內容的最小長度。" + desktop_category_page_style: "/categories 頁面的視覺樣式。" category_colors: "設定分類顏色的十六進制色彩值列表。" category_style: "分類圖標的視覺樣式。" max_image_size_kb: "允許用戶上傳的最大圖片大小(以kB為單位)。確保也在nginx(client_max_body_size),apache 或代理中進行限制文件大小的設定。" max_attachment_size_kb: "允許用戶上傳的最大文件大小(以kB為單位)。確保也在nginx(client_max_body_size),apache 或代理中進行限制文件大小的設定。" authorized_extensions: "允許上傳文件的副檔名列表('*' 表示允許所有文件類型)" max_similar_results: "當用戶撰寫新主題時,顯示多少類似主題給用戶。比較根據標題和內容進行。" + max_image_megapixels: "圖像所允許的最大百萬畫素數質。" title_prettify: "防止常見標題裡的錯別字和錯誤,包括全部大寫,首字小寫,多個!和?,結尾多餘的. 等等。" topic_views_heat_low: "多少次瀏覽後,該視圖將稍稍高亮。" topic_views_heat_medium: "多少次瀏覽後,該視圖將明顯高亮。" topic_views_heat_high: "多少次瀏覽後,該視圖將強烈高亮。" + cold_age_days_low: "在討論開始多少天后,最後活躍日期將輕微暗淡。" + cold_age_days_medium: "在討論開始多少天后,最後活躍日期將明顯暗淡。" + cold_age_days_high: "在討論開始多少天后,最後活躍日期將顯著暗淡。" history_hours_low: "帖子在編輯後編輯指示器輕微高亮的小時數" history_hours_medium: "帖子在編輯後編輯指示器明顯高亮的小時數" history_hours_high: "帖子在編輯後編輯指示器強烈高亮的小時數" @@ -668,38 +1050,196 @@ zh_TW: faq_url: "如果你的 FAQ 文件存放在外部,那麼請在此填寫其完整的 URL 地址。" tos_url: "如果你想要使用一個部署在某個地方的服務條款文檔,那麼請在此填寫其完整URL地址。" privacy_policy_url: "如果你想要使用一個部署在某個地方的隱私政策文檔,那麼請在此填寫其完整URL地址。" + newuser_spam_host_threshold: "新用戶能添加至指向同一主機的連結的 newuser_spam_host_threshold 次數。超過閾值後將用戶視為垃圾投遞者。" white_listed_spam_host_domains: "域名的白名單列表,新用戶可以任意連結到這些主機,而不會因防止廣告的測試過濾被檔下" staff_like_weight: "管理員按讚時所給予的額外加權係數。" + topic_view_duration_hours: "按照每 IP/用戶每 N 小時來記錄一次新的主題訪問" + user_profile_view_duration_hours: "按照每 IP/用戶每 N 小時來記錄用戶資料訪問數" levenshtein_distance_spammer_emails: "當比對廣告Email時,數字與文字將仍使用模糊比對" max_new_accounts_per_registration_ip: "如果已經有了從這個 IP 創建的 (n) 個信任等級0的賬戶(並且沒有一個是職員或者是信任等級2以上的用戶),不再允許來自該 IP 地址的註冊請求。" min_ban_entries_for_roll_up: "當點擊折疊按鈕且不少於 (N) 條記錄時,將會創建一個子網禁止記錄。" max_age_unmatched_emails: "在 (N) 天後刪除不匹配的電郵地址。" max_age_unmatched_ips: "在 (N) 天後刪除不匹配的 IP 記錄。" + num_flaggers_to_close_topic: "要自動終止一個主題的討論並介入時所需的最小數量的獨立標記者" + num_flags_to_close_topic: "要自動終止一個主題的討論並介入時所需的最小數量的有效標記" auto_respond_to_flag_actions: "啟用自動回覆當加入一個標籤。" + min_first_post_typing_time: "用戶發表第一帖時打字的最小時間(以毫秒計),如果沒有達到該閾值,帖子將自動進入需要批准隊列。設置為 0 禁用(不推薦)" + auto_block_fast_typers_on_first_post: "自動封禁沒有達到首貼輸入時間 min_first_post_typing_time 要求的用戶" + auto_block_fast_typers_max_trust_level: "自動封禁輸入過于快速的用戶的最高信任等級" + auto_block_first_post_regex: "大小寫不相關的正則表達式,如果匹配成功,會導致該用戶不能發表第一帖,而是進入審核隊列。例如:求下載|謝謝樓[主豬],會阻止包含求下載、謝謝樓主或謝謝樓豬的帖子。該選項只適用於首貼。" reply_by_email_enabled: "啟用通過電郵回覆。" + reply_by_email_address: "通過郵件回覆的回覆地址模板,例如:%{reply_key}@reply.example.com 或 replies+%{reply_key}@example.com" + alternative_reply_by_email_addresses: "通過郵件回覆的回覆地址模板,例如:%{reply_key}@reply.example.com|replies+%{reply_key}@example.com" + incoming_email_prefer_html: "對進站郵件優先使用 HTML 而不是純文字檔案。可能導致格式問題。" + disable_emails: "禁止 Discourse 發送任何郵件" + strip_images_from_short_emails: "忽略郵件中小於 2800 位元組的圖片" + short_email_length: "短郵件地址長度(以比特作為單位)" + display_name_on_email_from: "在郵件的來自欄顯示暱稱" + unsubscribe_via_email: "允許用戶在發送的郵件“退訂”來退訂郵件訂閲,“退訂”可在主題或正文中。" + unsubscribe_via_email_footer: "在發出的郵件底部包含退訂連結" + delete_email_logs_after_days: "在(N)天后刪除郵件日誌。設置為 0 無限期保留" + max_emails_per_day_per_user: "每日發送給用戶的最大帖子數量。設置為 0 禁止限制" + enable_staged_users: "處理進站郵件時自動創建暫存用戶。" + maximum_staged_users_per_email: "處理進站郵件時可創建的最大暫存用戶量。" + auto_generated_whitelist: "不會被檢查是否是自動生成內容的郵件地址列表。例如:foo@bar.com|discourse@bar.com" + block_auto_generated_emails: "阻止被檢測為自動生成的進站郵件。" + ignore_by_title: "使用正則表達式根據標題忽略進站郵件。" + mailgun_api_key: "用以驗證 webhook 消息的 Mailgun 密鑰 API。" + soft_bounce_score: "當碰到臨時拒信時,增加用戶的累計退信分值。" + hard_bounce_score: "當碰到永久拒信時,增加用戶的累計退信分值。" + bounce_score_threshold: "停止發送郵件給用戶的累計退信分值。" + bounce_score_threshold_deactivate: "取消激活用戶的累計退信分值。" + reset_bounce_score_after_days: "自動在 X 天后重置累計退信分值。" + attachment_content_type_blacklist: "基于 content type 禁止附件的黑名單列表。" + attachment_filename_blacklist: "基于檔案名禁止附件的黑名單列表。" + enable_forwarded_emails: "[測試] 允許用戶通過抄送郵件發表主題。" + always_show_trimmed_content: "總是顯示進站郵件中被截斷的部分。警告:可能顯示某些郵件地址。" + manual_polling_enabled: "用 API 推送郵件回覆。" + pop3_polling_enabled: "輪詢 POP3 收取郵件回覆。" + pop3_polling_ssl: "連接至 POP3 伺服器時使用 SSL。(推薦)" + pop3_polling_openssl_verify: "驗證伺服器的 TLS 證書(預設:啟用)" + pop3_polling_period_mins: "查詢用於郵件的 POP3 賬戶的間隔(以分鐘計)。注意:需要重新啟動。" + pop3_polling_port: "POP3 輪詢賬戶連接埠。" + pop3_polling_host: "需用 POP3 向該地址輪詢電子郵件的主機。" + pop3_polling_username: "輪詢 POP3 賬戶所用的用戶名。" + pop3_polling_password: "輪詢 POP3 賬戶所用的密碼。" + log_mail_processing_failures: "記錄所有郵件失敗處理日誌至 http://yoursitename.com/logs" + email_in: "允許用戶通過郵件發表新主題(需要 pop3 輪詢)。在每一個分類的“設置”標籤頁配置地址。" email_in_min_trust: "能使用 EMail 發表新話題的最低的用戶信任等級" email_prefix: "EMail主題中使用的 [ 標籤 ],留空將預設使用 'title'" + email_site_title: "郵件發送人站點標題。如果沒有設置,預設為“title”。如果標題包含了任何不允許的字元,使用這個設置。" + minimum_topics_similar: "在編寫新主題時,需要有多少相似主題存在?" + relative_date_duration: "發表多少天內將顯示相對時間(7天)而非絶對時間(2月20日)。" delete_user_max_post_age: "不允許刪除首發表文章超過 (x) 天的用戶" + delete_all_posts_max: "通過刪除所有帖子按鈕可以刪除的最大帖子數量。如果用戶有比這更多的帖子,這些帖子不能一次性刪除並且這個用戶不能被刪除。" + username_change_period: "用戶在註冊多少天內可以更改他們的用戶名(0 表示禁用用戶名更改)" email_editable: "允許用戶在註冊後改變他們的 EMail" + logout_redirect: "登出後重定向至的地址。(如:http://somesite.com/logout)" + allow_uploaded_avatars: "允許用戶上傳自定義個人頭像。" + allow_animated_avatars: "允許用戶使用動畫個人頭像。警告:更改設置後運行 avatars:refresh 這個 rake 任務。" allow_animated_thumbnails: "為 gif 動畫生成動態縮略圖。" default_avatars: "新用戶將會使用的默認頭像的網址。" automatically_download_gravatars: "當用戶註冊或更改EMail時下載 Gravatars 圖片" + digest_topics: "郵件摘要中顯示的流行主題的最大數目。" + digest_posts: "郵件摘要中顯示的最流行帖子的數量。" + digest_other_topics: "郵件摘要中“你關注的主題和分類中的新內容”欄目顯示的主題數目上限。" + digest_min_excerpt_length: "郵件摘要中顯示的帖子摘要字元數下限。" + delete_digest_email_after_days: "不發送摘要郵件給超過(n)天沒訪問的用戶。" + digest_suppress_categories: "不在摘要郵件中顯示這些分類的內容。" + disable_digest_emails: "禁用所有用戶摘要郵件功能。" + email_accent_bg_color: "HTML 郵件中某些元素的背景使用的強調顏色。輸入色彩名(“red”)或十六進制值(“#FF0000”)。" + email_accent_fg_color: "HTML 郵件中背景使用的字型顏色。輸入色彩名(“white”)或十六進制值(“#FFFFFF”)。" + email_link_color: "HTML 郵件中的連結顏色。輸入色彩名字(“blue”)或十六進制值(“#0000FF”)。" + detect_custom_avatars: "檢測用戶是否上傳了自定義個人頭像。" max_daily_gravatar_crawls: "一天內 Discourse 將自動檢查 Gravatar 自訂個人圖示的次數" public_user_custom_fields: "用戶可設定公開顯示的自定欄位白名單。" staff_user_custom_fields: "用戶可設定只給管理員顯示的自定欄位白名單。" + enable_user_directory: "提供可供瀏覽的用戶目錄" + enable_group_directory: "提供可供瀏覽的群組目錄" + allow_anonymous_posting: "允許用戶切換至匿名模式" + anonymous_posting_min_trust_level: "啟用匿名發帖所需的最小信任等級" + anonymous_account_duration_minutes: "為了匿名性,為每個用戶每 N 分鐘創建一個匿名賬戶。例如:如果設置為 600,只要發帖後 600 分鐘到了,並且用戶切換至了匿名模式,就會創建一個新的匿名賬戶。" + hide_user_profiles_from_public: "不對來訪用戶顯示用戶信息卡、用戶資料和用戶目錄。" + user_website_domains_whitelist: "用戶網站要屬於這些域名中。用 | 分割。" allow_profile_backgrounds: "允許使用者上傳個人檔案背景圖片" + sequential_replies_threshold: "在被提醒回覆了太多連續的回覆前,用戶在主題中可以連續回覆的帖子的數量。" + enable_mobile_theme: "為移動設備啟用移動友好的主題,但也能切換回完整站點。如果你想要使用自定義的響應式主題請禁用它。" + dominating_topic_minimum_percent: "用戶在主題中的帖子占到多少百分比時使得用戶主導話題。" + disable_avatar_education_message: "禁用更改頭像操作的教育消息。" suppress_uncategorized_badge: "不在\"無分類\"的話題列表內顯示徽章。" + permalink_normalizations: "在匹配永久連結之前應用如下正則表達式,例如:/(topic.*)\\?.*/\\1 將去掉所有主題路徑的參數字元串。格式為使用正則表達式+使用 \\1 等字元串來訪問捕獲內容" + global_notice: "為所有訪客顯示“緊急的”全局橫幅,留空隱藏它(可以使用 HTML)" + disable_edit_notifications: "當 'download_remote_images_to_local' 啟用時禁用系統編輯提醒。" + automatically_unpin_topics: "當用戶到達底部時自動解除主題置頂。" + read_time_word_count: "一分鐘閲讀的詞的數量,用於估計閲讀時間。" + topic_page_title_includes_category: "主題頁面標題包含分類名。" + native_app_install_banner: "邀請常客安裝 Discourse 本機應用程序" + max_prints_per_hour_per_user: "/print 頁面的每小時最大展示量(設置為 0 禁用)" + full_name_required: "全名是用戶個人信息的必填項。" + enable_names: "在用戶的個人信息、用戶卡片和郵件中顯示全名。禁用將在所有地方隱藏全名。" + display_name_on_posts: "在用戶的帖子中顯示他們的全名以及他們的 @username。" + show_time_gap_days: "如果兩個帖子發表間隔多天,在主題中顯示時間間隔提示。" invites_per_page: "默認在用戶頁顯示的邀請。" + short_progress_text_threshold: "在主題中的帖子數超過這個設定後,進度條將只顯示當前的帖子數。如果你更改了進度條的寬度,你需要修改這個值。" + default_code_lang: "預設語法高亮語言,使用 GitHub 代碼塊(lang-auto、ruby、python或者其他等等。)" + warn_reviving_old_topic_age: "當有人開始回覆最後一貼超過一定天數前的主題時,將有一個警告顯示,不鼓勵他們復活一個老的討論。將其設置為 0 以禁用。" autohighlight_all_code: "即使未顯示特定語言,仍為所有預編排程式套用程式碼顏色提示" + highlighted_languages: "包含語法高亮規則。(警告:包含太多的語言可能影響性能)見:https://highlightjs.org/static/demo/ 查看演示" + feed_polling_enabled: "僅用於嵌入:是否將 RSS/ATOM 訂閲為帖子。" + feed_polling_url: "僅用於嵌入:RSS/ATOM 訂閲的 URL。" + embed_by_username: "創建嵌入主題的 Discourse 的用戶名。" + embed_username_key_from_feed: "從流中獲取 discourse 用戶名的 Key。" + embed_title_scrubber: "抓取嵌入主題的正則表達式。" embed_truncate: "截斷 embed 過的文章" + allowed_href_schemes: "除了 http 和 https 外允許的連結協議。" embed_post_limit: "文章內 embed 的最大數量" + embed_username_required: "創建主題需要用戶名。" embed_whitelist_selector: "在 embeds 頁面允許 CSS 元素選擇器" embed_blacklist_selector: "在 embeds 頁面移除 CSS 元件選擇器" - enable_cdn_js_debugging: "允許 /logs 適當的顯示 crossorigin permissions 所有 js 的錯誤" + notify_about_flags_after: "如果有標記沒有在設定小時後處理,發送一封郵件給 contact_email。設為 0 將禁用。" show_create_topics_notice: "如果網站的公開討論話題少於 5 個,顯示通知要求管理員建立一些討論話題。" + delete_drafts_older_than_n_days: 刪除超過 n 天得草稿。 + bootstrap_mode_min_users: "禁用摘要模式的用戶數下限(0 為禁用)。" + vacuum_db_days: "在資料庫遷移後使用完整掃瞄回收資料庫空間(設置 0 為禁用)" + prevent_anons_from_downloading_files: "禁止匿名用戶下載附件。警告:這將禁止他們訪問任何發表在帖子中的非圖片資源。" + slug_generation_method: "選擇一個連結生成方式。“encoded”將生成以百分號編碼的連結。“none”將禁用自定義連結,只生成預設連結。" enable_emoji: "啟用表情符號" emoji_set: "你會如何喜歡你的表情符號?" enforce_square_emoji: "強制為所有 emojis 設置的正方形比例。" + approve_post_count: "新用戶或基礎用戶需要被審核的帖子數量" + approve_unless_trust_level: "該信任等級之下的用戶的帖子必須被審核" + approve_new_topics_unless_trust_level: "低於該信任等級的用戶的新帖子需要被審核" + notify_about_queued_posts_after: "如果帖子在設定的小時數後仍在等候處理,發送一封郵件至 contact_email。設為 0 將禁用這些郵件。" + auto_close_messages_post_count: "消息中貼子數上限,達到後自動關閉消息(0 為禁用)" + auto_close_topics_post_count: "主題中貼子數上限,達到後自動關閉主題 ( 0 為禁用 )" + code_formatting_style: "編輯器中的代碼格式化按鈕設置的預設格式" + default_email_digest_frequency: "用戶收到摘要郵件的預設頻率。" + default_include_tl0_in_digests: "在摘要郵件中預設包含新用戶帖子。用戶可以自行在參數設置中更改這個設置。" + default_email_private_messages: "預設在有人發消息給用戶時發送一封郵件通知。" + default_email_direct: "預設在有人引用、回覆、提及或者邀請用戶時發送一封郵件通知。" + default_email_mailing_list_mode: "預設為每一個新帖子發送一封郵件通知。" + default_email_mailing_list_mode_frequency: "郵件列表模式下,用戶收到郵件的預設頻率。" + disable_mailing_list_mode: "禁止用戶使用郵件列表模式。" + default_email_always: "即使用戶活躍時,仍預設發送郵件通知。" + default_email_previous_replies: "預設在郵件中包含之前的回覆。" + default_email_in_reply_to: "預設在郵件中包含回覆的摘要文本。" + default_other_new_topic_duration_minutes: "近期主題條件的全局預設設置" + default_other_auto_track_topics_after_msecs: "經過多少毫秒之後一個主題就被自動追蹤的全局預設設置" + default_other_notification_level_when_replying: "用戶回覆主題時的全局預設通知等級" + default_other_external_links_in_new_tab: "預設在新的標籤頁打開外部連結" + default_other_enable_quoting: "預設在高亮選擇文字時啟用引用回覆" + default_other_dynamic_favicon: "預設在瀏覽器表徵圖上顯示新/更新的主題數量" + default_other_disable_jump_reply: "預設不在用戶回覆後跳轉到新帖子位置" + default_other_like_notification_frequency: "預設通知用戶讚的消息" + default_topics_automatic_unpin: "預設時當用戶到達底部時自動解除主題置頂。" + default_categories_watching: "分類列表預設跟蹤。" + default_categories_tracking: "分類列表預設追蹤。" + default_categories_muted: "分類列表預設不顯示。" + default_categories_watching_first_post: "預設監看這些分類中每個新主題的第一貼" + max_user_api_reqs_per_day: "用戶API每日每密鑰最高請求數" + max_user_api_reqs_per_minute: "用戶API每密鑰每分鐘最高請求數" + allow_user_api_keys: "允許生成用戶API密鑰" + allow_user_api_key_scopes: "用戶API授權範圍列表" + max_api_keys_per_user: "每用戶最多持有的用戶 API 數" + min_trust_level_for_user_api_key: "生成用戶 API 密鑰所需的信任等級" + allowed_user_api_auth_redirects: "允許用戶 API 密鑰重定向授權至" + allowed_user_api_push_urls: "允許使用伺服器推送至用戶 API 的 URL" + tagging_enabled: "啟用標籤功能,允許為主題設置標籤?" + min_trust_to_create_tag: "創建標籤所需的最小信任等級。" + max_tags_per_topic: "主題最多允許有多少個標籤。" + max_tag_length: "標籤允許的最大字元數。" + max_tag_search_results: "當搜索標籤時,顯示的結果數上限。" + show_filter_by_tag: "顯示下拉菜單以按照標籤過濾主題列表。" + max_tags_in_filter_list: "過濾菜單中顯示的標籤數上限。優先顯示最常用的標籤。" + tags_sort_alphabetically: "按照字母順序顯示標籤。預設按流行度顯示。" + tag_style: "標籤的視覺樣式。" + staff_tags: "只可由管理人員使用的標籤列表" + min_trust_level_to_tag_topics: "給主題加標籤的最小信任等級" + suppress_overlapping_tags_in_list: "如果標籤匹配了主題標題中的詞,不顯示該標籤" + remove_muted_tags_from_latest: "在最新主題列表中,不顯示有靜音標籤的主題。" + company_short_name: "公司名(短)" + company_full_name: "公司名(全)" + company_domain: "公司域名" errors: invalid_email: "無效的電子郵件地址" invalid_username: "沒有用戶使用該用戶名稱。" @@ -713,121 +1253,844 @@ zh_TW: invalid_string_min_max: "必須介於 %{min} 到 %{max} 字之間。" invalid_string_min: "必須至少 %{min} 個字。" invalid_string_max: "不能超過 %{max} 個字。" + invalid_reply_by_email_address: "值必須包含 '%{reply_key}' 並且要與通知郵件不同。" + invalid_alternative_reply_by_email_addresses: "必須包括 “%{reply_key}” 並與通知郵件地址不同。" + pop3_polling_host_is_empty: "在啟用 POP3 輪詢前,你必須設置 'pop3 polling host'。" + pop3_polling_username_is_empty: "在啟用 POP3 輪詢前,你必須設置 'pop3 polling username'。" + pop3_polling_password_is_empty: "在啟用 POP3 輪詢前,你必須設置 'pop3 polling password'。" + pop3_polling_authentication_failed: "POP3 驗證失敗。請驗證你的 pop3 賬戶信息。" + reply_by_email_address_is_empty: "在啟用郵件回覆之前,你必須設置“reply by email address”。" + email_polling_disabled: "在啟用郵件回覆功能前,你必須啟用手動或者 POP3 輪詢。" + user_locale_not_enabled: "你必須先設置 'allow user locale' 再啟用該設置。" + invalid_regex: "正則表達式非法或者不允許。" search: + within_post: "#{{post_number}} 由 {{username}}" types: category: '分類' topic: '結果' user: '用戶' + sso: + not_found: "無法找到你的賬戶。請聯繫站點管理人員。" + account_not_approved: "你的帳號尚未被審核通過。一旦你的帳號獲得批准,你就會收到一封電子郵件提醒。" + unknown_error: "你的賬戶發生了問題。請聯繫站點管理人員。" + timeout_expired: "賬戶登錄超時,請重新嘗試登錄。" original_poster: "原始作者" most_posts: "大部分文章" most_recent_poster: "當前大部分文章作者" frequent_poster: "頻繁發文者" + redirected_to_top_reasons: + new_user: "歡迎來到我們的社區!這是我們最近的熱門主題。" + not_seen_in_a_month: "歡迎回來!我們已經好久沒見到你了。這些是你不在時的最熱門主題。" + merge_posts: + edit_reason: + other: "%{username}合併了 %{count} 個帖子" + errors: + different_topics: "無法合並不同主題的帖子。" + different_users: "無法合並不同用戶的帖子。" + move_posts: + new_topic_moderator_post: + other: "%{count} 個帖子被分離到了新主題:%{topic_link}" + existing_topic_moderator_post: + other: "%{count} 個帖子被合併到現存主題:%{topic_link}" change_owner: post_revision_text: "所有權從 %{old_user} 轉移至 %{new_user}" + deleted_user: "已經刪除的用戶" + emoji: + errors: + name_already_exists: "抱歉,名字 '%{name}' 已經被另一個 emoji 使用。" + error_while_storing_emoji: "抱歉,存儲 emoji 時發生錯誤。" topic_statuses: archived_enabled: "此討論話題已封存,即已經凍結,無法修改。" archived_disabled: "此討論話題已被解除封存,即不再凍結,可以修改。" closed_enabled: "此討論話題已關閉,不再接受新的回覆。" closed_disabled: "此討論話題已開放,可以發表新的回覆。" + autoclosed_message_max_posts: + other: "消息中回覆已經達到上限 %{count},自動鎖定。" + autoclosed_topic_max_posts: + other: "主題中回覆已經達到上限 %{count},自動關閉。" + autoclosed_enabled_days: + other: "該主題在創建%{count}天后自動關閉。不再允許添加新回覆。" + autoclosed_enabled_hours: + other: "該主題在創建%{count}小時後自動關閉。不再允許新的回覆。" + autoclosed_enabled_minutes: + other: "該主題在創建%{count}分鐘後自動關閉。不再允許新的回覆。" + autoclosed_enabled_lastpost_days: + other: "該主題在最後一個回覆創建後%{count}天后自動關閉。不再允許新的回覆。" + autoclosed_enabled_lastpost_hours: + other: "該主題在最後一個回覆創建後%{count}小時後自動關閉。不再允許添加新回覆。" + autoclosed_enabled_lastpost_minutes: + other: "本主題在最後一個回覆創建後%{count}分鐘後自動鎖定。不再允許添加新回覆。" autoclosed_disabled: "此討論話題已開放,可以發表新的回覆。" + autoclosed_disabled_lastpost: "本主題現在開放了。可以添加新的回覆。" + pinned_enabled: "本主題已置頂,它將始終顯示在它所屬分類的頂部。可由管理人員對所有人解除置頂,或者由用戶自己取消置頂。" pinned_disabled: "此討論話題已被解除置頂,它將不再顯示在它所屬分類的頂部。" + pinned_globally_enabled: "本主題已全局置頂,它將始終顯示在它所屬分類的頂部。可由管理人員對所有人解除置頂,或者由用戶自己取消置頂。" pinned_globally_disabled: "本主題已被解除置頂,它將不再置頂於所屬分類" + visible_enabled: "本主題已設置為顯示在主題列表中。" + visible_disabled: "本主題設置為不顯示在主題列表中。只能通過直達連結來訪問。" login: not_approved: "你的帳號尚未獲得批准。一旦你的帳號獲得批准,你會收到一封電子郵件。" incorrect_username_email_or_password: "用戶名、電子郵箱或密碼不正確" wait_approval: "謝謝註冊帳號。我們會在你的帳號獲得批准之後通知你。" active: "你的帳號已經被啟用,可以使用了。" + activate_email: "

    快完成了!我們發送了一封激活郵件到%{email}。請按照郵件中的步驟來激活你的帳號。

    如果你沒有收到郵件,請檢查你的垃圾郵件收件箱,或者試試再登錄一次,看看能不能收到另一封激活郵件。

    " not_activated: "你還不能登入。我們發送了一封啟用郵件給你,請按照郵件中的步驟來啟用你的帳號。" not_allowed_from_ip_address: "你無法透過此 IP 登入成為 %{username}。" admin_not_allowed_from_ip_address: "你無法透過此 IP 登入成為管理員。" suspended: "你在 %{date} 之前無法登入。" + suspended_with_reason: "賬號暫停至%{date}: %{reason}" errors: "%{errors}" not_available: "不可用,試試 %{suggestion}?" something_already_taken: "出了一些問題,可能此用戶名或電子郵箱已經被註冊。試試 忘記密碼 連結吧。" + omniauth_error: "抱歉,在驗證你的帳號時發生了錯誤。可能你沒有批准授權申請?" omniauth_error_unknown: "在處理你的登入過程中發生了錯誤,請重試。" + authenticator_error_no_valid_email: "關聯%{account}的賬戶沒有優秀的郵件地址。你可能需要用不同的郵件地址配置你的賬戶。" new_registrations_disabled: "現在不允許註冊新的帳戶" password_too_long: "密碼不能超過 200 個字符。" + email_too_long: "你輸入的郵件太長了。郵箱名不得超過 254 字元,域名必須不超過 253 字元。" + reserved_username: "該用戶名不可被使用。" missing_user_field: "你還沒有填寫完所有用戶字段" close_window: "驗證已經完成。關閉視窗以繼續。" + already_logged_in: "喔,看起來你正嘗試查看給另一個用戶的邀請連結。如果你不是%{current_user},請退出再重試。" user: no_accounts_associated: "無關聯的帳戶" + deactivated: "因發送至“%{email}”的郵件被多次退信,取消激活" + deactivated_by_staff: "已由管理員撤銷" + activated_by_staff: "已由管理員啟動" username: short: "必須至少 %{min} 個字" long: "不能超過 %{max} 個字" characters: "必須只包含字母和數位" unique: "必須是唯一的" blank: "必須存在" + must_begin_with_alphanumeric_or_underscore: "必須以字母、數字或下劃線開頭" + must_end_with_alphanumeric: "必須以字母或數字結尾" + must_not_contain_two_special_chars_in_seq: "必須不包括連續的 2 個或更多的特殊字元(.-_)" + must_not_end_with_confusing_suffix: "不能以難以分辨的尾碼結尾,比如 .json 或者 .png 等" email: not_allowed: "本站不允許使用該郵箱服務商提供的電子郵箱,請使用其它郵箱位址。" blocked: "不被允許。" + revoked: "在%{date}之前不發送郵件至“%{email}”" + ip_address: + blocked: "不允許從你的 IP 地址註冊新用戶。" + max_new_accounts_per_registration_ip: "不允許從你的 IP 地址註冊新用戶(達到上限)。聯繫一個管理人員。" + website: + domain_not_allowed: "網站無效。允許的域名有:%{domains}" + flags_reminder: + flags_were_submitted: + other: "這些標記在過去 %{count} 小時內被提交。請審核他們。" + subject_template: + other: "%{count} 個標記需要被處理" + unsubscribe_mailer: + title: "取消訂閱 Mailer" + subject_template: "確認你不想要收到%{site_title}的電子郵件更新" + text_body_template: | + 有人(可能是你?)請求不再接受來自%{site_domain_name}的郵件更新。 + 點擊連結以確認退訂: + + %{confirm_unsubscribe_link} + + + 如果你想要繼續接受郵件更新,你可以忽略這封郵件。 invite_mailer: + title: "邀請 Mailer" subject_template: "%{invitee_name} 邀請你參與在 %{site_domain_name} 討論的話題 '%{topic_title}'" + text_body_template: | + %{invitee_name} 邀請你參與討論 + + > **%{topic_title}** + > + > %{topic_excerpt} + + 位於站點 + + > %{site_title} -- %{site_description} + + 如果你有興趣,點擊下面的連結: + + %{invite_link} + + 這封邀請來組于受信任的用戶,所以你可以立即回覆。 + custom_invite_mailer: + title: "客製邀請 Mailer" + subject_template: "%{invitee_name}邀請你'%{topic_title}'在%{site_domain_name}" + text_body_template: | + %{invitee_name}邀請你參與 + + > %{site_title} -- %{site_description} + + 中的 + + > **%{topic_title}** + > + > %{topic_excerpt} + + %{invitee_name}的留言: + + %{user_custom_message} + + 如果你有興趣,點擊下面的連結: + + %{invite_link} + + 這封邀請發自受信任的用戶,所以你可以立即回覆主題。 invite_forum_mailer: + title: "邀請論壇 Mailer" subject_template: "%{invitee_name} 邀請你加入 %{site_domain_name}" + custom_invite_forum_mailer: + title: "邀請論壇 Mailer" + subject_template: "%{invitee_name}邀請你加入%{site_domain_name}" invite_password_instructions: + title: "邀請密碼的說明" subject_template: "為 %{site_name} 的帳戶設置密碼" + text_body_template: | + 感謝你接受來自%{site_name}的邀請——歡迎! + + 點擊下面的連結立即選擇一個密碼: + %{base_url}/users/password-reset/%{email_token} + + (如果連結已經過期,在登錄時用,選擇“我忘記了密碼”,再次輸入你的郵箱即可。) test_mailer: + title: "測試 Mailer" subject_template: "[%{site_name}] 電子郵件發送測試" + text_body_template: | + 這是一封測試電子郵件,發自: + + [**%{base_url}**][0] + + 電子郵件分發很複雜。以下是一些你應該檢查的重點: + + - 確定你在站點設置中為 `notification email` 設置了正確的地址。**這是系統發送郵件裡的“發自”地址,並需要你的域名配置正確以供相關驗證。**。 + + - 學習使用郵件客戶端查看電子郵件原始碼,這樣你可以通過查看郵件頭部來排查重要線索。在 Gmail 中,可以通過每一封郵件下拉菜單中的“顯示原始消息”來查看。 + + - **重要:** 你的 ISP 是否對你發送郵件的域名和 IP 作了反向 DNS 解析?你可以在此[測試你的反向枚舉指針(PTR)記錄][2]。如果你的 ISP 沒有設置正確的反向 DNS 記錄,那麼很可能你的任何電子郵件都不會被成功發送。 + + - 你的域名的[發件人策略框架(SPF)記錄][8]是否正確?你可以在此[測試你的SPF記錄][1]。注意 TXT 是一種正確的官方 SPF 記錄。 + + - 你域名的[域名密鑰身份識別郵件(DKIM)記錄][3]設置是否正確?這將顯著提高郵件分發的成功率。在此[測試你的 DKIM 記錄][7]。 + + - 如果你自己運行郵件伺服器,檢查確認你發送電子郵件的伺服器 IP [不在任何郵件黑名單中][4]。驗證你的 DNS 記錄的 HELO 消息中設置了符合要求的主機名。如果沒有,那麼會導致很多郵件服務商拒收你的郵件。 + + - 我們強烈建議你**發送測試郵件至 [mail-tester.com][mt]**,這樣可以檢查上述設置是否正確。 + + (最簡單的方法是在 [SendGrid][sg]、[SparkPost][sp]、[Mailgun][mg] 和 [Mailjet][mj]註冊免費賬戶,他們的免費賬戶對一個小社群是足夠的。不過你仍然需要在 DNS 設置中設定 SPF 和 DKIM 記錄!) + + 我們衷心希望你成功完成郵件發送測試! + + 祝好運! + + 你的朋友,[Discourse](http://www.discourse.org) + + [0]: %{base_url} + [1]: http://www.kitterman.com/spf/validate.html + [2]: http://mxtoolbox.com/ReverseLookup.aspx + [3]: http://www.dkim.org/ + [4]: http://whatismyipaddress.com/blacklist-check + [7]: https://www.mail-tester.com/spf-dkim-check + [8]: http://www.openspf.org/SPF_Record_Syntax + [sg]: https://sendgrid.com/ + [sp]: https://www.sparkpost.com/ + [mg]: http://www.mailgun.com/ + [mj]: https://www.mailjet.com/pricing + [mt]: http://www.mail-tester.com/ new_version_mailer: + title: "新版本 Mailer" subject_template: "[%{site_name}] 有可用的新版 Discourse 更新" + text_body_template: | + 哇哦,有新版本的 [Discourse](http://www.discourse.org) 可以升級! + + 你的版本:%{installed_version} + 新的版本:**%{new_version}** + + - 瀏覽器訪問**[一鍵更新工具](%{base_url}/admin/upgrade)**升級。 + + - 查看[GitHub 改動日誌(英文)](https://github.com/discourse/discourse/commits/master)中更新的內容。 + + - 訪問 [meta.discourse.org(英文)](https://meta.discourse.org) 獲取 Discourse 的最新資訊、討論和支持。也可訪問 [meta.discoursecn.org 非官方的中文支持論壇](https://meta.discoursecn.org) 獲得支持。 new_version_mailer_with_notes: + title: "包含提醒的新版本 Mailer" subject_template: "[%{site_name}] 可以升級" + text_body_template: | + 哇哦,有新版本的 [Discourse](http://www.discourse.org) 可以升級! + + 你的版本:%{installed_version} + 新的版本:**%{new_version}** + + - 查看[GitHub 改動日誌(英文)](https://github.com/discourse/discourse/commits/master)中更新的內容。 + + - 瀏覽器訪問**[一鍵更新工具](%{base_url}/admin/upgrade)**升級。 + + - 訪問 [meta.discourse.org(英文)](http://meta.discourse.org) 獲取 Discourse 的最新資訊、討論和支持。也可訪問 [meta.discoursecn.org 非官方的中文支持論壇](http://meta.discoursecn.org) 獲得支持。 + + ### 發行註記 + + %{notes} + queued_posts_reminder: + title: "排定中的文章提醒" + subject_template: + other: "[%{site_name}] %{count} 個帖子等待審核" + text_body_template: | + 你好, + + 新用戶的帖子等待被編輯或審核。[審核通過或者拒絶](%{base_url}/queued-posts)。 + flag_reasons: + off_topic: "你的帖子被標記為 **偏離主題**:鑒於當前的主題標題和第一個帖子,社群成員們感覺它不適合處于這個主題中。" + inappropriate: "你的帖子被標記為 **不恰當**:社群成員感覺它有冒犯或者侮辱的意味,亦或是它違反了[社群準則](/guidelines)。" + spam: "你的帖子被標記為 **廣告**:社群成員覺得它是廣告,像是在過度地推廣着什麼,而不是預期中與主題有關的內容。" + notify_moderators: "你的帖子被標記為 **需要版主關注**:社群成員認為帖子需要管理人員介入。" flags_dispositions: + agreed: "謝謝你的消息。我們認為這是個問題。我們正在進行處理。" + agreed_and_deleted: "感謝通知我們。我們認為這是一個問題,並且我們已經刪除了帖子。" disagreed: "感謝你讓我們知道。我們正在調查。" deferred: "感謝你讓我們知道。我們正在調查。" + deferred_and_deleted: "感謝通知我們。我們已經刪除了帖子。" + temporarily_closed_due_to_flags: "主題因為大量的社群標記暫時關閉" system_messages: + post_hidden: + title: "文章已隱藏" + subject_template: "帖子因社群標記隱藏" + text_body_template: | + 你好, + + 這是%{site_name}自動發出的郵件,通知你的帖子已被隱藏。 + + %{base_url}%{url} + + %{flag_reason} + + 你的帖子是因為被多個社群成員標記才被隱藏的,所以請考慮根據他們的反饋修改你的帖子。**你可以在 %{edit_delay} 分鐘後開始編輯你的帖子,然後它將重新被顯示。** + + 然而,如果帖子再次被社群成員標記並隱藏,它將被隱藏至版主處理後——並且可能導致進一步的措施,如封禁帳號。 + + 想瞭解更多,請查看我們的[社群指引](%{base_url}/guidelines)。 + usage_tips: + text_body_template: "要查看給新用戶的簡要技巧,[(英文)看看這篇博客文章](http://blog.discourse.org/2016/12/discourse-new-user-tips-and-tricks/)。\n\n只要你參與,我們將更瞭解你,並且新用戶的臨時限制將被移除。\b隨着時間,你將獲得[信任等級](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924),這將提供一些特殊功能來幫助我們更好地管理社群。\n" welcome_user: + title: "歡迎使用者" subject_template: "歡迎來到 %{site_name}!" + text_body_template: |+ + 感謝你加入%{site_name},歡迎討論! + + %{new_user_tips} + + 我們相信始終相信[公民社群守則](%{base_url}/guidelines) 。好好享受你在論壇的時光! + + (如果身為新的使用者你需要聯絡[工作人員](%{base_url}/about),請直接回覆本訊息) + welcome_invite: + title: "歡迎邀請" subject_template: "歡迎來到 %{site_name}!" backup_succeeded: + title: "備份成功" subject_template: "備份成功完成" + text_body_template: | + 備份成功。 + + 訪問[管理 > 備份](%{base_url}/admin/backups)下載你的新備份檔案。 + + 以下為日誌: + + ```text + %{logs} + ``` backup_failed: + title: "備份失敗" subject_template: "備份失敗" + text_body_template: | + 備份已經失敗了。 + + 以下是日誌: + + ```text + %{logs} + ``` restore_succeeded: + title: "復原成功" subject_template: "恢復成功完成" + text_body_template: | + 恢復成功。 + + 以下是日誌: + + ``` + %{logs} + ``` restore_failed: + title: "復原失敗" subject_template: "復原失敗" + text_body_template: | + 恢復失敗。 + + 以下是日誌: + + ``` + %{logs} + ``` bulk_invite_succeeded: subject_template: "批次用戶邀請已完成處理" + text_body_template: "你的批量邀請用戶已經完成,發送了 %{sent} 個邀請。" bulk_invite_failed: + title: "批量邀請失敗" subject_template: "批次使用者邀請處理已經完成,發生了些錯誤" + text_body_template: | + 批量邀請已經完成,發出了 %{sent} 個邀請並且 %{failed} 個失敗。 + + 查看日誌: + + ``` + %{logs} + ``` csv_export_succeeded: + title: "CSV 檔匯出成功" subject_template: "資料匯出完成" + text_body_template: | + 數據成功導出!:dvd: + + %{file_name}(%{file_size}) + + 以上的下載連結將在 48 小時後失效。 csv_export_failed: + title: "CSV 檔匯出失敗" subject_template: "資料匯出失敗" + text_body_template: "我們很抱歉,但是你的數據導出請求失敗了。請檢查日誌或聯繫一位管理人員。" + email_reject_insufficient_trust_level: + title: "電子郵件拒絕 信任等級不足" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 信任等級不足" + text_body_template: | + 我們很抱歉,但是你發送至%{destination}(名為 %{former_title})的郵件出問題了。 + + 你的賬戶沒有足夠的信任等級以該郵件地址發佈新主題。如果你有異議,聯繫管理人員。 + email_reject_user_not_found: + title: "電子郵件拒絕 找不到用戶" + subject_template: "[%{site_name}] 郵件問題 -- 用戶未找到" + text_body_template: | + 我們非常抱歉,但是你發送至 %{destination}(名為%{former_title}) 的郵件出問題了。 + + 你發送回覆的郵件地址是未知的郵件地址。試試從另外一個郵件地址發送,或者聯繫管理人員。 + email_reject_screened_email: + title: "電子郵件拒絕 屏蔽的電子郵件地址" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 被封禁的郵件地址" + text_body_template: | + 我們非常抱歉,但是你發送至%{destination}(名為%{former_title})的郵件出問題了。 + + 你發送回覆的郵件地址是已被封禁的郵件地址。試試從另外一個郵件地址發送,或者聯繫管理人員。 + email_reject_inactive_user: + title: "電子郵件拒絕 用戶尚未啟動" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 未激活用戶" + text_body_template: | + 我們非常抱歉,但是你發送至 %{destination}(名為%{former_title}) 的郵件出問題了。 + + 與你賬戶關聯的郵件地址沒有激活,請先激活你的賬號再發送郵件。 + email_reject_blocked_user: + title: "電子郵件拒絕 已封鎖的用戶" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 被封禁的用戶" + text_body_template: | + 我們非常抱歉,但是你發送至 %{destination}(名為%{former_title}) 的郵件出問題了。 + + 與你賬戶關聯的郵件地址已經被封禁。 + email_reject_reply_user_not_matching: + title: "點子郵件拒絕 未找到符合的用戶" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 未預期的回覆地址" + text_body_template: | + 我們非常抱歉,但是你發送至 %{destination}(名為%{former_title}) 的郵件出問題了。 + + 你發送回覆的郵件地址與我們等待的地址不同,所以我們不確定你是不是同一個人。試試從另外一個郵件地址發送,或者聯繫管理人員。 + email_reject_no_account: + title: "電子郵件拒絕 沒有帳號" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 未知賬戶" + text_body_template: | + 我們非常抱歉,但是你發送至 %{destination}(名為%{former_title}) 的郵件出問題了。 + + 我們找不到匹配你郵件地址的賬號。試試從另外一個郵件地址發送,或者聯繫管理人員。 + email_reject_empty: + title: "電子郵件拒絕 空白" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 無內容" + text_body_template: | + 我們很抱歉,但是你發送至 %{destination}(名為 %{former_title})的郵件沒有成功。 + + 我們不能找到你郵件中的任何回覆內容。 + + 如果你**確定**你的郵件中有回覆內容,試試用更簡單的格式。 + email_reject_parsing: + title: "電子郵件拒絕 分析" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 內容無法識別" + text_body_template: | + 我們很抱歉,但是你發送至 %{destination}(名為 %{former_title})的郵件無法發送。 + + 我們不能找到你郵件中的回覆。**請確認將你的回覆置於郵件頂端**——我們不能處理行內回覆。 + email_reject_invalid_access: + title: "電子郵件拒絕 無效存取" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 無權限" + text_body_template: | + 我們很抱歉,但是你發送至%{destination}(名為 %{former_title})的郵件出問題了。 + + 你的賬戶沒有達到足夠的信任等級在該分類發佈新主題。如果你有異議,聯繫管理人員。 + email_reject_strangers_not_allowed: + title: "電子郵件拒絕 陌生人禁止" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 無權限" + text_body_template: |+ + 我們非常抱歉,但是你發送至%{destination}(名為%{former_title})的郵件出問題了。 + + 郵件發至的分類只接受來自合法帳戶且郵件地址已確認的用戶的有郵件。如果你有異議,聯繫管理人員。 + + email_reject_invalid_post: + title: "電子郵件拒絕 無效貼文" + subject_template: "[%{site_name}] 郵件問題 -- 發佈時錯誤" + text_body_template: | + 我們非常抱歉,但是你發送至%{destination}(名為%{former_title})的郵件出問題了。 + + 可能的原因是:複雜的格式、消息超長、消息太短。請再試一次,如果還不行,使用網站發表。 + email_reject_invalid_post_specified: + subject_template: "[%{site_name}] 郵件問題 -- 發佈時錯誤" + text_body_template: | + 我們非常抱歉,但是你發送至%{destination}(名為%{former_title})的郵件出問題了。 + + 原因: + + %{post_error} + + 如果你能解決錯誤,請再試一次。 + email_reject_invalid_post_action: + title: "電子郵件拒絕 無效貼文動作" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 無發表權限" + text_body_template: | + 我們非常抱歉,但是你發送至%{destination}(名為%{former_title})的郵件出問題了。 + + 發送的命令無法被識別。請再試一次,如果還有問題,使用網站發表。 + email_reject_reply_key: + title: "電子郵件拒絕 復原金鑰" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 未知回覆指紋" + text_body_template: | + 我們非常抱歉,但是你發送至%{destination}(名為%{former_title})的郵件出問題了。 + + 郵件中的回覆信令是無效或者未知的,所以我們不知道這封郵件回覆給誰了。請聯繫管理人員。 + email_reject_bad_destination_address: + title: "電子郵件拒絕 不良目的地位址" + subject_template: "[%{site_name}] 電子郵件錯誤 -- 未知的回覆至地址" + text_body_template: | + 我們非常抱歉,但是你發送至%{destination}(名為%{former_title}) 郵件出問題了。 + + 目標郵件地址無法識別。請確保你在向管理人員提供的郵件地址發信。 + email_reject_topic_not_found: + title: "電子郵件拒絕 未找到討論話題" + subject_template: "[%{site_name}] 郵件問題 -- 主題未找到" + text_body_template: | + 我們很抱歉,但是你發送至%{destination}(名為 %{former_title})的郵件出問題了。 + + 你回覆的主題不存在——可能已經被刪除了?如果你有異議,聯繫管理人員。 + email_reject_topic_closed: + title: "電子郵件拒絕 討論話題已關閉" + subject_template: "[%{site_name}] 郵件問題 -- 主題已關閉" + text_body_template: | + 我們很抱歉,但是你發送至 %{destination} ( 名為 %{former_title} )的郵件出問題了。 + + 你回覆的主題已經被關閉,不允許回覆。如果你有異議,聯繫管理人員。 + email_reject_auto_generated: + title: "電子郵件拒絕 自動生成" + subject_template: "[%{site_name}] 郵件問題 -- 自動生成的回覆" + text_body_template: | + 我們很抱歉,但是你發送至%{destination}(名為 %{former_title})的郵件出問題了。 + + 系統覺得你的郵件是“自動生成”的,即電腦生成了該郵件而不是由你輸入的;我們不能接受這樣的郵件。如果你有異議,聯繫管理人員。 + email_error_notification: + title: "電子郵件錯誤通知" + subject_template: "[%{site_name}] 電子郵件錯誤 -- POP 驗證錯誤" + text_body_template: | + 不幸的是,從 POP 伺服器查詢郵件時遇到了驗證錯誤。 + + 請確認你在[站點設置](%{base_url}/admin/site_settings/category/email)中已經正確配置了 POP 驗證信息。 + + 如果 POP 郵件賬號有圖形界面,你可以登錄後查看郵箱設置。 + too_many_spam_flags: + title: "過多垃圾文章投訴" + subject_template: "新賬戶被暫時封禁" + text_body_template: | + 你好, + + 這是%{site_name}自動發出的郵件。你的帖子因社群標記而被臨時隱藏。 + + 出於謹慎的考慮,在管理人員審核通過前,你的新賬戶不能再發表新的回覆或者主題。我們對此帶來的不便表示歉意。 + + 要查看更多指引,請參考我們的[社群指引](%{base_url}/guidelines)。 + too_many_tl3_flags: + title: "過多 TL3 投訴" + subject_template: "新賬戶被暫時封禁" + text_body_template: | + 你好, + + 這是%{site_name}自動發出的郵件。你的帳戶因大量社群標記而被暫停使用。 + + 出於謹慎的考慮,在管理人員審核通過前,你的新賬戶不能再發表新的回覆或者主題。我們對此帶來的不便表示歉意。 + + 要查看更多指引,請參考我們的[社群指引](%{base_url}/guidelines)。 + blocked_by_staff: + title: "被管理員封鎖" + subject_template: "賬戶被暫時封禁" + text_body_template: | + 你好, + + 這是%{site_name}自動發出的郵件。出於謹慎的考慮,你的帳戶臨時暫停使用。 + + 請繼續瀏覽,但在管理人員審核通過前,你的賬戶不能再發表新的回覆或者主題。我們對此帶來的不便表示歉意。 + + 要查看更多指引,請參考我們的[社群指引](%{base_url}/guidelines)。 + user_automatically_blocked: + title: "用戶自動封鎖" + subject_template: "新用戶%{username}因社群標記而被封禁" + text_body_template: | + 這是自動發出的郵件。 + + 因多位用戶標記%{username}的帖子,新用戶[%{username}](%{base_url}%{user_url})已被自動封禁。 + + 請[查看這些標記](%{base_url}/admin/flags)。如果%{username}被意外禁用了編輯功能,點擊[該用戶管理頁面](%{base_url}%{user_url})內的解封按鈕。 + + 該閾值可以通過站點設置中的 `block_new_user` 更改。 spam_post_blocked: + title: "因垃圾貼文而被封鎖" subject_template: "新用戶 %{username} 由於重複貼連結,文章已被封鎖" + text_body_template: | + 這是自動發出的郵件。 + + 新用戶[%{username}](%{base_url}%{user_url})試圖創建多個連結至 %{domains} 的帖子,但這些帖子因為反垃圾策略而被阻擋了。用戶仍能夠發表不包含到 %{domains} 的帖子。 + + 請[審核該用戶](%{base_url}%{user_url})。 + + 該閾值可以通過站點設置中的 `newuser_spam_host_threshold` 和 `white_listed_spam_host_domains` 更改。 + unblocked: + title: "解除封鎖" + subject_template: "賬戶已解除封禁" + text_body_template: | + 你好, + + 這是%{site_name}自動發出的郵件。管理人員審核你的帳戶後,你的帳戶不再受到限制。 + + 你現在可以創建新回覆和主題了。感謝你的耐心等待。 pending_users_reminder: subject_template: other: "%{count} 個用戶等待審核" + text_body_template: | + 有新註冊的用戶在訪問論壇前需要被確認(或者拒絶)。 + + [請在管理欄目中審核他們](%{base_url}/admin/users/list/pending)。 download_remote_images_disabled: + title: "停用遠端圖片下載" subject_template: "停用下載遠端圖片" + text_body_template: "`download_remote_images_to_local` 設定已被禁用,因為已經達到 ``download_remote_images_threshold` 設定中的磁碟空間限制。" + dashboard_problems: + title: "控制台問題" + subject_template: "發現問題了" + text_body_template: | + 系統在管理員面板中報告了發現的問題。 + + [請檢查並修復他們](%{base_url}/admin)。 + unsubscribe_link: | + 要退訂這些郵件,[點擊這裡](%{unsubscribe_url})。 + unsubscribe_link_and_mail: | + 要退訂這些郵件,[點擊這裡](%{unsubscribe_url})。 + unsubscribe_mailing_list: | + 你啟用了郵件列表模式,所以收到了這些郵件。 + + 要退訂這些郵件,[點擊這裡](%{unsubscribe_url})。 subject_re: "回覆:" subject_pm: "[私訊]" user_notifications: previous_discussion: "之前的回覆" + reached_limit: + other: "警告:你達到了每日郵件限額(%{count})。之後郵件通知將被禁用。" in_reply_to: "回覆給" unsubscribe: title: "取消訂閱" description: "不再對這些郵件感興趣?沒問題!點擊下面按鈕來立即取消訂閱:" + reply_by_email: "[訪問主題](%{base_url}%{url})或者發郵件回覆。" + reply_by_email_pm: "[訪問消息](%{base_url}%{url})或者發郵件回覆。" + only_reply_by_email: "發郵件回覆。" + visit_link_to_respond: "[訪問主題](%{base_url}%{url})以回覆." + visit_link_to_respond_pm: "[訪問消息](%{base_url}%{url})以回覆." posted_by: "由 %{username} 張貼於 %{post_date}" + invited_to_private_message_body: | + %{username} 邀請你至消息交流: + + > **%{topic_title}** + > + > %{topic_excerpt} + + 論壇: + + > %{site_title} -- %{site_description} + invited_to_topic_body: | + %{username} 邀請你參與討論: + + > **%{topic_title}** + > + > %{topic_excerpt} + + 論壇: + + > %{site_title} -- %{site_description} user_invited_to_private_message_pm: + title: "用戶被邀請至私人訊息" subject_template: "[%{site_name}] %{username} 邀請你參與討論 '%{topic_title}'" + text_body_template: | + %{header_instructions} + + %{message} + + %{respond_instructions} + user_invited_to_private_message_pm_staged: + title: "用戶被邀請至私人訊息狀態" + subject_template: "[%{site_name}] %{username} 邀請你加入消息交流:'%{topic_title}'" + text_body_template: | + %{header_instructions} + + %{message} + + %{respond_instructions} + user_invited_to_topic: + title: "用戶被邀請至討論話題" + subject_template: "[%{site_name}] %{username}邀請你參與“%{topic_title}”" + text_body_template: | + %{header_instructions} + + %{message} + + %{respond_instructions} user_replied: + title: "用戶回覆" subject_template: "[%{site_name}] %{username} 在 '%{topic_title}' 討論話題回覆了你的文章" - user_quoted: - subject_template: "[%{site_name}] %{username} 在 '%{topic_title}' 討論話題引用了你的內容" - user_mentioned: - subject_template: "[%{site_name}] %{username} 在 '%{topic_title}' 討論話題提及了你" - user_posted: - subject_template: "[%{site_name}] %{subject_prefix}%{username} 在 '%{topic_title}' 討論話題發表了文章" - user_posted_pm: + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_replied_pm: + title: "用戶回復私人訊息" subject_template: "[%{site_name}] [PM] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_quoted: + title: "用戶引述" + subject_template: "[%{site_name}] %{username} 在 '%{topic_title}' 討論話題引用了你的內容" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_linked: + title: "用戶連結" + subject_template: "[%{site_name}] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_mentioned: + title: "用戶提及" + subject_template: "[%{site_name}] %{username} 在 '%{topic_title}' 討論話題提及了你" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_group_mentioned: + title: "用戶群組提及" + subject_template: "[%{site_name}] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_posted: + title: "用戶貼文" + subject_template: "[%{site_name}] %{subject_prefix}%{username} 在 '%{topic_title}' 討論話題發表了文章" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_watching_first_post: + title: "用戶觀看第一個主題" + subject_template: "[%{site_name}] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_posted_pm: + title: "用戶發表私人訊息" + subject_template: "[%{site_name}] [PM] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_posted_pm_staged: + title: "用戶發表私人訊息後備" + subject_template: "%{optional_re}%{topic_title}" + text_body_template: |2 + + %{message} digest: why: "在你上一次於 %{last_seen_at} 訪問後,在 %{site_link} 上的摘要。" + since_last_visit: "自從你上次訪問" + new_topics: "新主題" + unread_messages: "未讀私信" + unread_notifications: "未讀通知" + liked_received: "獲得贊" + new_posts: "新帖子" + new_users: "新用戶" + popular_topics: "熱門主題" + follow_topic: "關注主題" + join_the_discussion: "閲讀更多" + popular_posts: "流行帖子" + from_topic_label: "來自" + more_new: "新內容" + subject_template: "[%{site_name}] 摘要" + unsubscribe: "這是封來自%{site_link}的摘要郵件,因為你長時間沒有訪問而發送。%{unsubscribe_link}取消訂閲。" click_here: "點擊此處" + from: "%{site_name}的摘要" + preheader: "在你上次於%{last_seen_at}訪問後的新內容摘要" + mailing_list: + why: "%{date}%{site_link}上的所有情況" + subject_template: "[%{site_name}] %{date}摘要" + unsubscribe: "這是每日摘要郵件。站點啟用了郵件列表模式,點擊連結 %{unsubscribe_link} 退訂。" + from: "%{site_name}的摘要" + new_topics: "近期主題" + topic_updates: "主題更新" + view_this_topic: "查看此主題" + back_to_top: "回到頂部" forgot_password: + title: "忘記密碼" subject_template: "[%{site_name}] 密碼重設" text_body_template: | 有人請求重設你在 [%{site_name}](%{base_url}) 上的密碼。 @@ -837,12 +2100,81 @@ zh_TW: 點擊下面的連結來選擇一個新密碼: %{base_url}/users/password-reset/%{email_token} set_password: + title: "設定密碼" subject_template: "[%{site_name}] 設定密碼" + text_body_template: | + 有人請求添加你在 [%{site_name}](%{base_url}) 的密碼。除此之外,你可以通過已驗證過你郵件地址的在綫服務商登錄。 + + 如果不是你在請求添加密碼,你可以直接忽略本郵件。 + + 點擊下面的連結來選擇一個新密碼: + %{base_url}/users/password-reset/%{email_token} + admin_login: + title: "管理員登入" + subject_template: "[%{site_name}]登錄" + text_body_template: | + 有人嘗試登錄你在[%{site_name}](%{base_url})的賬戶。 + + 如果不是你在操作,你可以安全地忽略這封郵件。 + + 點擊下面的連結登錄: + %{base_url}/users/admin-login/%{email_token} account_created: + title: "建立用戶" subject_template: "[%{site_name}] 你的新帳號" + text_body_template: | + 你在 %{site_name} 上建立了一個新賬號 + + 點擊下面的連結來為新賬戶設置密碼: + %{base_url}/users/password-reset/%{email_token} + confirm_new_email: + title: "確認新郵件" + subject_template: "[%{site_name}] 確認你的電子郵件位址" + text_body_template: | + 點擊以下連結確認你在[%{site_name}]上的新電子郵件: + + %{base_url}/users/authorize-email/%{email_token} + confirm_old_email: + title: "確認舊郵件" + subject_template: "[%{site_name}] 確認你的新電子郵箱地址" + text_body_template: | + 在我們修改你的郵箱地址前,我們需要你確認你擁有當前的郵件賬號。在你完成這步之後,我們將確認你的新郵件地址。 + + 點擊下面的連結來確認你當前在%{site_name}上的電子郵箱地址: + + %{base_url}/users/authorize-email/%{email_token} + notify_old_email: + title: "通知舊的郵件" + subject_template: "[%{site_name}] 你的郵箱地址已經修改成功" + text_body_template: | + 這是%{site_name}自動發出的郵件,以告知你的郵箱地址已經被修改了。如果這是一個錯誤,請聯繫站點管理人員。 + + 你的郵箱地址被修改為: + + %{new_email} signup_after_approval: + title: "在同意之後註冊" subject_template: "你已受到 %{site_name} 的認可!" + text_body_template: | + 歡迎加入%{site_name}! + + 一個管理人員批准了你在%{site_name}的賬戶。 + + 點擊下面的連結來確認並激活你在 %{site_name} 上的新賬號: + %{base_url}/users/activate-account/%{email_token} + + 如果上面的連結無法點擊,請拷貝該連結並粘貼到你的瀏覽器的地址欄裡。 + + %{new_user_tips} + + 我們始終相信[討論應該文明](%{base_url}/guidelines)。 + + 好好享受你在論壇的時光吧! + + (如果你在新用戶級別需要和[管理人員](%{base_url/about)溝通的話,直接回覆這個消息。) signup: + title: "註冊" + subject_template: "[%{site_name}] 確認你的新賬戶" text_body_template: | 歡迎來到 %{site_name}! @@ -851,22 +2183,39 @@ zh_TW: 如果上面的連結無法點擊,請拷貝該連結並粘貼到你的流覽器的地址欄裡。 page_not_found: + title: "抱歉!這個頁面不存在或者是私密的。" popular_topics: "熱門" recent_topics: "最近" see_more: "更多" search_title: "搜尋該網頁" search_google: "Google" + login_required: + welcome_message: | + #[歡迎來到 %{title}](#welcome) + 你需要一個賬號。請創建一個賬號或者登錄以繼續。 terms_of_service: title: "服務條款" signup_form_message: '我已閱讀並接受 服務條款' deleted: '已刪除' upload: edit_reason: "下載外部圖片留做存檔" + unauthorized: "抱歉,你沒有上傳檔案的權限(驗證擴展:%{authorized_extensions})。" pasted_image_filename: "貼上的圖片" store_failure: "用戶 #%{user_id} 上傳 #%{upload_id} 儲存失敗" + file_missing: "抱歉,你必須選擇一個檔案上傳。" + attachments: + too_large: "抱歉,你試圖上傳的檔案太大了(最大限製為%{max_size_kb}%KB)。" images: + too_large: "抱歉,你試圖上傳的圖片太大了(最大限製為%{max_size_kb}%KB),請裁剪它並重試。" + larger_than_x_megapixels: "對不起,您試圖上傳的影像太大了(最大限制是%{max_image_megapixels} 百萬畫素),請調整大小後重試。" size_not_found: "抱歉,我們無法獲取圖片大小,請檢查你的圖片是否已損壞。" + avatar: + missing: "抱歉,我們沒法找到與你郵件地址關聯的頭像。你能再上傳一次試試嗎?" + flag_reason: + sockpuppet: "新用戶創建了主題,而另一個新用戶以同一個 IP 在該主題回覆。查看站點設置的 `flag_sockpuppets`。" + spam_hosts: "新用戶試圖在多個創建帖子中發錶鏈接到同一個域名的內容。查看站點設置的 `newuser_spam_host_threshold`。" email_log: + post_user_deleted: "帖子的用戶已被刪除。" no_user: "無法找到 ID 為 %{user_id} 的使用者" anonymous_user: "匿名用戶" suspended_not_pm: "用戶已被停權,不是訊息" @@ -877,10 +2226,13 @@ zh_TW: post_deleted: "文章已被做刪除" user_suspended: "用戶被停權" already_read: "此文章用戶已讀" + exceeded_emails_limit: "超過 max_emails_per_day_per_user" + exceeded_bounces_limit: "超過 bounce_score_threshold" message_blank: "訊息空白" message_to_blank: "message.to 為空" text_part_body_blank: "text_part.body is 為空" body_blank: "內容空白" + no_echo_mailing_list_mode: "郵件列表通知已對用戶自己的帖子禁用" color_schemes: base_theme_name: "基礎" about: "關於" @@ -894,19 +2246,684 @@ zh_TW: 編輯本主題的第一帖以改變 %{page_name} 頁面的內容。 guidelines_topic: title: "FAQ / 使用守則" + body: | + + + ## [這是一個文明討論的地方](#civilized) + + 在論壇上請表現得像在公共公園一樣得體。我們一群人共享着一個公共社群資源 — 一個通過不斷進行討論以分享我們技能、知識和興趣的地方。 + + 這些都不是死規矩或者是草率決定,只是一些幫助社群的人們來判斷的規定。試用這些指引來保持乾淨和充滿靈感的文明的公開論壇。 + + + + ## [改善討論](#improve) + + 幫助我們讓這個地方變成一個討論的好地方。你可以總是一致的做一些幫助改善討論的事,即使是小事也行。如果你不確定你的帖子有益於討論,認真想一想你要說什麼再發佈。 + + 這裡討論的主題對我們很重要,並且我們希望你也覺得這些內容對你很重要。尊重這些討論的主題,以及討論他們的人們,特別是當你不同意他們所說的時候。 + + 改善討論的一種方法是找一找已經發生過的事。請在發帖或創建你自己的主題前,花一些時間瀏覽這些主題,這樣你更有機會遇見和你有共同愛好的人。 + + + + ## [即使你不同意他人時,尊重他人](#agreeable) + + 你可能想表達你的不同意。這沒問題。但是,記住_批評觀點,而不是人_。請避免: + + * 指名道姓。 + * 人生攻擊。 + * 回覆帖子無關於帖子的內容。 + * 下意識的反駁。 + + 相反,提供合理的觀點改善討論。 + + + + ## [你的參與有意義](#participate) + + 我們在這兒的討論為大家樹立了榜樣。通過選擇參與有意義的討論,幫助我們將論壇變成一個有意思的地方 — 並且避免那些沒有幫助的行為。 + + Discourse 提供了讓社群共同鑒別最棒(或最差)的貢獻的工具:收藏、書籤、贊、標記、回覆和編輯等等。使用這些工具不僅能改善你自己的體驗,也能改善其他人的體驗。 + + 讓我們創造一個更美好的社群。 + + + + ## [如果你發現問題了,標記它](#flag-problems) + 版主有特別的權力;他們對論壇負責。但是你也是。有了你的幫助,版主能成為社群監察者,而不僅是守衛或者警察。 + + 當你見到不合適的行為,不要回覆。這種承認變相鼓勵了這種不合適的行為,浪費了你的精力,並且浪費了每一個人的時間。_只要標記它。_如果收到了足夠的標記,將會有相應的處理,這個處理可能是自動地,也可能由版主介入。 + + 為了維護我們的社群,版主保留了任何情況下刪除任何內容和任何用戶的權力。版主沒有預先審核任何新帖子;版主和站點維護人員對社群裡發表的任何言論均不負責任。 + + + + ## [永遠保持文明](#be-civil) + + 粗魯這樣的行為會破壞健康的討論: + + * 文明。不要發表任何理智的人會認為冒犯的、過分的或招致怨恨的言論。 + * 拒絶色情。不要發表任何淫穢或性暗示的東西。 + * 尊重每一個人。不要騷擾或者讓別人難過,檢視別人,或暴露他們的個人信息。 + * 尊重我們的論壇。不要發表廣告或者其他垃圾信息。 + + 這些條款不是法律條文,並且沒有準確的定義 — 避免任何做關於他們的_可能擦邊_的事。如果你不確定,問問自己的帖子是否能出現在紐約時報的頭版頭條上。 + + 這是一個公共論壇,並且搜索引擎會索引這些討論。注意發表的語言、連結和圖片,不要在其中包含你的家庭和朋友。 + + + + ## [保持整潔](#keep-tidy) + + 花一點時間讓東西出現在正確的位置,這樣我們能花更多的時間在討論上而非清理格式。所以: + + * 不要在錯誤的分類發表新主題。 + * 不要在多個主題中回覆同樣的內容。 + * 不要發佈沒有內容的回覆。 + * 不要在中途改變主題。 + * 不要在你的帖子中簽名 — 每一貼都附有你的個人信息。 + + 比起發表“+1”或者“同意”,使用贊按鈕。比起將帖子帶向一個決然不同的方向,使用“回覆為關聯主題”。 + + + + ## [只發表你自己的東西](#stealing) + + 你不能在沒有他人授權的情況下發表任何屬於他人的數字資產。你可能不能發表關於竊據他人知識產權(軟件、視頻、音頻和圖像)的任何簡介、連結或方法,或其他任何違反法律的內容。 + + + + ## [有你參與](#power) + + 這個站點由[一群友善的管理人員](/about)、你和社群一起運營。如果你對這裡的事情仍有疑問,在[站點反饋](/c/site-feedback)分類新建一個主題並且開始討論!如果遇到了重要或緊急的事情,並且不能用站務分類的主題或標記解決,通過[管理人員頁面](/about)聯繫我們。 + + + + ## [使用條款](#tos) + + 是的,法律很無聊,但是我們必須保護我們自己 – 引申開來,你和你的數據 – 用於針對不友好的傢伙們。我們有一個[使用條款](/tos)描述你的(以及我們)關於內容、隱私和法律的行為和權力。要使用我們的服務,你必須同意遵守[使用條款](/tos)。 tos_topic: title: "服務條款" + body: | + The following terms and conditions govern all use of the %{company_domain} website and all content, services and products available at or through the website, including, but not limited to, %{company_domain} Forum Software, %{company_domain} Support Forums and the %{company_domain} Hosting service ("Hosting"), (taken together, the Website). The Website is owned and operated by %{company_full_name} ("%{company_name}"). The Website is offered subject to your acceptance without modification of all of the terms and conditions contained herein and all other operating rules, policies (including, without limitation, %{company_domain}’s [Privacy Policy](/privacy) and [Community Guidelines](/faq)) and procedures that may be published from time to time on this Site by %{company_name} (collectively, the "Agreement"). + + Please read this Agreement carefully before accessing or using the Website. By accessing or using any part of the web site, you agree to become bound by the terms and conditions of this agreement. If you do not agree to all the terms and conditions of this agreement, then you may not access the Website or use any services. If these terms and conditions are considered an offer by %{company_name}, acceptance is expressly limited to these terms. The Website is available only to individuals who are at least 13 years old. + + + + ## [1. Your %{company_domain} Account](#1) + + If you create an account on the Website, you are responsible for maintaining the security of your account and you are fully responsible for all activities that occur under the account. You must immediately notify %{company_name} of any unauthorized uses of your account or any other breaches of security. %{company_name} will not be liable for any acts or omissions by you, including any damages of any kind incurred as a result of such acts or omissions. + + + + ## [2. Responsibility of Contributors](#2) + + If you post material to the Website, post links on the Website, or otherwise make (or allow any third party to make) material available by means of the Website (any such material, "Content"), You are entirely responsible for the content of, and any harm resulting from, that Content. That is the case regardless of whether the Content in question constitutes text, graphics, an audio file, or computer software. By making Content available, you represent and warrant that: + + * the downloading, copying and use of the Content will not infringe the proprietary rights, including but not limited to the copyright, patent, trademark or trade secret rights, of any third party; + * if your employer has rights to intellectual property you create, you have either (i) received permission from your employer to post or make available the Content, including but not limited to any software, or (ii) secured from your employer a waiver as to all rights in or to the Content; + * you have fully complied with any third-party licenses relating to the Content, and have done all things necessary to successfully pass through to end users any required terms; + * the Content does not contain or install any viruses, worms, malware, Trojan horses or other harmful or destructive content; + * the Content is not spam, is not machine- or randomly-generated, and does not contain unethical or unwanted commercial content designed to drive traffic to third party sites or boost the search engine rankings of third party sites, or to further unlawful acts (such as phishing) or mislead recipients as to the source of the material (such as spoofing); + * the Content is not pornographic, does not contain threats or incite violence, and does not violate the privacy or publicity rights of any third party; + * your content is not getting advertised via unwanted electronic messages such as spam links on newsgroups, email lists, blogs and web sites, and similar unsolicited promotional methods; + * your content is not named in a manner that misleads your readers into thinking that you are another person or company; and + * you have, in the case of Content that includes computer code, accurately categorized and/or described the type, nature, uses and effects of the materials, whether requested to do so by %{company_name} or otherwise. + + + + ## [3. User Content License](#3) + + User contributions are licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US). Without limiting any of those representations or warranties, %{company_name} has the right (though not the obligation) to, in %{company_name}’s sole discretion (i) refuse or remove any content that, in %{company_name}’s reasonable opinion, violates any %{company_name} policy or is in any way harmful or objectionable, or (ii) terminate or deny access to and use of the Website to any individual or entity for any reason, in %{company_name}’s sole discretion. %{company_name} will have no obligation to provide a refund of any amounts previously paid. + + + + + ## [4. Payment and Renewal](#4) + + ### General Terms + + Optional paid services or upgrades may be available on the Website. When utilizing an optional paid service or upgrade, you agree to pay %{company_name} the monthly or annual subscription fees indicated. Payments will be charged on a pre-pay basis on the day you begin utilizing the service or upgrade and will cover the use of that service or upgrade for a monthly or annual subscription period as indicated. These fees are not refundable. + + ### Automatic Renewal + + Unless you notify %{company_name} before the end of the applicable subscription period that you want to cancel a service or upgrade, your subscription will automatically renew and you authorize us to collect the then-applicable annual or monthly subscription fee (as well as any taxes) using any credit card or other payment mechanism we have on record for you. Subscriptions can be canceled at any time. + + + + ## [5. Services](#5) + + ### Hosting, Support Services + + Optional Hosting and Support services may be provided by %{company_name} under the terms and conditions for each such service. By signing up for a Hosting/Support or Support services account, you agree to abide by such terms and conditions. + + + + ## [6. Responsibility of Website Visitors](#6) + + %{company_name} has not reviewed, and cannot review, all of the material, including computer software, posted to the Website, and cannot therefore be responsible for that material’s content, use or effects. By operating the Website, %{company_name} does not represent or imply that it endorses the material there posted, or that it believes such material to be accurate, useful or non-harmful. You are responsible for taking precautions as necessary to protect yourself and your computer systems from viruses, worms, Trojan horses, and other harmful or destructive content. The Website may contain content that is offensive, indecent, or otherwise objectionable, as well as content containing technical inaccuracies, typographical mistakes, and other errors. The Website may also contain material that violates the privacy or publicity rights, or infringes the intellectual property and other proprietary rights, of third parties, or the downloading, copying or use of which is subject to additional terms and conditions, stated or unstated. %{company_name} disclaims any responsibility for any harm resulting from the use by visitors of the Website, or from any downloading by those visitors of content there posted. + + + + ## [7. Content Posted on Other Websites](#7) + + We have not reviewed, and cannot review, all of the material, including computer software, made available through the websites and webpages to which %{company_domain} links, and that link to %{company_domain}. %{company_name} does not have any control over those non-%{company_domain} websites and webpages, and is not responsible for their contents or their use. By linking to a non-%{company_domain} website or webpage, %{company_name} does not represent or imply that it endorses such website or webpage. You are responsible for taking precautions as necessary to protect yourself and your computer systems from viruses, worms, Trojan horses, and other harmful or destructive content. %{company_name} disclaims any responsibility for any harm resulting from your use of non-%{company_domain} websites and webpages. + + + + ## [8. Copyright Infringement and DMCA Policy](#8) + + As %{company_name} asks others to respect its intellectual property rights, it respects the intellectual property rights of others. If you believe that material located on or linked to by %{company_domain} violates your copyright, and if this website resides in the USA, you are encouraged to notify %{company_name} in accordance with %{company_name}’s [Digital Millennium Copyright Act](http://en.wikipedia.org/wiki/Digital_Millennium_Copyright_Act) ("DMCA") Policy. %{company_name} will respond to all such notices, including as required or appropriate by removing the infringing material or disabling all links to the infringing material. %{company_name} will terminate a visitor’s access to and use of the Website if, under appropriate circumstances, the visitor is determined to be a repeat infringer of the copyrights or other intellectual property rights of %{company_name} or others. In the case of such termination, %{company_name} will have no obligation to provide a refund of any amounts previously paid to %{company_name}. + + + + ## [9. Intellectual Property](#9) + + This Agreement does not transfer from %{company_name} to you any %{company_name} or third party intellectual property, and all right, title and interest in and to such property will remain (as between the parties) solely with %{company_name}. %{company_name}, %{company_domain}, the %{company_domain} logo, and all other trademarks, service marks, graphics and logos used in connection with %{company_domain}, or the Website are trademarks or registered trademarks of %{company_name} or %{company_name}’s licensors. Other trademarks, service marks, graphics and logos used in connection with the Website may be the trademarks of other third parties. Your use of the Website grants you no right or license to reproduce or otherwise use any %{company_name} or third-party trademarks. + + + + ## [10. Advertisements](#10) + + %{company_name} reserves the right to display advertisements on your content unless you have purchased an Ad-free Upgrade or a Services account. + + + + ## [11. Attribution](#11) + + %{company_name} reserves the right to display attribution links such as ‘Powered by %{company_domain},’ theme author, and font attribution in your content footer or toolbar. Footer credits and the %{company_domain} toolbar may not be removed regardless of upgrades purchased. + + + + ## [12. Changes](#12) + + %{company_name} reserves the right, at its sole discretion, to modify or replace any part of this Agreement. It is your responsibility to check this Agreement periodically for changes. Your continued use of or access to the Website following the posting of any changes to this Agreement constitutes acceptance of those changes. %{company_name} may also, in the future, offer new services and/or features through the Website (including, the release of new tools and resources). Such new features and/or services shall be subject to the terms and conditions of this Agreement. + + + + ## [13. Termination](#13) + + %{company_name} may terminate your access to all or any part of the Website at any time, with or without cause, with or without notice, effective immediately. If you wish to terminate this Agreement or your %{company_domain} account (if you have one), you may simply discontinue using the Website. All provisions of this Agreement which by their nature should survive termination shall survive termination, including, without limitation, ownership provisions, warranty disclaimers, indemnity and limitations of liability. + + + + ## [14. Disclaimer of Warranties](#14) + + The Website is provided "as is". %{company_name} and its suppliers and licensors hereby disclaim all warranties of any kind, express or implied, including, without limitation, the warranties of merchantability, fitness for a particular purpose and non-infringement. Neither %{company_name} nor its suppliers and licensors, makes any warranty that the Website will be error free or that access thereto will be continuous or uninterrupted. If you’re actually reading this, here’s [a treat](http://www.newyorker.com/online/blogs/shouts/2012/12/the-hundred-best-lists-of-all-time.html). You understand that you download from, or otherwise obtain content or services through, the Website at your own discretion and risk. + + + + ## [15. Limitation of Liability](#15) + + In no event will %{company_name}, or its suppliers or licensors, be liable with respect to any subject matter of this agreement under any contract, negligence, strict liability or other legal or equitable theory for: (i) any special, incidental or consequential damages; (ii) the cost of procurement for substitute products or services; (iii) for interruption of use or loss or corruption of data; or (iv) for any amounts that exceed the fees paid by you to %{company_name} under this agreement during the twelve (12) month period prior to the cause of action. %{company_name} shall have no liability for any failure or delay due to matters beyond their reasonable control. The foregoing shall not apply to the extent prohibited by applicable law. + + + + ## [16. General Representation and Warranty](#16) + + You represent and warrant that (i) your use of the Website will be in strict accordance with the %{company_name} [Privacy Policy](/privacy), [Community Guidelines](/guidelines), with this Agreement and with all applicable laws and regulations (including without limitation any local laws or regulations in your country, state, city, or other governmental area, regarding online conduct and acceptable content, and including all applicable laws regarding the transmission of technical data exported from the country in which this website resides or the country in which you reside) and (ii) your use of the Website will not infringe or misappropriate the intellectual property rights of any third party. + + + + ## [17. Indemnification](#17) + + You agree to indemnify and hold harmless %{company_name}, its contractors, and its licensors, and their respective directors, officers, employees and agents from and against any and all claims and expenses, including attorneys’ fees, arising out of your use of the Website, including but not limited to your violation of this Agreement. + + + + ## [18. Miscellaneous](#18) + + This Agreement constitutes the entire agreement between %{company_name} and you concerning the subject matter hereof, and they may only be modified by a written amendment signed by an authorized executive of %{company_name}, or by the posting by %{company_name} of a revised version. Except to the extent applicable law, if any, provides otherwise, this Agreement, any access to or use of the Website will be governed by the laws of the state of California, U.S.A., excluding its conflict of law provisions, and the proper venue for any disputes arising out of or relating to any of the same will be the state and federal courts located in San Francisco County, California. Except for claims for injunctive or equitable relief or claims regarding intellectual property rights (which may be brought in any competent court without the posting of a bond), any dispute arising under this Agreement shall be finally settled in accordance with the Comprehensive Arbitration Rules of the Judicial Arbitration and Mediation Service, Inc. (“JAMS”) by three arbitrators appointed in accordance with such Rules. The arbitration shall take place in San Francisco, California, in the English language and the arbitral decision may be enforced in any court. The prevailing party in any action or proceeding to enforce this Agreement shall be entitled to costs and attorneys’ fees. If any part of this Agreement is held invalid or unenforceable, that part will be construed to reflect the parties’ original intent, and the remaining portions will remain in full force and effect. A waiver by either party of any term or condition of this Agreement or any breach thereof, in any one instance, will not waive such term or condition or any subsequent breach thereof. You may assign your rights under this Agreement to any party that consents to, and agrees to be bound by, its terms and conditions; %{company_name} may assign its rights under this Agreement without condition. This Agreement will be binding upon and will inure to the benefit of the parties, their successors and permitted assigns. + + This document is CC-BY-SA. It was last updated May 31, 2013. + + Originally adapted from the [WordPress Terms of Service](http://en.wordpress.com/tos/). privacy_topic: title: "隱私政策" + body: | + + + ## [我們收集什麼信息?](#collect) + + 我們從你在我們站點註冊開始從你那開始收集信息,並收集關於你在論壇的閲讀和寫作的數據,並評估分享的內容。 + + 當在我們站點註冊時,你可能被要求輸入你的名字和郵件地址。然而你可以在不用註冊的情況下訪問站點。你的郵件地將通過一個獨一無二的連結驗證。如果連結被訪問了,我們就知道你控制了該郵件地址。 + + 當已註冊和發帖時,我們記錄發佈帖子時的 IP 地址。我們也可能保留伺服器日誌,其中包括了每一個向我們伺服器的請求。 + + + + ## [我們如何使用你的信息?](#use) + + 從你那收集的任何數據將以以下方式使用: + + * 改進你的個人體驗 — 你的信息幫助我們更好地滿足你的個人需求。 + * 改進我們的站點 — 我們基于信息和我們從你那收到的反饋不斷地試圖改進我們的站點。 + * 改善我們的客戶服務 — 你的信息幫助我們更有效地回應用戶服務請求和支持。 + * 用於發送階段性的郵件 — 你提供的郵件地址可能用於接受信息、你想看到的通知或與你用戶名有關的回覆和詢問,或是其他的請求和問題。 + + + + ## [我們如何保護你的信息?](#protect) + + 我們實現了一系列的安全措施保證你輸入、提交或者訪問你個人信息的數據安全。 + + + + ## [數據保存政策是什麼?](#data-retention) + + 我們將善意地: + + * 保存 90 天內的所有向伺服器的包含 IP 地址的請求。 + * 保存 5 年內已註冊用戶和與他們的帖子有關的 IP 地址。 + + + + ## [我們使用 Cookie 嗎?](#cookies) + + 是的。Cookie 是網站或它的服務商通過網頁瀏覽器存儲在你電腦硬碟上的小檔案(如果你同意)。這些 Cookie 使站點能分辨你的瀏覽器,並且,如果你註冊了一個賬戶,與你的註冊賬戶關聯。 + + 我們使用 Cookie 為之後的訪問和編譯一小段關於站點流量和交互的數據來判斷並保存你的個人設置,這樣我們可以在之後提供更好的站點體驗和工具。我們可能使用第三方服務商來幫助我們更好地理解我們的站點訪客。這些服務商是不允許代表我們使用收集的信息,除非是在幫助我們執行和改進我們的站點。 + + + + ## [我們會在站外提供任何信息嗎?](#disclose) + + 我們絶不銷售、教育或任何向外轉移你個人信息的行為。這不包括幫助我們管理站點、改進站定或給你提供服務的第三方團體,這些團體需要保證對這些信息保密。當我們認為提交你的信息符合法律、我們的站點政策或保護我們或其他人的權利、知識產權或安全時,我們也可能提交你的信息。然而,非個人訪問信息可能供其他團體使用,用於市場、廣告或其他用途。 + + + + ## [第三方連結](#third-party) + + 偶爾地,根據我們的判斷,我們可能在我們的站點上包括或提供第三方團體的產品或服務。這些第三方站點用於獨立和不同的隱私政策。因此我們對連結到的站點或活動沒有責任和權利。儘管如此,我們尋求保護我們的整個站點冰鞋歡迎你給這些站點反饋。 + + + + ## [兒童在綫隱私保護法案合規](#coppa) + + 我們的站點、產品和服務提供給 13 歲以上的人們。如果伺服器位於美國,並且你小於 13 歲,根據[兒童在綫隱私保護法案合規](https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act),不要使用這個站點。 + + + + ## [僅用於在綫隱私政策](#online) + + 這個線上隱私政策只適用於通過我們站點收集到的信息,並不包括線下收集的信息。 + + + + ## [你的同意](#consent) + + 你使用站點的同時,代表你同意了我們網站的隱私政策。 + + + + ## [隱私政策的更改](#changes) + + 如果我們決定更改我們的隱私政策,我們將在此頁更新這些改變。 + + 文檔以 CC-BY-SA 發佈。最後更新時間為2013年5月31日。 + badges: + editor: + name: 編輯 + description: 首次編輯帖子 + long_description: | + 該徽章授予給第一次編輯自己帖子的你。雖然你不能永遠在編輯自己的帖子,但是編輯他們總是一個好辦法——你可以改進你的帖子、修正小錯誤,或者是增補你原來沒有寫的內容。編輯能讓你的帖子質量變得更好! + basic_user: + name: 初級用戶 + description: 授予所有常用社群功能 + long_description: | + 該徽章授予給用戶等級達到 1 的成員。感謝你在社群裡花了一些時間並且閲讀了一些帖子,瞭解了我們的社群。你的新用戶限制已經被取消;並且你已經被授予了所有基本的社群權限,必須個人消息、標記、維基編輯和發佈多張圖片和多個連結的能力。 + member: + name: 成員 + description: 授予邀請、群組消息和更多的贊 + long_description: | + 該徽章授予給達到用戶等級 2 的你。感謝你在社群待了幾周,真正融入到了社群中。你現在可以在你的用戶頁或者主題中邀請他人或者創建群組消息了。每天你也可以點更多次讚了。 + regular: + name: 活躍用戶 + description: 授予重分類、重命名、跟蹤連結、維基功能和更多的贊 + long_description: | + 該徽章授予給達到用戶等級 3 的你。感謝你在這幾個月持續地參與社群。你現在是我們之中最活躍的讀者之一了,你持續的貢獻極大地幫助了我們的社群。你現在可以社群待了幾周,真正融入到了社群中。你現在可以重新分類或者重命名主題、使用能力強大的垃圾標記功能以及訪問隱藏的貴賓分類了。而且每天你可以點更多次讚了。 + leader: + name: 資深 + description: 授予全局編輯、固定、鎖定、存檔、分割、合併和更多的贊 + long_description: | + 該徽章授予給達到用戶等級 4 的你。你被管理人員選作了社群的領導力量,你用你的行動和言辭為社群樹立了正面的形象。你現在可以修改所有帖子,使用常見的版主的主題管理功能,比如置頂、鎖定、隱藏、存檔、分割和合併功能。你每天可以點更多的讚了。 + welcome: + name: 歡迎 + description: 得到一個贊 + long_description: | + 該徽章授予給帖子收到了第一個讚的成員。恭喜,有社群成員發現你發表的內容有意思、酷炫或者有用! + autobiographer: + name: 自傳作者 + description: 已填寫用戶資料信息 + long_description: | + 該徽章授予給填寫了用戶頁面並選擇了用戶頭像的你。讓社群成員們多瞭解你一點以及你感興趣的內容,能幫助我們打造一個更好、更團結的社群。讓我們一起努力! + anniversary: + name: 年度紀念日 + description: 一年活躍用戶,至少發了一個帖子 + long_description: | + 該徽章授予給在社群註冊一年並超至少發佈了一個帖子的你。感謝你的持續關注和對我們社群的貢獻!我們希望你繼續參與我們的社群。 + nice_post: + name: 不錯的回覆 + description: 回覆被讚了 10 次 + long_description: | + 該徽章授予給回覆被讚了 10 次的你。你的回覆給社群成員們留下了印象,並且你推動了討論的進程! + good_post: + name: 很好的回覆 + description: 回覆被讚了 25 次 + long_description: | + 該徽章授予給回覆被讚了 25 次的你。你的回覆很傑出,這個討論對每個人都變得更有意義了! + great_post: + name: 精彩的回覆 + description: 回覆被讚了 50 次 + long_description: | + 該徽章授予給回覆被讚了 50 次的你。哇!你的回覆很有啟發、引經據典、令人冷俊不禁或者十分有內涵,整個社群都喜歡它。 + nice_topic: + name: 不錯的主題 + description: 主題被讚了 10 次 + long_description: | + 該徽章授予給主題獲得 10 個讚的你。嗨,你開啟了一個社群成員覺得有意思的討論! + good_topic: + name: 很好的主題 + description: 主題被讚了 25 次 + long_description: | + 該徽章授予給主題獲得 25 個讚的你。你開啟了一個有意義的主題,整個社群都在積極響應,而且大家喜歡你的主題! + great_topic: + name: 精彩的主題 + description: 主題被讚了 50 次 + long_description: | + 該徽章授予給主題獲得 50 個讚的你。你開啟了一個引人入勝的主題,整個社群都沉浸于討論之中。 + nice_share: + name: 不錯的分享 + description: 分享了一個有 25 個獨立訪問者的帖子 + long_description: | + 該徽章授予給分享連結給 25 個其他訪客的你。感謝你廣而告之我們的討論,和對這個社群的幫助。 + good_share: + name: 很棒的分享 + description: 分享了一個有 300 個獨立訪問者的帖子 + long_description: | + 該徽章授予給分享連結給 300 個其他訪客的你。幹得漂亮!你把一個有意思的討論介紹給了許多新的朋友,並且幫助社群前進了一步。 + great_share: + name: 精彩的分享 + description: 分享了一個有 1000 個獨立訪問者的帖子 + long_description: |+ + 該徽章授予給分享連結給 1000 個其他訪客的你。哇!你把一個有意思的討論推廣給了廣大的讀者們,並且幫助社群前進了一大步! + + first_like: + name: 首次贊 + description: 已讚過了一個帖子 + long_description: | + 該徽章授予給第一次使用 :heart: 按鈕讚了帖子的成員。給帖子點贊是一個極好的讓社群成員知道他們的帖子有意思、有用、酷炫或者好玩的方法。分享愛! + first_flag: + name: 首次標記 + description: 已標記過了一個帖子 + long_description: | + 該徽章授予給第一次標記帖子的你。標記是幫助我們幫助社群保持健康、合宜的工具。如果你注意到哪個帖子需要版主的注意,不用在乎什麼原因,直接標記。如果你注意到別人帖子裡的某個問題,你也可用標記功能發送私信給該成員。如果你發現了問題,:flag_black: 標記吧! + promoter: + name: 推廣者 + description: 已邀請了 1 個用戶 + long_description: | + 該徽章授予給邀請他人加入社群的你。你曾使用了用戶頁面的邀請按鈕或主題底部的邀請按鈕。邀請對某個討論感興趣的朋友是引介新人的好辦法,非常感謝! + campaigner: + name: 活動家 + description: 已邀請了 3 個初級用戶 + long_description: |+ + 該徽章授予給邀請了 3 人加入社群的你,你的朋友在站點上度過了很長的時間,已經成為了基礎用戶。活躍的社區需要新鮮的血液日常參與,併為交流帶來多元視點。 + + champion: + name: 外交官 + description: 已邀請了 5 個成員 + long_description: | + 該徽章授予給邀請了 5 人加入社群的你,你的朋友在站點上度過了很長的時間,已經成為了成員。哇!感謝你幫助社群成長,社群因此變得更多元了! + first_share: + name: 首次分享 + description: 已分享了一個帖子 + long_description: | + 該徽章授予給第一次用分享按鈕分享了回覆或者主題的連結的成員。分享連結是一個極好的方式向外部世界展示有趣的討論的方法,並且能推動社群增長。 + first_link: + name: 首個連結 + description: 已連結了另一個主題 + long_description: | + 該徽章授予給第一次連結到另一個主題的你。聯結主題會在各個主題的右側顯示連結和標題,這可以幫助閲讀者迅速地找到相關討論。多連結一些主題吧! + first_quote: + name: 首次引用 + description: 已引用過一個帖子 + long_description: | + 該徽章授予給第一次在回覆中引用帖子的你。在你的回覆中引用之前帖子中的相關的段落將把主題關聯在一起並切題。只要選中別的帖子中的任何文字,然後點擊回覆按鈕將可以引用啦。多引用一些吧! + read_guidelines: + name: 閲讀指引 + description: 閲讀社群指引 + long_description: | + 該徽章授予給閲讀了社群指引的你。遵守和分享簡單的指引能讓我們打造一個穩定、有趣和可持續的社群。永遠記住別人,一個和你有很多共同點的人,就在屏幕的那一側。友好一些! + reader: + name: 讀者 + description: 閲讀了有至少 100 個回覆的主題中的所有回覆 + long_description: | + 該徽章授予給第一次閲讀了超過 100 個回覆的長主題的你。仔細地閲讀對話內容能讓你關注到討論的中心,理解不同的觀點,而且能幫助我們打造更有趣的對話情景。你讀得越多,對話的效果就會越好。就如我們常說的那般,閲讀是最重要的! :slight_smile: + popular_link: + name: 流行連結 + description: 分享的連結被點擊了 50 次 + long_description: | + 該徽章授予給分享的連結被點擊過 50 次的你。感謝你貼出了有用的連結,這讓討論的情節更形象了! + hot_link: + name: 熱門連結 + description: 分享的連結被點擊了 300 次 + long_description: | + 該徽章授予給分享的連結被點擊過 300 次的你。感謝你貼出了精彩的連結,這推進了討論的進程,並且裝點了討論! + famous_link: + name: 著名連結 + description: 分享的連結被點擊了 1000 次 + long_description: | + 該徽章授予給分享的連結被點擊過 1000 次的你。哇!你貼出的連結明顯地推動了交流,它提供了重要的細節、上下文和其他信息,幹得好! + appreciated: + name: 感謝 + description: 有 20 個帖子都被讚了 1 次 + long_description: | + 該徽章授予給 20 個不同的帖子都收到了至少 1 個讚的你。社群感謝你對討論的貢獻! + respected: + name: 尊敬 + description: 有 100 個帖子都被讚了 2 次 + long_description: | + 該徽章授予給 100 個不同的帖子都收到了至少 2 個讚的你。社群越來越尊重你在討論中的貢獻了。 + admired: + name: 敬仰 + description: 有 300 個帖子都被讚了 5 次 + long_description: | + 該徽章授予給 300 個不同的帖子都收到了至少 5 個讚的你。哇!社群敬仰你在討論中頻繁和高質量的貢獻。 + out_of_love: + name: 熱情 + description: 1 天內讚了 50 次 + long_description: | + 該徽章授予給一天內讚了 50 次的你。別忘記休息一下。讚你喜歡的帖子能鼓勵成員不斷改進討論的內容。 + higher_love: + name: "激情\b" + description: 5 天都讚過 50 次 + long_description: | + 該徽章授予給 5 天讚過 50 次的你。感謝你每天都花點時間鼓勵討論的進行! + crazy_in_love: + name: 狂熱 + description: 20 天都讚過 50 次 + long_description: | + 該徽章授予給 20 天讚過 50 次的你。哇!你為社群成員們樹立了一個令人鼓舞的模範! + thank_you: + name: 感謝你 + description: 有 20 個被讚的帖子,給出過 10 個贊 + long_description: | + 該徽章授予給收到了 20 個贊,且讚過別人至少 10 次的你。當別人讚你的帖子的時候,你也找機會贊別人的帖子。 + gives_back: + name: 回饋 + description: 有 100 個被讚的帖子,給出過 100 個贊 + long_description: | + 該徽章授予給收到了 100 個贊,且讚過別人至少 100 次的你。感謝你分享感激! + empathetic: + name: 感性 + description: 有 500 個被讚的帖子,給出過 1000 個贊 + long_description: | + 該徽章授予給收到了 500 個贊,且讚過別人至少 1000 次的你。哇!你是一個富有同情心且會換位思考的模範。 :two_hearts: + first_emoji: + name: 首個表情 + description: 在帖子中使用表情符號 + long_description: | + 該徽章授予給第一次在帖子中使用 Emoji 的你 :thumbsup:。Emoji 讓你在帖子中表達快樂 :smiley:、悲傷 :anguished:、憤怒 :angry: 以及任何東西 :sunglasses:。輸入 :(冒號)或在編輯器中的 Emoji 工具欄中選擇吧 :ok_hand: + first_mention: + name: 首次提及 + description: 在帖子中提到用戶 + long_description: 該徽章授予給第一次在帖子中@別人的你。每個提及都將通知對方,讓他們知道你發了貼。輸入 @ 提及任何用戶,如果可以的話,也可以提及群組——這是個獲得他們注意的好辦法。 + first_onebox: + name: 首個Onebox + description: 發佈過 oneboxed 連結 + long_description: 該徽章授予給第一次在空行中發錶鏈接的你,連結將被展開成 onebox。其中有連結摘要、標題和(如果有)圖片。 + first_reply_by_email: + name: 首次郵件回覆 + description: 通過郵件回覆 + long_description: | + 該徽章授予給第一次通過郵件回覆的你 :e-mail:。 admin_login: success: "已發送郵件" error: "錯誤" email_input: "管理者郵件" submit_button: "送出電子郵件" + discourse_hub: + access_token_problem: "告訴管理員:請更新站點設置,應使用正確的 discourse_org_access_key。" performance_report: + initial_post_raw: 這個主題將用來展示網站每日性能報告。 initial_topic_title: 網站效能報表 - time: - <<: *datetime_formats + topic_invite: + user_exists: "抱歉,用戶已經被邀請了。你可能只想邀請用戶參與主題一次。" + tags: + title: "標籤" + staff_tag_disallowed: "“%{tag}”只可由管理人員使用。" + staff_tag_remove_disallowed: "“%{tag}”只可由管理人員刪除。" + rss_by_tag: "主題標籤 %{tag}" + finish_installation: + congratulations: "祝賀,你已經安裝好了 Discourse!" + register: + button: "註冊" + title: "註冊管理員賬戶" + help: "註冊新賬戶以開始" + no_emails: "不幸的是,在嚮導中你沒有設置管理員郵件地址,所以完善配置可能有點困難。" + confirm_email: + title: "配置你的郵件" + message: "

    我們發送了一封激活郵件到%{email}。請按照郵件中的步驟來激活你的帳號。

    如果你沒有收到郵件,請檢查你正確設置了 Discourse 郵件配置,然後查看你的垃圾郵件收件箱。

    " + resend_email: + title: "重發激活郵件" + message: "

    我們重發了激活郵件至%{email}" + safe_mode: + title: "進入安全模式" + description: "安全模式讓你的站點不載入插件或站點自定義設置。" + no_customizations: "禁止所以站點自定義" + only_official: "禁用非官方插件" + no_plugins: "禁用所以插件" + enter: "進入安全模式" + wizard: + title: "Discourse 安裝" + step: + locale: + title: "歡迎來到 Discourse!" + fields: + default_locale: + description: "你的社群主要使用什麼語言?" + forum_title: + title: "名字" + description: "名字就像遠方可見的路標一樣,訪客“首先”將看到這個社群的名字。你起的名字和標題怎樣描述了你的社群?" + fields: + title: + label: "你社群的名字" + placeholder: "小明的論壇" + site_description: + label: "用一句簡短的話描述你的社群" + placeholder: "小明和他的朋友討論酷東西的論壇" + introduction: + title: "介紹" + fields: + welcome: + label: "歡迎主題" + one_paragraph: "請限制你的歡迎消息至一段話。" + privacy: + title: "訪問" + fields: + privacy: + choices: + open: + label: "公開" + description: "任何人都可訪問社群,可以創建賬戶" + restricted: + label: "私密" + description: "只有我邀請或審核通過的人可以訪問社群" + contact: + title: "聯繫" + fields: + contact_email: + label: "郵件" + placeholder: "name@example.com" + description: "社群的負責人或小組的郵件地址。將用來接收關於未處理標記和安全更新的緊急通知,並顯示在關於頁面上作為緊急聯繫的方式。" + contact_url: + label: "網頁" + placeholder: "http://www.example.com/contact-us" + description: "你或者你的組織平時用於聯絡的網頁。將被顯示在關於頁面中。" + site_contact: + label: "自動消息" + description: "所有自動發送自 Discourse 的私人消息將以該用戶的名義發送。最重要的是,這個用戶將被指定為發送給每個新用戶的歡迎消息的發送人。" + corporate: + title: "組織" + fields: + company_short_name: + label: "公司名(短)" + placeholder: "國際科技" + company_full_name: + label: "公司名(全)" + placeholder: "國際科技有限公司。" + company_domain: + label: "公司域名名字" + placeholder: "initech.com" + colors: + title: "主題" + fields: + theme_id: + choices: + default: + label: "簡潔亮" + dark: + label: "簡潔黑" + logos: + title: "標誌" + fields: + logo_url: + label: "主要標誌" + description: "在你站點左上角出現的小號標誌圖片,應為一個長方形。" + logo_small_url: + label: "緊湊 Logo" + description: "站點標誌的緊湊版本,在向下滾動時出現在左上角。用正方形的圖片。" + icons: + title: "表徵圖" + fields: + favicon_url: + label: "小表徵圖" + description: "瀏覽器中你站點顯示的表徵圖,要在小尺寸的情況下表現出色,例如 32px X 32px。" + apple_touch_icon_url: + label: "大表徵圖" + description: "現代設備中你站點顯示的表徵圖,要在大一點尺寸的情況下表現出色。推薦的尺寸至少要達到144px X 144px。" + homepage: + title: "主頁" + fields: + homepage_style: + choices: + latest: + label: "最新主題" + categories: + label: "分類" + emoji: + title: "Emoji" + invites: + title: "邀請工作人員" + description: "您就快完成啦!讓我們邀請一些工作人員來幫您創建一些種子討論話題,好讓您的社群朋友產生興趣並開始回覆。" + finished: + title: "你的 Discourse 已經準備就緒!" + description: | +

    如果你覺得需要修改這些設置,訪問管理員分塊;你可以在站點菜單找到扳手表徵圖旁找到。

    +

    祝你玩得開心,還有祝你建設新社區好運!

    activemodel: errors: <<: *errors diff --git a/config/routes.rb b/config/routes.rb index e3bfdb39b28..3f1a5be6c72 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -7,7 +7,7 @@ require_dependency "permalink_constraint" # This used to be User#username_format, but that causes a preload of the User object # and makes Guard not work properly. -USERNAME_ROUTE_FORMAT = /[\w.\-]+/ unless defined? USERNAME_ROUTE_FORMAT +USERNAME_ROUTE_FORMAT = /[\w.\-]+?/ unless defined? USERNAME_ROUTE_FORMAT BACKUP_ROUTE_FORMAT = /.+\.(sql\.gz|tar\.gz|tgz)/i unless defined? BACKUP_ROUTE_FORMAT @@ -183,7 +183,8 @@ Discourse::Application.routes.draw do post "flags/disagree/:id" => "flags#disagree" post "flags/defer/:id" => "flags#defer" resources :site_customizations, constraints: AdminConstraint.new - scope "/customize" do + + scope "/customize", constraints: AdminConstraint.new do resources :user_fields, constraints: AdminConstraint.new resources :emojis, constraints: AdminConstraint.new @@ -326,8 +327,8 @@ Discourse::Application.routes.draw do get "users/:username/messages/group/:group_name/archive" => "user_actions#private_messages", constraints: {username: USERNAME_ROUTE_FORMAT, group_name: USERNAME_ROUTE_FORMAT} get "users/:username.json" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}, defaults: {format: :json} - get "users/:username" => "users#show", as: 'user', constraints: {username: USERNAME_ROUTE_FORMAT} - put "users/:username" => "users#update", constraints: {username: USERNAME_ROUTE_FORMAT} + get "users/:username" => "users#show", as: 'user', constraints: {username: USERNAME_ROUTE_FORMAT, format: /(json|html)/} + put "users/:username" => "users#update", constraints: {username: USERNAME_ROUTE_FORMAT}, defaults: { format: :json } get "users/:username/emails" => "users#check_emails", constraints: {username: USERNAME_ROUTE_FORMAT} get "users/:username/preferences" => "users#preferences", constraints: {username: USERNAME_ROUTE_FORMAT}, as: :email_preferences get "users/:username/preferences/email" => "users_email#index", constraints: {username: USERNAME_ROUTE_FORMAT} @@ -384,11 +385,11 @@ Discourse::Application.routes.draw do post "uploads" => "uploads#create" # used to download original images - get "uploads/:site/:sha" => "uploads#show", constraints: { site: /\w+/, sha: /[a-f0-9]{40}/ } + get "uploads/:site/:sha(.:extension)" => "uploads#show", constraints: { site: /\w+/, sha: /\h{40}/, extension: /[a-z0-9\.]+/i } # used to download attachments - get "uploads/:site/original/:tree:sha" => "uploads#show", constraints: { site: /\w+/, tree: /(\w+\/)+/i, sha: /[a-f0-9]{40}/ } + get "uploads/:site/original/:tree:sha(.:extension)" => "uploads#show", constraints: { site: /\w+/, tree: /([a-z0-9]+\/)+/i, sha: /\h{40}/, extension: /[a-z0-9\.]+/i } # used to download attachments (old route) - get "uploads/:site/:id/:sha" => "uploads#show", constraints: { site: /\w+/, id: /\d+/, sha: /[a-f0-9]{16}/ } + get "uploads/:site/:id/:sha" => "uploads#show", constraints: { site: /\w+/, id: /\d+/, sha: /\h{16}/ } get "posts" => "posts#latest", id: "latest_posts" get "private-posts" => "posts#latest", id: "private_posts" @@ -397,13 +398,14 @@ Discourse::Application.routes.draw do get "posts/:username/deleted" => "posts#deleted_posts", constraints: {username: USERNAME_ROUTE_FORMAT} get "posts/:username/flagged" => "posts#flagged_posts", constraints: {username: USERNAME_ROUTE_FORMAT} - get "groups/:id.json" => 'groups#show', constraints: {id: USERNAME_ROUTE_FORMAT}, defaults: {format: 'json'} - resources :groups, id: USERNAME_ROUTE_FORMAT do get "posts.rss" => "groups#posts_feed", format: :rss get "mentions.rss" => "groups#mentions_feed", format: :rss + get 'activity' => "groups#show" + get 'activity/:filter' => "groups#show" get 'members' + get 'owners' get 'posts' get 'topics' get 'mentions' @@ -423,10 +425,6 @@ Discourse::Application.routes.draw do delete "admin/groups/:id/members" => "groups#remove_member", constraints: AdminConstraint.new put "admin/groups/:id/members" => "groups#add_members", constraints: AdminConstraint.new - # In case people try the wrong URL - get '/group/:id', to: redirect('/groups/%{id}') - get '/group/:id/members', to: redirect('/groups/%{id}/members') - resources :posts do put "bookmark" put "wiki" @@ -626,6 +624,7 @@ Discourse::Application.routes.draw do post "invites/disposable" => "invites#create_disposable_invite" get "invites/redeem/:token" => "invites#redeem_disposable_invite" delete "invites" => "invites#destroy" + put "invites/show/:id" => "invites#perform_accept_invitation", as: 'perform_accept_invite' resources :export_csv do collection do diff --git a/config/site_settings.yml b/config/site_settings.yml index 1d4eaee0a33..ae668d64e45 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -298,6 +298,7 @@ login: enable_sso: client: true default: false + sso_allows_all_return_paths: false enable_sso_provider: false verbose_sso_logging: false sso_url: @@ -388,7 +389,6 @@ users: email_token_valid_hours: default: 48 min: 1 - email_token_grace_period_hours: 0 purge_unactivated_users_grace_period_days: 14 public_user_custom_fields: type: list @@ -410,6 +410,14 @@ users: hide_user_profiles_from_public: default: false client: true + user_website_domains_whitelist: + default: '' + type: list + +groups: + enable_group_directory: + client: true + default: true posting: min_post_length: @@ -599,6 +607,9 @@ email: disable_digest_emails: default: false client: true + email_accent_bg_color: "#2F70AC" + email_accent_fg_color: "#FFFFFF" + email_link_color: "#006699" show_topic_featured_link_in_digest: false email_custom_headers: 'Auto-Submitted: auto-generated' email_subject: '[%{site_name}] %{optional_pm}%{optional_cat}%{topic_title}' @@ -688,9 +699,13 @@ files: max_attachment_size_kb: client: true default: 3072 + max_image_megapixels: + default: 40 + min: 5 + max: 100 authorized_extensions: client: true - default: 'jpg|jpeg|png|gif|csv' + default: 'jpg|jpeg|png|gif' refresh: true type: list crawl_images: @@ -883,8 +898,8 @@ spam: cooldown_minutes_after_hiding_posts: 10 num_spam_flags_to_block_new_user: 3 num_users_to_block_new_user: 3 - num_tl3_flags_to_block_new_user: 6 - num_tl3_users_to_block_new_user: 4 + num_tl3_flags_to_block_new_user: 4 + num_tl3_users_to_block_new_user: 2 notify_mods_when_user_blocked: false flag_sockpuppets: false newuser_spam_host_threshold: 3 @@ -1211,7 +1226,7 @@ uncategorized: disable_edit_notifications: false - vacuum_db_days: 9000 + vacuum_db_days: 90 last_vacuum: default: 0 hidden: true @@ -1249,6 +1264,8 @@ uncategorized: topic_page_title_includes_category: true + native_app_install_banner: false + user_preferences: default_email_digest_frequency: diff --git a/db/fixtures/001_categories.rb b/db/fixtures/001_categories.rb index 5e47dbcf2c1..bef41c56d62 100644 --- a/db/fixtures/001_categories.rb +++ b/db/fixtures/001_categories.rb @@ -23,3 +23,27 @@ if uncat_id == -1 || !Category.exists?(uncat_id) Category.exec_sql "INSERT INTO site_settings(name, data_type, value, created_at, updated_at) VALUES ('uncategorized_category_id', 3, #{category_id}, now(), now())" end + +# 60 minutes after our migration runs we need to exectue this code... +duration = Rails.env.production? ? 60 : 0 +if Category.exec_sql(" + SELECT 1 FROM schema_migration_details + WHERE EXISTS( + SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS + WHERE table_schema = 'public' AND table_name = 'categories' AND column_name = 'logo_url' + ) AND + name = 'AddUploadsToCategories' AND + created_at < (current_timestamp at time zone 'UTC' - interval '#{duration} minutes') + ").to_a.length > 0 + + + Category.transaction do + STDERR.puts "Removing superflous category columns!" + %w[ + logo_url + background_url + ].each do |column| + Category.exec_sql("ALTER TABLE categories DROP column IF EXISTS #{column}") + end + end +end diff --git a/db/fixtures/999_topics.rb b/db/fixtures/999_topics.rb index e46419fd20e..477ea2d40c2 100644 --- a/db/fixtures/999_topics.rb +++ b/db/fixtures/999_topics.rb @@ -40,10 +40,9 @@ end if seed_welcome_topics puts "Seeding welcome topics" - PostCreator.create(Discourse.system_user, raw: I18n.t('assets_topic_body'), title: "Assets for the site design", skip_validations: true, category: staff ? staff.name : nil) + PostCreator.create(Discourse.system_user, raw: I18n.t('assets_topic_body'), title: I18n.t('assets_topic_title'), skip_validations: true, category: staff ? staff.name : nil) - welcome = File.read(Rails.root + 'docs/WELCOME-TO-DISCOURSE.md') - post = PostCreator.create(Discourse.system_user, raw: welcome, title: "Welcome to Discourse", skip_validations: true) + post = PostCreator.create(Discourse.system_user, raw: I18n.t('discourse_welcome_topic.body'), title: I18n.t('discourse_welcome_topic.title'), skip_validations: true) post.topic.update_pinned(true, true) lounge = Category.find_by(id: SiteSetting.lounge_category_id) diff --git a/db/migrate/20161202034856_add_uploads_to_categories.rb b/db/migrate/20161202034856_add_uploads_to_categories.rb index 93506dec18b..de35b1a0d0d 100644 --- a/db/migrate/20161202034856_add_uploads_to_categories.rb +++ b/db/migrate/20161202034856_add_uploads_to_categories.rb @@ -6,12 +6,12 @@ class AddUploadsToCategories < ActiveRecord::Migration transaction do Category.find_each do |category| logo_upload = Upload.find_by(url: category.logo_url) - category.uploaded_logo_id = logo_upload.id if logo_upload - background_upload = Upload.find_by(url: category.background_url) - category.uploaded_background_id = background_upload.id if background_upload - category.save! + category.update_columns( + uploaded_logo_id: logo_upload&.id, + uploaded_background_id: background_upload&.id + ) end end end diff --git a/db/migrate/20161213073938_add_full_name_to_groups.rb b/db/migrate/20161213073938_add_full_name_to_groups.rb new file mode 100644 index 00000000000..655b89551b5 --- /dev/null +++ b/db/migrate/20161213073938_add_full_name_to_groups.rb @@ -0,0 +1,5 @@ +class AddFullNameToGroups < ActiveRecord::Migration + def change + add_column :groups, :full_name, :string + end +end diff --git a/db/migrate/20161215201907_migrate_featured_link_fields.rb b/db/migrate/20161215201907_migrate_featured_link_fields.rb new file mode 100644 index 00000000000..44820a912e9 --- /dev/null +++ b/db/migrate/20161215201907_migrate_featured_link_fields.rb @@ -0,0 +1,6 @@ +class MigrateFeaturedLinkFields < ActiveRecord::Migration + def change + add_column :topics, :featured_link, :string + add_column :categories, :topic_featured_link_allowed, :boolean, default: true + end +end diff --git a/db/migrate/20161216101352_add_all_topics_wiki_to_categories.rb b/db/migrate/20161216101352_add_all_topics_wiki_to_categories.rb new file mode 100644 index 00000000000..7d5fc430002 --- /dev/null +++ b/db/migrate/20161216101352_add_all_topics_wiki_to_categories.rb @@ -0,0 +1,5 @@ +class AddAllTopicsWikiToCategories < ActiveRecord::Migration + def change + add_column :categories, :all_topics_wiki, :boolean, default: false, null: false + end +end \ No newline at end of file diff --git a/docs/INSTALL-cloud.md b/docs/INSTALL-cloud.md index 5e01cb0e101..a3fb2204e69 100644 --- a/docs/INSTALL-cloud.md +++ b/docs/INSTALL-cloud.md @@ -1,6 +1,6 @@ -**Set up Discourse in the cloud in under 30 minutes** with zero knowledge of Rails or Linux shell using our [Discourse Docker image][dd]. We recommend [DigitalOcean][do], but these steps will work on any Docker-compatible cloud provider or local server. +**Set up Discourse in the cloud in under 30 minutes** with zero knowledge of Rails or Linux shell. We recommend [DigitalOcean][do], but these steps will work on any **Docker-compatible** cloud provider or local server. -> 🔔 Don't have 30 minutes to set this up? For a flat one-time fee of $99, the community can install Discourse in the cloud for you. [Click here to purchase a self-supported community install](http://jaypfaffman.com/product/99-install/). +> 🔔 Don't have 30 minutes to set this up? For a flat one-time fee of $99, the community can install Discourse in the cloud for you. [Click here to purchase a self-supported community install](https://www.literatecomputing.com/product/discourse-install/). ### Create New Cloud Server @@ -136,8 +136,12 @@ Do you want... - Free HTTPS / SSL support? [Configure Let's Encrypt](https://meta.discourse.org/t/setting-up-lets-encrypt-cert-with-discourse-docker/40709). Paid HTTPS / SSL support? [Configure SSL](https://meta.discourse.org/t/allowing-ssl-for-your-discourse-docker-setup/13847). +- Use a plugin [from Discourse](https://github.com/discourse) or a third party? [Configure plugins](https://meta.discourse.org/t/install-a-plugin/19157) + - Multiple Discourse sites on the same server? [Configure multisite](https://meta.discourse.org/t/multisite-configuration-with-docker/14084). +- Webhooks when events happen in Discourse? [Configure webhooks](https://meta.discourse.org/t/setting-up-webhooks/49045). + - A Content Delivery Network to speed up worldwide access? [Configure a CDN](https://meta.discourse.org/t/enable-a-cdn-for-your-discourse/14857). We recommend [Fastly](http://www.fastly.com/). - Import old content from vBulletin, PHPbb, Vanilla, Drupal, BBPress, etc? [See our open source importers](https://github.com/discourse/discourse/tree/master/script/import_scripts). diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 5df5dabbfc0..f523b49db94 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -1,16 +1,16 @@ # How Do I Install Discourse? -Simple 30 minute basic install: +> :bell: The only officially supported installs of Discourse are [Docker](https://www.docker.io/) based. You must have SSH access to a 64-bit Linux server **with Docker support**. We regret that we cannot support any other methods of installation including cpanel, plesk, webmin, etc. + +Simple 30 minute basic install: [**Beginner Docker install guide**][basic] -Powerful, flexible, large or multiple server install: +Powerful, flexible, large / multiple server install: [**Advanced Docker install guide**][advanced] -The only officially supported installs of Discourse are the [Docker](https://www.docker.io/) based beginner and advanced installs. We regret that we cannot support any other methods of installation. - ### Why do you only officially support Docker? -Hosting Rails applications is complicated. Even if you already have Postgres, Redis and Ruby installed on your server, you still need to worry about running and monitoring your Sidekiq and Rails processes. Additionally, our Docker install comes bundled with a web-based GUI that makes upgrading to new versions of Discourse as easy as clicking a button. +Hosting Rails applications is complicated. Even if you already have Postgres, Redis and Ruby installed on your server, you still need to worry about running and monitoring your Sidekiq and Rails processes, as well as configuring Nginx. With Docker, our fully optimized Discourse configuration is available to you in a simple container, along with a web-based GUI that makes upgrading to new versions of Discourse as easy as clicking a button. ### Hardware Requirements diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 7c95b01a68a..01fc37fb19c 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -4,7 +4,7 @@ We take security very seriously at Discourse. We welcome any peer review of our ### Where should I report security issues? -In order to give the community time to respond and upgrade we strongly urge you report all security issues privately. Please email us at `team@discourse.org` with details and we will respond ASAP. Security issues *always* take precedence over bug fixes and feature work. We can and do mark releases as "urgent" if they contain serious security fixes. +In order to give the community time to respond and upgrade we strongly urge you report all security issues privately. Please use our [vulnerability disclosure program at Hacker One](https://hackerone.com/discourse) to provide details and repro steps and we will respond ASAP. If you prefer not to use Hacker One, email us directly at `team@discourse.org` with details and repro steps. Security issues *always* take precedence over bug fixes and feature work. We can and do mark releases as "urgent" if they contain serious security fixes. ### Password Storage diff --git a/docs/WELCOME-TO-DISCOURSE.md b/docs/WELCOME-TO-DISCOURSE.md deleted file mode 100644 index 42c2f12fb95..00000000000 --- a/docs/WELCOME-TO-DISCOURSE.md +++ /dev/null @@ -1,12 +0,0 @@ -The first paragraph of this pinned topic will be visible as a welcome message to all new visitors on your homepage. It's important! - -**Edit this** into a brief description of your community: - -- Who is it for? -- What can they find here? -- Why should they come here? -- Where can they read more (links, resources, etc)? - - - -You may want to close this topic via the admin :wrench: (at the upper right and bottom), so that replies don't pile up on an announcement. diff --git a/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb b/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb index 2f2e75030cd..84500b50f77 100644 --- a/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb +++ b/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb @@ -52,7 +52,7 @@ class PostgreSQLFallbackHandler logger.warn "#{log_prefix}: Master server is active. Reconnecting..." self.master_up(key) - Discourse.disable_readonly_mode + Discourse.disable_readonly_mode(Discourse::PG_READONLY_MODE_KEY) end rescue => e logger.warn "#{log_prefix}: Connection to master PostgreSQL server failed with '#{e.message}'" @@ -103,7 +103,7 @@ module ActiveRecord })) verify_replica(connection) - Discourse.enable_readonly_mode + Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY) else begin connection = postgresql_connection(config) diff --git a/lib/admin_constraint.rb b/lib/admin_constraint.rb index 923e5e806c0..0ee711c2bca 100644 --- a/lib/admin_constraint.rb +++ b/lib/admin_constraint.rb @@ -10,6 +10,8 @@ class AdminConstraint return false if @require_master && RailsMultisite::ConnectionManagement.current_db != "default" provider = Discourse.current_user_provider.new(request.env) provider.current_user && provider.current_user.admin? + rescue Discourse::InvalidAccess + false end end diff --git a/lib/auth/current_user_provider.rb b/lib/auth/current_user_provider.rb index 4de839d7d7c..cdd4d495fcc 100644 --- a/lib/auth/current_user_provider.rb +++ b/lib/auth/current_user_provider.rb @@ -25,6 +25,10 @@ class Auth::CurrentUserProvider raise NotImplementedError end + def is_user_api? + raise NotImplementedError + end + # we may need to know very early on in the middleware if an auth token # exists, to optimise caching def has_auth_cookie? diff --git a/lib/auth/default_current_user_provider.rb b/lib/auth/default_current_user_provider.rb index 3326cbc51c7..3bd91684f2f 100644 --- a/lib/auth/default_current_user_provider.rb +++ b/lib/auth/default_current_user_provider.rb @@ -8,6 +8,7 @@ class Auth::DefaultCurrentUserProvider USER_API_KEY ||= "HTTP_USER_API_KEY".freeze USER_API_CLIENT_ID ||= "HTTP_USER_API_CLIENT_ID".freeze API_KEY_ENV ||= "_DISCOURSE_API".freeze + USER_API_KEY_ENV ||= "_DISCOURSE_USER_API".freeze TOKEN_COOKIE ||= "_t".freeze PATH_INFO ||= "PATH_INFO".freeze COOKIE_ATTEMPTS_PER_MIN ||= 10 @@ -97,7 +98,7 @@ class Auth::DefaultCurrentUserProvider limiter_min.performed! limiter_day.performed! - @env[API_KEY_ENV] = true + @env[USER_API_KEY_ENV] = true end @env[CURRENT_USER_KEY] = current_user @@ -172,7 +173,12 @@ class Auth::DefaultCurrentUserProvider # api has special rights return true if api was detected def is_api? current_user - @env[API_KEY_ENV] + !!(@env[API_KEY_ENV]) + end + + def is_user_api? + current_user + !!(@env[USER_API_KEY_ENV]) end def has_auth_cookie? diff --git a/lib/current_user.rb b/lib/current_user.rb index 5c5ec6b2509..79a04e4a71f 100644 --- a/lib/current_user.rb +++ b/lib/current_user.rb @@ -26,6 +26,10 @@ module CurrentUser current_user_provider.is_api? end + def is_user_api? + current_user_provider.is_user_api? + end + def current_user current_user_provider.current_user end diff --git a/lib/custom_setting_providers.rb b/lib/custom_setting_providers.rb new file mode 100644 index 00000000000..370097d4247 --- /dev/null +++ b/lib/custom_setting_providers.rb @@ -0,0 +1,7 @@ +# Support for plugins to register custom setting providers. They can do this +# by having a file, `register_provider.rb` in their root that will be run +# at this point. + +Dir.glob(File.join(File.dirname(__FILE__), '../plugins', '*', "register_provider.rb")) do |p| + require p +end diff --git a/lib/discourse.rb b/lib/discourse.rb index 9f27827f4c5..20227f2dfcd 100644 --- a/lib/discourse.rb +++ b/lib/discourse.rb @@ -113,24 +113,6 @@ module Discourse end end - def self.last_read_only - @last_read_only ||= {} - end - - def self.recently_readonly? - read_only = last_read_only[$redis.namespace] - return false unless read_only - read_only > 15.seconds.ago - end - - def self.received_readonly! - last_read_only[$redis.namespace] = Time.zone.now - end - - def self.clear_readonly! - last_read_only[$redis.namespace] = nil - end - def self.disabled_plugin_names plugins.select { |p| !p.enabled? }.map(&:name) end @@ -139,6 +121,10 @@ module Discourse @plugins ||= [] end + def self.plugin_themes + @plugin_themes ||= plugins.map(&:themes).flatten + end + def self.official_plugins plugins.find_all{|p| p.metadata.official?} end @@ -210,43 +196,66 @@ module Discourse base_url_no_prefix + base_uri end - READONLY_MODE_KEY_TTL ||= 60 - READONLY_MODE_KEY ||= 'readonly_mode'.freeze + READONLY_MODE_KEY_TTL ||= 60 + READONLY_MODE_KEY ||= 'readonly_mode'.freeze + PG_READONLY_MODE_KEY ||= 'readonly_mode:postgres'.freeze USER_READONLY_MODE_KEY ||= 'readonly_mode:user'.freeze - def self.enable_readonly_mode(user_enabled: false) - if user_enabled - $redis.set(USER_READONLY_MODE_KEY, 1) + READONLY_KEYS ||= [ + READONLY_MODE_KEY, + PG_READONLY_MODE_KEY, + USER_READONLY_MODE_KEY + ] + + def self.enable_readonly_mode(key = READONLY_MODE_KEY) + if key == USER_READONLY_MODE_KEY + $redis.set(key, 1) else - $redis.setex(READONLY_MODE_KEY, READONLY_MODE_KEY_TTL, 1) - keep_readonly_mode + $redis.setex(key, READONLY_MODE_KEY_TTL, 1) + keep_readonly_mode(key) end MessageBus.publish(readonly_channel, true) true end - def self.keep_readonly_mode + def self.keep_readonly_mode(key) # extend the expiry by 1 minute every 30 seconds unless Rails.env.test? Thread.new do while readonly_mode? - $redis.expire(READONLY_MODE_KEY, READONLY_MODE_KEY_TTL) + $redis.expire(key, READONLY_MODE_KEY_TTL) sleep 30.seconds end end end end - def self.disable_readonly_mode(user_enabled: false) - key = user_enabled ? USER_READONLY_MODE_KEY : READONLY_MODE_KEY + def self.disable_readonly_mode(key = READONLY_MODE_KEY) $redis.del(key) MessageBus.publish(readonly_channel, false) true end def self.readonly_mode? - recently_readonly? || !!$redis.get(READONLY_MODE_KEY) || !!$redis.get(USER_READONLY_MODE_KEY) + recently_readonly? || READONLY_KEYS.any? { |key| !!$redis.get(key) } + end + + def self.last_read_only + @last_read_only ||= {} + end + + def self.recently_readonly? + return false unless read_only = last_read_only[$redis.namespace] + read_only > 15.seconds.ago + end + + def self.received_readonly! + last_read_only[$redis.namespace] = Time.zone.now + end + + def self.clear_readonly! + last_read_only[$redis.namespace] = nil end def self.request_refresh! diff --git a/lib/discourse_featured_link.rb b/lib/discourse_featured_link.rb deleted file mode 100644 index 304383e9234..00000000000 --- a/lib/discourse_featured_link.rb +++ /dev/null @@ -1,27 +0,0 @@ -module DiscourseFeaturedLink - CUSTOM_FIELD_NAME = 'featured_link'.freeze - - AdminDashboardData::GLOBAL_REPORTS << CUSTOM_FIELD_NAME - - Report.add_report(CUSTOM_FIELD_NAME) do |report| - report.data = [] - link_topics = TopicCustomField.where(name: CUSTOM_FIELD_NAME) - link_topics = link_topics.joins(:topic).where("topics.category_id = ?", report.category_id) if report.category_id - link_topics.where("topic_custom_fields.created_at >= ?", report.start_date) - .where("topic_custom_fields.created_at <= ?", report.end_date) - .group("DATE(topic_custom_fields.created_at)") - .order("DATE(topic_custom_fields.created_at)") - .count - .each { |date, count| report.data << { x: date, y: count } } - report.total = link_topics.count - report.prev30Days = link_topics.where("topic_custom_fields.created_at >= ?", report.start_date - 30.days) - .where("topic_custom_fields.created_at <= ?", report.start_date) - .count - end - - def self.cache_onebox_link(link) - # If the link is pasted swiftly, onebox may not have time to cache it - Oneboxer.onebox(link, invalidate_oneboxes: false) - link - end -end diff --git a/lib/discourse_hub.rb b/lib/discourse_hub.rb index e174cf065a5..3176902c849 100644 --- a/lib/discourse_hub.rb +++ b/lib/discourse_hub.rb @@ -42,7 +42,7 @@ module DiscourseHub def self.hub_base_url if Rails.env.production? - 'https://api.discourse.org/api' + ENV['HUB_BASE_URL'] || 'https://api.discourse.org/api' else ENV['HUB_BASE_URL'] || 'http://local.hub:3000/api' end diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb index b64c250957f..843a64d55ea 100644 --- a/lib/email/receiver.rb +++ b/lib/email/receiver.rb @@ -156,7 +156,7 @@ module Email elsif bounce_score >= SiteSetting.bounce_score_threshold # NOTE: we check bounce_score before sending emails, nothing to do # here other than log it happened. - reason = I18n.t("user.email.revoked", email: user.email, date: user.user_stat.reset_bounce_score_after) + reason = I18n.t("user.email.revoked", date: user.user_stat.reset_bounce_score_after) StaffActionLogger.new(Discourse.system_user).log_revoke_email(user, reason) end end @@ -239,6 +239,8 @@ module Email end def parse_from_field(mail) + return unless mail[:from] + if mail[:from].errors.blank? mail[:from].address_list.addresses.each do |address_field| address_field.decoded @@ -370,7 +372,7 @@ module Email end def has_been_forwarded? - subject[/^[[:blank]]*(re|fwd?)[[:blank]]?:/i] && embedded_email_raw.present? + subject[/^[[:blank]]*(fwd?|tr)[[:blank]]?:/i] && embedded_email_raw.present? end def embedded_email_raw @@ -381,7 +383,7 @@ module Email end def process_forwarded_email(destination, user) - embedded = Mail.new(@embedded_email_raw) + embedded = Mail.new(embedded_email_raw) email, display_name = parse_from_field(embedded) return false if email.blank? || !email["@"] @@ -419,15 +421,21 @@ module Email return false end - if post && post.topic && @before_embedded.present? - post_type = Post.types[:regular] - post_type = Post.types[:whisper] if post.topic.private_message? && group.usernames[user.username] + if post&.topic + # mark post as seen for the forwarder + PostTiming.record_timing(user_id: user.id, topic_id: post.topic_id, post_number: post.post_number, msecs: 5000) - create_reply(user: user, - raw: @before_embedded, - post: post, - topic: post.topic, - post_type: post_type) + # create reply when available + if @before_embedded.present? + post_type = Post.types[:regular] + post_type = Post.types[:whisper] if post.topic.private_message? && group.usernames[user.username] + + create_reply(user: user, + raw: @before_embedded, + post: post, + topic: post.topic, + post_type: post_type) + end end true @@ -565,6 +573,10 @@ module Email # ensure posts aren't created in the future options[:created_at] ||= @mail.date + if options[:created_at].nil? + raise InvalidPost, "No post creation date found. Is the e-mail missing a Date: header?" + end + options[:created_at] = DateTime.now if options[:created_at] > DateTime.now is_private_message = options[:archetype] == Archetype.private_message || @@ -579,8 +591,7 @@ module Email end user = options.delete(:user) - manager = NewPostManager.new(user, options) - result = manager.perform + result = NewPostManager.new(user, options).perform raise InvalidPost, result.errors.full_messages.join("\n") if result.errors.any? diff --git a/lib/email/styles.rb b/lib/email/styles.rb index 39adcf88cd1..eaa69c81456 100644 --- a/lib/email/styles.rb +++ b/lib/email/styles.rb @@ -109,11 +109,9 @@ module Email def onebox_styles # Links to other topics - style('aside.quote', 'border-left: 5px solid #e9e9e9; background-color: #f8f8f8; padding: 12px 25px 2px 12px; margin-bottom: 10px;') - style('aside.quote blockquote', 'border: 0px; padding: 0; margin: 7px 0; background-color: clear;') - style('aside.quote blockquote > p', 'padding: 0;') + style('aside.quote', 'padding: 12px 25px 2px 12px; margin-bottom: 10px;') style('aside.quote div.info-line', 'color: #666; margin: 10px 0') - style('aside.quote .avatar', 'margin-right: 5px; width:20px; height:20px') + style('aside.quote .avatar', 'margin-right: 5px; width:20px; height:20px; vertical-align:middle;') style('blockquote', 'border-left: 5px solid #e9e9e9; background-color: #f8f8f8; margin: 0;') style('blockquote > p', 'padding: 1em;') @@ -126,6 +124,19 @@ module Email style('aside.onebox .onebox-body h3, aside.onebox .onebox-body h4', "font-size: 1.17em; margin: 10px 0;") style('.onebox-metadata', "color: #919191") + @fragment.css('aside.quote blockquote > p').each do |p| + p['style'] = 'padding: 0;' + end + + # Convert all `aside.quote` tags to `blockquote`s + @fragment.css('aside.quote').each do |n| + original_node = n.dup + original_node.search('div.quote-controls').remove + blockquote = original_node.css('blockquote').inner_html.strip.start_with?("#{original_node.css('blockquote').inner_html}

    " + n.inner_html = original_node.css('div.title').inner_html + blockquote + n.name = "blockquote" + end + # Finally, convert all `aside` tags to `div`s @fragment.css('aside, article, header').each do |n| n.name = "div" @@ -152,23 +163,24 @@ module Email end def format_html + style('.with-accent-colors', "background-color: #{SiteSetting.email_accent_bg_color}; color: #{SiteSetting.email_accent_fg_color};") style('h4', 'color: #222;') style('h3', 'margin: 15px 0 20px 0;') style('hr', 'background-color: #ddd; height: 1px; border: 1px;') - style('a', 'text-decoration: none; font-weight: bold; color: #006699;') + style('a', "text-decoration: none; font-weight: bold; color: #{SiteSetting.email_link_color};") style('ul', 'margin: 0 0 0 10px; padding: 0 0 0 20px;') style('li', 'padding-bottom: 10px') - style('div.digest-post', 'margin-left: 15px; margin-top: -5px; max-width: 694px;') - style('div.digest-post h1', 'font-size: 20px;') style('div.footer', 'color:#666; font-size:95%; text-align:center; padding-top:15px;') style('span.post-count', 'margin: 0 5px; color: #777;') style('pre', 'word-wrap: break-word; max-width: 694px;') style('code', 'background-color: #f1f1ff; padding: 2px 5px;') style('pre code', 'display: block; background-color: #f1f1ff; padding: 5px;') - style('.featured-topic a', 'text-decoration: none; font-weight: bold; color: #006699; line-height:1.5em;') + style('.featured-topic a', "text-decoration: none; font-weight: bold; color: #{SiteSetting.email_link_color}; line-height:1.5em;") onebox_styles plugin_styles + + style('.post-excerpt img', "max-width: 50%; max-height: 400px;") end # this method is reserved for styles specific to plugin diff --git a/lib/email_updater.rb b/lib/email_updater.rb index ff6b13c9903..ab4c8246a2a 100644 --- a/lib/email_updater.rb +++ b/lib/email_updater.rb @@ -40,14 +40,14 @@ class EmailUpdater if authorize_both? args[:change_state] = EmailChangeRequest.states[:authorizing_old] - email_token = @user.email_tokens.create(email: args[:old_email]) + email_token = @user.email_tokens.create!(email: args[:old_email]) args[:old_email_token] = email_token else args[:change_state] = EmailChangeRequest.states[:authorizing_new] - email_token = @user.email_tokens.create(email: args[:new_email]) + email_token = @user.email_tokens.create!(email: args[:new_email]) args[:new_email_token] = email_token end - @user.email_change_requests.create(args) + @user.email_change_requests.create!(args) if args[:change_state] == EmailChangeRequest.states[:authorizing_new] send_email(:confirm_new_email, email_token) diff --git a/lib/freedom_patches/fast_pluck.rb b/lib/freedom_patches/fast_pluck.rb index 45da8550365..ac1203c66d0 100644 --- a/lib/freedom_patches/fast_pluck.rb +++ b/lib/freedom_patches/fast_pluck.rb @@ -1,5 +1,6 @@ # Speeds up #pluck so its about 2.2x faster, importantly makes pluck avoid creation of a slew # of AR objects +# require_dependency 'sql_builder' @@ -34,22 +35,10 @@ class ActiveRecord::Relation # end class ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter - if Rails.version >= "4.2.0" - def select_raw(arel, name = nil, binds = [], &block) - arel, binds = binds_from_relation arel, binds - sql = to_sql(arel, binds) - execute_and_clear(sql, name, binds, &block) - end - else - - def select_raw(arel, name = nil, binds = [], &block) - arel, binds = binds_from_relation arel, binds - sql = to_sql(arel, binds) - - result = without_prepared_statement?(binds) ? exec_no_cache(sql, 'SQL', binds) : - exec_cache(sql, 'SQL', binds) - yield result, nil - end + def select_raw(arel, name = nil, binds = [], &block) + arel, binds = binds_from_relation arel, binds + sql = to_sql(arel, binds) + execute_and_clear(sql, name, binds, &block) end end @@ -66,7 +55,6 @@ class ActiveRecord::Relation end end - if has_include?(cols.first) construct_relation_for_association_calculations.pluck(*cols) else @@ -76,7 +64,7 @@ class ActiveRecord::Relation columns_hash.key?(cn) ? arel_table[cn] : cn } - conn.select_raw(relation) do |result,_| + conn.select_raw(relation, nil, relation.arel.bind_values + bind_values) do |result,_| result.type_map = SqlBuilder.pg_type_map result.nfields == 1 ? result.column_values(0) : result.values end diff --git a/lib/guardian.rb b/lib/guardian.rb index ecfedc92e54..bd678fd811b 100644 --- a/lib/guardian.rb +++ b/lib/guardian.rb @@ -177,7 +177,7 @@ class Guardian end def can_grant_admin?(user) - can_administer_user?(user) && not(user.admin?) + can_administer_user?(user) && !user.admin? end def can_revoke_moderation?(moderator) @@ -185,7 +185,7 @@ class Guardian end def can_grant_moderation?(user) - can_administer?(user) && not(user.moderator?) + can_administer?(user) && !user.moderator? end def can_grant_title?(user) @@ -313,7 +313,7 @@ class Guardian end def can_administer?(obj) - is_admin? && obj.present? + is_admin? && obj.present? && obj.id&.positive? end def can_administer_user?(other_user) diff --git a/lib/guardian/category_guardian.rb b/lib/guardian/category_guardian.rb index ccebde7dbf1..7e67066e892 100644 --- a/lib/guardian/category_guardian.rb +++ b/lib/guardian/category_guardian.rb @@ -70,7 +70,6 @@ module CategoryGuardian end def topic_featured_link_allowed_category_ids - @topic_featured_link_allowed_category_ids = CategoryCustomField.where(name: "topic_featured_link_allowed", value: "true") - .pluck(:category_id) + @topic_featured_link_allowed_category_ids = Category.where(topic_featured_link_allowed: true).pluck(:id) end end diff --git a/lib/guardian/post_guardian.rb b/lib/guardian/post_guardian.rb index c928290efe7..b29467ceede 100644 --- a/lib/guardian/post_guardian.rb +++ b/lib/guardian/post_guardian.rb @@ -4,6 +4,12 @@ module PostGuardian # Can the user act on the post in a particular way. # taken_actions = the list of actions the user has already taken def post_can_act?(post, action_key, opts={}) + + return false unless can_see_post?(post) + + # no warnings except for staff + return false if (action_key == :notify_user && !is_staff? && opts[:is_warning].present? && opts[:is_warning] == 'true') + taken = opts[:taken_actions].try(:keys).to_a is_flag = PostActionType.is_flag?(action_key) already_taken_this_action = taken.any? && taken.include?(PostActionType.types[action_key]) @@ -32,9 +38,6 @@ module PostGuardian # new users can't notify_user because they are not allowed to send private messages not(action_key == :notify_user && !@user.has_trust_level?(SiteSetting.min_trust_to_send_messages)) && - # non-staff can't send an official warning - not(action_key == :notify_user && !is_staff? && opts[:is_warning].present? && opts[:is_warning] == 'true') && - # can't send private messages if they're disabled globally not(action_key == :notify_user && !SiteSetting.enable_private_messages) && @@ -46,7 +49,7 @@ module PostGuardian end def can_defer_flags?(post) - is_staff? && post + can_see_post?(post) && is_staff? && post end # Can we see who acted on a post in a particular way? @@ -127,6 +130,8 @@ module PostGuardian # Deleting Methods def can_delete_post?(post) + can_see_post?(post) + # Can't delete the first post return false if post.is_first_post? diff --git a/lib/guardian/topic_guardian.rb b/lib/guardian/topic_guardian.rb index b107fc7e669..f61a6139f8b 100644 --- a/lib/guardian/topic_guardian.rb +++ b/lib/guardian/topic_guardian.rb @@ -106,8 +106,7 @@ module TopicGuardian end def can_edit_featured_link?(category_id) - SiteSetting.topic_featured_link_enabled && - (topic_featured_link_allowed_category_ids.empty? || # no per category restrictions - category_id && topic_featured_link_allowed_category_ids.include?(category_id.to_i)) # category restriction exists + return false unless SiteSetting.topic_featured_link_enabled + Category.where(id: category_id||SiteSetting.uncategorized_category_id, topic_featured_link_allowed: true).exists? end end diff --git a/lib/homepage_constraint.rb b/lib/homepage_constraint.rb index 0783fd51f04..a5cfb347582 100644 --- a/lib/homepage_constraint.rb +++ b/lib/homepage_constraint.rb @@ -9,5 +9,7 @@ class HomePageConstraint provider = Discourse.current_user_provider.new(request.env) homepage = provider.current_user ? SiteSetting.homepage : SiteSetting.anonymous_homepage homepage == @filter + rescue Discourse::InvalidAccess + false end end diff --git a/lib/import_export/category_exporter.rb b/lib/import_export/category_exporter.rb index 745c9f9dbdb..9f182e72470 100644 --- a/lib/import_export/category_exporter.rb +++ b/lib/import_export/category_exporter.rb @@ -25,7 +25,7 @@ module ImportExport CATEGORY_ATTRS = [:id, :name, :color, :created_at, :user_id, :slug, :description, :text_color, :auto_close_hours, :auto_close_based_on_last_post, - :topic_template, :suppress_from_homepage, :permissions_params] + :topic_template, :suppress_from_homepage, :all_topics_wiki, :permissions_params] def export_categories @export_data[:category] = CATEGORY_ATTRS.inject({}) { |h,a| h[a] = @category.send(a); h } diff --git a/lib/javascripts/locale/uk.js b/lib/javascripts/locale/uk.js index aad90c79729..edb43885ab4 100644 --- a/lib/javascripts/locale/uk.js +++ b/lib/javascripts/locale/uk.js @@ -8,7 +8,8 @@ MessageFormat.locale.uk = function (n) { } if ((n % 10) === 0 || ((n % 10) >= 5 && (n % 10) <= 9) || ((n % 100) >= 11 && (n % 100) <= 14) && n == Math.floor(n)) { - return 'many'; + // return 'many'; + return 'other'; // TODO should be "many" but is not defined in translations } return 'other'; }; diff --git a/lib/letter_avatar.rb b/lib/letter_avatar.rb index 7c79c033e9d..79e1a9b884e 100644 --- a/lib/letter_avatar.rb +++ b/lib/letter_avatar.rb @@ -57,11 +57,11 @@ class LetterAvatar def cached_path(identity, size) dir = "#{cache_path}/#{identity.letter}/#{identity.color.join("_")}" FileUtils.mkdir_p(dir) - "#{dir}/#{size}.png" + File.expand_path "#{dir}/#{size}.png" end def fullsize_path(identity) - cached_path(identity, FULLSIZE) + File.expand_path cached_path(identity, FULLSIZE) end def generate_fullsize(identity) diff --git a/lib/middleware/unicorn_oobgc.rb b/lib/middleware/unicorn_oobgc.rb deleted file mode 100644 index 0764b27e51e..00000000000 --- a/lib/middleware/unicorn_oobgc.rb +++ /dev/null @@ -1,141 +0,0 @@ -# THIS FILE IS TO BE EXTRACTED FROM DISCOURSE IT IS LICENSED UNDER THE MIT LICENSE -# -# The MIT License (MIT) -# -# Copyright (c) 2013 Discourse -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -# Hook into unicorn, unicorn middleware, not rack middleware -# -# Since we need no knowledge about the request we can simply -# hook unicorn -module Middleware::UnicornOobgc - - MIN_REQUESTS_PER_OOBGC = 3 - - # TUNE ME, for Discourse this number is good - MIN_FREE_SLOTS = 50_000 - - # The oobgc implementation is far more efficient in 2.1 - # as we have a bunch of profiling hooks to hook it - # use @tmm1s implementation - def use_gctools? - if @use_gctools.nil? - @use_gctools = - if RUBY_VERSION >= "2.1.0" - require "gctools/oobgc" - true - else - false - end - end - @use_gctools - end - - def verbose(msg=nil) - @verbose ||= ENV["OOBGC_VERBOSE"] == "1" ? :true : :false - if @verbose == :true - if(msg) - puts msg - end - - true - end - end - - def self.init - # hook up HttpServer intercept - ObjectSpace.each_object(Unicorn::HttpServer) do |s| - s.extend(self) - end - rescue - puts "Attempted to patch Unicorn but it is not loaded" - end - - # the closer this is to the GC run the more accurate it is - def estimate_live_num_at_gc(stat) - stat[:heap_live_num] + stat[:heap_free_num] - end - - def process_client(client) - - if use_gctools? - super(client) - GC::OOB.run - return - end - - stat = GC.stat - - @num_requests ||= 0 - @num_requests += 1 - - gc_count = stat[:count] - live_num = stat[:heap_live_num] - - @expect_gc_at ||= estimate_live_num_at_gc(stat) - - super(client) # Unicorn::HttpServer#process_client - - # at this point client is serviced - stat = GC.stat - new_gc_count = stat[:count] - new_live_num = stat[:heap_live_num] - - # no GC happened during the request - if new_gc_count == gc_count - delta = new_live_num - live_num - - @max_delta ||= delta - - if delta > @max_delta - new_delta = (@max_delta * 1.5).to_i - @max_delta = [new_delta, delta].min - else - # this may seem like a very tiny decay rate, but some apps using caching - # can really mess stuff up, if our delta is too low the algorithm fails - new_delta = (@max_delta * 0.99).to_i - @max_delta = [new_delta, delta].max - end - - if @max_delta < MIN_FREE_SLOTS - @max_delta = MIN_FREE_SLOTS - end - - if @num_requests > MIN_REQUESTS_PER_OOBGC && @max_delta * 2 + new_live_num > @expect_gc_at - t = Time.now - GC.start - stat = GC.stat - @expect_gc_at = estimate_live_num_at_gc(stat) - verbose "OobGC hit pid: #{Process.pid} req: #{@num_requests} max delta: #{@max_delta} expect at: #{@expect_gc_at} #{((Time.now - t) * 1000).to_i}ms saved" - @num_requests = 0 - end - else - - verbose "OobGC miss pid: #{Process.pid} reqs: #{@num_requests} max delta: #{@max_delta}" - - @num_requests = 0 - @expect_gc_at = estimate_live_num_at_gc(stat) - - end - - end - -end diff --git a/lib/onebox/engine/discourse_local_onebox.rb b/lib/onebox/engine/discourse_local_onebox.rb index 34bc2789619..44b60030390 100644 --- a/lib/onebox/engine/discourse_local_onebox.rb +++ b/lib/onebox/engine/discourse_local_onebox.rb @@ -34,9 +34,9 @@ module Onebox def upload_html(path) case File.extname(path) - when /^\.(mov|mp4|webm|ogv)$/ + when /^\.(mov|mp4|webm|ogv)$/i "" - when /^\.(mp3|ogg|wav)$/ + when /^\.(mp3|ogg|wav|m4a)$/i "" end end diff --git a/lib/onebox/engine/whitelisted_generic_onebox.rb b/lib/onebox/engine/whitelisted_generic_onebox.rb index 1ea9a90892f..e711b960c9b 100644 --- a/lib/onebox/engine/whitelisted_generic_onebox.rb +++ b/lib/onebox/engine/whitelisted_generic_onebox.rb @@ -1,10 +1,12 @@ +require "ipaddr" + module Onebox module Engine class WhitelistedGenericOnebox # overwrite the whitelist def self.===(other) - true + other.is_a?(URI) ? (IPAddr.new(other.hostname) rescue nil).nil? : true end # ensure we're the last engine to be used diff --git a/lib/oneboxer.rb b/lib/oneboxer.rb index 13d81522025..db043464381 100644 --- a/lib/oneboxer.rb +++ b/lib/oneboxer.rb @@ -16,13 +16,13 @@ module Oneboxer def self.preview(url, options=nil) options ||= {} - Oneboxer.invalidate(url) if options[:invalidate_oneboxes] + invalidate(url) if options[:invalidate_oneboxes] onebox_raw(url)[:preview] end def self.onebox(url, options=nil) options ||= {} - Oneboxer.invalidate(url) if options[:invalidate_oneboxes] + invalidate(url) if options[:invalidate_oneboxes] onebox_raw(url)[:onebox] end @@ -46,10 +46,6 @@ module Oneboxer "" end - def self.oneboxer_exists_for_url?(url) - Onebox.has_matcher?(url) - end - def self.invalidate(url) Rails.cache.delete(onebox_cache_key(url)) end @@ -88,7 +84,7 @@ module Oneboxer doc = Nokogiri::HTML::fragment(doc) if doc.is_a?(String) changed = false - Oneboxer.each_onebox_link(doc) do |url, element| + each_onebox_link(doc) do |url, element| if args && args[:topic_id] url = append_source_topic_id(url, args[:topic_id]) end @@ -112,8 +108,28 @@ module Oneboxer Result.new(doc, changed) end + def self.is_previewing?(user_id) + $redis.get(preview_key(user_id)) == "1" + end + + def self.preview_onebox!(user_id) + $redis.setex(preview_key(user_id), 1.minute, "1") + end + + def self.onebox_previewed!(user_id) + $redis.del(preview_key(user_id)) + end + + def self.engine(url) + Onebox::Matcher.new(url).oneboxed + end + private + def self.preview_key(user_id) + "onebox:preview:#{user_id}" + end + def self.blank_onebox { preview: "", onebox: "" } end diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index a41ab8af8c0..af1174aab22 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -2,6 +2,7 @@ require 'digest/sha1' require 'fileutils' require_dependency 'plugin/metadata' require_dependency 'plugin/auth_provider' +require_dependency 'plugin/theme' class Plugin::CustomEmoji def self.cache_key @@ -24,7 +25,13 @@ class Plugin::Instance attr_reader :admin_route # Memoized array readers - [:assets, :auth_providers, :color_schemes, :initializers, :javascripts, :styles].each do |att| + [:assets, + :auth_providers, + :color_schemes, + :initializers, + :javascripts, + :styles, + :themes].each do |att| class_eval %Q{ def #{att} @#{att} ||= [] @@ -173,6 +180,10 @@ class Plugin::Instance end end + def directory + File.dirname(path) + end + def auto_generated_path File.dirname(path) << "/auto_generated" end @@ -244,6 +255,14 @@ class Plugin::Instance Plugin::CustomEmoji.register(name, url) end + def register_theme(name) + return unless enabled? + + theme = Plugin::Theme.new(self, name) + yield theme + themes << theme + end + def automatic_assets css = styles.join("\n") js = javascripts.join("\n") @@ -363,27 +382,7 @@ JS # # This is a very rough initial implementation def gem(name, version, opts = {}) - gems_path = File.dirname(path) + "/gems/#{RUBY_VERSION}" - spec_path = gems_path + "/specifications" - spec_file = spec_path + "/#{name}-#{version}.gemspec" - unless File.exists? spec_file - command = "gem install #{name} -v #{version} -i #{gems_path} --no-document --ignore-dependencies" - if opts[:source] - command << " --source #{opts[:source]}" - end - puts command - puts `#{command}` - end - if File.exists? spec_file - spec = Gem::Specification.load spec_file - spec.activate - unless opts[:require] == false - require opts[:require_name] ? opts[:require_name] : name - end - else - puts "You are specifying the gem #{name} in #{path}, however it does not exist!" - exit(-1) - end + PluginGem.load(path, name, version, opts) end def enabled_site_setting(setting=nil) diff --git a/lib/plugin/theme.rb b/lib/plugin/theme.rb new file mode 100644 index 00000000000..04128d6f352 --- /dev/null +++ b/lib/plugin/theme.rb @@ -0,0 +1,30 @@ +class Plugin::Theme + attr_reader :color_scheme + + def initialize(plugin, name) + @plugin = plugin + @name = name + end + + def css(name) + @plugin.register_asset("stylesheets/#{name}.scss") + end + + def set_color_scheme(scheme) + @color_scheme = scheme + end + + def register_public + public_dir = "#{@plugin.directory}/public" + if File.exist?(public_dir) + Rails.application.config.before_initialize do |app| + app.middleware.insert_before( + ::Rack::Runtime, + ::ActionDispatch::Static, + public_dir + ) + end + end + end +end + diff --git a/lib/plugin_gem.rb b/lib/plugin_gem.rb new file mode 100644 index 00000000000..48df5e57c8b --- /dev/null +++ b/lib/plugin_gem.rb @@ -0,0 +1,27 @@ +module PluginGem + def self.load(path, name, version, opts=nil) + opts ||= {} + + gems_path = File.dirname(path) + "/gems/#{RUBY_VERSION}" + spec_path = gems_path + "/specifications" + spec_file = spec_path + "/#{name}-#{version}.gemspec" + unless File.exists? spec_file + command = "gem install #{name} -v #{version} -i #{gems_path} --no-document --ignore-dependencies" + if opts[:source] + command << " --source #{opts[:source]}" + end + puts command + puts `#{command}` + end + if File.exists? spec_file + spec = Gem::Specification.load spec_file + spec.activate + unless opts[:require] == false + require opts[:require_name] ? opts[:require_name] : name + end + else + puts "You are specifying the gem #{name} in #{path}, however it does not exist!" + exit(-1) + end + end +end diff --git a/lib/post_creator.rb b/lib/post_creator.rb index 8797a48f8f1..928c8473623 100644 --- a/lib/post_creator.rb +++ b/lib/post_creator.rb @@ -5,7 +5,6 @@ require_dependency 'topic_creator' require_dependency 'post_jobs_enqueuer' require_dependency 'distributed_mutex' require_dependency 'has_errors' -require_dependency 'discourse_featured_link' class PostCreator include HasErrors @@ -93,6 +92,17 @@ class PostCreator return false end + # Make sure none of the users have muted the creator + names = @opts[:target_usernames] + if names.present? && !skip_validations? && !@user.staff? + users = User.where(username: names.split(',').flatten).pluck(:id, :username).to_h + + MutedUser.where(user_id: users.keys, muted_user_id: @user.id).pluck(:user_id).each do |m| + errors[:base] << I18n.t(:not_accepting_pms, username: users[m]) + end + return false if errors[:base].present? + end + if new_topic? topic_creator = TopicCreator.new(@user, guardian, @opts) return false unless skip_validations? || validate_child(topic_creator) @@ -361,6 +371,9 @@ class PostCreator end @post.topic_id = @topic.id @post.topic = @topic + if @topic && @topic.category && @topic.category.all_topics_wiki + @post.wiki = true + end end def update_topic_stats diff --git a/lib/post_destroyer.rb b/lib/post_destroyer.rb index fbb9bff2f5f..49fd91b887d 100644 --- a/lib/post_destroyer.rb +++ b/lib/post_destroyer.rb @@ -29,7 +29,7 @@ class PostDestroyer pa.post_action_type_id IN (?) )", PostActionType.notify_flag_type_ids) .each do |post| - PostDestroyer.new(Discourse.system_user, post).destroy + PostDestroyer.new(Discourse.system_user, post, {context: I18n.t('remove_posts_deleted_by_author')}).destroy end end @@ -187,7 +187,7 @@ class PostDestroyer def recover_user_actions # TODO: Use a trash concept for `user_actions` to avoid churn and simplify this? - UserActionObserver.log_post(@post) + UserActionCreator.log_post(@post) end def remove_associated_replies diff --git a/lib/post_revisor.rb b/lib/post_revisor.rb index 4fea530847f..9b9ef68d54b 100644 --- a/lib/post_revisor.rb +++ b/lib/post_revisor.rb @@ -250,7 +250,7 @@ class PostRevisor prev_owner = User.find(@post.user_id) new_owner = User.find(@fields["user_id"]) - # UserActionObserver will create new UserAction records for the new owner + # UserActionCreator will create new UserAction records for the new owner UserAction.where(target_post_id: @post.id) .where(user_id: prev_owner.id) @@ -287,22 +287,26 @@ class PostRevisor .where(action_type: UserAction::WAS_LIKED) .update_all(user_id: new_owner.id) - prev_owner.user_stat.post_count -= 1 - prev_owner.user_stat.topic_count -= 1 if @post.is_first_post? - prev_owner.user_stat.likes_received -= likes - prev_owner.user_stat.update_topic_reply_count + private_message = @post.topic.private_message? + + prev_owner_user_stat = prev_owner.user_stat + prev_owner_user_stat.post_count -= 1 + prev_owner_user_stat.topic_count -= 1 if @post.is_first_post? + prev_owner_user_stat.likes_received -= likes if !private_message + prev_owner_user_stat.update_topic_reply_count if @post.created_at == prev_owner.user_stat.first_post_created_at - prev_owner.user_stat.first_post_created_at = prev_owner.posts.order('created_at ASC').first.try(:created_at) + prev_owner_user_stat.first_post_created_at = prev_owner.posts.order('created_at ASC').first.try(:created_at) end - prev_owner.user_stat.save + prev_owner_user_stat.save! - new_owner.user_stat.post_count += 1 - new_owner.user_stat.topic_count += 1 if @post.is_first_post? - new_owner.user_stat.likes_received += likes - new_owner.user_stat.update_topic_reply_count - new_owner.user_stat.save + new_owner_user_stat = new_owner.user_stat + new_owner_user_stat.post_count += 1 + new_owner_user_stat.topic_count += 1 if @post.is_first_post? + new_owner_user_stat.likes_received += likes if !private_message + new_owner_user_stat.update_topic_reply_count + new_owner_user_stat.save! end end diff --git a/lib/pretty_text/helpers.rb b/lib/pretty_text/helpers.rb index fa61e9efc2f..1c0c2f0e1a1 100644 --- a/lib/pretty_text/helpers.rb +++ b/lib/pretty_text/helpers.rb @@ -50,7 +50,7 @@ module PrettyText topic = Topic.find_by(id: topic_id) if topic && Guardian.new.can_see?(topic) { - title: topic.title, + title: Rack::Utils.escape_html(topic.title), href: topic.url } end diff --git a/lib/sass/discourse_sass_importer.rb b/lib/sass/discourse_sass_importer.rb index a3e877b8e50..62230db937f 100644 --- a/lib/sass/discourse_sass_importer.rb +++ b/lib/sass/discourse_sass_importer.rb @@ -41,15 +41,9 @@ class DiscourseSassImporter < Sass::Importers::Filesystem case name when "theme_variables" contents = "" - if color_scheme = ColorScheme.enabled - ColorScheme.base_colors.each do |n, base_hex| - override = color_scheme.colors_by_name[n] - contents << "$#{n}: ##{override ? override.hex : base_hex} !default;\n" - end - else - special_imports[name].each do |css_file| - contents << File.read(css_file) - end + ColorScheme.base_colors.each do |n, base_hex| + hex_val = ColorScheme.hex_for_name(n) || base_hex + contents << "$#{n}: ##{hex_val} !default;\n" end when "category_backgrounds" contents = "" diff --git a/lib/search.rb b/lib/search.rb index 6f0e374faa3..cdad501bd86 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -54,7 +54,7 @@ class Search posts.each do |post| # force indexing post.cooked += " " - SearchObserver.index(post) + SearchIndexer.index(post) end posts = Post.joins(:topic) @@ -67,7 +67,7 @@ class Search posts.each do |post| # force indexing post.cooked += " " - SearchObserver.index(post) + SearchIndexer.index(post) end nil diff --git a/lib/search/grouped_search_results.rb b/lib/search/grouped_search_results.rb index 2fa450bb745..47e13254883 100644 --- a/lib/search/grouped_search_results.rb +++ b/lib/search/grouped_search_results.rb @@ -49,7 +49,7 @@ class Search def self.blurb_for(cooked, term=nil, blurb_length=200) - cooked = SearchObserver::HtmlScrubber.scrub(cooked).squish + cooked = SearchIndexer::HtmlScrubber.scrub(cooked).squish blurb = nil if term diff --git a/lib/secure_session.rb b/lib/secure_session.rb new file mode 100644 index 00000000000..bbe9a71833e --- /dev/null +++ b/lib/secure_session.rb @@ -0,0 +1,18 @@ +# session that is not stored in cookie, expires after 1.hour unconditionally +class SecureSession + def initialize(prefix) + @prefix = prefix + end + + def [](key) + $redis.get("#{@prefix}#{key}") + end + + def []=(key,val) + if val == nil + $redis.del("#{@prefix}#{key}") + else + $redis.setex("#{@prefix}#{key}", 1.hour, val.to_s) + end + end +end diff --git a/lib/tasks/emoji.rake b/lib/tasks/emoji.rake index 14190b74eb7..6ea15b77f34 100644 --- a/lib/tasks/emoji.rake +++ b/lib/tasks/emoji.rake @@ -40,7 +40,10 @@ task "emoji:update" => :environment do code = cells[1].at_css("a")["name"] - next unless emojis[code] + unless emojis[code] + code = code.gsub(/_fe0f/, "") + next unless emojis[code] + end apple = cell_to_image(cells[4]) google = cell_to_image(cells[5]) @@ -50,7 +53,7 @@ task "emoji:update" => :environment do if WINDOWS_FLAGS.include?(code) windows = custom_windows_flag(code) else - windows = cell_to_image(cells[9]) + windows = cell_to_image(cells[11]) end if apple.blank? || google.blank? || twitter.blank? || one.blank? || windows.blank? @@ -94,13 +97,16 @@ def custom_windows_flag(code) end def write_emojis(emojis, aliases, style, folder) - path = "public/images/emoji/#{folder}/" + path = "public/images/emoji/#{folder}" - FileUtils.rm_f Dir.glob("#{path}/*") + # Uncomment to recreate all emojis + # FileUtils.rm_f Dir.glob("#{path}/*") puts folder emojis.values.each do |emoji| + next if emoji[style].nil? + write_emoji("#{path}/#{emoji[:name]}.png", emoji[style]) if aliases[emoji[:name]] aliases[emoji[:name]].each do |new_name| @@ -113,7 +119,9 @@ def write_emojis(emojis, aliases, style, folder) end def write_emoji(path, emoji) - open(path, "wb") { |f| f << emoji } - `pngout #{path}` - putc "." + open(path, "wb") { |f| f << emoji } + `pngout #{path}` + putc "." +ensure + raise "Failed to write emoji: #{path}" if File.exists?(path) && !File.size?(path) end diff --git a/lib/tasks/posts.rake b/lib/tasks/posts.rake index 324d3ded1d5..b6a696f111d 100644 --- a/lib/tasks/posts.rake +++ b/lib/tasks/posts.rake @@ -116,16 +116,7 @@ task 'posts:normalize_code' => :environment do puts "#{i} posts normalized!" end -desc 'Remap all posts matching specific string' -task 'posts:remap', [:find, :replace] => [:environment] do |_,args| - find = args[:find] - replace = args[:replace] - if !find || !replace - puts "ERROR: Expecting rake posts:rebake_match[find,replace]" - exit 1 - end - - puts "Remapping" +def remap_posts(find, replace="") i = 0 Post.where("raw LIKE ?", "%#{find}%").each do |p| new_raw = p.raw.dup @@ -137,5 +128,41 @@ task 'posts:remap', [:find, :replace] => [:environment] do |_,args| i += 1 end end - puts "", "#{i} posts remapped!", "" + i +end + +desc 'Remap all posts matching specific string' +task 'posts:remap', [:find, :replace] => [:environment] do |_,args| + + find = args[:find] + replace = args[:replace] + if !find + puts "ERROR: Expecting rake posts:remap['find','replace']" + exit 1 + elsif !replace + puts "ERROR: Expecting rake posts:remap['find','replace']. Want to delete a word/string instead? Try rake posts:delete_word['word-to-delete']" + exit 1 + end + + puts "Remapping" + total = remap_posts(find, replace) + puts "", "#{total} posts remapped!", "" +end + +desc 'Delete occurrence of a word/string' +task 'posts:delete_word', [:find] => [:environment] do |_,args| + require 'highline/import' + + find = args[:find] + if !find + puts "ERROR: Expecting rake posts:delete_word['word-to-delete']" + exit 1 + else + confirm_replace = ask("Are you sure you want to remove all occurrences of '#{find}'? (Y/n) ") + exit 1 unless (confirm_replace == "" || confirm_replace.downcase == 'y') + end + + puts "Processing" + total = remap_posts(find) + puts "", "#{total} posts updated!", "" end diff --git a/lib/tasks/search.rake b/lib/tasks/search.rake index 4f118227c69..c944812d793 100644 --- a/lib/tasks/search.rake +++ b/lib/tasks/search.rake @@ -18,8 +18,8 @@ def reindex_search(db=RailsMultisite::ConnectionManagement.current_db) post_number = p["post_number"].to_i topic_id = p["topic_id"].to_i - SearchObserver.update_posts_index(post_id, cooked, title, category) - SearchObserver.update_topics_index(topic_id, title , cooked) if post_number == 1 + SearchIndexer.update_posts_index(post_id, cooked, title, category) + SearchIndexer.update_topics_index(topic_id, title , cooked) if post_number == 1 putc "." end @@ -30,7 +30,7 @@ def reindex_search(db=RailsMultisite::ConnectionManagement.current_db) id = u["id"] name = u["name"] username = u["username"] - SearchObserver.update_users_index(id, username, name) + SearchIndexer.update_users_index(id, username, name) putc "." end @@ -41,7 +41,7 @@ def reindex_search(db=RailsMultisite::ConnectionManagement.current_db) Category.exec_sql("select id, name from categories").each do |c| id = c["id"] name = c["name"] - SearchObserver.update_categories_index(id, name) + SearchIndexer.update_categories_index(id, name) end puts diff --git a/lib/tasks/user_actions.rake b/lib/tasks/user_actions.rake index b9ced27e4e5..ffba1f2b228 100644 --- a/lib/tasks/user_actions.rake +++ b/lib/tasks/user_actions.rake @@ -1,13 +1,15 @@ desc "rebuild the user_actions table" task "user_actions:rebuild" => :environment do - o = UserActionObserver.send :new MessageBus.off UserAction.delete_all - PostAction.all.each{|i| o.after_save(i)} - Topic.all.each {|i| o.after_save(i)} - Post.all.each {|i| o.after_save(i)} - Notification.all.each {|i| o.after_save(i)} - # not really needed but who knows - MessageBus.on + PostAction.all.each{|i| UserActionCreator.log_post_action(i)} + Topic.all.each {|i| UserActionCreator.log_topic(i)} + Post.all.each {|i| UserActionCreator.log_post(i)} + Notification.all.each do |notification| + UserActionCreator.log_notification(notification.post, + notification.user, + notification.notification_type, + notification.user) + end end diff --git a/lib/topic_view.rb b/lib/topic_view.rb index 93bda88857e..81e69997968 100644 --- a/lib/topic_view.rb +++ b/lib/topic_view.rb @@ -280,7 +280,7 @@ class TopicView def participants @participants ||= begin participants = {} - User.where(id: post_counts_by_user.map {|k,v| k}).each {|u| participants[u.id] = u} + User.where(id: post_counts_by_user.map {|k,v| k}).includes(:primary_group).each {|u| participants[u.id] = u} participants end end diff --git a/lib/validators/censored_words_validator.rb b/lib/validators/censored_words_validator.rb new file mode 100644 index 00000000000..58abb9a6cd6 --- /dev/null +++ b/lib/validators/censored_words_validator.rb @@ -0,0 +1,27 @@ +class CensoredWordsValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + if !SiteSetting.censored_words.blank? && + !(censored_words = value.scan(/#{SiteSetting.censored_words}/i)).empty? + + record.errors.add( + attribute, :contains_censored_words, + censored_words: join_censored_words(censored_words) + ) + elsif !SiteSetting.censored_pattern.blank? && + !(censored_words = value.scan(/#{SiteSetting.censored_pattern}/i)).empty? + + record.errors.add( + attribute, :matches_censored_pattern, + censored_words: join_censored_words(censored_words) + ) + end + end + + private + + def join_censored_words(censored_words) + censored_words.map!(&:downcase) + censored_words.uniq! + censored_words.join(", ") + end +end diff --git a/lib/validators/email_validator.rb b/lib/validators/email_validator.rb index b686379571a..468c0050710 100644 --- a/lib/validators/email_validator.rb +++ b/lib/validators/email_validator.rb @@ -26,7 +26,7 @@ class EmailValidator < ActiveModel::EachValidator end def self.email_regex - /^[a-zA-Z0-9!#\$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-zA-Z0-9!#\$%&'\*+\/=?\^_`{|}~\-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/ + /\A[a-zA-Z0-9!#\$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-zA-Z0-9!#\$%&'\*+\/=?\^_`{|}~\-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$\z/ end end diff --git a/lib/version.rb b/lib/version.rb index 11ffbe50335..312e96a6f54 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -3,9 +3,9 @@ module Discourse unless defined? ::Discourse::VERSION module VERSION #:nodoc: MAJOR = 1 - MINOR = 7 + MINOR = 8 TINY = 0 - PRE = 'beta9' + PRE = 'beta2' STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end diff --git a/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 b/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 index ca9cbbda66a..074d93a3b42 100644 --- a/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 +++ b/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 @@ -21,6 +21,7 @@ function initializeDetails(api) { "details_text", { multiline: false } ); + this.set('optionsVisible', false); } } }); diff --git a/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 b/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 index afe45dfffd6..427687886ab 100644 --- a/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 +++ b/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 @@ -36,7 +36,7 @@ test('details button', () => { equal( find(".d-editor-input").val(), `[details=${I18n.t("composer.details_title")}]This is my title[/details]`, - 'it should contain the right output' + 'it should contain the right selected output' ); const textarea = findTextarea(); diff --git a/plugins/lazyYT/assets/javascripts/initializers/lazyYT.js.es6 b/plugins/lazyYT/assets/javascripts/initializers/lazyYT.js.es6 index b05cf205393..21037618f79 100644 --- a/plugins/lazyYT/assets/javascripts/initializers/lazyYT.js.es6 +++ b/plugins/lazyYT/assets/javascripts/initializers/lazyYT.js.es6 @@ -11,14 +11,6 @@ export default { const iframes = $('.lazyYT', $elem); if (iframes.length === 0) { return; } - // We use this because watching videos fullscreen in Chrome was super buggy - // otherwise. Thanks to arrendek from q23 for the technique. - $elem.iframeTracker({ blurCallback: () => { - $(document).on("scroll.discourse-youtube", returnFalse); - window.setTimeout(() => $(document).off('scroll.discourse-youtube', returnFalse), 1500); - $(document).scroll(); - }}); - $('.lazyYT', $elem).lazyYT({ onPlay(e, $el) { // don't cloak posts that have playing videos in them @@ -26,6 +18,14 @@ export default { if (postId) { api.preventCloak(postId); } + + // We use this because watching videos fullscreen in Chrome was super buggy + // otherwise. Thanks to arrendek from q23 for the technique. + $('iframe', iframes).iframeTracker({ blurCallback: () => { + $(document).on("scroll.discourse-youtube", returnFalse); + window.setTimeout(() => $(document).off('scroll.discourse-youtube', returnFalse), 1500); + $(document).scroll(); + }}); } }); diff --git a/plugins/lazyYT/assets/stylesheets/lazyYT.css b/plugins/lazyYT/assets/stylesheets/lazyYT.css index 732735138a0..38d6bbff693 100644 --- a/plugins/lazyYT/assets/stylesheets/lazyYT.css +++ b/plugins/lazyYT/assets/stylesheets/lazyYT.css @@ -13,6 +13,7 @@ padding: 0 0 56.25% 0; overflow: hidden; background-color: #000000; + margin-bottom: 12px; } .lazyYT-container iframe { diff --git a/plugins/poll/assets/javascripts/initializers/extend-for-poll.js.es6 b/plugins/poll/assets/javascripts/initializers/extend-for-poll.js.es6 index 09b8fdfa319..9fa2577af64 100644 --- a/plugins/poll/assets/javascripts/initializers/extend-for-poll.js.es6 +++ b/plugins/poll/assets/javascripts/initializers/extend-for-poll.js.es6 @@ -43,6 +43,7 @@ function initializePolls(api) { } }); this.set("pollsObject", this._polls); + _glued.forEach(g => g.queueRerender()); } } }); diff --git a/plugins/poll/assets/javascripts/widgets/discourse-poll.js.es6 b/plugins/poll/assets/javascripts/widgets/discourse-poll.js.es6 index 1f2fe22c323..60fc833e39c 100644 --- a/plugins/poll/assets/javascripts/widgets/discourse-poll.js.es6 +++ b/plugins/poll/assets/javascripts/widgets/discourse-poll.js.es6 @@ -78,8 +78,10 @@ createWidget('discourse-poll-voters', { fetchVoters() { const { attrs, state } = this; + if (state.loaded === 'loading') { return; } const { voterIds } = attrs; + if (!voterIds.length) { return; } const windowSize = Math.round(($('.poll-container:eq(0)').width() / 25) * 2); @@ -133,10 +135,22 @@ createWidget('discourse-poll-standard-results', { html(attrs) { const { poll } = attrs; const options = poll.get('options'); - if (options) { + if (options) { const voters = poll.get('voters'); - const ordered = options.sort((a, b) => b.votes - a.votes); + const ordered = _.clone(options).sort((a, b) => { + if (a.votes < b.votes) { + return 1; + } else if (a.votes === b.votes) { + if (a.html < b.html) { + return -1; + } else { + return 1; + } + } else { + return -1; + } + }); const percentages = voters === 0 ? Array(ordered.length).fill(0) : @@ -146,8 +160,9 @@ createWidget('discourse-poll-standard-results', { return ordered.map((option, idx) => { const contents = []; - const per = rounded[idx].toString(); + const chosen = attrs.vote.includes(option.id); + contents.push(h('div.option', h('p', [ h('span.percentage', `${per}%`), optionHtml(option) ]) )); @@ -164,7 +179,7 @@ createWidget('discourse-poll-standard-results', { })); } - return h('li', contents); + return h('li', { className: `${chosen ? 'chosen' : ''}` }, contents); }); } } diff --git a/plugins/poll/assets/stylesheets/common/poll.scss b/plugins/poll/assets/stylesheets/common/poll.scss index 762ce7638f8..d52c6e1429a 100644 --- a/plugins/poll/assets/stylesheets/common/poll.scss +++ b/plugins/poll/assets/stylesheets/common/poll.scss @@ -77,7 +77,7 @@ div.poll { display: inline; } - margin-top: 10px; + margin-top: 4px; } .poll-voters-toggle-expand { @@ -107,7 +107,11 @@ div.poll { .bar { height: 10px; - background: $primary; + background: dark-light-diff($primary, $secondary, 50%, -25%);; + } + + .chosen .bar { + background: $tertiary; } } diff --git a/plugins/poll/config/locales/client.nb_NO.yml b/plugins/poll/config/locales/client.nb_NO.yml index b0793b45be7..c7b43bab0c4 100644 --- a/plugins/poll/config/locales/client.nb_NO.yml +++ b/plugins/poll/config/locales/client.nb_NO.yml @@ -16,12 +16,19 @@ nb_NO: other: "antall stemmer" average_rating: "Gjennomsnitt: %{average}." public: - title: "Stemmer er offentlig." + title: "Stemmer er offentlige." multiple: help: at_least_min_options: one: "Velg minst 1 alternativ" - other: "Velg minst %{count} alternativ" + other: "Velg minst %{count} alternativer" + up_to_max_options: + one: "Velg inntil 1 alternativ" + other: "Velg inntil %{count} alternativer" + x_options: + one: "Velg 1 alternativ" + other: "Velg %{count} alternativer" + between_min_and_max_options: "Velg mellom %{min} og %{max} alternativer" cast-votes: title: "Stem nå" label: "Stem!" @@ -32,24 +39,31 @@ nb_NO: title: "Tilbake til dine stemmer" label: "Skjul resultater" open: - title: "Åpne avstemming" + title: "Åpne avstemning" label: "Åpne" - confirm: "Er du sikker på at du vil åpne avstemmingen?" + confirm: "Er du sikker på at du vil åpne denne avstemningen?" close: - title: "Lukk avstemming" + title: "Lukk avstemning" label: "Lukk" - confirm: "Er du sikker på at du vil lukke avstemmingen?" - error_while_casting_votes: "Beklager, det oppstod en feil når du ga din stemme." + confirm: "Er du sikker på at du vil lukke avstemningen?" + error_while_toggling_status: "Beklager, det oppstod en feil ved endring av status på denne avstemningen." + error_while_casting_votes: "Beklager, det oppstod en feil da du ga din stemme." + error_while_fetching_voters: "Beklager, det oppstod en feil når stemmegivere skulle vises." ui_builder: - insert: 'Sett inn avstemming ' + title: Lag avstemning. + insert: 'Sett inn avstemning ' help: options_count: Må inneholde minst 2 alternativer poll_type: - regular: Enkelt valg + label: Type + regular: Et valg multiple: Flere valg - number: Nummer vurdering + number: Nummervurdering poll_config: - max: Maks - step: skritt + max: Maksimum + min: Minimum + step: Steg poll_public: - label: Se hvem som har stemt + label: Vis hvem som har stemt + poll_options: + label: Oppgi et valgalternativ for avstemning per linje diff --git a/plugins/poll/config/locales/client.uk.yml b/plugins/poll/config/locales/client.uk.yml index f825d6d3d67..aa468da1dc8 100644 --- a/plugins/poll/config/locales/client.uk.yml +++ b/plugins/poll/config/locales/client.uk.yml @@ -8,6 +8,19 @@ uk: js: poll: + total_votes: + one: "голос" + few: "голосів" + other: "голоси" + average_rating: "Середній рейтинг: %{average}." + multiple: + help: + at_least_min_options: + one: "Виберіть хоча б 1 варіант" + few: "Виберіть хоча б %{count} варіантів" + other: "Виберіть хоча б %{count} варіанти" + cast-votes: + label: "Проголосувати!" show-results: label: "Показати результати" hide-results: diff --git a/plugins/poll/config/locales/client.ur.yml b/plugins/poll/config/locales/client.ur.yml index 7739827c863..58bc9735bcb 100644 --- a/plugins/poll/config/locales/client.ur.yml +++ b/plugins/poll/config/locales/client.ur.yml @@ -1,89 +1,8 @@ # encoding: utf-8 -# This file contains content for the client portion of the poll plugin, sent out -# to the Javascript app. # -# To work with us on translations, see: +# Never edit this file. It will be overwritten when translations are pulled from Transifex. +# +# To work with us on translations, join this project: # https://www.transifex.com/projects/p/discourse-org/ -# -# This is a "source" file, which is used by Transifex to get translations for other languages. -# After this file is changed, it needs to be pushed by a maintainer to Transifex: -# -# tx push -s -# -# Read more here: https://meta.discourse.org/t/contribute-a-translation-to-discourse/14882 -# -# To validate this YAML file after you change it, please paste it into -# http://yamllint.com/ -ur: - js: - poll: - voters: - one: "voter" - other: "voters" - total_votes: - one: "total vote" - other: "total votes" - - average_rating: "Average rating: %{average}." - - public: - title: "Votes are public." - - multiple: - help: - at_least_min_options: - one: "Choose at least 1 option" - other: "Choose at least %{count} options" - up_to_max_options: - one: "Choose up to 1 option" - other: "Choose up to %{count} options" - x_options: - one: "Choose 1 option" - other: "Choose %{count} options" - between_min_and_max_options: "Choose between %{min} and %{max} options" - - cast-votes: - title: "Cast your votes" - label: "Vote now!" - - show-results: - title: "Display the poll results" - label: "Show results" - - hide-results: - title: "Back to your votes" - label: "Hide results" - - open: - title: "Open the poll" - label: "Open" - confirm: "Are you sure you want to open this poll?" - - close: - title: "Close the poll" - label: "Close" - confirm: "Are you sure you want to close this poll?" - - error_while_toggling_status: "Sorry, there was an error toggling the status of this poll." - error_while_casting_votes: "Sorry, there was an error casting your votes." - error_while_fetching_voters: "Sorry, there was an error displaying the voters." - - ui_builder: - title: Build Poll - insert: Insert Poll - help: - options_count: Enter at least 2 options - poll_type: - label: Type - regular: Single Choice - multiple: Multiple Choice - number: Number Rating - poll_config: - max: Max - min: Min - step: Step - poll_public: - label: Show who voted - poll_options: - label: Enter one poll option per line +ur: {} diff --git a/plugins/poll/config/locales/client.zh_TW.yml b/plugins/poll/config/locales/client.zh_TW.yml index 92c18de9aec..d3690bc5197 100644 --- a/plugins/poll/config/locales/client.zh_TW.yml +++ b/plugins/poll/config/locales/client.zh_TW.yml @@ -5,4 +5,60 @@ # To work with us on translations, join this project: # https://www.transifex.com/projects/p/discourse-org/ -zh_TW: {} +zh_TW: + js: + poll: + voters: + other: "投票者" + total_votes: + other: "總票數" + average_rating: "平均評分:%{average}。" + public: + title: "投票是公開的。" + multiple: + help: + at_least_min_options: + other: "至少選擇 %{count} 個選項" + up_to_max_options: + other: "最多選擇 %{count} 個選項" + x_options: + other: "選擇 %{count} 個選項" + between_min_and_max_options: "選擇 %{min}%{max} 個選項" + cast-votes: + title: "投你的票" + label: "現在投票!" + show-results: + title: "顯示投票結果" + label: "顯示結果" + hide-results: + title: "返回到你的投票" + label: "隱藏結果" + open: + title: "開啟投票" + label: "開啟" + confirm: "你確定要開啟這個投票麼?" + close: + title: "關閉投票" + label: "關閉" + confirm: "你確定要關閉這個投票?" + error_while_toggling_status: "對不起,改變投票狀態時出錯了。" + error_while_casting_votes: "對不起,投票時出錯了。" + error_while_fetching_voters: "對不起,顯示投票者時出錯了。" + ui_builder: + title: 創建投票 + insert: 插入投票 + help: + options_count: 輸入至少 2 個選項 + poll_type: + label: 類型 + regular: 單選 + multiple: 多選 + number: 評分 + poll_config: + max: 最大 + min: 最小 + step: 梯級 + poll_public: + label: 顯示投票人 + poll_options: + label: 每行輸入一個調查選項 diff --git a/plugins/poll/config/locales/server.de.yml b/plugins/poll/config/locales/server.de.yml index 48855612b12..5c62af1aa34 100644 --- a/plugins/poll/config/locales/server.de.yml +++ b/plugins/poll/config/locales/server.de.yml @@ -38,6 +38,6 @@ de: topic_must_be_open_to_vote: "Das Thema muss zum Abstimmen geöffnet sein." poll_must_be_open_to_vote: "Die Umfrage muss zum Abstimmen gestartet sein." topic_must_be_open_to_toggle_status: "Damit du den Status ändern kannst, muss das Thema geöffnet sein." - only_staff_or_op_can_toggle_status: "Nur Mitarbeiter und der Autor des Beitrags können den Status der Umfrage ändern." + only_staff_or_op_can_toggle_status: "Nur ein Team-Mitglied und der Autor des Beitrags können den Status der Umfrage ändern." email: link_to_poll: "Klicke hier, um die Umfrage zu sehen." diff --git a/plugins/poll/config/locales/server.ja.yml b/plugins/poll/config/locales/server.ja.yml index 7866ecedb99..7cb65b2a8ac 100644 --- a/plugins/poll/config/locales/server.ja.yml +++ b/plugins/poll/config/locales/server.ja.yml @@ -7,7 +7,7 @@ ja: site_settings: - poll_enabled: "ユーザによる投票を許可しますか?" + poll_enabled: "ユーザーによる投票を許可しますか?" poll_maximum_options: "投票で許可されるオプションの最大数。" poll: multiple_polls_without_name: "名前のない複数の投票があります。一意に投票結果を識別するために、属性'name'を使用します。" diff --git a/plugins/poll/config/locales/server.nb_NO.yml b/plugins/poll/config/locales/server.nb_NO.yml index 51352fbefdd..8351e953157 100644 --- a/plugins/poll/config/locales/server.nb_NO.yml +++ b/plugins/poll/config/locales/server.nb_NO.yml @@ -7,27 +7,37 @@ nb_NO: site_settings: - poll_enabled: "Tillat brukere å opprette spørreundersøkelser" - poll_maximum_options: "Maksimalt antall alternativer i en spørreundersøkelse som tillates." + poll_enabled: "Tillate brukere å opprette avstemning?" + poll_maximum_options: "Maksimalt antall alternativer som tillates i en avstemning." + poll_edit_window_mins: "Antall minutter etter at et innlegg er opprettet som avstemninger kan redigeres." poll: - multiple_polls_without_name: "Det er flere spørreundersøkelser uten et navn. Bruk 'navn' attributten til å identifisere spørreundersøkelsene dine." - multiple_polls_with_same_name: "Det er flere spørreundersøkelser med samme navn: %{name}. Bruk 'name' attributten til å bestemme spørreundersøkelsene dine entydig." - default_poll_must_have_at_least_2_options: "Spørrsundersøkelser må inneholde minst 2 alternativer." - named_poll_must_have_at_least_2_options: "Spørresundersøkelsen %{name} må ha minst 2 svaralternativer." + multiple_polls_without_name: "Det er flere avstemninger uten et navn. Bruk 'navn'-attributten til å identifisere avstemningene dine." + multiple_polls_with_same_name: "Det er flere avstemninger med samme navn: %{name}. Bruk 'name'-attributten til å identifisere avstemningene dine entydig." + default_poll_must_have_at_least_2_options: "Avstemninger må inneholde minst 2 alternativer." + named_poll_must_have_at_least_2_options: "Avstemningen %{name} må ha minst 2 svaralternativer." default_poll_must_have_less_options: - one: "Spørreundersøkelsen må ha mindre enn 1 svaralternativ" - other: "Spørreundersøkelsen må ha mindre enn %{max} svaralternativer." - default_poll_must_have_different_options: "Spørreundersøkelsen må ha ulike alternativer." - named_poll_must_have_different_options: "Spørresundersøkelsen %{name} må ha ulike svaralternativer." - default_poll_with_multiple_choices_has_invalid_parameters: "Spørreundersøkelsen med flere svaralternativer har ugyldige parametere." - named_poll_with_multiple_choices_has_invalid_parameters: "Spørresundersøkelsen %{name} med flere svaralternativer har ugyldige parametere." + one: "Avstemningen må ha mindre enn 1 svaralternativ" + other: "Avstemningen må ha mindre enn %{max} svaralternativer." + named_poll_must_have_less_options: + one: "Avstemningen %{name} må ha mindre enn 1 valg." + other: "Avstemningen %{name} må ha mindre enn %{count} valg." + default_poll_must_have_different_options: "Avstemningen må ha ulike alternativer." + named_poll_must_have_different_options: "Avstemningen %{name} må ha ulike svaralternativer." + default_poll_with_multiple_choices_has_invalid_parameters: "Avstemningen med flere svaralternativer har ugyldige parametere." + named_poll_with_multiple_choices_has_invalid_parameters: "Avstemningen %{name} med flere svaralternativer har ugyldige parametere." requires_at_least_1_valid_option: "Du må velge minst 1 gyldig alternativ." - no_polls_associated_with_this_post: "Ingen spørreunderøkelser er assosiert med dette innlegget." - no_poll_with_this_name: "Ingen undersøkelse med navnet %{name} er assosiert med dette innlegget." + default_cannot_be_made_public: "Avstemninger med avgitte stemmer kan ikke gjøres offentlige." + named_cannot_be_made_public: "Avstemningen %{name} har avgitte stemmer og kan ikke gjøres offentlig." + edit_window_expired: + cannot_change_polls: "Du kan ikke legge til, fjerne eller navne om avstemninger etter de første %{minutes} minuttene." + op_cannot_edit_options: "Du kan ikke legge til eller fjerne svaralternativer etter de første %{minutes} minuttene. Kontakt en moderator hvis du har behov for å redigere et svaralternativ." + staff_cannot_add_or_remove_options: "Du kan ikke lette til eller fjerne valgalternativer for avstemningen etter de første %{minutes} minuttene. Du bør stenge dette emnet og lage et nytt i stedet." + no_polls_associated_with_this_post: "Ingen avstemning er assosiert med dette innlegget." + no_poll_with_this_name: "Ingen avstemning med navnet %{name} er assosiert med dette innlegget." post_is_deleted: "Kan ikke agere på et slettet innlegg." topic_must_be_open_to_vote: "Emnet må være åpent for å kunne avgi stemme." - poll_must_be_open_to_vote: "Spørreundersøkelsen må være åpen for å kunne avigi stemme." + poll_must_be_open_to_vote: "Avstemningen må være åpen for å kunne avgi stemme." topic_must_be_open_to_toggle_status: "Emnet må være åpent for å redigere status." - only_staff_or_op_can_toggle_status: "Kun forumpersonalet eller den forfatteren av emnet kan redigere status på spørreundersøkelsen." + only_staff_or_op_can_toggle_status: "Kun forumpersonalet eller den forfatteren av emnet kan redigere status på avstemningen." email: link_to_poll: "Klikk for å se avstemningen" diff --git a/plugins/poll/config/locales/server.nl.yml b/plugins/poll/config/locales/server.nl.yml index 735e14eb8d9..c451e42c332 100644 --- a/plugins/poll/config/locales/server.nl.yml +++ b/plugins/poll/config/locales/server.nl.yml @@ -30,8 +30,8 @@ nl: named_cannot_be_made_public: "De poll genaamd %{name} heeft stemmen die niet openbaar gemaakt kunnen worden" edit_window_expired: cannot_change_polls: "Je kunt na %{minutes} minuten geen polls meer toevoegen, verwijderen of hernoemen." - op_cannot_edit_options: "Je kunt na %{minutes} minuten geen polls meer toevoegen, verwijderen of hernoemen. Neem contact op met een moderator als je een poll optie wilt wijzigen." - staff_cannot_add_or_remove_options: "Je kunt na %{minutes} minuten geen polls meer toevoegen, verwijderen of hernoemen. Sluit deze topic en maak een nieuwe." + op_cannot_edit_options: "Je kunt na %{minutes} minuten geen poll opties meer toevoegen of verwijderen. Neem contact op met een moderator als je een poll optie wilt wijzigen." + staff_cannot_add_or_remove_options: "Je kunt na %{minutes} minuten geen poll opties meer toevoegen of verwijderen. Je kan dit topic sluiten en een nieuw topic maken." no_polls_associated_with_this_post: "Er bestaan geen polls voor dit bericht." no_poll_with_this_name: "Er bestaat geen poll met de naam %{name} voor dit bericht." post_is_deleted: "Dit kan niet bij een verwijderd bericht." diff --git a/plugins/poll/config/locales/server.ur.yml b/plugins/poll/config/locales/server.ur.yml index 051a9d61d85..58bc9735bcb 100644 --- a/plugins/poll/config/locales/server.ur.yml +++ b/plugins/poll/config/locales/server.ur.yml @@ -1,65 +1,8 @@ # encoding: utf-8 -# This file contains content for the server portion of the poll plugin used by Ruby # -# To work with us on translations, see: +# Never edit this file. It will be overwritten when translations are pulled from Transifex. +# +# To work with us on translations, join this project: # https://www.transifex.com/projects/p/discourse-org/ -# -# This is a "source" file, which is used by Transifex to get translations for other languages. -# After this file is changed, it needs to be pushed by a maintainer to Transifex: -# -# tx push -s -# -# Read more here: https://meta.discourse.org/t/contribute-a-translation-to-discourse/14882 -# -# To validate this YAML file after you change it, please paste it into -# http://yamllint.com/ -ur: - site_settings: - poll_enabled: "Allow users to create polls?" - poll_maximum_options: "Maximum number of options allowed in a poll." - poll_edit_window_mins: "Number of minutes after post creation during which polls can be edited." - - poll: - multiple_polls_without_name: "There are multiple polls without a name. Use the 'name' attribute to uniquely identify your polls." - multiple_polls_with_same_name: "There are multiple polls with the same name: %{name}. Use the 'name' attribute to uniquely identify your polls." - - default_poll_must_have_at_least_2_options: "Poll must have at least 2 options." - named_poll_must_have_at_least_2_options: "Poll named %{name} must have at least 2 options." - - default_poll_must_have_less_options: - one: "Poll must have less than 1 option." - other: "Poll must have less than %{count} options." - named_poll_must_have_less_options: - one: "Poll named %{name} must have less than 1 option." - other: "Poll named %{name} must have less than %{count} options." - - default_poll_must_have_different_options: "Poll must have different options." - named_poll_must_have_different_options: "Poll named %{name} must have different options." - - default_poll_with_multiple_choices_has_invalid_parameters: "Poll with multiple choices has invalid parameters." - named_poll_with_multiple_choices_has_invalid_parameters: "Poll named %{name} with multiple choice has invalid parameters." - - requires_at_least_1_valid_option: "You must select at least 1 valid option." - - default_cannot_be_made_public: "Poll with votes cannot be made public." - named_cannot_be_made_public: "Poll named %{name} has votes cannot be made public." - - edit_window_expired: - cannot_change_polls: "You cannot add, remove or rename polls after the first %{minutes} minutes." - op_cannot_edit_options: "You cannot add or remove poll options after the first %{minutes} minutes. Please contact a moderator if you need to edit a poll option." - staff_cannot_add_or_remove_options: "You cannot add or remove poll options after the first %{minutes} minutes. You should close this topic and create a new one instead." - - no_polls_associated_with_this_post: "No polls are associated with this post." - no_poll_with_this_name: "No poll named %{name} associated with this post." - - post_is_deleted: "Cannot act on a deleted post." - - topic_must_be_open_to_vote: "The topic must be open to vote." - poll_must_be_open_to_vote: "Poll must be open to vote." - - topic_must_be_open_to_toggle_status: "The topic must be open to toggle status." - only_staff_or_op_can_toggle_status: "Only a staff member or the original poster can toggle a poll status." - - email: - link_to_poll: "Click to view the poll." +ur: {} diff --git a/plugins/poll/config/locales/server.zh_TW.yml b/plugins/poll/config/locales/server.zh_TW.yml index 92c18de9aec..80ad753ae3d 100644 --- a/plugins/poll/config/locales/server.zh_TW.yml +++ b/plugins/poll/config/locales/server.zh_TW.yml @@ -5,4 +5,37 @@ # To work with us on translations, join this project: # https://www.transifex.com/projects/p/discourse-org/ -zh_TW: {} +zh_TW: + site_settings: + poll_enabled: "允許用戶創建投票?" + poll_maximum_options: "投票允許的最大選項數。" + poll_edit_window_mins: "投票創建後多少分鐘內可以編輯?" + poll: + multiple_polls_without_name: "有多個投票沒有名字。使用“name”屬性區分各投票。" + multiple_polls_with_same_name: "有多個投票的名字相同:%{name}。使用“name”屬性區分各投票。" + default_poll_must_have_at_least_2_options: "投票至少要有 2 個選項。" + named_poll_must_have_at_least_2_options: "投票“%{name}”必須要有 2 個選項。" + default_poll_must_have_less_options: + other: "投票選項必須少於%{count}個。" + named_poll_must_have_less_options: + other: "“%{name}”投票的選項必須少於%{count}個。" + default_poll_must_have_different_options: "投票必須有不同的選項。" + named_poll_must_have_different_options: "投票“%{name}”的選項必須有不同的選項。" + default_poll_with_multiple_choices_has_invalid_parameters: "多選投票有無效選項。" + named_poll_with_multiple_choices_has_invalid_parameters: "“%{name}”多選投票有無效參數。" + requires_at_least_1_valid_option: "你必須選擇至少 1 個有效的選項。" + default_cannot_be_made_public: "投票調查不能公開。" + named_cannot_be_made_public: "投票“%{name}”有投票不能公開。" + edit_window_expired: + cannot_change_polls: "在創建話題%{minutes}分鐘後,你不可以增加、刪除或者重命名該投票。" + op_cannot_edit_options: "在創建話題%{minutes}分鐘後,你不可以增加、刪除投票選項。如果你需要修改投票選項,請聯繫管理員。" + staff_cannot_add_or_remove_options: "在創建話題%{minutes}分鐘後,你不能增加或者刪除投票選項。你可以選擇刪除該話題然後重新創建一個。" + no_polls_associated_with_this_post: "這個帖子中沒有投票。" + no_poll_with_this_name: "投票“%{name}”沒有被關聯到帖子。" + post_is_deleted: "帖子已經刪除,無法操作。" + topic_must_be_open_to_vote: "主題必須未被鎖定才能投票。" + poll_must_be_open_to_vote: "投票必須開啟。" + topic_must_be_open_to_toggle_status: "主題必須未被鎖定才能改變狀態。" + only_staff_or_op_can_toggle_status: "只有管理人員或者發佈投票的人才能改變投票狀態。" + email: + link_to_poll: "點擊查看投票。" diff --git a/plugins/poll/lib/polls_updater.rb b/plugins/poll/lib/polls_updater.rb index 42d67f219d7..696a62eed11 100644 --- a/plugins/poll/lib/polls_updater.rb +++ b/plugins/poll/lib/polls_updater.rb @@ -64,7 +64,10 @@ module DiscoursePoll end polls[poll_name]["voters"] = previous_polls[poll_name]["voters"] - polls[poll_name]["anonymous_voters"] = previous_polls[poll_name]["anonymous_voters"] if previous_polls[poll_name].has_key?("anonymous_voters") + + if previous_polls[poll_name].has_key?("anonymous_voters") + polls[poll_name]["anonymous_voters"] = previous_polls[poll_name]["anonymous_voters"] + end previous_options = previous_polls[poll_name]["options"] public_poll = polls[poll_name]["public"] == "true" @@ -72,7 +75,19 @@ module DiscoursePoll polls[poll_name]["options"].each_with_index do |option, index| previous_option = previous_options[index] option["votes"] = previous_option["votes"] - option["anonymous_votes"] = previous_option["anonymous_votes"] if previous_option.has_key?("anonymous_votes") + + if previous_option["id"] != option["id"] + if votes_fields = post.custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD] + votes_fields.each do |key, value| + index = value[poll_name].index(previous_option["id"]) + votes_fields[key][poll_name][index] = option["id"] if index + end + end + end + + if previous_option.has_key?("anonymous_votes") + option["anonymous_votes"] = previous_option["anonymous_votes"] + end if public_poll && previous_option.has_key?("voter_ids") option["voter_ids"] = previous_option["voter_ids"] diff --git a/plugins/poll/spec/lib/polls_updater_spec.rb b/plugins/poll/spec/lib/polls_updater_spec.rb index 4210b12d5e7..3d679d071a4 100644 --- a/plugins/poll/spec/lib/polls_updater_spec.rb +++ b/plugins/poll/spec/lib/polls_updater_spec.rb @@ -1,6 +1,8 @@ require 'rails_helper' describe DiscoursePoll::PollsUpdater do + let(:user) { Fabricate(:user) } + let(:post_with_two_polls) do raw = <<-RAW.strip_heredoc [poll] @@ -127,8 +129,6 @@ describe DiscoursePoll::PollsUpdater do DiscoursePoll::PollsValidator.new(Fabricate(:post, raw: raw)).validate_polls end - let(:user) { Fabricate(:user) } - before do DiscoursePoll::Poll.vote(post.id, "poll", ["5c24fc1df56d764b550ceae1b9319125"], user) post.reload @@ -222,9 +222,16 @@ describe DiscoursePoll::PollsUpdater do let(:another_post) { Fabricate(:post, created_at: Time.zone.now - poll_edit_window_mins.minutes) } before do - polls.each { |key, value| value["voters"] = 2 } described_class.update(another_post, polls) + another_post.reload SiteSetting.poll_edit_window_mins = poll_edit_window_mins + + DiscoursePoll::Poll.vote( + another_post.id, + "poll", + [polls["poll"]["options"].first["id"]], + user + ) end it "should not allow new polls to be added" do @@ -254,6 +261,8 @@ describe DiscoursePoll::PollsUpdater do end context "staff" do + let(:another_user) { Fabricate(:user) } + it "should not allow staff to add options if votes have been casted" do another_post.update_attributes!(last_editor_id: User.staff.first.id) @@ -284,8 +293,15 @@ describe DiscoursePoll::PollsUpdater do expect(message.data[:polls]).to eq(polls_with_3_options) end - it "should allow staff to edit options if votes have been casted" do - another_post.update_attributes!(last_editor_id: User.staff.first.id) + it "should allow staff to edit options even if votes have been casted" do + another_post.update!(last_editor_id: User.staff.first.id) + + DiscoursePoll::Poll.vote( + another_post.id, + "poll", + [polls["poll"]["options"].first["id"]], + another_user + ) raw = <<-RAW.strip_heredoc [poll] @@ -301,9 +317,16 @@ describe DiscoursePoll::PollsUpdater do described_class.update(another_post, different_polls) end.first - different_polls.each { |key, value| value["voters"] = 2 } + custom_fields = another_post.reload.custom_fields + + expect(custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD]) + .to eq(different_polls) + + [user, another_user].each do |u| + expect(custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD][u.id.to_s]["poll"]) + .to eq(["68b434ff88aeae7054e42cd05a4d9056"]) + end - expect(another_post.reload.custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD]).to eq(different_polls) expect(message.data[:post_id]).to eq(another_post.id) expect(message.data[:polls]).to eq(different_polls) end diff --git a/plugins/poll/test/javascripts/acceptance/polls-test.js.es6 b/plugins/poll/test/javascripts/acceptance/polls-test.js.es6 index 401838b6103..35aec81b5c4 100644 --- a/plugins/poll/test/javascripts/acceptance/polls-test.js.es6 +++ b/plugins/poll/test/javascripts/acceptance/polls-test.js.es6 @@ -1,5 +1,4 @@ -import { acceptance, controllerFor } from "helpers/qunit-helpers"; -import PostCooked from 'discourse/widgets/post-cooked'; +import { acceptance } from "helpers/qunit-helpers"; acceptance("Rendering polls", { loggedIn: true, @@ -11,7 +10,7 @@ acceptance("Rendering polls", { { "Content-Type": "application/json" }, object ]; - } + }; server.get('/t/13.json', () => { return response({"post_stream":{"posts":[{"id":19,"name":null,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png","created_at":"2016-12-01T02:39:49.199Z","cooked":"
    \n
    \n
      \n
    • test
    • \n
    • haha
    • \n
    \n

    0voters

    \n
    \n\n
    \n\n
    \n
    \n
      \n
    • donkey
    • \n
    • kong
    • \n
    \n

    0voters

    \n
    \n\n
    ","post_number":1,"post_type":1,"updated_at":"2016-12-01T02:47:18.317Z","reply_count":0,"reply_to_post_number":null,"quote_count":0,"avg_time":null,"incoming_link_count":0,"reads":1,"score":0,"yours":true,"topic_id":13,"topic_slug":"this-is-a-test-topic-for-polls","display_username":null,"primary_group_name":null,"primary_group_flair_url":null,"primary_group_flair_bg_color":null,"primary_group_flair_color":null,"version":2,"can_edit":true,"can_delete":false,"can_recover":true,"can_wiki":true,"read":true,"user_title":null,"actions_summary":[{"id":3,"can_act":true},{"id":4,"can_act":true},{"id":5,"hidden":true,"can_act":true},{"id":7,"can_act":true},{"id":8,"can_act":true}],"moderator":false,"admin":true,"staff":true,"user_id":1,"hidden":false,"hidden_reason_id":null,"trust_level":4,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"polls":{"poll":{"options":[{"id":"57ddd734344eb7436d64a7d68a0df444","html":"test","votes":0},{"id":"b5b78d79ab5b5d75d4d33d8b87f5d2aa","html":"haha","votes":0}],"voters":2,"status":"open","name":"poll"},"test":{"options":[{"id":"c26ad90783b0d80936e5fdb292b7963c","html":"donkey","votes":0},{"id":"99f2b9ac452ba73b115fcf3556e6d2d4","html":"kong","votes":0}],"voters":3,"status":"open","name":"test"}}}],"stream":[19]},"timeline_lookup":[[1,0]],"id":13,"title":"This is a test topic for polls","fancy_title":"This is a test topic for polls","posts_count":1,"created_at":"2016-12-01T02:39:48.055Z","views":1,"reply_count":0,"participant_count":1,"like_count":0,"last_posted_at":"2016-12-01T02:39:49.199Z","visible":true,"closed":false,"archived":false,"has_summary":false,"archetype":"regular","slug":"this-is-a-test-topic-for-polls","category_id":1,"word_count":10,"deleted_at":null,"user_id":1,"draft":null,"draft_key":"topic_13","draft_sequence":4,"posted":true,"unpinned":null,"pinned_globally":false,"pinned":false,"pinned_at":null,"pinned_until":null,"details":{"auto_close_at":null,"auto_close_hours":null,"auto_close_based_on_last_post":false,"created_by":{"id":1,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png"},"last_poster":{"id":1,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png"},"participants":[{"id":1,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png","post_count":1}],"suggested_topics":[{"id":8,"title":"Welcome to Discourse","fancy_title":"Welcome to Discourse","slug":"welcome-to-discourse","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2016-11-24T02:10:54.328Z","last_posted_at":"2016-11-24T02:10:54.393Z","bumped":true,"bumped_at":"2016-11-24T02:10:54.393Z","unseen":false,"pinned":true,"unpinned":null,"excerpt":"The first paragraph of this pinned topic will be visible as a welcome message to all new visitors on your homepage. It's important! \n\nEdit this into a brief description of your community: \n\n\nWho is it for?\nWhat can they …","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"archetype":"regular","like_count":0,"views":0,"category_id":1,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":-1,"username":"system","avatar_template":"/letter_avatar_proxy/v2/letter/s/bcef8e/{size}.png"}}]},{"id":12,"title":"Some testing topic testing","fancy_title":"Some testing topic testing","slug":"some-testing-topic-testing","posts_count":4,"reply_count":0,"highest_post_number":4,"image_url":null,"created_at":"2016-11-24T08:36:08.773Z","last_posted_at":"2016-12-01T01:15:52.008Z","bumped":true,"bumped_at":"2016-12-01T01:15:52.008Z","unseen":false,"last_read_post_number":4,"unread":0,"new_posts":0,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"notification_level":3,"bookmarked":false,"liked":false,"archetype":"regular","like_count":0,"views":2,"category_id":1,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":1,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png"}}]},{"id":11,"title":"Some testing topic","fancy_title":"Some testing topic","slug":"some-testing-topic","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2016-11-24T08:35:26.758Z","last_posted_at":"2016-11-24T08:35:26.894Z","bumped":true,"bumped_at":"2016-11-24T08:35:26.894Z","unseen":false,"last_read_post_number":1,"unread":0,"new_posts":0,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"notification_level":3,"bookmarked":false,"liked":false,"archetype":"regular","like_count":0,"views":0,"category_id":1,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":1,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png"}}]}],"notification_level":3,"notifications_reason_id":1,"can_move_posts":true,"can_edit":true,"can_delete":true,"can_recover":true,"can_remove_allowed_users":true,"can_invite_to":true,"can_create_post":true,"can_reply_as_new_topic":true,"can_flag_topic":true},"highest_post_number":1,"last_read_post_number":1,"last_read_post_id":19,"deleted_by":null,"has_deleted":false,"actions_summary":[{"id":4,"count":0,"hidden":false,"can_act":true},{"id":7,"count":0,"hidden":false,"can_act":true},{"id":8,"count":0,"hidden":false,"can_act":true}],"chunk_size":20,"bookmarked":false}); diff --git a/plugins/poll/test/javascripts/widgets/discourse-poll-standard-results-test.js.es6 b/plugins/poll/test/javascripts/widgets/discourse-poll-standard-results-test.js.es6 index a4172adcee1..f1668b11791 100644 --- a/plugins/poll/test/javascripts/widgets/discourse-poll-standard-results-test.js.es6 +++ b/plugins/poll/test/javascripts/widgets/discourse-poll-standard-results-test.js.es6 @@ -45,10 +45,11 @@ widgetTest('multiple options in descending order', { this.set('poll', Ember.Object.create({ type: 'multiple', options: [ - { votes: 5 }, - { votes: 2 }, - { votes: 4 }, - { votes: 1 } + { votes: 5, html: 'a' }, + { votes: 2, html: 'b' }, + { votes: 4, html: 'c' }, + { votes: 1, html: 'b' }, + { votes: 1, html: 'a' } ], voters: 12 })); @@ -59,5 +60,8 @@ widgetTest('multiple options in descending order', { assert.equal(this.$('.option .percentage:eq(1)').text(), '33%'); assert.equal(this.$('.option .percentage:eq(2)').text(), '16%'); assert.equal(this.$('.option .percentage:eq(3)').text(), '8%'); + assert.equal(this.$('.option span:nth-child(2):eq(3)').text(), 'a'); + assert.equal(this.$('.option .percentage:eq(4)').text(), '8%'); + assert.equal(this.$('.option span:nth-child(2):eq(4)').text(), 'b'); } }); diff --git a/public/403.nb_NO.html b/public/403.nb_NO.html index ba3f7b3130f..76b6e9a1cf0 100644 --- a/public/403.nb_NO.html +++ b/public/403.nb_NO.html @@ -1,6 +1,6 @@ -Du kan ikke gjøre det (403) +Du har ikke tilgang til å gjøre dette (403) -

    403

    -

    You can't view that resource!

    +

    اپ اس وسیلے کو نہیں دیکھ سکتے!

    -

    This will be replaced by a custom Discourse 403 page.

    +

    یہ ایک حاص403 صفہے سے بدل دیا جایے گا،

    diff --git a/public/422.nb_NO.html b/public/422.nb_NO.html index 242507b515e..acdcb6b08b2 100644 --- a/public/422.nb_NO.html +++ b/public/422.nb_NO.html @@ -18,7 +18,7 @@
    -

    Endringen du ønsket ble avvist

    +

    Endringen du ønsket, ble avvist

    Kanskje du prøvde å endre noe du ikke har tilgang til.

    diff --git a/public/422.ur.html b/public/422.ur.html index 244e10b089b..9827ed711d9 100644 --- a/public/422.ur.html +++ b/public/422.ur.html @@ -1,9 +1,8 @@ - - The change you wanted was rejected (422) - - -
    -

    The change you wanted was rejected.

    -

    Maybe you tried to change something you didn't have access to.

    +

    جو تبدیلی آپ چاہتے تھے اس کو مسترد کر دیا گیا.

    +

    شاید آپ نے اس چیز کو تبدیل کرنے کی کوشش کی، جس کو تبدیل کر نے کی اجازت آپ کے پاس نہ ہو.

    diff --git a/public/500.nb_NO.html b/public/500.nb_NO.html index d83339ef8b3..2aa31d97ca9 100644 --- a/public/500.nb_NO.html +++ b/public/500.nb_NO.html @@ -4,9 +4,9 @@ -

    Oops

    +

    Oisann

    Programvaren til dette diskusjonsforum fikk et uventet problem. Vi beklager dette.

    Detaljert informasjon om feilen ble logget, og et automatisk varsel generert. Vi vil ta en titt på det.

    -

    No further action is necessary. However, if the error condition persists, you can provide additional detail, including steps to reproduce the error, by posting a discussion topic in the site's feedback category.

    +

    Ingen flere handlinger kreves. Skulle denne feilen fortsette å oppstå, kan du

    diff --git a/public/500.ur.html b/public/500.ur.html index c22502737c8..af41c9343d8 100644 --- a/public/500.ur.html +++ b/public/500.ur.html @@ -1,13 +1,12 @@ - - Oops - Error 500 - +افوہ - تکنیکی خرابی 500 + -

    Oops

    -

    The software powering this discussion forum encountered an unexpected problem. We apologize for the inconvenience.

    -

    Detailed information about the error was logged, and an automatic notification generated. We'll take a look at it.

    -

    No further action is necessary. However, if the error condition persists, you can provide additional detail, including steps to reproduce the error, by posting a discussion topic in the site's feedback category.

    +

    افوہ

    +

    سافٹ ویئر جو اِس فورم کو چلا رہا ہے اس کو ایک غیر متوقع مسئلہ کا سامنا کرنا پرا ہے. ہم تکلیف کے لیے معذرت خواہ ہیں.

    +

    خرابی کے بارے میں تفصیلی معلومات ریکارڈ، اور ایک خود کار طریقے سے پیدا کردہ اطلاع تیار کر لی گئی ہے. ہم اس پر ایک نظر ڈالیں گے.

    +

    کسی مزید عمل کی ضرورت نہیں ہے. تاہم اگر تکنیکی خرابی برقرار رہتی ہے، تو آپ اضافی تفصیل، بشمول خرابی کو دوبارہ پیش کرنے کے لیے لیے جانے والے اقدامات، ایک ڈسکشن ٹوپک ویب سائٹ کی آراء کے زمرے میں پوسٹ کر سکتے ہیں.

    diff --git a/public/503.nb_NO.html b/public/503.nb_NO.html index 6dd61387aa3..80ebfe2b004 100644 --- a/public/503.nb_NO.html +++ b/public/503.nb_NO.html @@ -5,7 +5,7 @@

    Vi er for øyeblikket ikke tilgjengelig på grunn av planlagt vedlikehold av nettstedet

    -

    Vennligst sjekk tilbake om noen minutter.

    +

    Kom tilbake om noen minutter.

    Beklager ulempene dette medfører!

    diff --git a/public/503.ur.html b/public/503.ur.html index 937e5bcda64..c6b8726fc94 100644 --- a/public/503.ur.html +++ b/public/503.ur.html @@ -1,12 +1,11 @@ - - Site Is Undergoing Maintenance - Discourse.org - +ویب سائٹ کی محافظت ہو رہی ہے - Discourse.org + -

    We are currently down for planned site maintenance

    -

    Please check back in a few minutes.

    -

    Sorry for the inconvenience!

    +

    ویب سائٹ ابھی وقتی محافظت کے لیے ڈاون ہے۔

    +

    کچھ منٹ بعد چیک کریں۔

    +

    تکلیف کے لئے معذرت!

    diff --git a/public/images/emoji/apple/hash.png b/public/images/emoji/apple/hash.png index e69de29bb2d..64f9f559649 100644 Binary files a/public/images/emoji/apple/hash.png and b/public/images/emoji/apple/hash.png differ diff --git a/public/images/emoji/apple/keycap_star.png b/public/images/emoji/apple/keycap_star.png index e69de29bb2d..f847acf58c4 100644 Binary files a/public/images/emoji/apple/keycap_star.png and b/public/images/emoji/apple/keycap_star.png differ diff --git a/public/images/emoji/apple/zero.png b/public/images/emoji/apple/zero.png index e69de29bb2d..4b2b38dce0a 100644 Binary files a/public/images/emoji/apple/zero.png and b/public/images/emoji/apple/zero.png differ diff --git a/public/images/emoji/emoji_one/hash.png b/public/images/emoji/emoji_one/hash.png index e69de29bb2d..1efc8cc6e35 100644 Binary files a/public/images/emoji/emoji_one/hash.png and b/public/images/emoji/emoji_one/hash.png differ diff --git a/public/images/emoji/emoji_one/keycap_star.png b/public/images/emoji/emoji_one/keycap_star.png index e69de29bb2d..8ed4edab8fc 100644 Binary files a/public/images/emoji/emoji_one/keycap_star.png and b/public/images/emoji/emoji_one/keycap_star.png differ diff --git a/public/images/emoji/emoji_one/zero.png b/public/images/emoji/emoji_one/zero.png index e69de29bb2d..8123d5e090e 100644 Binary files a/public/images/emoji/emoji_one/zero.png and b/public/images/emoji/emoji_one/zero.png differ diff --git a/public/images/emoji/google/hash.png b/public/images/emoji/google/hash.png index e69de29bb2d..706a31c13b1 100644 Binary files a/public/images/emoji/google/hash.png and b/public/images/emoji/google/hash.png differ diff --git a/public/images/emoji/google/keycap_star.png b/public/images/emoji/google/keycap_star.png index e69de29bb2d..bc41c667b2c 100644 Binary files a/public/images/emoji/google/keycap_star.png and b/public/images/emoji/google/keycap_star.png differ diff --git a/public/images/emoji/google/zero.png b/public/images/emoji/google/zero.png index e69de29bb2d..ce02394db08 100644 Binary files a/public/images/emoji/google/zero.png and b/public/images/emoji/google/zero.png differ diff --git a/public/images/emoji/twitter/hash.png b/public/images/emoji/twitter/hash.png index e69de29bb2d..5309b3d0c97 100644 Binary files a/public/images/emoji/twitter/hash.png and b/public/images/emoji/twitter/hash.png differ diff --git a/public/images/emoji/twitter/keycap_star.png b/public/images/emoji/twitter/keycap_star.png index e69de29bb2d..2bfefce2bec 100644 Binary files a/public/images/emoji/twitter/keycap_star.png and b/public/images/emoji/twitter/keycap_star.png differ diff --git a/public/images/emoji/twitter/zero.png b/public/images/emoji/twitter/zero.png index e69de29bb2d..f4244918d5b 100644 Binary files a/public/images/emoji/twitter/zero.png and b/public/images/emoji/twitter/zero.png differ diff --git a/public/images/emoji/win10/eight.png b/public/images/emoji/win10/eight.png index 941ddf7da0d..4fe4c5f23e2 100644 Binary files a/public/images/emoji/win10/eight.png and b/public/images/emoji/win10/eight.png differ diff --git a/public/images/emoji/win10/five.png b/public/images/emoji/win10/five.png index f8b21706daf..1e284bf610a 100644 Binary files a/public/images/emoji/win10/five.png and b/public/images/emoji/win10/five.png differ diff --git a/public/images/emoji/win10/four.png b/public/images/emoji/win10/four.png index 3a22419dc59..a5d7e4f82e7 100644 Binary files a/public/images/emoji/win10/four.png and b/public/images/emoji/win10/four.png differ diff --git a/public/images/emoji/win10/hash.png b/public/images/emoji/win10/hash.png index e69de29bb2d..7d06801e1f5 100644 Binary files a/public/images/emoji/win10/hash.png and b/public/images/emoji/win10/hash.png differ diff --git a/public/images/emoji/win10/nine.png b/public/images/emoji/win10/nine.png index 655f80a7f9e..290dc7fe930 100644 Binary files a/public/images/emoji/win10/nine.png and b/public/images/emoji/win10/nine.png differ diff --git a/public/images/emoji/win10/one.png b/public/images/emoji/win10/one.png index eba530a82c8..95e3c094c86 100644 Binary files a/public/images/emoji/win10/one.png and b/public/images/emoji/win10/one.png differ diff --git a/public/images/emoji/win10/seven.png b/public/images/emoji/win10/seven.png index c1329dd7734..1c839c4e10d 100644 Binary files a/public/images/emoji/win10/seven.png and b/public/images/emoji/win10/seven.png differ diff --git a/public/images/emoji/win10/six.png b/public/images/emoji/win10/six.png index 8e4b23b3ba0..8e8a805e87d 100644 Binary files a/public/images/emoji/win10/six.png and b/public/images/emoji/win10/six.png differ diff --git a/public/images/emoji/win10/three.png b/public/images/emoji/win10/three.png index bf930925c43..9cb4d40b0f3 100644 Binary files a/public/images/emoji/win10/three.png and b/public/images/emoji/win10/three.png differ diff --git a/public/images/emoji/win10/two.png b/public/images/emoji/win10/two.png index 5a7e4819477..da3eb230b73 100644 Binary files a/public/images/emoji/win10/two.png and b/public/images/emoji/win10/two.png differ diff --git a/public/images/emoji/win10/zero.png b/public/images/emoji/win10/zero.png index e69de29bb2d..e5b08a12679 100644 Binary files a/public/images/emoji/win10/zero.png and b/public/images/emoji/win10/zero.png differ diff --git a/script/import_scripts/bbpress.rb b/script/import_scripts/bbpress.rb index bd5e872650b..27c3be1deab 100644 --- a/script/import_scripts/bbpress.rb +++ b/script/import_scripts/bbpress.rb @@ -16,6 +16,8 @@ class ImportScripts::Bbpress < ImportScripts::Base BATCH_SIZE ||= 1000 BB_PRESS_PW ||= ENV['BBPRESS_PW'] || "" BB_PRESS_USER ||= ENV['BBPRESS_USER'] || "root" + BB_PRESS_PREFIX ||= ENV['BBPRESS_PREFIX'] || "wp_" + def initialize super @@ -37,12 +39,12 @@ class ImportScripts::Bbpress < ImportScripts::Base puts "", "importing users..." last_user_id = -1 - total_users = bbpress_query("SELECT COUNT(*) count FROM wp_users WHERE user_email LIKE '%@%'").first["count"] + total_users = bbpress_query("SELECT COUNT(*) count FROM #{BB_PRESS_PREFIX}users WHERE user_email LIKE '%@%'").first["count"] batches(BATCH_SIZE) do |offset| users = bbpress_query(<<-SQL SELECT id, user_nicename, display_name, user_email, user_registered, user_url - FROM wp_users + FROM #{BB_PRESS_PREFIX}users WHERE user_email LIKE '%@%' AND id > #{last_user_id} ORDER BY id @@ -62,7 +64,7 @@ class ImportScripts::Bbpress < ImportScripts::Base users_description = {} bbpress_query(<<-SQL SELECT user_id, meta_value description - FROM wp_usermeta + FROM #{BB_PRESS_PREFIX}usermeta WHERE user_id IN (#{user_ids_sql}) AND meta_key = 'description' SQL @@ -71,7 +73,7 @@ class ImportScripts::Bbpress < ImportScripts::Base users_last_activity = {} bbpress_query(<<-SQL SELECT user_id, meta_value last_activity - FROM wp_usermeta + FROM #{BB_PRESS_PREFIX}usermeta WHERE user_id IN (#{user_ids_sql}) AND meta_key = 'last_activity' SQL @@ -82,7 +84,7 @@ class ImportScripts::Bbpress < ImportScripts::Base id: u["id"].to_i, username: u["user_nicename"], email: u["user_email"].downcase, - name: u["display_name"], + name: u["display_name"].presence || u['user_nicename'], created_at: u["user_registered"], website: u["user_url"], bio_raw: users_description[u["id"]], @@ -97,7 +99,7 @@ class ImportScripts::Bbpress < ImportScripts::Base categories = bbpress_query(<<-SQL SELECT id, post_name, post_parent - FROM wp_posts + FROM #{BB_PRESS_PREFIX}posts WHERE post_type = 'forum' AND LENGTH(COALESCE(post_name, '')) > 0 ORDER BY post_parent, id @@ -119,7 +121,7 @@ class ImportScripts::Bbpress < ImportScripts::Base last_post_id = -1 total_posts = bbpress_query(<<-SQL SELECT COUNT(*) count - FROM wp_posts + FROM #{BB_PRESS_PREFIX}posts WHERE post_status <> 'spam' AND post_type IN ('topic', 'reply') SQL @@ -134,7 +136,7 @@ class ImportScripts::Bbpress < ImportScripts::Base post_title, post_type, post_parent - FROM wp_posts + FROM #{BB_PRESS_PREFIX}posts WHERE post_status <> 'spam' AND post_type IN ('topic', 'reply') AND id > #{last_post_id} @@ -155,7 +157,7 @@ class ImportScripts::Bbpress < ImportScripts::Base posts_likes = {} bbpress_query(<<-SQL SELECT post_id, meta_value likes - FROM wp_postmeta + FROM #{BB_PRESS_PREFIX}postmeta WHERE post_id IN (#{post_ids_sql}) AND meta_key = 'Likes' SQL diff --git a/script/import_scripts/drupal-6.rb b/script/import_scripts/drupal-6.rb new file mode 100644 index 00000000000..1df513df409 --- /dev/null +++ b/script/import_scripts/drupal-6.rb @@ -0,0 +1,210 @@ +require "mysql2" +require File.expand_path(File.dirname(__FILE__) + "/base.rb") + +class ImportScripts::Drupal < ImportScripts::Base + + DRUPAL_DB = ENV['DRUPAL_DB'] || "newsite3" + VID = ENV['DRUPAL_VID'] || 1 + + def initialize + super + + @client = Mysql2::Client.new( + host: "localhost", + username: "root", + #password: "password", + database: DRUPAL_DB + ) + end + + def categories_query + @client.query("SELECT tid, name, description FROM term_data WHERE vid = #{VID}") + end + + def execute + create_users(@client.query("SELECT uid id, name, mail email, created FROM users;")) do |row| + {id: row['id'], username: row['name'], email: row['email'], created_at: Time.zone.at(row['created'])} + end + + # You'll need to edit the following query for your Drupal install: + # + # * Drupal allows duplicate category names, so you may need to exclude some categories or rename them here. + # * Table name may be term_data. + # * May need to select a vid other than 1. + create_categories(categories_query) do |c| + {id: c['tid'], name: c['name'], description: c['description']} + end + + # "Nodes" in Drupal are divided into types. Here we import two types, + # and will later import all the comments/replies for each node. + # You will need to figure out what the type names are on your install and edit the queries to match. + if ENV['DRUPAL_IMPORT_BLOG'] + create_blog_topics + end + + create_forum_topics + + create_replies + + begin + create_admin(email: 'neil.lalonde@discourse.org', username: UserNameSuggester.suggest('neil')) + rescue => e + puts '', "Failed to create admin user" + puts e.message + end + end + + def create_blog_topics + puts '', "creating blog topics" + + create_category({ + name: 'Blog', + user_id: -1, + description: "Articles from the blog" + }, nil) unless Category.find_by_name('Blog') + + results = @client.query(" + SELECT n.nid nid, + n.title title, + n.uid uid, + n.created created, + n.sticky sticky, + nr.body body + FROM node n + LEFT JOIN node_revisions nr ON nr.vid=n.vid + WHERE n.type = 'blog' + AND n.status = 1 + ", cache_rows: false) + + create_posts(results) do |row| + { + id: "nid:#{row['nid']}", + user_id: user_id_from_imported_user_id(row['uid']) || -1, + category: 'Blog', + raw: row['body'], + created_at: Time.zone.at(row['created']), + pinned_at: row['sticky'].to_i == 1 ? Time.zone.at(row['created']) : nil, + title: row['title'].try(:strip), + custom_fields: {import_id: "nid:#{row['nid']}"} + } + end + end + + def create_forum_topics + puts '', "creating forum topics" + + total_count = @client.query(" + SELECT COUNT(*) count + FROM node n + LEFT JOIN forum f ON f.vid=n.vid + WHERE n.type = 'forum' + AND n.status = 1 + ").first['count'] + + batch_size = 1000 + + batches(batch_size) do |offset| + results = @client.query(" + SELECT n.nid nid, + n.title title, + f.tid tid, + n.uid uid, + n.created created, + n.sticky sticky, + nr.body body + FROM node n + LEFT JOIN forum f ON f.vid=n.vid + LEFT JOIN node_revisions nr ON nr.vid=n.vid + WHERE node.type = 'forum' + AND node.status = 1 + LIMIT #{batch_size} + OFFSET #{offset}; + ", cache_rows: false) + + break if results.size < 1 + + next if all_records_exist? :posts, results.map {|p| "nid:#{p['nid']}"} + + create_posts(results, total: total_count, offset: offset) do |row| + { + id: "nid:#{row['nid']}", + user_id: user_id_from_imported_user_id(row['uid']) || -1, + category: category_id_from_imported_category_id(row['tid']), + raw: row['body'], + created_at: Time.zone.at(row['created']), + pinned_at: row['sticky'].to_i == 1 ? Time.zone.at(row['created']) : nil, + title: row['title'].try(:strip) + } + end + end + end + + def create_replies + puts '', "creating replies in topics" + + if ENV['DRUPAL_IMPORT_BLOG'] + node_types = "('forum','blog')" + else + node_types = "('forum')" + end + + total_count = @client.query(" + SELECT COUNT(*) count + FROM comments c + LEFT JOIN node n ON n.nid=c.nid + WHERE node.type IN #{node_types} + AND node.status = 1 + AND comments.status=0; + ").first['count'] + + batch_size = 1000 + + batches(batch_size) do |offset| + results = @client.query(" + SELECT c.cid, + c.pid, + c.nid, + c.uid, + c.timestamp, + c.comment body + FROM comments c + LEFT JOIN node n ON n.nid=c.nid + WHERE n.type IN #{node_types} + AND n.status = 1 + AND c.status=0 + LIMIT #{batch_size} + OFFSET #{offset}; + ", cache_rows: false) + + break if results.size < 1 + + next if all_records_exist? :posts, results.map {|p| "cid:#{p['cid']}"} + + create_posts(results, total: total_count, offset: offset) do |row| + topic_mapping = topic_lookup_from_imported_post_id("nid:#{row['nid']}") + if topic_mapping && topic_id = topic_mapping[:topic_id] + h = { + id: "cid:#{row['cid']}", + topic_id: topic_id, + user_id: user_id_from_imported_user_id(row['uid']) || -1, + raw: row['body'], + created_at: Time.zone.at(row['timestamp']), + } + if row['pid'] + parent = topic_lookup_from_imported_post_id("cid:#{row['pid']}") + h[:reply_to_post_number] = parent[:post_number] if parent and parent[:post_number] > 1 + end + h + else + puts "No topic found for comment #{row['cid']}" + nil + end + end + end + end + +end + +if __FILE__==$0 + ImportScripts::Drupal.new.perform +end diff --git a/script/import_scripts/json_generic.rb b/script/import_scripts/json_generic.rb new file mode 100755 index 00000000000..c6474b26674 --- /dev/null +++ b/script/import_scripts/json_generic.rb @@ -0,0 +1,108 @@ +require "csv" +require File.expand_path(File.dirname(__FILE__) + "/base.rb") + +# Edit the constants and initialize method for your import data. + +class ImportScripts::JsonGeneric < ImportScripts::Base + + JSON_FILE_PATH = ENV['JSON_FILE'] + BATCH_SIZE ||= 1000 + + def initialize + super + + @imported_json = load_json + end + + def execute + puts "", "Importing from JSON file..." + + import_users + import_discussions + + puts "", "Done" + end + + def load_json + JSON.parse(File.read(JSON_FILE_PATH)) + end + + def username_for(name) + result = name.downcase.gsub(/[^a-z0-9\-\_]/, '') + + if result.blank? + result = Digest::SHA1.hexdigest(name)[0...10] + end + + result + end + + def import_users + puts '', "Importing users" + + users = [] + @imported_json['topics'].each do |t| + t['posts'].each do |p| + users << p['author'].scrub + end + end + users.uniq! + + create_users(users) do |u| + { + id: username_for(u), + username: username_for(u), + name: u, + email: "#{username_for(u)}@example.com", + created_at: Time.now + } + end + end + + + def import_discussions + puts "", "Importing discussions" + + topics = 0 + posts = 0 + + @imported_json['topics'].each do |t| + first_post = t['posts'][0] + next unless first_post + + topic = { + id: t["id"], + user_id: user_id_from_imported_user_id(username_for(first_post["author"])) || -1, + raw: first_post["body"], + created_at: Time.zone.parse(first_post["date"]), + cook_method: Post.cook_methods[:raw_html], + title: t['title'], + category: ENV['CATEGORY_ID'], + custom_fields: { import_id: "pid:#{first_post['id']}" } + } + + topic[:pinned_at] = Time.zone.parse(first_post["date"]) if t['pinned'] + topics += 1 + parent_post = create_post(topic, topic[:id]) + + t['posts'][1..-1].each do |p| + create_post({ + id: p["id"], + topic_id: parent_post.topic_id, + user_id: user_id_from_imported_user_id(username_for(p["author"])) || -1, + raw: p["body"], + created_at: Time.zone.parse(p["date"]), + cook_method: Post.cook_methods[:raw_html], + custom_fields: { import_id: "pid:#{p['id']}" } + }, p['id']) + posts += 1 + end + end + + puts "", "Imported #{topics} topics with #{topics + posts} posts." + end +end + +if __FILE__==$0 + ImportScripts::JsonGeneric.new.perform +end diff --git a/script/import_scripts/vbulletin.rb b/script/import_scripts/vbulletin.rb index 8ff7c0340af..967a88bf714 100644 --- a/script/import_scripts/vbulletin.rb +++ b/script/import_scripts/vbulletin.rb @@ -227,9 +227,6 @@ class ImportScripts::VBulletin < ImportScripts::Base def import_topics puts "", "importing topics..." - # keep track of closed topics - @closed_topic_ids = [] - topic_count = mysql_query("SELECT COUNT(threadid) count FROM #{TABLE_PREFIX}thread").first["count"] batches(BATCH_SIZE) do |offset| @@ -250,7 +247,6 @@ class ImportScripts::VBulletin < ImportScripts::Base raw = preprocess_post_raw(topic["raw"]) rescue nil next if raw.blank? topic_id = "thread-#{topic["threadid"]}" - @closed_topic_ids << topic_id if topic["open"] == 0 t = { id: topic_id, user_id: user_id_from_imported_user_id(topic["postuserid"]) || Discourse::SYSTEM_USER_ID, @@ -509,6 +505,20 @@ class ImportScripts::VBulletin < ImportScripts::Base def close_topics puts "", "Closing topics..." + # keep track of closed topics + closed_topic_ids = [] + + topics = mysql_query <<-MYSQL + SELECT t.threadid threadid, firstpostid, open + FROM #{TABLE_PREFIX}thread t + JOIN #{TABLE_PREFIX}post p ON p.postid = t.firstpostid + ORDER BY t.threadid + MYSQL + topics.each do |topic| + topic_id = "thread-#{topic["threadid"]}" + closed_topic_ids << topic_id if topic["open"] == 0 + end + sql = <<-SQL WITH closed_topic_ids AS ( SELECT t.id AS topic_id @@ -523,7 +533,7 @@ class ImportScripts::VBulletin < ImportScripts::Base WHERE id IN (SELECT topic_id FROM closed_topic_ids) SQL - Topic.exec_sql(sql, @closed_topic_ids) + Topic.exec_sql(sql, closed_topic_ids) end def post_process_posts diff --git a/spec/components/active_record/connection_adapters/postgresql_fallback_adapter_spec.rb b/spec/components/active_record/connection_adapters/postgresql_fallback_adapter_spec.rb index a9e61dbea15..74f48940754 100644 --- a/spec/components/active_record/connection_adapters/postgresql_fallback_adapter_spec.rb +++ b/spec/components/active_record/connection_adapters/postgresql_fallback_adapter_spec.rb @@ -42,8 +42,13 @@ describe ActiveRecord::ConnectionHandling do end after do - with_multisite_db(multisite_db) { Discourse.disable_readonly_mode } - Discourse.disable_readonly_mode + pg_readonly_mode_key = Discourse::PG_READONLY_MODE_KEY + + with_multisite_db(multisite_db) do + Discourse.disable_readonly_mode(pg_readonly_mode_key) + end + + Discourse.disable_readonly_mode(pg_readonly_mode_key) ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[Rails.env]) end diff --git a/spec/components/auth/default_current_user_provider_spec.rb b/spec/components/auth/default_current_user_provider_spec.rb index 54559c15869..e9a680dd22e 100644 --- a/spec/components/auth/default_current_user_provider_spec.rb +++ b/spec/components/auth/default_current_user_provider_spec.rb @@ -175,7 +175,11 @@ describe Auth::DefaultCurrentUserProvider do "HTTP_USER_API_KEY" => api_key.key, } - expect(provider("/", params).current_user.id).to eq(user.id) + good_provider = provider("/", params) + + expect(good_provider.current_user.id).to eq(user.id) + expect(good_provider.is_api?).to eq(false) + expect(good_provider.is_user_api?).to eq(true) expect { provider("/", params.merge({"REQUEST_METHOD" => "POST"})).current_user diff --git a/spec/components/discourse_spec.rb b/spec/components/discourse_spec.rb index 5d441eacc33..b1b21cfd5c9 100644 --- a/spec/components/discourse_spec.rb +++ b/spec/components/discourse_spec.rb @@ -118,7 +118,7 @@ describe Discourse do context 'user enabled readonly mode' do it "adds a key in redis and publish a message through the message bus" do expect($redis.get(user_readonly_mode_key)).to eq(nil) - message = MessageBus.track_publish { Discourse.enable_readonly_mode(user_enabled: true) }.first + message = MessageBus.track_publish { Discourse.enable_readonly_mode(user_readonly_mode_key) }.first assert_readonly_mode(message, user_readonly_mode_key) end end @@ -160,10 +160,10 @@ describe Discourse do end it "returns true when user enabled readonly mode key is present in redis" do - Discourse.enable_readonly_mode(user_enabled: true) + Discourse.enable_readonly_mode(user_readonly_mode_key) expect(Discourse.readonly_mode?).to eq(true) - Discourse.disable_readonly_mode(user_enabled: true) + Discourse.disable_readonly_mode(user_readonly_mode_key) expect(Discourse.readonly_mode?).to eq(false) end end diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb index 0a7b0a1bed0..3019c5a780f 100644 --- a/spec/components/email/receiver_spec.rb +++ b/spec/components/email/receiver_spec.rb @@ -341,7 +341,7 @@ describe Email::Receiver do it "handles email with no subject" do expect { process(:no_subject) }.to change(Topic, :count) - expect(Topic.last.title).to eq("Incoming email from some@one.com") + expect(Topic.last.title).to eq("This topic needs a title") end it "invites everyone in the chain but emails configured as 'incoming' (via reply, group or category)" do @@ -383,37 +383,46 @@ describe Email::Receiver do expect(Post.last.raw).to match(/discourse\.rb/) end - it "handles forwarded emails" do - SiteSetting.enable_forwarded_emails = true - expect { process(:forwarded_email_1) }.to change(Topic, :count) + context "with forwarded emails enabled" do + before { SiteSetting.enable_forwarded_emails = true } - forwarded_post, last_post = *Post.last(2) + it "handles forwarded emails" do + expect { process(:forwarded_email_1) }.to change(Topic, :count) - expect(forwarded_post.user.email).to eq("some@one.com") - expect(last_post.user.email).to eq("ba@bar.com") + forwarded_post, last_post = *Post.last(2) - expect(forwarded_post.raw).to match(/XoXo/) - expect(last_post.raw).to match(/can you have a look at this email below/) + expect(forwarded_post.user.email).to eq("some@one.com") + expect(last_post.user.email).to eq("ba@bar.com") - expect(last_post.post_type).to eq(Post.types[:regular]) - end + expect(forwarded_post.raw).to match(/XoXo/) + expect(last_post.raw).to match(/can you have a look at this email below/) - it "handles weirdly forwarded emails" do - group.add(Fabricate(:user, email: "ba@bar.com")) - group.save + expect(last_post.post_type).to eq(Post.types[:regular]) + end - SiteSetting.enable_forwarded_emails = true - expect { process(:forwarded_email_2) }.to change(Topic, :count) + it "handles weirdly forwarded emails" do + group.add(Fabricate(:user, email: "ba@bar.com")) + group.save - forwarded_post, last_post = *Post.last(2) + SiteSetting.enable_forwarded_emails = true + expect { process(:forwarded_email_2) }.to change(Topic, :count) - expect(forwarded_post.user.email).to eq("some@one.com") - expect(last_post.user.email).to eq("ba@bar.com") + forwarded_post, last_post = *Post.last(2) - expect(forwarded_post.raw).to match(/XoXo/) - expect(last_post.raw).to match(/can you have a look at this email below/) + expect(forwarded_post.user.email).to eq("some@one.com") + expect(last_post.user.email).to eq("ba@bar.com") + + expect(forwarded_post.raw).to match(/XoXo/) + expect(last_post.raw).to match(/can you have a look at this email below/) + + expect(last_post.post_type).to eq(Post.types[:whisper]) + end + + # Who thought this was a good idea?! + it "doesn't blow up with localized email headers" do + expect { process(:forwarded_email_3) }.to change(Topic, :count) + end - expect(last_post.post_type).to eq(Post.types[:whisper]) end end diff --git a/spec/components/email/sender_spec.rb b/spec/components/email/sender_spec.rb index b3d53ccce4b..09076a56277 100644 --- a/spec/components/email/sender_spec.rb +++ b/spec/components/email/sender_spec.rb @@ -80,19 +80,19 @@ describe Email::Sender do context "doesn't add return_path when no plus addressing" do before { SiteSetting.reply_by_email_address = '%{reply_key}@test.com' } - When { email_sender.send } - Then { + it 'should not set the return_path' do + email_sender.send expect(message.header[:return_path].to_s).to eq("") - } + end end context "adds return_path with plus addressing" do before { SiteSetting.reply_by_email_address = 'replies+%{reply_key}@test.com' } - When { email_sender.send } - Then { + it 'should set the return_path' do + email_sender.send expect(message.header[:return_path].to_s).to eq("replies+verp-#{EmailLog.last.bounce_key}@test.com") - } + end end context "adds a List-ID header to identify the forum" do @@ -102,14 +102,21 @@ describe Email::Sender do message.header['X-Discourse-Topic-Id'] = topic.id end - When { email_sender.send } - Then { expect(message.header['List-ID']).to be_present } - Then { expect(message.header['List-ID'].to_s).to match('name-with-space') } + it 'should add the right header' do + email_sender.send + + expect(message.header['List-ID']).to be_present + expect(message.header['List-ID'].to_s).to match('name-with-space') + end end context "adds a Message-ID header even when topic id is not present" do - When { email_sender.send } - Then { expect(message.header['Message-ID']).to be_present } + + it 'should add the right header' do + email_sender.send + + expect(message.header['Message-ID']).to be_present + end end context "adds Precedence header" do @@ -117,8 +124,10 @@ describe Email::Sender do message.header['X-Discourse-Topic-Id'] = 5577 end - When { email_sender.send } - Then { expect(message.header['Precedence']).to be_present } + it 'should add the right header' do + email_sender.send + expect(message.header['Precedence']).to be_present + end end context "removes custom Discourse headers from topic notification mails" do @@ -126,17 +135,21 @@ describe Email::Sender do message.header['X-Discourse-Topic-Id'] = 5577 end - When { email_sender.send } - Then { expect(message.header['X-Discourse-Topic-Id']).not_to be_present } - Then { expect(message.header['X-Discourse-Post-Id']).not_to be_present } - Then { expect(message.header['X-Discourse-Reply-Key']).not_to be_present } + it 'should remove the right headers' do + email_sender.send + expect(message.header['X-Discourse-Topic-Id']).not_to be_present + expect(message.header['X-Discourse-Post-Id']).not_to be_present + expect(message.header['X-Discourse-Reply-Key']).not_to be_present + end end context "removes custom Discourse headers from digest/registration/other mails" do - When { email_sender.send } - Then { expect(message.header['X-Discourse-Topic-Id']).not_to be_present } - Then { expect(message.header['X-Discourse-Post-Id']).not_to be_present } - Then { expect(message.header['X-Discourse-Reply-Key']).not_to be_present } + it 'should remove the right headers' do + email_sender.send + expect(message.header['X-Discourse-Topic-Id']).not_to be_present + expect(message.header['X-Discourse-Post-Id']).not_to be_present + expect(message.header['X-Discourse-Reply-Key']).not_to be_present + end end context "email threading" do @@ -214,8 +227,10 @@ describe Email::Sender do message.header['X-MC-Metadata'] = { foo: "bar" }.to_json end - When { email_sender.send } - Then { expect(message.header['X-MC-Metadata'].to_s).to match(message.message_id) } + it 'should set the right header' do + email_sender.send + expect(message.header['X-MC-Metadata'].to_s).to match(message.message_id) + end end context "merges custom sparkpost header" do @@ -224,19 +239,24 @@ describe Email::Sender do message.header['X-MSYS-API'] = { foo: "bar" }.to_json end - When { email_sender.send } - Then { expect(message.header['X-MSYS-API'].to_s).to match(message.message_id) } + it 'should set the right header' do + email_sender.send + expect(message.header['X-MSYS-API'].to_s).to match(message.message_id) + end end context 'email logs' do let(:email_log) { EmailLog.last } - When { email_sender.send } - Then { expect(email_log).to be_present } - Then { expect(email_log.email_type).to eq('valid_type') } - Then { expect(email_log.to_address).to eq('eviltrout@test.domain') } - Then { expect(email_log.reply_key).to be_blank } - Then { expect(email_log.user_id).to be_blank } + it 'should create the right log' do + email_sender.send + + expect(email_log).to be_present + expect(email_log.email_type).to eq('valid_type') + expect(email_log.to_address).to eq('eviltrout@test.domain') + expect(email_log.reply_key).to be_blank + expect(email_log.user_id).to be_blank + end end context "email log with a post id and topic id" do @@ -246,9 +266,12 @@ describe Email::Sender do end let(:email_log) { EmailLog.last } - When { email_sender.send } - Then { expect(email_log.post_id).to eq(3344) } - Then { expect(email_log.topic_id).to eq(5577) } + + it 'should create the right log' do + email_sender.send + expect(email_log.post_id).to eq(3344) + expect(email_log.topic_id).to eq(5577) + end end context "email log with a reply key" do @@ -257,17 +280,23 @@ describe Email::Sender do end let(:email_log) { EmailLog.last } - When { email_sender.send } - Then { expect(email_log.reply_key).to eq(reply_key) } + + it 'should create the right log' do + email_sender.send + expect(email_log.reply_key).to eq(reply_key) + end end context 'email parts' do - When { email_sender.send } - Then { expect(message).to be_multipart } - Then { expect(message.text_part.content_type).to eq('text/plain; charset=UTF-8') } - Then { expect(message.html_part.content_type).to eq('text/html; charset=UTF-8') } - Then { expect(message.html_part.body.to_s).to match("

    hello

    ") } + it 'should contain the right message' do + email_sender.send + + expect(message).to be_multipart + expect(message.text_part.content_type).to eq('text/plain; charset=UTF-8') + expect(message.html_part.content_type).to eq('text/html; charset=UTF-8') + expect(message.html_part.body.to_s).to match("

    hello

    ") + end end end diff --git a/spec/components/email/styles_spec.rb b/spec/components/email/styles_spec.rb index 97e09c726c5..07061dbc3ae 100644 --- a/spec/components/email/styles_spec.rb +++ b/spec/components/email/styles_spec.rb @@ -169,5 +169,11 @@ describe Email::Styles do end end + context "onebox_styles" do + it "renders quote as
    " do + fragment = html_fragment('') + expect(fragment.to_s.squish).to match(/^$/) + end + end end diff --git a/spec/components/guardian_spec.rb b/spec/components/guardian_spec.rb index bf51aadfe4d..346265a7187 100644 --- a/spec/components/guardian_spec.rb +++ b/spec/components/guardian_spec.rb @@ -4,9 +4,9 @@ require_dependency 'post_destroyer' describe Guardian do - let(:user) { build(:user) } - let(:moderator) { build(:moderator) } - let(:admin) { build(:admin) } + let(:user) { Fabricate(:user) } + let(:moderator) { Fabricate(:moderator) } + let(:admin) { Fabricate(:admin) } let(:trust_level_2) { build(:user, trust_level: 2) } let(:trust_level_3) { build(:user, trust_level: 3) } let(:trust_level_4) { build(:user, trust_level: 4) } @@ -90,8 +90,9 @@ describe Guardian do end it "returns true for a new user flagging a private message as spam" do - post.topic.archetype = Archetype.private_message + post = Fabricate(:private_message_post, user: Fabricate(:admin)) user.trust_level = TrustLevel[0] + post.topic.allowed_users << user expect(Guardian.new(user).post_can_act?(post, :spam)).to be_truthy end @@ -1557,6 +1558,15 @@ describe Guardian do user.id = 2 expect(Guardian.new(admin).can_grant_admin?(user)).to be_truthy end + + it 'should not allow an admin to grant admin access to a non real user' do + begin + Discourse.system_user.update!(admin: false) + expect(Guardian.new(admin).can_grant_admin?(Discourse.system_user)).to be(false) + ensure + Discourse.system_user.update!(admin: true) + end + end end context 'can_revoke_admin?' do @@ -1578,6 +1588,10 @@ describe Guardian do expect(Guardian.new(admin).can_revoke_admin?(another_admin)).to be_truthy end + + it "should not allow an admin to revoke a no real user's admin access" do + expect(Guardian.new(admin).can_revoke_admin?(Discourse.system_user)).to be(false) + end end context 'can_grant_moderation?' do @@ -1601,6 +1615,15 @@ describe Guardian do it "allows an admin to grant a regular user access" do expect(Guardian.new(admin).can_grant_moderation?(user)).to be_truthy end + + it "should not allow an admin to grant moderation to a non real user" do + begin + Discourse.system_user.update!(moderator: false) + expect(Guardian.new(admin).can_grant_moderation?(Discourse.system_user)).to be(false) + ensure + Discourse.system_user.update!(moderator: true) + end + end end context 'can_revoke_moderation?' do @@ -1628,6 +1651,10 @@ describe Guardian do it "does not allow revoke from non moderators" do expect(Guardian.new(admin).can_revoke_moderation?(admin)).to be_falsey end + + it "should not allow an admin to revoke moderation from a non real user" do + expect(Guardian.new(admin).can_revoke_moderation?(Discourse.system_user)).to be(false) + end end context "can_see_invite_details?" do @@ -2284,21 +2311,33 @@ describe Guardian do context 'topic featured link category restriction' do before { SiteSetting.topic_featured_link_enabled = true } let(:guardian) { Guardian.new } + let(:uncategorized) { Category.find(SiteSetting.uncategorized_category_id) } - it 'returns true if no category restricts editing link' do - expect(guardian.can_edit_featured_link?(nil)).to eq(true) - expect(guardian.can_edit_featured_link?(5)).to eq(true) + context "uncategorized" do + let!(:link_category) { Fabricate(:link_category) } + + it "allows featured links if uncategorized allows it" do + uncategorized.topic_featured_link_allowed = true + uncategorized.save! + expect(guardian.can_edit_featured_link?(nil)).to eq(true) + end + + it "forbids featured links if uncategorized forbids it" do + uncategorized.topic_featured_link_allowed = false + uncategorized.save! + expect(guardian.can_edit_featured_link?(nil)).to eq(false) + end end context 'when exist' do - let!(:category) { Fabricate(:category) } + let!(:category) { Fabricate(:category, topic_featured_link_allowed: false) } let!(:link_category) { Fabricate(:link_category) } it 'returns true if the category is listed' do expect(guardian.can_edit_featured_link?(link_category.id)).to eq(true) end - it 'returns false if the category is not listed' do + it 'returns false if the category does not allow it' do expect(guardian.can_edit_featured_link?(category.id)).to eq(false) end end diff --git a/spec/components/onebox/engine/discourse_local_onebox_spec.rb b/spec/components/onebox/engine/discourse_local_onebox_spec.rb index c3b015befc8..752eebc6e83 100644 --- a/spec/components/onebox/engine/discourse_local_onebox_spec.rb +++ b/spec/components/onebox/engine/discourse_local_onebox_spec.rb @@ -10,19 +10,19 @@ describe Onebox::Engine::DiscourseLocalOnebox do it "returns a link if post isn't found" do url = "#{Discourse.base_url}/t/not-exist/3/2" - expect(Onebox.preview(url).to_s).to eq("#{url}") + expect(Onebox.preview(url).to_s).to eq(%|#{url}|) end it "returns a link if not allowed to see the post" do url = "#{Discourse.base_url}#{post2.url}" Guardian.any_instance.expects(:can_see_post?).returns(false) - expect(Onebox.preview(url).to_s).to eq("#{url}") + expect(Onebox.preview(url).to_s).to eq(%|#{url}|) end it "returns a link if post is hidden" do hidden_post = Fabricate(:post, topic: post.topic, post_number: 2, hidden: true, hidden_reason_id: Post.hidden_reasons[:flag_threshold_reached]) url = "#{Discourse.base_url}#{hidden_post.url}" - expect(Onebox.preview(url).to_s).to eq("#{url}") + expect(Onebox.preview(url).to_s).to eq(%|#{url}|) end it "returns some onebox goodness if post exists and can be seen" do @@ -43,13 +43,13 @@ describe Onebox::Engine::DiscourseLocalOnebox do it "returns a link if topic isn't found" do url = "#{Discourse.base_url}/t/not-found/123" - expect(Onebox.preview(url).to_s).to eq("#{url}") + expect(Onebox.preview(url).to_s).to eq(%|#{url}|) end it "returns a link if not allowed to see the topic" do url = topic.url Guardian.any_instance.expects(:can_see_topic?).returns(false) - expect(Onebox.preview(url).to_s).to eq("#{url}") + expect(Onebox.preview(url).to_s).to eq(%|#{url}|) end it "replaces emoji in the title" do @@ -66,22 +66,27 @@ describe Onebox::Engine::DiscourseLocalOnebox do context "for a link to an internal audio or video file" do + let(:sha) { Digest::SHA1.hexdigest("discourse") } + let(:path) { "/uploads/default/original/3X/5/c/#{sha}" } + it "returns nil if file type is not audio or video" do - url = "#{Discourse.base_url}/uploads/default/original/3X/5/c/24asdf42.pdf" + url = "#{Discourse.base_url}#{path}.pdf" FakeWeb.register_uri(:get, url, body: "") expect(Onebox.preview(url).to_s).to eq("") end it "returns some onebox goodness for audio file" do - url = "#{Discourse.base_url}/uploads/default/original/3X/5/c/24asdf42.mp3" + url = "#{Discourse.base_url}#{path}.MP3" html = Onebox.preview(url).to_s - expect(html).to eq("") + # will be removed by the browser + # need to fix https://github.com/rubys/nokogumbo/issues/14 + expect(html).to eq(%||) end it "returns some onebox goodness for video file" do - url = "#{Discourse.base_url}/uploads/default/original/3X/5/c/24asdf42.mp4" + url = "#{Discourse.base_url}#{path}.mov" html = Onebox.preview(url).to_s - expect(html).to eq("") + expect(html).to eq(%||) end end diff --git a/spec/components/onebox/engine/whitelisted_generic_onebox_spec.rb b/spec/components/onebox/engine/whitelisted_generic_onebox_spec.rb new file mode 100644 index 00000000000..f6d8c38840b --- /dev/null +++ b/spec/components/onebox/engine/whitelisted_generic_onebox_spec.rb @@ -0,0 +1,18 @@ +require 'rails_helper' + +describe Onebox::Engine::WhitelistedGenericOnebox do + + describe ".===" do + + it "matches any domain" do + expect(described_class === URI('http://foo.bar/resource')).to be(true) + end + + it "doesn't match an IP address" do + expect(described_class === URI('http://1.2.3.4/resource')).to be(false) + expect(described_class === URI('http://1.2.3.4:1234/resource')).to be(false) + end + + end + +end diff --git a/spec/components/plugin/instance_spec.rb b/spec/components/plugin/instance_spec.rb index d5c71508503..0e9c0fd592b 100644 --- a/spec/components/plugin/instance_spec.rb +++ b/spec/components/plugin/instance_spec.rb @@ -160,6 +160,27 @@ describe Plugin::Instance do end end + context "themes" do + it "can register a theme" do + plugin = Plugin::Instance.new nil, "/tmp/test.rb" + plugin.register_theme('plugin') do |theme| + theme.set_color_scheme( + primary: 'ffff00', + secondary: '222222', + tertiary: '0f82af', + quaternary: 'c14924', + header_background: '111111', + header_primary: '333333', + highlight: 'a87137', + danger: 'e45735', + success: '1ca551', + love: 'fa6c8d' + ) + end + expect(plugin.themes).to be_present + end + end + context "register_color_scheme" do it "can add a color scheme for the first time" do plugin = Plugin::Instance.new nil, "/tmp/test.rb" @@ -207,7 +228,7 @@ describe Plugin::Instance do it 'should add the right callback' do called = 0 - method_name = plugin_instance.add_model_callback(User, :after_create) do + plugin_instance.add_model_callback(User, :after_create) do called += 1 end @@ -223,7 +244,7 @@ describe Plugin::Instance do it 'should add the right callback with options' do called = 0 - method_name = plugin_instance.add_model_callback(User, :after_commit, on: :create) do + plugin_instance.add_model_callback(User, :after_commit, on: :create) do called += 1 end diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb index b6fe3fb6606..b59758adb41 100644 --- a/spec/components/post_creator_spec.rb +++ b/spec/components/post_creator_spec.rb @@ -5,7 +5,6 @@ require 'topic_subtype' describe PostCreator do before do - ActiveRecord::Base.observers.enable :all end let(:user) { Fabricate(:user) } @@ -34,6 +33,14 @@ describe PostCreator do expect(TopicUser.where(user_id: p.user_id, topic_id: p.topic_id).count).to eq(0) end + it "can be created with first post as wiki" do + cat = Fabricate(:category) + cat.all_topics_wiki = true + cat.save + post = PostCreator.create(user, basic_topic_params.merge(category: cat.id )) + expect(post.wiki).to eq(true) + end + it "ensures the user can create the topic" do Guardian.any_instance.expects(:can_create?).with(Topic,nil).returns(false) expect { creator.create }.to raise_error(Discourse::InvalidAccess) @@ -99,6 +106,8 @@ describe PostCreator do it "generates the correct messages for a secure topic" do + UserActionCreator.enable + admin = Fabricate(:admin) cat = Fabricate(:category) @@ -132,6 +141,8 @@ describe PostCreator do it 'generates the correct messages for a normal topic' do + UserActionCreator.enable + p = nil messages = MessageBus.track_publish do p = creator.create @@ -893,4 +904,39 @@ describe PostCreator do end end + context "private message to a muted user" do + let(:muted_me) { Fabricate(:evil_trout) } + + it 'should fail' do + updater = UserUpdater.new(muted_me, muted_me) + updater.update_muted_users("#{user.username}") + + pc = PostCreator.new( + user, + title: 'this message is to someone who muted me!', + raw: "you will have to see this even if you muted me!", + archetype: Archetype.private_message, + target_usernames: "#{muted_me.username}" + ) + expect(pc).not_to be_valid + expect(pc.errors).to be_present + end + + let(:staff_user) { Fabricate(:admin) } + + it 'succeeds if the user is staff' do + updater = UserUpdater.new(muted_me, muted_me) + updater.update_muted_users("#{staff_user.username}") + + pc = PostCreator.new( + staff_user, + title: 'this message is to someone who muted me!', + raw: "you will have to see this even if you muted me!", + archetype: Archetype.private_message, + target_usernames: "#{muted_me.username}" + ) + expect(pc).to be_valid + expect(pc.errors).to be_blank + end + end end diff --git a/spec/components/post_destroyer_spec.rb b/spec/components/post_destroyer_spec.rb index 6a506fd6a00..58781bd2f14 100644 --- a/spec/components/post_destroyer_spec.rb +++ b/spec/components/post_destroyer_spec.rb @@ -4,7 +4,7 @@ require 'post_destroyer' describe PostDestroyer do before do - ActiveRecord::Base.observers.enable :all + UserActionCreator.enable end let(:moderator) { Fabricate(:moderator) } diff --git a/spec/components/pretty_text_spec.rb b/spec/components/pretty_text_spec.rb index 6066d93e028..b63d77584b4 100644 --- a/spec/components/pretty_text_spec.rb +++ b/spec/components/pretty_text_spec.rb @@ -10,10 +10,10 @@ describe PrettyText do describe "off topic quoting" do it "can correctly populate topic title" do - topic = Fabricate(:topic, title: "this is a test topic") + topic = Fabricate(:topic, title: "this is a test topic :slight_smile:") expected = <

    ddd

    HTML @@ -23,23 +23,22 @@ HTML describe "with avatar" do let(:default_avatar) { "//test.localhost/uploads/default/avatars/42d/57c/46ce7ee487/{size}.png" } + let(:user) { Fabricate(:user) } before do - eviltrout = User.new User.stubs(:default_template).returns(default_avatar) - User.expects(:find_by).with(username_lower: "eviltrout").returns(eviltrout) end it "produces a quote even with new lines in it" do - expect(PrettyText.cook("[quote=\"EvilTrout, post:123, topic:456, full:true\"]ddd\n[/quote]")).to match_html "" + expect(PrettyText.cook("[quote=\"#{user.username}, post:123, topic:456, full:true\"]ddd\n[/quote]")).to match_html "" end it "should produce a quote" do - expect(PrettyText.cook("[quote=\"EvilTrout, post:123, topic:456, full:true\"]ddd[/quote]")).to match_html "" + expect(PrettyText.cook("[quote=\"#{user.username}, post:123, topic:456, full:true\"]ddd[/quote]")).to match_html "" end it "trims spaces on quote params" do - expect(PrettyText.cook("[quote=\"EvilTrout, post:555, topic: 666\"]ddd[/quote]")).to match_html "" + expect(PrettyText.cook("[quote=\"#{user.username}, post:555, topic: 666\"]ddd[/quote]")).to match_html "" end end diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index 8d054157b1d..a9184ef0906 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -10,7 +10,7 @@ describe Search do end before do - ActiveRecord::Base.observers.enable :search_observer + SearchIndexer.enable end context 'post indexing observer' do diff --git a/spec/components/secure_session_spec.rb b/spec/components/secure_session_spec.rb new file mode 100644 index 00000000000..df5f5532532 --- /dev/null +++ b/spec/components/secure_session_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' +require_dependency 'secure_session' + +describe SecureSession do + it "operates correctly" do + s = SecureSession.new("abc") + + s["hello"] = "world" + s["foo"] = "bar" + expect(s["hello"]).to eq("world") + expect(s["foo"]).to eq("bar") + + s["hello"] = nil + expect(s["hello"]).to eq(nil) + end +end diff --git a/spec/components/validators/email_validator_spec.rb b/spec/components/validators/email_validator_spec.rb index 05edfbbf47c..bb7d6cb6ec1 100644 --- a/spec/components/validators/email_validator_spec.rb +++ b/spec/components/validators/email_validator_spec.rb @@ -32,4 +32,16 @@ describe EmailValidator do end end + context '.email_regex' do + it 'should match valid emails' do + expect(!!('test@discourse.org' =~ EmailValidator.email_regex)).to eq(true) + end + + it 'should not match invalid emails' do + ['testdiscourse.org', 'test@discourse.org; a@discourse.org', 'random'].each do |email| + expect(!!(email =~ EmailValidator.email_regex)).to eq(false) + end + end + end + end diff --git a/spec/controllers/admin/backups_controller_spec.rb b/spec/controllers/admin/backups_controller_spec.rb index 080f4eb6c35..0669f667b3e 100644 --- a/spec/controllers/admin/backups_controller_spec.rb +++ b/spec/controllers/admin/backups_controller_spec.rb @@ -90,16 +90,18 @@ describe Admin::BackupsController do describe ".show" do it "uses send_file to transmit the backup" do - FileUtils.mkdir_p Backup.base_directory - File.open(Backup.base_directory << "/" << backup_filename, "w") do |f| - f.write("hello") - end + path = File.join(Backup.base_directory, backup_filename) + File.open(path, "w") { |f| f.write("hello") } Backup.create_from_filename(backup_filename) + StaffActionLogger.any_instance.expects(:log_backup_download).once + get :show, id: backup_filename - expect(response.headers['Content-Length']).to eq(5) + File.delete(path) rescue nil + + expect(response.headers['Content-Length']).to eq("5") expect(response.headers['Content-Disposition']).to match(/attachment; filename/) end @@ -120,7 +122,11 @@ describe Admin::BackupsController do it "removes the backup if found" do Backup.expects(:[]).with(backup_filename).returns(b) b.expects(:remove) + + StaffActionLogger.any_instance.expects(:log_backup_destroy).with(b).once + xhr :delete, :destroy, id: backup_filename + expect(response).to be_success end @@ -179,17 +185,29 @@ describe Admin::BackupsController do it "enables readonly mode" do Discourse.expects(:enable_readonly_mode) - xhr :put, :readonly, enable: true + expect { xhr :put, :readonly, enable: true } + .to change { UserHistory.count }.by(1) expect(response).to be_success + + user_history = UserHistory.last + + expect(UserHistory.last.action).to eq(UserHistory.actions[:change_readonly_mode]) + expect(UserHistory.last.new_value).to eq('t') end it "disables readonly mode" do Discourse.expects(:disable_readonly_mode) - xhr :put, :readonly, enable: false + expect { xhr :put, :readonly, enable: false } + .to change { UserHistory.count }.by(1) expect(response).to be_success + + user_history = UserHistory.last + + expect(UserHistory.last.action).to eq(UserHistory.actions[:change_readonly_mode]) + expect(UserHistory.last.new_value).to eq('f') end end @@ -211,8 +229,10 @@ describe Admin::BackupsController do it "should upload the file successfully" do described_class.any_instance.expects(:has_enough_space_on_disk?).returns(true) + filename = 'test_Site-0123456789.tar.gz' + xhr :post, :upload_backup_chunk, - resumableFilename: 'test_Site-0123456789.tar.gz', + resumableFilename: filename, resumableTotalSize: 1, resumableIdentifier: 'test', resumableChunkNumber: '1', @@ -222,6 +242,8 @@ describe Admin::BackupsController do expect(response.status).to eq(200) expect(response.body).to eq("") + + File.delete(File.join(Backup.base_directory, filename)) rescue nil end end end diff --git a/spec/controllers/admin/groups_controller_spec.rb b/spec/controllers/admin/groups_controller_spec.rb index f9ee82f9ee6..732d07c3ad2 100644 --- a/spec/controllers/admin/groups_controller_spec.rb +++ b/spec/controllers/admin/groups_controller_spec.rb @@ -41,7 +41,8 @@ describe Admin::GroupsController do "bio_raw"=>nil, "bio_cooked"=>nil, "public"=>false, - "allow_membership_requests"=>false + "allow_membership_requests"=>false, + "full_name"=>group.full_name }]) end @@ -87,14 +88,19 @@ describe Admin::GroupsController do it "ignore name change on automatic group" do expect do - xhr :put, :update, { id: 1, group: { name: "WAT", visible: "true" } } - end.to_not change { GroupHistory.count } + xhr :put, :update, { id: 1, group: { + name: "WAT", + visible: "true", + allow_membership_requests: "true" + } } + end.to change { GroupHistory.count }.by(1) expect(response).to be_success group = Group.find(1) expect(group.name).not_to eq("WAT") expect(group.visible).to eq(true) + expect(group.allow_membership_requests).to eq(true) end it "doesn't launch the 'automatic group membership' job when it's not retroactive" do diff --git a/spec/controllers/embed_controller_spec.rb b/spec/controllers/embed_controller_spec.rb index bd906895eaf..a7ca371c1d3 100644 --- a/spec/controllers/embed_controller_spec.rb +++ b/spec/controllers/embed_controller_spec.rb @@ -8,12 +8,12 @@ describe EmbedController do it "is 404 without an embed_url" do get :comments - expect(response).not_to be_success + expect(response).to render_template :embed_error end it "raises an error with a missing host" do get :comments, embed_url: embed_url - expect(response).not_to be_success + expect(response).to render_template :embed_error end context "by topic id" do @@ -34,7 +34,7 @@ describe EmbedController do context "without api key" do it "fails" do get :info, format: :json - expect(response).not_to be_success + expect(response).to render_template :embed_error end end @@ -69,7 +69,7 @@ describe EmbedController do it "raises an error with no referer" do get :comments, embed_url: embed_url - expect(response).not_to be_success + expect(response).to render_template :embed_error end context "success" do @@ -133,7 +133,7 @@ describe EmbedController do it "doesn't work with a made up host" do controller.request.stubs(:referer).returns("http://codinghorror.com/invalid-url") get :comments, embed_url: embed_url - expect(response).to_not be_success + expect(response).to render_template :embed_error end end end diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb index be07bb78943..6c9ace61b2a 100644 --- a/spec/controllers/invites_controller_spec.rb +++ b/spec/controllers/invites_controller_spec.rb @@ -123,15 +123,16 @@ describe InvitesController do end end - context '.show' do + context '.perform_accept_invitation' do context 'with an invalid invite id' do before do - get :show, id: "doesn't exist" + put :perform_accept_invitation, id: "doesn't exist" end it "redirects to the root" do - expect(response).to redirect_to("/") + expect(response).to be_success + expect(flash[:error]).to be_present end it "should not change the session" do @@ -144,11 +145,12 @@ describe InvitesController do let(:invite) { topic.invite_by_email(topic.user, "iceking@adventuretime.ooo") } let(:deleted_invite) { invite.destroy; invite } before do - get :show, id: deleted_invite.invite_key + put :perform_accept_invitation, id: deleted_invite.invite_key end it "redirects to the root" do - expect(response).to redirect_to("/") + expect(response).to be_success + expect(flash[:error]).to be_present end it "should not change the session" do @@ -160,10 +162,9 @@ describe InvitesController do let(:topic) { Fabricate(:topic) } let(:invite) { topic.invite_by_email(topic.user, "iceking@adventuretime.ooo") } - it 'redeems the invite' do Invite.any_instance.expects(:redeem) - get :show, id: invite.invite_key + put :perform_accept_invitation, id: invite.invite_key end context 'when redeem returns a user' do @@ -172,7 +173,7 @@ describe InvitesController do context 'success' do before do Invite.any_instance.expects(:redeem).returns(user) - get :show, id: invite.invite_key + put :perform_accept_invitation, id: invite.invite_key end it 'logs in the user' do @@ -193,18 +194,15 @@ describe InvitesController do it 'sends a welcome message if set' do user.send_welcome_message = true user.expects(:enqueue_welcome_message).with('welcome_invite') - get :show, id: invite.invite_key + put :perform_accept_invitation, id: invite.invite_key end it "doesn't send a welcome message if not set" do user.expects(:enqueue_welcome_message).with('welcome_invite').never - get :show, id: invite.invite_key + put :perform_accept_invitation, id: invite.invite_key end - end - end - end context 'new registrations are disabled' do @@ -214,7 +212,7 @@ describe InvitesController do it "doesn't redeem the invite" do Invite.any_instance.stubs(:redeem).never - get :show, id: invite.invite_key + put :perform_accept_invitation, id: invite.invite_key end end @@ -225,7 +223,7 @@ describe InvitesController do it "doesn't redeem the invite" do Invite.any_instance.stubs(:redeem).never - get :show, id: invite.invite_key + put :perform_accept_invitation, id: invite.invite_key end end end diff --git a/spec/controllers/onebox_controller_spec.rb b/spec/controllers/onebox_controller_spec.rb index a2f5c381740..adec21d4f8a 100644 --- a/spec/controllers/onebox_controller_spec.rb +++ b/spec/controllers/onebox_controller_spec.rb @@ -4,42 +4,82 @@ describe OneboxController do let(:url) { "http://google.com" } - it 'invalidates the cache if refresh is passed' do - Oneboxer.expects(:preview).with(url, invalidate_oneboxes: true) - xhr :get, :show, url: url, refresh: 'true' + it "requires the user to be logged in" do + expect { xhr :get, :show, url: url }.to raise_error(Discourse::NotLoggedIn) end - describe "found onebox" do + describe "logged in" do - let(:body) { "this is the onebox body"} + before { @user = log_in(:admin) } - before do - Oneboxer.expects(:preview).with(url, invalidate_oneboxes: false).returns(body) - xhr :get, :show, url: url + it 'invalidates the cache if refresh is passed' do + Oneboxer.expects(:preview).with(url, invalidate_oneboxes: true) + xhr :get, :show, url: url, refresh: 'true', user_id: @user.id end - it 'returns success' do - expect(response).to be_success + describe "cached onebox" do + + let(:body) { "This is a cached onebox body" } + + before do + Oneboxer.expects(:cached_preview).with(url).returns(body) + Oneboxer.expects(:preview).never + xhr :get, :show, url: url, user_id: @user.id + end + + it "returns success" do + expect(response).to be_success + end + + it "returns the cached onebox response in the body" do + expect(response.body).to eq(body) + end + end - it 'returns the onebox response in the body' do - expect(response.body).to eq(body) + describe "only 1 outgoing preview per user" do + + it "returns 429" do + Oneboxer.expects(:is_previewing?).returns(true) + xhr :get, :show, url: url, user_id: @user.id + expect(response.status).to eq(429) + end + end - end + describe "found onebox" do - describe "missing onebox" do + let(:body) { "this is the onebox body"} + + before do + Oneboxer.expects(:preview).with(url, invalidate_oneboxes: false).returns(body) + xhr :get, :show, url: url, user_id: @user.id + end + + it 'returns success' do + expect(response).to be_success + end + + it 'returns the onebox response in the body' do + expect(response.body).to eq(body) + end - it "returns 404 if the onebox is nil" do - Oneboxer.expects(:preview).with(url, invalidate_oneboxes: false).returns(nil) - xhr :get, :show, url: url - expect(response.response_code).to eq(404) end - it "returns 404 if the onebox is an empty string" do - Oneboxer.expects(:preview).with(url, invalidate_oneboxes: false).returns(" \t ") - xhr :get, :show, url: url - expect(response.response_code).to eq(404) + describe "missing onebox" do + + it "returns 404 if the onebox is nil" do + Oneboxer.expects(:preview).with(url, invalidate_oneboxes: false).returns(nil) + xhr :get, :show, url: url, user_id: @user.id + expect(response.response_code).to eq(404) + end + + it "returns 404 if the onebox is an empty string" do + Oneboxer.expects(:preview).with(url, invalidate_oneboxes: false).returns(" \t ") + xhr :get, :show, url: url, user_id: @user.id + expect(response.response_code).to eq(404) + end + end end diff --git a/spec/controllers/post_actions_controller_spec.rb b/spec/controllers/post_actions_controller_spec.rb index a9780ac2838..141e99ca9ff 100644 --- a/spec/controllers/post_actions_controller_spec.rb +++ b/spec/controllers/post_actions_controller_spec.rb @@ -7,6 +7,20 @@ describe PostActionsController do expect { xhr :post, :create }.to raise_error(Discourse::NotLoggedIn) end + context 'logged in as user' do + let(:user) { Fabricate(:user) } + let(:private_message) { Fabricate(:private_message_post, user: Fabricate(:coding_horror)) } + + before do + log_in_user(user) + end + + it 'fails when the user does not have permission to see the post' do + xhr :post, :create, id: private_message.id, post_action_type_id: PostActionType.types[:bookmark] + expect(response).to be_forbidden + end + end + describe 'logged in as moderator' do before do @user = log_in(:moderator) @@ -17,18 +31,17 @@ describe PostActionsController do expect { xhr :post, :create, post_action_type_id: PostActionType.types[:like] }.to raise_error(ActionController::ParameterMissing) end + it 'fails when the id is invalid' do + xhr :post, :create, post_action_type_id: PostActionType.types[:like], id: -1 + expect(response.status).to eq(404) + end + it 'raises an error when the post_action_type_id index is missing' do expect { xhr :post, :create, id: @post.id }.to raise_error(ActionController::ParameterMissing) end it "fails when the user doesn't have permission to see the post" do - Guardian.any_instance.expects(:can_see?).with(@post).returns(false) - xhr :post, :create, id: @post.id, post_action_type_id: PostActionType.types[:like] - expect(response).to be_forbidden - end - - it "fails when the user doesn't have permission to perform that action" do - Guardian.any_instance.expects(:post_can_act?).with(@post, :like, taken_actions: nil).returns(false) + @post = Fabricate(:private_message_post, user: Fabricate(:user)) xhr :post, :create, id: @post.id, post_action_type_id: PostActionType.types[:like] expect(response).to be_forbidden end diff --git a/spec/controllers/posts_controller_spec.rb b/spec/controllers/posts_controller_spec.rb index 9f29a456393..8c8ba76a89e 100644 --- a/spec/controllers/posts_controller_spec.rb +++ b/spec/controllers/posts_controller_spec.rb @@ -426,13 +426,12 @@ describe PostsController do include_examples 'action requires login', :put, :bookmark, post_id: 2 describe 'when logged in' do - let(:post) { Fabricate(:post, user: log_in) } + let(:private_message) { Fabricate(:private_message_post) } it "raises an error if the user doesn't have permission to see the post" do - Guardian.any_instance.expects(:can_see?).with(post).returns(false).once - - xhr :put, :bookmark, post_id: post.id, bookmarked: 'true' + post + xhr :put, :bookmark, post_id: private_message.id, bookmarked: 'true' expect(response).to be_forbidden end @@ -466,6 +465,23 @@ describe PostsController do expect(response).to be_forbidden end + it "toggle wiki status should create a new version" do + admin = log_in(:admin) + another_user = Fabricate(:user) + another_post = Fabricate(:post, user: another_user) + + expect { xhr :put, :wiki, post_id: another_post.id, wiki: 'true' } + .to change { another_post.reload.version }.by(1) + + expect { xhr :put, :wiki, post_id: another_post.id, wiki: 'false' } + .to change { another_post.reload.version }.by(-1) + + another_admin = log_in(:admin) + + expect { xhr :put, :wiki, post_id: another_post.id, wiki: 'true' } + .to change { another_post.reload.version }.by(1) + end + it "can wiki a post" do Guardian.any_instance.expects(:can_wiki?).with(post).returns(true) diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index ceb07f93de8..7e967f0b7d2 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -5,7 +5,7 @@ describe SearchController do context "integration" do before do - ActiveRecord::Base.observers.enable :search_observer + SearchIndexer.enable end it "can search correctly" do diff --git a/spec/controllers/session_controller_spec.rb b/spec/controllers/session_controller_spec.rb index 0354ff813dd..50858f7acdb 100644 --- a/spec/controllers/session_controller_spec.rb +++ b/spec/controllers/session_controller_spec.rb @@ -141,6 +141,19 @@ describe SessionController do expect(response).to redirect_to('/b/') end + it 'redirects to random url if it is allowed' do + SiteSetting.sso_allows_all_return_paths = true + + sso = get_sso('https://gusundtrout.com') + sso.external_id = '666' # the number of the beast + sso.email = 'bob@bob.com' + sso.name = 'Sam Saffron' + sso.username = 'sam' + + get :sso_login, Rack::Utils.parse_query(sso.payload) + expect(response).to redirect_to('https://gusundtrout.com') + end + it 'redirects to root if the host of the return_path is different' do sso = get_sso('//eviltrout.com') sso.external_id = '666' # the number of the beast diff --git a/spec/controllers/static_controller_spec.rb b/spec/controllers/static_controller_spec.rb index f8ba6629848..732f94255a8 100644 --- a/spec/controllers/static_controller_spec.rb +++ b/spec/controllers/static_controller_spec.rb @@ -3,6 +3,15 @@ require 'rails_helper' describe StaticController do context 'brotli_asset' do + it 'returns a brotli encoded 404 if asset is missing' do + + get :brotli_asset, path: 'missing.js' + + expect(response.status).to eq(404) + expect(response.headers['Content-Encoding']).not_to eq('br') + expect(response.headers["Cache-Control"]).to match(/max-age=5/) + end + it 'has correct headers for brotli assets' do begin assets_path = Rails.root.join("public/assets") diff --git a/spec/controllers/topics_controller_spec.rb b/spec/controllers/topics_controller_spec.rb index 452470abdae..67342edd042 100644 --- a/spec/controllers/topics_controller_spec.rb +++ b/spec/controllers/topics_controller_spec.rb @@ -1255,6 +1255,15 @@ describe TopicsController do xhr :put, :remove_bookmarks, topic_id: post.topic_id expect(PostAction.where(user_id: user.id, post_action_type: bookmark).count).to eq(0) end + + it "should disallow bookmarks on posts you have no access to" do + log_in + user = Fabricate(:user) + pm = create_post(user: user, archetype: 'private_message', target_usernames: [user.username]) + + xhr :put, :bookmark, topic_id: pm.topic_id + expect(response).to be_forbidden + end end diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 90c3426b17d..3dd88514a07 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -33,6 +33,20 @@ describe UploadsController do }) end + it 'fails if type is invalid' do + xhr :post, :create, file: logo, type: "invalid type cause has space" + expect(response.status).to eq 403 + + xhr :post, :create, file: logo, type: "\\invalid" + expect(response.status).to eq 403 + + xhr :post, :create, file: logo, type: "invalid." + expect(response.status).to eq 403 + + xhr :post, :create, file: logo, type: "toolong"*100 + expect(response.status).to eq 403 + end + it 'is successful with an image' do Jobs.expects(:enqueue).with(:create_thumbnails, anything) @@ -156,7 +170,7 @@ describe UploadsController do expect(response.response_code).to eq(404) end - it "returns 404 when the upload doens't exist" do + it "returns 404 when the upload doesn't exist" do Upload.stubs(:find_by).returns(nil) get :show, site: site, sha: sha, extension: "pdf" @@ -173,6 +187,16 @@ describe UploadsController do get :show, site: site, sha: sha, extension: "zip" end + it "handles file without extension" do + SiteSetting.authorized_extensions = "*" + upload = Fabricate(:upload, original_filename: "image_file", sha1: sha) + controller.stubs(:render) + controller.expects(:send_file) + + get :show, site: site, sha: sha + expect(response).to be_success + end + context "prevent anons from downloading files" do before { SiteSetting.stubs(:prevent_anons_from_downloading_files).returns(true) } diff --git a/spec/controllers/user_actions_controller_spec.rb b/spec/controllers/user_actions_controller_spec.rb index 52583c7f86a..9e606101272 100644 --- a/spec/controllers/user_actions_controller_spec.rb +++ b/spec/controllers/user_actions_controller_spec.rb @@ -9,7 +9,7 @@ describe UserActionsController do end it 'renders list correctly' do - ActiveRecord::Base.observers.enable :all + UserActionCreator.enable post = Fabricate(:post) xhr :get, :index, username: post.user.username diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 95a8f2e5737..5d4f5cb80bf 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -237,6 +237,18 @@ describe UsersController do end context 'valid token' do + context 'when rendered' do + render_views + + it 'renders referrer never on get requests' do + user = Fabricate(:user, auth_token: SecureRandom.hex(16)) + token = user.email_tokens.create(email: user.email).token + get :password_reset, token: token + + expect(response.body).to include('') + end + end + it 'returns success' do user = Fabricate(:user, auth_token: SecureRandom.hex(16)) token = user.email_tokens.create(email: user.email).token @@ -254,6 +266,19 @@ describe UsersController do expect(session["password-#{token}"]).to be_blank end + it 'disallows double password reset' do + + user = Fabricate(:user, auth_token: SecureRandom.hex(16)) + token = user.email_tokens.create(email: user.email).token + + get :password_reset, token: token + put :password_reset, token: token, password: 'hg9ow8yhg98o' + put :password_reset, token: token, password: 'test123123Asdfsdf' + + user.reload + expect(user.confirm_password?('hg9ow8yhg98o')).to eq(true) + end + it "redirects to the wizard if you're the first admin" do user = Fabricate(:admin, auth_token: SecureRandom.hex(16), auth_token_updated_at: Time.now) token = user.email_tokens.create(email: user.email).token @@ -1306,7 +1331,7 @@ describe UsersController do let(:user) { Fabricate :user, username: "joecabot", name: "Lawrence Tierney" } before do - ActiveRecord::Base.observers.enable :all + SearchIndexer.enable Fabricate :post, user: user, topic: topic end diff --git a/spec/fabricators/email_change_request_fabricator.rb b/spec/fabricators/email_change_request_fabricator.rb new file mode 100644 index 00000000000..ba5a96f6bee --- /dev/null +++ b/spec/fabricators/email_change_request_fabricator.rb @@ -0,0 +1,6 @@ +Fabricator(:email_change_request) do + user + old_email { sequence(:old_email) { |i| "bruce#{i}@wayne.com" } } + new_email { sequence(:new_email) { |i| "super#{i}@man.com" } } + change_state EmailChangeRequest.states[:authorizing_old] +end diff --git a/spec/fabricators/embeddable_host_fabricator.rb b/spec/fabricators/embeddable_host_fabricator.rb index 9f589d389e0..582619f23bb 100644 --- a/spec/fabricators/embeddable_host_fabricator.rb +++ b/spec/fabricators/embeddable_host_fabricator.rb @@ -27,5 +27,5 @@ Fabricator(:private_category, from: :category) do end Fabricator(:link_category, from: :category) do - before_validation { |category, transients| category.custom_fields['topic_featured_link_allowed'] = 'true' } + before_validation { |category, transients| category.topic_featured_link_allowed = true } end diff --git a/spec/fabricators/group_fabricator.rb b/spec/fabricators/group_fabricator.rb index 0ec42da4c5e..d190d520e69 100644 --- a/spec/fabricators/group_fabricator.rb +++ b/spec/fabricators/group_fabricator.rb @@ -1,3 +1,3 @@ Fabricator(:group) do - name 'my_group' + name { sequence(:name) { |n| "my_group_#{n}" } } end diff --git a/spec/fixtures/emails/forwarded_email_2.eml b/spec/fixtures/emails/forwarded_email_2.eml index d31d5c44eac..146570a9580 100644 --- a/spec/fixtures/emails/forwarded_email_2.eml +++ b/spec/fixtures/emails/forwarded_email_2.eml @@ -2,7 +2,7 @@ Message-ID: <59@foo.bar.mail> From: Ba Bar To: Team Date: Mon, 1 Dec 2016 13:37:42 +0100 -Subject: Re: Discoursing much? +Subject: Tr: Discoursing much? @team, can you have a look at this email below? diff --git a/spec/fixtures/emails/forwarded_email_3.eml b/spec/fixtures/emails/forwarded_email_3.eml new file mode 100644 index 00000000000..1f37822b0a7 --- /dev/null +++ b/spec/fixtures/emails/forwarded_email_3.eml @@ -0,0 +1,18 @@ +Message-ID: <60@foo.bar.mail> +From: Ba Bar +To: Team +Date: Mon, 9 Dec 2016 13:37:42 +0100 +Subject: Fwd: Ça Discourse ? + +@team, can you have a look at this email below? + +Objet: Ça Discourse ? +Date: 2017-01-04 11:27 +De: Un Français +À: ba@bar.com + +Bonjour, + +Ça Discourse bien aujourd'hui ? + +Bises diff --git a/spec/fixtures/images/huge.jpg b/spec/fixtures/images/huge.jpg new file mode 100644 index 00000000000..25f2d5c6fb4 Binary files /dev/null and b/spec/fixtures/images/huge.jpg differ diff --git a/spec/integration/groups_spec.rb b/spec/integration/groups_spec.rb index 0a53cee2f89..bc721bf2e3d 100644 --- a/spec/integration/groups_spec.rb +++ b/spec/integration/groups_spec.rb @@ -4,12 +4,61 @@ describe "Groups" do let(:user) { Fabricate(:user) } let(:group) { Fabricate(:group, users: [user]) } - def sign_in(user) - password = 'somecomplicatedpassword' - user.update!(password: password) - Fabricate(:email_token, confirmed: true, user: user) - post "/session.json", { login: user.username, password: password } - expect(response).to be_success + describe 'viewing groups' do + let(:other_group) do + Fabricate(:group, name: '0000', visible: true, automatic: false) + end + + before do + other_group + group.update_attributes!(automatic: true, visible: true) + end + + context 'when group directory is disabled' do + site_setting(:enable_group_directory, false) + + it 'should deny access' do + get "/groups.json" + expect(response).to be_forbidden + end + end + + it 'should return the right response' do + get "/groups.json" + + expect(response).to be_success + + response_body = JSON.parse(response.body) + + group_ids = response_body["groups"].map { |g| g["id"] } + + expect(response_body["extras"]["group_user_ids"]).to eq([]) + expect(group_ids).to include(other_group.id) + expect(group_ids).to_not include(group.id) + expect(response_body["load_more_groups"]).to eq("/groups?page=1") + expect(response_body["total_rows_groups"]).to eq(1) + end + + context 'viewing as an admin' do + it 'should display automatic groups' do + admin = Fabricate(:admin) + sign_in(admin) + group.add(admin) + + get "/groups.json" + + expect(response).to be_success + + response_body = JSON.parse(response.body) + + group_ids = response_body["groups"].map { |g| g["id"] } + + expect(response_body["extras"]["group_user_ids"]).to eq([group.id]) + expect(group_ids).to include(group.id, other_group.id) + expect(response_body["load_more_groups"]).to eq("/groups?page=1") + expect(response_body["total_rows_groups"]).to eq(10) + end + end end describe "checking if a group can be mentioned" do @@ -48,13 +97,15 @@ describe "Groups" do end it "should be able update the group" do + group.update!(allow_membership_requests: false) + expect do xhr :put, "/groups/#{group.id}", { group: { flair_bg_color: 'FFF', flair_color: 'BBB', flair_url: 'fa-adjust', bio_raw: 'testing', - title: 'awesome team', + full_name: 'awesome team', public: true, allow_membership_requests: true } } @@ -68,7 +119,7 @@ describe "Groups" do expect(group.flair_color).to eq('BBB') expect(group.flair_url).to eq('fa-adjust') expect(group.bio_raw).to eq('testing') - expect(group.title).to eq('awesome team') + expect(group.full_name).to eq('awesome team') expect(group.public).to eq(true) expect(group.allow_membership_requests).to eq(true) expect(GroupHistory.last.subject).to eq('allow_membership_requests') @@ -100,6 +151,26 @@ describe "Groups" do end end + describe 'owners' do + let(:user1) { Fabricate(:user, last_seen_at: Time.zone.now) } + let(:user2) { Fabricate(:user, last_seen_at: Time.zone.now - 1 .day) } + let(:group) { Fabricate(:group, users: [user, user1, user2]) } + + it 'should return the right list of owners' do + group.add_owner(user1) + group.add_owner(user2) + + xhr :get, "/groups/#{group.name}/owners" + + expect(response).to be_success + + owners = JSON.parse(response.body) + + expect(owners.count).to eq(2) + expect(owners.map { |o| o["id"] }.sort).to eq([user1.id, user2.id]) + end + end + describe 'members' do let(:user1) do Fabricate(:user, @@ -117,7 +188,15 @@ describe "Groups" do ) end - let(:group) { Fabricate(:group, users: [user1, user2]) } + let(:user3) do + Fabricate(:user, + last_seen_at: nil, + last_posted_at: nil, + email: 'c@test.org' + ) + end + + let(:group) { Fabricate(:group, users: [user1, user2, user3]) } it "should allow members to be sorted by" do xhr :get, "/groups/#{group.name}/members", order: 'last_seen_at', desc: true @@ -126,7 +205,7 @@ describe "Groups" do members = JSON.parse(response.body)["members"] - expect(members.map { |m| m["id"] }).to eq([user1.id, user2.id]) + expect(members.map { |m| m["id"] }).to eq([user1.id, user2.id, user3.id]) xhr :get, "/groups/#{group.name}/members", order: 'last_seen_at' @@ -134,7 +213,7 @@ describe "Groups" do members = JSON.parse(response.body)["members"] - expect(members.map { |m| m["id"] }).to eq([user2.id, user1.id]) + expect(members.map { |m| m["id"] }).to eq([user2.id, user1.id, user3.id]) xhr :get, "/groups/#{group.name}/members", order: 'last_posted_at', desc: true @@ -142,7 +221,7 @@ describe "Groups" do members = JSON.parse(response.body)["members"] - expect(members.map { |m| m["id"] }).to eq([user2.id, user1.id]) + expect(members.map { |m| m["id"] }).to eq([user2.id, user1.id, user3.id]) end it "should not allow members to be sorted by columns that are not allowed" do @@ -152,7 +231,7 @@ describe "Groups" do members = JSON.parse(response.body)["members"] - expect(members.map { |m| m["id"] }).to eq([user1.id, user2.id]) + expect(members.map { |m| m["id"] }).to eq([user1.id, user2.id, user3.id]) end end @@ -237,20 +316,6 @@ describe "Groups" do expect(group_history.target_user).to eq(user2) end - it "can make incremental deletes" do - expect do - xhr :delete, "/groups/#{group.id}/members", username: user.username - end.to change { group.users.count }.by(-1) - - expect(response).to be_success - - group_history = GroupHistory.last - - expect(group_history.action).to eq(GroupHistory.actions[:remove_user_from_group]) - expect(group_history.acting_user).to eq(admin) - expect(group_history.target_user).to eq(user) - end - it "cannot add members to automatic groups" do group.update!(automatic: true) @@ -296,6 +361,22 @@ describe "Groups" do group.update!(public: true) end + context 'admin' do + it "can make incremental adds" do + expect do + xhr :put, "/groups/#{group.id}/members", usernames: other_user.username + end.to change { group.users.count }.by(1) + + expect(response).to be_success + + group_history = GroupHistory.last + + expect(group_history.action).to eq(GroupHistory.actions[:add_user_to_group]) + expect(group_history.acting_user).to eq(admin) + expect(group_history.target_user).to eq(other_user) + end + end + it 'should allow a user to join the group' do sign_in(other_user) @@ -305,7 +386,9 @@ describe "Groups" do expect(response).to be_success end - it 'should not allow a user to add another user to a group' do + it 'should not allow an underprivilege user to add another user to a group' do + sign_in(user) + xhr :put, "/groups/#{group.id}/members", usernames: other_user.username expect(response).to be_forbidden @@ -364,6 +447,15 @@ describe "Groups" do group.update!(public: true) end + context "admin" do + it "removes by username" do + expect { xhr :delete, "/groups/#{group.id}/members", username: other_user.username } + .to change { group.users.count }.by(-1) + + expect(response).to be_success + end + end + it 'should allow a user to leave a group' do sign_in(other_user) @@ -373,7 +465,9 @@ describe "Groups" do expect(response).to be_success end - it 'should not allow a user to leave a group for another user' do + it 'should not allow a underprivilege user to leave a group for another user' do + sign_in(user) + xhr :delete, "/groups/#{group.id}/members", username: other_user.username expect(response).to be_forbidden diff --git a/spec/integration/safe_mode_spec.rb b/spec/integration/safe_mode_spec.rb new file mode 100644 index 00000000000..f421c8fb976 --- /dev/null +++ b/spec/integration/safe_mode_spec.rb @@ -0,0 +1,13 @@ +require 'rails_helper' + +RSpec.describe 'Safe mode' do + describe 'entering safe mode' do + context 'when no params are given' do + it 'should redirect back to safe mode page' do + post '/safe-mode' + + expect(response.status).to redirect_to(safe_mode_path) + end + end + end +end diff --git a/spec/integration/same_ip_spammers_spec.rb b/spec/integration/same_ip_spammers_spec.rb index d6341c03c96..63f339fcc49 100644 --- a/spec/integration/same_ip_spammers_spec.rb +++ b/spec/integration/same_ip_spammers_spec.rb @@ -4,53 +4,66 @@ require 'rails_helper' describe SpamRulesEnforcer do - Given(:ip_address) { '182.189.119.174' } - Given!(:spammer1) { Fabricate(:user, ip_address: ip_address) } - Given!(:spammer2) { Fabricate(:user, ip_address: ip_address) } - Given(:spammer3) { Fabricate(:user, ip_address: ip_address) } + let(:ip_address) { '182.189.119.174' } + let!(:spammer1) { Fabricate(:user, ip_address: ip_address) } + let!(:spammer2) { Fabricate(:user, ip_address: ip_address) } + let(:spammer3) { Fabricate(:user, ip_address: ip_address) } context 'flag_sockpuppets is disabled' do - Given { SiteSetting.stubs(:flag_sockpuppets).returns(false) } - Given!(:first_post) { create_post(user: spammer1) } - Given!(:second_post) { create_post(user: spammer2, topic: first_post.topic) } + let!(:first_post) { create_post(user: spammer1) } + let!(:second_post) { create_post(user: spammer2, topic: first_post.topic) } - Then { expect(first_post.reload.spam_count).to eq(0) } - And { expect(second_post.reload.spam_count).to eq(0) } + it 'should not increase spam count' do + expect(first_post.reload.spam_count).to eq(0) + expect(second_post.reload.spam_count).to eq(0) + end end context 'flag_sockpuppets is enabled' do - Given { SiteSetting.stubs(:flag_sockpuppets).returns(true) } + before do + SiteSetting.flag_sockpuppets = true + end + + after do + SiteSetting.flag_sockpuppets = false + end context 'first spammer starts a topic' do - Given!(:first_post) { create_post(user: spammer1) } + let!(:first_post) { create_post(user: spammer1) } context 'second spammer replies' do - Given!(:second_post) { create_post(user: spammer2, topic: first_post.topic) } + let!(:second_post) { create_post(user: spammer2, topic: first_post.topic) } - Then { expect(first_post.reload.spam_count).to eq(1) } - And { expect(second_post.reload.spam_count).to eq(1) } + it 'should increase spam count' do + expect(first_post.reload.spam_count).to eq(1) + expect(second_post.reload.spam_count).to eq(1) + end context 'third spam post' do - Given!(:third_post) { create_post(user: spammer3, topic: first_post.topic) } + let!(:third_post) { create_post(user: spammer3, topic: first_post.topic) } - Then { expect(first_post.reload.spam_count).to eq(1) } - And { expect(second_post.reload.spam_count).to eq(1) } - And { expect(third_post.reload.spam_count).to eq(1) } + it 'should increase spam count' do + expect(first_post.reload.spam_count).to eq(1) + expect(second_post.reload.spam_count).to eq(1) + expect(third_post.reload.spam_count).to eq(1) + end end end end context 'first user is not new' do - Given!(:old_user) { Fabricate(:user, ip_address: ip_address, created_at: 2.days.ago, trust_level: TrustLevel[1]) } + let!(:old_user) { Fabricate(:user, ip_address: ip_address, created_at: 2.days.ago, trust_level: TrustLevel[1]) } context 'first user starts a topic' do - Given!(:first_post) { create_post(user: old_user) } + let!(:first_post) { create_post(user: old_user) } context 'a reply by a new user at the same IP address' do - Given!(:second_post) { create_post(user: spammer2, topic: first_post.topic) } + let!(:second_post) { create_post(user: spammer2, topic: first_post.topic) } - Then { expect(first_post.reload.spam_count).to eq(0) } - And { expect(second_post.reload.spam_count).to eq(1) } + it 'should increase the spam count correctly' do + expect(first_post.reload.spam_count).to eq(0) + expect(second_post.reload.spam_count).to eq(1) + end end end end diff --git a/spec/integration/spam_rules_spec.rb b/spec/integration/spam_rules_spec.rb index 1a637d8b7b9..c1c22b4ff7d 100644 --- a/spec/integration/spam_rules_spec.rb +++ b/spec/integration/spam_rules_spec.rb @@ -5,102 +5,129 @@ require 'rails_helper' describe SpamRulesEnforcer do describe 'auto-blocking users based on flagging' do - before do - SiteSetting.stubs(:flags_required_to_hide_post).returns(0) # never - SiteSetting.stubs(:num_spam_flags_to_block_new_user).returns(2) - SiteSetting.stubs(:num_users_to_block_new_user).returns(2) - end + site_setting(:flags_required_to_hide_post, 0) + site_setting(:num_spam_flags_to_block_new_user, 2) + site_setting(:num_users_to_block_new_user, 2) - Given!(:admin) { Fabricate(:admin) } # needed to send a system message - Given!(:moderator) { Fabricate(:moderator) } - Given(:user1) { Fabricate(:user) } - Given(:user2) { Fabricate(:user) } + let!(:admin) { Fabricate(:admin) } # needed to send a system message + let!(:moderator) { Fabricate(:moderator) } + let(:user1) { Fabricate(:user) } + let(:user2) { Fabricate(:user) } context 'spammer is a new user' do - Given(:spammer) { Fabricate(:user, trust_level: TrustLevel[0]) } + let(:spammer) { Fabricate(:user, trust_level: TrustLevel[0]) } context 'spammer post is not flagged enough times' do - Given!(:spam_post) { create_post(user: spammer) } - Given!(:spam_post2) { create_post(user: spammer) } - When { PostAction.act(user1, spam_post, PostActionType.types[:spam]) } - Then { expect(spam_post.reload).to_not be_hidden } + let!(:spam_post) { create_post(user: spammer) } + let!(:spam_post2) { create_post(user: spammer) } + + before do + PostAction.act(user1, spam_post, PostActionType.types[:spam]) + end + + it 'should not hide the post' do + expect(spam_post.reload).to_not be_hidden + end context 'spam posts are flagged enough times, but not by enough users' do - When { PostAction.act(user1, spam_post2, PostActionType.types[:spam]) } - Then { expect(spam_post.reload).to_not be_hidden } - And { expect(spam_post2.reload).to_not be_hidden } - And { expect(spammer.reload).to_not be_blocked } + it 'should not hide the post' do + PostAction.act(user1, spam_post2, PostActionType.types[:spam]) + + expect(spam_post.reload).to_not be_hidden + expect(spam_post2.reload).to_not be_hidden + expect(spammer.reload).to_not be_blocked + end end context 'one spam post is flagged enough times by enough users' do - Given!(:another_topic) { Fabricate(:topic) } - Given!(:private_messages_count) { spammer.private_topics_count } - Given!(:mod_pm_count) { moderator.private_topics_count } + let!(:another_topic) { Fabricate(:topic) } + let!(:private_messages_count) { spammer.private_topics_count } + let!(:mod_pm_count) { moderator.private_topics_count } - When { PostAction.act(user2, spam_post, PostActionType.types[:spam]) } + before do + PostAction.act(user2, spam_post, PostActionType.types[:spam]) - Invariant { expect(Guardian.new(spammer).can_create_topic?(nil)).to be false } - Invariant { expect{PostCreator.create(spammer, {title: 'limited time offer for you', raw: 'better buy this stuff ok', archetype_id: 1})}.to raise_error(Discourse::InvalidAccess) } - Invariant { expect(PostCreator.create(spammer, {topic_id: another_topic.id, raw: 'my reply is spam in your topic', archetype_id: 1})).to eq(nil) } - - Then { expect(spammer.reload).to be_blocked } - And { expect(spam_post.reload).to be_hidden } - And { expect(spam_post2.reload).to be_hidden } - And { expect(spammer.reload.private_topics_count).to eq(private_messages_count + 1) } + expect(Guardian.new(spammer).can_create_topic?(nil)).to be(false) + expect{PostCreator.create(spammer, {title: 'limited time offer for you', raw: 'better buy this stuff ok', archetype_id: 1})}.to raise_error(Discourse::InvalidAccess) + expect(PostCreator.create(spammer, {topic_id: another_topic.id, raw: 'my reply is spam in your topic', archetype_id: 1})).to eq(nil) + end + it 'should hide the posts' do + expect(spammer.reload).to be_blocked + expect(spam_post.reload).to be_hidden + expect(spam_post2.reload).to be_hidden + expect(spammer.reload.private_topics_count).to eq(private_messages_count + 1) + end # The following cases describe when a staff user takes some action, but the user # still won't be able to make posts. # A staff user needs to clear the blocked flag from the user record. context "a post's flags are cleared" do - When { PostAction.clear_flags!(spam_post, admin); spammer.reload } - Then { expect(spammer.reload).to be_blocked } + it 'should block the spammer' do + PostAction.clear_flags!(spam_post, admin); spammer.reload + expect(spammer.reload).to be_blocked + end end context "a post is deleted" do - When { spam_post.trash!(moderator); spammer.reload } - Then { expect(spammer.reload).to be_blocked } + it 'should block the spammer' do + spam_post.trash!(moderator); spammer.reload + expect(spammer.reload).to be_blocked + end end context "spammer becomes trust level 1" do - When { spammer.change_trust_level!(TrustLevel[1]); spammer.reload } - Then { expect(spammer.reload).to be_blocked } + it 'should block the spammer' do + spammer.change_trust_level!(TrustLevel[1]); spammer.reload + expect(spammer.reload).to be_blocked + end end end context 'flags_required_to_hide_post takes effect too' do - Given { SiteSetting.stubs(:flags_required_to_hide_post).returns(2) } - When { PostAction.act(user2, spam_post, PostActionType.types[:spam]) } - Then { expect(spammer.reload).to be_blocked } - And { expect(Guardian.new(spammer).can_create_topic?(nil)).to be false } + site_setting(:flags_required_to_hide_post, 2) + + it 'should block the spammer' do + PostAction.act(user2, spam_post, PostActionType.types[:spam]) + expect(spammer.reload).to be_blocked + expect(Guardian.new(spammer).can_create_topic?(nil)).to be false + end end end end context "spammer has trust level basic" do - Given(:spammer) { Fabricate(:user, trust_level: TrustLevel[1]) } + let(:spammer) { Fabricate(:user, trust_level: TrustLevel[1]) } context 'one spam post is flagged enough times by enough users' do - Given!(:spam_post) { Fabricate(:post, user: spammer) } - Given!(:private_messages_count) { spammer.private_topics_count } - When { PostAction.act(user1, spam_post, PostActionType.types[:spam]) } - When { PostAction.act(user2, spam_post, PostActionType.types[:spam]) } - Then { expect(spam_post.reload).to_not be_hidden } - And { expect(Guardian.new(spammer).can_create_topic?(nil)).to be true } - And { expect{PostCreator.create(spammer, {title: 'limited time offer for you', raw: 'better buy this stuff ok', archetype_id: 1})}.to_not raise_error } - And { expect(spammer.reload.private_topics_count).to eq(private_messages_count) } + let!(:spam_post) { Fabricate(:post, user: spammer) } + let!(:private_messages_count) { spammer.private_topics_count } + + it 'should not allow spammer to create new posts' do + PostAction.act(user1, spam_post, PostActionType.types[:spam]) + PostAction.act(user2, spam_post, PostActionType.types[:spam]) + + expect(spam_post.reload).to_not be_hidden + expect(Guardian.new(spammer).can_create_topic?(nil)).to be(true) + expect{PostCreator.create(spammer, {title: 'limited time offer for you', raw: 'better buy this stuff ok', archetype_id: 1})}.to_not raise_error + expect(spammer.reload.private_topics_count).to eq(private_messages_count) + end end end [[:user, trust_level: TrustLevel[2]], [:admin], [:moderator]].each do |spammer_args| context "spammer is trusted #{spammer_args[0]}" do - Given!(:spammer) { Fabricate(*spammer_args) } - Given!(:spam_post) { Fabricate(:post, user: spammer) } - Given!(:private_messages_count) { spammer.private_topics_count } - When { PostAction.act(user1, spam_post, PostActionType.types[:spam]) } - When { PostAction.act(user2, spam_post, PostActionType.types[:spam]) } - Then { expect(spam_post.reload).to_not be_hidden } + let!(:spammer) { Fabricate(*spammer_args) } + let!(:spam_post) { Fabricate(:post, user: spammer) } + let!(:private_messages_count) { spammer.private_topics_count } + + it 'should not hide the post' do + PostAction.act(user1, spam_post, PostActionType.types[:spam]) + PostAction.act(user2, spam_post, PostActionType.types[:spam]) + + expect(spam_post.reload).to_not be_hidden + end end end end diff --git a/spec/integration/topic_auto_close_spec.rb b/spec/integration/topic_auto_close_spec.rb index 6f1d5fa2e10..c69d7108328 100644 --- a/spec/integration/topic_auto_close_spec.rb +++ b/spec/integration/topic_auto_close_spec.rb @@ -19,25 +19,35 @@ describe Topic do end end - - before { + before do + @original_value = SiteSetting.queue_jobs SiteSetting.queue_jobs = true Jobs::CloseTopic.jobs.clear - } + end + + after do + SiteSetting.queue_jobs = @original_value + end context 'creating a topic without auto-close' do - Given(:topic) { Fabricate(:topic, category: category) } + let(:topic) { Fabricate(:topic, category: category) } context 'uncategorized' do - Given(:category) { nil } - Then { expect(topic.auto_close_at).to eq(nil) } - And { expect(scheduled_jobs_for(:close_topic)).to be_empty } + let(:category) { nil } + + it 'should not schedule the topic to auto-close' do + expect(topic.auto_close_at).to eq(nil) + expect(scheduled_jobs_for(:close_topic)).to be_empty + end end context 'category without default auto-close' do - Given(:category) { Fabricate(:category, auto_close_hours: nil) } - Then { expect(topic.auto_close_at).to eq(nil) } - And { expect(scheduled_jobs_for(:close_topic)).to be_empty } + let(:category) { Fabricate(:category, auto_close_hours: nil) } + + it 'should not schedule the topic to auto-close' do + expect(topic.auto_close_at).to eq(nil) + expect(scheduled_jobs_for(:close_topic)).to be_empty + end end context 'jobs may be queued' do @@ -51,50 +61,69 @@ describe Topic do end context 'category has a default auto-close' do - Given(:category) { Fabricate(:category, auto_close_hours: 2.0) } - Then { expect(topic.auto_close_at).to be_within_one_second_of(2.hours.from_now) } - And { expect(topic.auto_close_started_at).to eq(Time.zone.now) } - And { expect(scheduled_jobs_for(:close_topic, {topic_id: topic.id}).size).to eq(1) } - And { expect(scheduled_jobs_for(:close_topic, {topic_id: category.topic.id})).to be_empty } + let(:category) { Fabricate(:category, auto_close_hours: 2.0) } + + it 'should schedule the topic to auto-close' do + expect(topic.auto_close_at).to be_within_one_second_of(2.hours.from_now) + expect(topic.auto_close_started_at).to eq(Time.zone.now) + expect(scheduled_jobs_for(:close_topic, {topic_id: topic.id}).size).to eq(1) + expect(scheduled_jobs_for(:close_topic, {topic_id: category.topic.id})).to be_empty + end context 'topic was created by staff user' do - Given(:admin) { Fabricate(:admin) } - Given(:staff_topic) { Fabricate(:topic, user: admin, category: category) } - Then { expect(scheduled_jobs_for(:close_topic, {topic_id: staff_topic.id, user_id: admin.id}).size).to eq(1) } + let(:admin) { Fabricate(:admin) } + let(:staff_topic) { Fabricate(:topic, user: admin, category: category) } + + it 'should schedule the topic to auto-close' do + expect(scheduled_jobs_for(:close_topic, {topic_id: staff_topic.id, user_id: admin.id}).size).to eq(1) + end context 'topic is closed manually' do - When { staff_topic.update_status('closed', true, admin) } - Then { expect(staff_topic.reload.auto_close_at).to eq(nil) } - And { expect(staff_topic.auto_close_started_at).to eq(nil) } + it 'should remove the schedule to auto-close the topic' do + staff_topic.update_status('closed', true, admin) + expect(staff_topic.reload.auto_close_at).to eq(nil) + expect(staff_topic.auto_close_started_at).to eq(nil) + end end end context 'topic was created by a non-staff user' do - Given!(:system_user) { Discourse.system_user } - Given { Discourse.stubs(:system_user).returns(system_user) } - Given(:regular_user) { Fabricate(:user) } - Given(:regular_user_topic) { Fabricate(:topic, user: regular_user, category: category) } - Then { expect(scheduled_jobs_for(:close_topic, {topic_id: regular_user_topic.id, user_id: system_user.id}).size).to eq(1) } + let(:regular_user) { Fabricate(:user) } + let(:regular_user_topic) { Fabricate(:topic, user: regular_user, category: category) } + + it 'should schedule the topic to auto-close' do + expect(scheduled_jobs_for(:close_topic, {topic_id: regular_user_topic.id, user_id: Discourse.system_user.id}).size).to eq(1) + end end context 'auto_close_hours of topic was set to 0' do - Given(:dont_close_topic) { Fabricate(:topic, auto_close_hours: 0, category: category) } - Then { expect(scheduled_jobs_for(:close_topic)).to be_empty } + let(:dont_close_topic) { Fabricate(:topic, auto_close_hours: 0, category: category) } + + it 'should not schedule the topic to auto-close' do + expect(scheduled_jobs_for(:close_topic)).to be_empty + end end context 'two topics in the category' do - Given!(:other_topic) { Fabricate(:topic, category: category) } - When { topic } # create the second topic - Then { expect(scheduled_jobs_for(:close_topic).size).to eq(2) } + let!(:other_topic) { Fabricate(:topic, category: category) } + + it 'should schedule the topic to auto-close' do + topic + + expect(scheduled_jobs_for(:close_topic).size).to eq(2) + end end end context 'a topic that has been auto-closed' do - Given(:admin) { Fabricate(:admin) } - Given!(:auto_closed_topic) { Fabricate(:topic, user: admin, closed: true, auto_close_at: 1.day.ago, auto_close_user_id: admin.id, auto_close_started_at: 6.days.ago) } - When { auto_closed_topic.update_status('closed', false, admin) } - Then { expect(auto_closed_topic.reload.auto_close_at).to eq(nil) } - And { expect(auto_closed_topic.auto_close_started_at).to eq(nil) } + let(:admin) { Fabricate(:admin) } + let!(:auto_closed_topic) { Fabricate(:topic, user: admin, closed: true, auto_close_at: 1.day.ago, auto_close_user_id: admin.id, auto_close_started_at: 6.days.ago) } + + it 'should set the right attributes' do + auto_closed_topic.update_status('closed', false, admin) + expect(auto_closed_topic.reload.auto_close_at).to eq(nil) + expect(auto_closed_topic.auto_close_started_at).to eq(nil) + end end end end diff --git a/spec/integration/users_spec.rb b/spec/integration/users_spec.rb new file mode 100644 index 00000000000..7350c87ca5f --- /dev/null +++ b/spec/integration/users_spec.rb @@ -0,0 +1,54 @@ +require 'rails_helper' + +RSpec.describe "Users" do + let(:user) { Fabricate(:user) } + + describe "viewing a user" do + + it "should be able to view a user" do + get "/users/#{user.username}" + + expect(response).to be_success + expect(response.body).to include(user.username) + end + + describe 'when username contains a period' do + before do + user.update!(username: 'test.test') + end + + it "should be able to view a user" do + get "/users/#{user.username}" + + expect(response).to be_success + expect(response.body).to include(user.username) + end + end + end + + describe "updating a user" do + before do + sign_in(user) + end + + it "should be able to update a user" do + put "/users/#{user.username}.json", { name: 'test.test' } + + expect(response).to be_success + expect(user.reload.name).to eq('test.test') + end + + describe 'when username contains a period' do + before do + user.update!(username: 'test.test') + end + + it "should be able to update a user" do + put "/users/#{user.username}.json", { name: 'testing123' } + + expect(response).to be_success + expect(user.reload.name).to eq('testing123') + end + end + end +end diff --git a/spec/jobs/automatic_group_membership_spec.rb b/spec/jobs/automatic_group_membership_spec.rb index e6d59993085..5989deb4898 100644 --- a/spec/jobs/automatic_group_membership_spec.rb +++ b/spec/jobs/automatic_group_membership_spec.rb @@ -10,6 +10,8 @@ describe Jobs::AutomaticGroupMembership do it "updates the membership" do user1 = Fabricate(:user, email: "foo@wat.com") user2 = Fabricate(:user, email: "foo@bar.com") + user3 = Fabricate(:user, email: "bar@wat.com", staged: true) + user4 = Fabricate(:user, email: "abc@wat.com", active: false) group = Fabricate(:group, automatic_membership_email_domains: "wat.com", automatic_membership_retroactive: true) Jobs::AutomaticGroupMembership.new.execute(group_id: group.id) @@ -17,6 +19,8 @@ describe Jobs::AutomaticGroupMembership do group.reload expect(group.users.include?(user1)).to eq(true) expect(group.users.include?(user2)).to eq(false) + expect(group.users.include?(user3)).to eq(false) + expect(group.users.include?(user4)).to eq(false) end end diff --git a/spec/jobs/enqueue_digest_emails_spec.rb b/spec/jobs/enqueue_digest_emails_spec.rb index f52a033a045..f9886294030 100644 --- a/spec/jobs/enqueue_digest_emails_spec.rb +++ b/spec/jobs/enqueue_digest_emails_spec.rb @@ -15,21 +15,32 @@ describe Jobs::EnqueueDigestEmails do end context 'unapproved users' do - Given!(:unapproved_user) { Fabricate(:active_user, approved: false, last_emailed_at: 8.days.ago, last_seen_at: 10.days.ago) } - When { SiteSetting.stubs(:must_approve_users?).returns(true) } - Then { expect(Jobs::EnqueueDigestEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(false) } + let!(:unapproved_user) { Fabricate(:active_user, approved: false, last_emailed_at: 8.days.ago, last_seen_at: 10.days.ago) } - # As a moderator - And { unapproved_user.update_column(:moderator, true) } - And { expect(Jobs::EnqueueDigestEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) } + before do + @original_value = SiteSetting.must_approve_users + SiteSetting.must_approve_users = true + end - # As an admin - And { unapproved_user.update_attributes(admin: true, moderator: false) } - And { expect(Jobs::EnqueueDigestEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) } + after do + SiteSetting.must_approve_users = @original_value + end - # As an approved user - And { unapproved_user.update_attributes(admin: false, moderator: false, approved: true ) } - And { expect(Jobs::EnqueueDigestEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) } + it 'should enqueue the right digest emails' do + expect(Jobs::EnqueueDigestEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(false) + + # As a moderator + unapproved_user.update_column(:moderator, true) + expect(Jobs::EnqueueDigestEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) + + # As an admin + unapproved_user.update_attributes(admin: true, moderator: false) + expect(Jobs::EnqueueDigestEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) + + # As an approved user + unapproved_user.update_attributes(admin: false, moderator: false, approved: true ) + expect(Jobs::EnqueueDigestEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) + end end context 'staged users' do diff --git a/spec/jobs/enqueue_mailing_list_emails_spec.rb b/spec/jobs/enqueue_mailing_list_emails_spec.rb index 3ee9ebe941a..23a9c6eae45 100644 --- a/spec/jobs/enqueue_mailing_list_emails_spec.rb +++ b/spec/jobs/enqueue_mailing_list_emails_spec.rb @@ -6,24 +6,33 @@ describe Jobs::EnqueueMailingListEmails do describe '#target_users' do context 'unapproved users' do - Given!(:unapproved_user) { Fabricate(:active_user, approved: false, first_seen_at: 24.hours.ago) } - When do + let!(:unapproved_user) { Fabricate(:active_user, approved: false, first_seen_at: 24.hours.ago) } + + before do + @original_value = SiteSetting.must_approve_users SiteSetting.must_approve_users = true - unapproved_user.user_option.update(mailing_list_mode: true, mailing_list_mode_frequency: 0) end - Then { expect(Jobs::EnqueueMailingListEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(false) } - # As a moderator - And { unapproved_user.update_column(:moderator, true) } - And { expect(Jobs::EnqueueMailingListEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) } + after do + SiteSetting.must_approve_users = @original_value + end - # As an admin - And { unapproved_user.update_attributes(admin: true, moderator: false) } - And { expect(Jobs::EnqueueMailingListEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) } + it 'should enqueue the right emails' do + unapproved_user.user_option.update(mailing_list_mode: true, mailing_list_mode_frequency: 0) + expect(Jobs::EnqueueMailingListEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(false) - # As an approved user - And { unapproved_user.update_attributes(admin: false, moderator: false, approved: true ) } - And { expect(Jobs::EnqueueMailingListEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) } + # As a moderator + unapproved_user.update_column(:moderator, true) + expect(Jobs::EnqueueMailingListEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) + + # As an admin + unapproved_user.update_attributes(admin: true, moderator: false) + expect(Jobs::EnqueueMailingListEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) + + # As an approved user + unapproved_user.update_attributes(admin: false, moderator: false, approved: true ) + expect(Jobs::EnqueueMailingListEmails.new.target_user_ids.include?(unapproved_user.id)).to eq(true) + end end context 'staged users' do diff --git a/spec/jobs/pull_hotlinked_images_spec.rb b/spec/jobs/pull_hotlinked_images_spec.rb new file mode 100644 index 00000000000..f9f50766785 --- /dev/null +++ b/spec/jobs/pull_hotlinked_images_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' +require 'jobs/regular/pull_hotlinked_images' + +describe Jobs::PullHotlinkedImages do + + png = Base64.decode64("R0lGODlhAQABALMAAAAAAIAAAACAAICAAAAAgIAAgACAgMDAwICAgP8AAAD/AP//AAAA//8A/wD//wBiZCH5BAEAAA8ALAAAAAABAAEAAAQC8EUAOw==") + FakeWeb.register_uri(:get, "http://wiki.mozilla.org/images/2/2e/Longcat1.png", body: png) + SiteSetting.download_remote_images_to_local = true + + it 'replaces image src' do + post = Fabricate(:post, raw: "") + + Jobs::PullHotlinkedImages.new.execute(post_id: post.id) + post.reload + + expect(post.raw).to match(/^") + + Jobs::PullHotlinkedImages.new.execute(post_id: post.id) + post.reload + + expect(post.raw).to match(/^ 0 + end + it "fix image orientation" do Upload.expects(:fix_image_orientation).with(image.path) Upload.create_for(user_id, image, image_filename, image_filesize) @@ -62,7 +72,6 @@ describe Upload do it "computes width & height for images" do ImageSizer.expects(:resize) - image.expects(:rewind).times(3) Upload.create_for(user_id, image, image_filename, image_filesize) end diff --git a/spec/models/user_action_spec.rb b/spec/models/user_action_spec.rb index 9e2ec982d06..73ccd9a0679 100644 --- a/spec/models/user_action_spec.rb +++ b/spec/models/user_action_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe UserAction do before do - ActiveRecord::Base.observers.enable :all + UserActionCreator.enable end it { is_expected.to validate_presence_of :action_type } @@ -19,6 +19,7 @@ describe UserAction do let(:private_topic) do topic = private_post.topic topic.update_columns(category_id: nil, archetype: Archetype::private_message) + TopicAllowedUser.create(topic_id: topic.id, user_id: user.id) topic end @@ -49,6 +50,8 @@ describe UserAction do end it 'includes the events correctly' do + PostActionNotifier.enable + mystats = stats_for_user(user) expecting = [UserAction::NEW_TOPIC, UserAction::NEW_PRIVATE_MESSAGE, UserAction::GOT_PRIVATE_MESSAGE, UserAction::BOOKMARK].sort expect(mystats).to eq(expecting) @@ -102,7 +105,7 @@ describe UserAction do describe 'when user likes' do - let!(:post) { Fabricate(:post) } + let(:post) { Fabricate(:post) } let(:likee) { post.user } let(:liker) { Fabricate(:coding_horror) } @@ -137,6 +140,23 @@ describe UserAction do expect(liker.user_stat.reload.likes_given).to eq(0) end + context 'private message' do + let(:post) { Fabricate(:private_message_post) } + let(:likee) { post.topic.topic_allowed_users.first.user } + let(:liker) { post.topic.topic_allowed_users.last.user } + + it 'should not increase user stats' do + expect(@liker_action).not_to eq(nil) + expect(liker.user_stat.reload.likes_given).to eq(0) + expect(@likee_action).not_to eq(nil) + expect(likee.user_stat.reload.likes_received).to eq(0) + + PostAction.remove_act(liker, post, PostActionType.types[:like]) + expect(liker.user_stat.reload.likes_given).to eq(0) + expect(likee.user_stat.reload.likes_received).to eq(0) + end + end + end context "liking a private message" do @@ -223,13 +243,13 @@ describe UserAction do end end - describe 'private messages' do + describe 'secures private messages' do let(:user) do Fabricate(:user) end - let(:target_user) do + let(:user2) do Fabricate(:user) end @@ -237,22 +257,35 @@ describe UserAction do PostCreator.create( user, raw: 'this is a private message', title: 'this is the pm title', - target_usernames: target_user.username, + target_usernames: user2.username, archetype: Archetype::private_message ) end - let!(:response) do - PostCreator.create(user, raw: 'oops I forgot to mention this', topic_id: private_message.topic_id) + def count_bookmarks + UserAction.stream( + user_id: user.id, + action_types: [UserAction::BOOKMARK], + ignore_private_messages: false, + guardian: Guardian.new(user) + ).count end - let!(:private_message2) do - PostCreator.create( target_user, - raw: 'this is a private message', - title: 'this is the pm title', - target_usernames: user.username, - archetype: Archetype::private_message - ) + it 'correctly secures stream' do + PostAction.act(user, private_message, PostActionType.types[:bookmark]) + + expect(count_bookmarks).to eq(1) + + private_message.topic.topic_allowed_users.where(user_id: user.id).destroy_all + + expect(count_bookmarks).to eq(0) + + group = Fabricate(:group) + group.add(user) + private_message.topic.topic_allowed_groups.create(group_id: group.id) + + expect(count_bookmarks).to eq(1) + end end diff --git a/spec/models/user_profile_spec.rb b/spec/models/user_profile_spec.rb index d6b2c6ac01f..34a88c48cd0 100644 --- a/spec/models/user_profile_spec.rb +++ b/spec/models/user_profile_spec.rb @@ -54,16 +54,19 @@ describe UserProfile do expect(user_profile).not_to be_valid end - it "doesn't support invalid website" do - user_profile = Fabricate.build(:user_profile, website: "http://https://google.com") - user_profile.user = Fabricate.build(:user) - expect(user_profile).not_to be_valid - end + context "website validation" do + let(:user) { Fabricate(:user) } - it "supports valid website" do - user_profile = Fabricate.build(:user_profile, website: "https://google.com") - user_profile.user = Fabricate.build(:user) - expect(user_profile.valid?).to be true + it "ensures website is valid" do + expect(Fabricate.build(:user_profile, user: user, website: "http://https://google.com")).not_to be_valid + expect(Fabricate.build(:user_profile, user: user, website: "https://google.com")).to be_valid + end + + it "validates website domain if user_website_domains_whitelist setting is present" do + SiteSetting.user_website_domains_whitelist = "discourse.org" + expect(Fabricate.build(:user_profile, user: user, website: "https://google.com")).not_to be_valid + expect(Fabricate.build(:user_profile, user: user, website: "http://discourse.org")).to be_valid + end end describe 'after save' do diff --git a/spec/models/user_search_spec.rb b/spec/models/user_search_spec.rb index 5d5a55f4f23..47621ef60f8 100644 --- a/spec/models/user_search_spec.rb +++ b/spec/models/user_search_spec.rb @@ -18,7 +18,7 @@ describe UserSearch do let(:staged) { Fabricate :staged } before do - ActiveRecord::Base.observers.enable :all + SearchIndexer.enable Fabricate :post, user: user1, topic: topic Fabricate :post, user: user2, topic: topic2 diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 614cf17697e..52cf4ea8415 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -3,8 +3,29 @@ require_dependency 'user' describe User do - it { is_expected.to validate_presence_of :username } - it { is_expected.to validate_presence_of :email } + context 'validations' do + it { is_expected.to validate_presence_of :username } + + describe 'emails' do + let(:user) { Fabricate.build(:user) } + + it { is_expected.to validate_presence_of :email } + + describe 'when record has a valid email' do + it "should be valid" do + user.email = 'test@gmail.com' + expect(user).to be_valid + end + end + + describe 'when record has an invalid email' do + it 'should not be valid' do + user.email = 'test@gmailcom' + expect(user).to_not be_valid + end + end + end + end describe '#count_by_signup_date' do before(:each) do @@ -922,6 +943,7 @@ describe User do before do # To make testing easier, say 1 reply is too much SiteSetting.stubs(:newuser_max_replies_per_topic).returns(1) + UserActionCreator.enable end context "for a user who didn't create the topic" do @@ -938,7 +960,10 @@ describe User do context "with a reply" do before do - PostCreator.new(Fabricate(:user), raw: 'whatever this is a raw post', topic_id: topic.id, reply_to_post_number: post.post_number).create + PostCreator.new(Fabricate(:user), + raw: 'whatever this is a raw post', + topic_id: topic.id, + reply_to_post_number: post.post_number).create end it "resets the `posted_too_much` threshold" do @@ -1171,6 +1196,28 @@ describe User do expect(group_history.target_user).to eq(user) end + it "get attributes from the group" do + group = Fabricate(:group, + automatic_membership_email_domains: "bar.com|wat.com", + grant_trust_level: 1, + title: "bars and wats", + primary_group: true + ) + + user = Fabricate.build(:user, + trust_level: 0, + email: "foo@bar.com", + password: "strongpassword4Uguys" + ) + + user.password_required! + user.save! + user.reload + + expect(user.title).to eq("bars and wats") + expect(user.trust_level).to eq(1) + expect(user.trust_level_locked).to eq(true) + end end describe "number_of_flags_given" do diff --git a/spec/models/web_hook_spec.rb b/spec/models/web_hook_spec.rb index 0022c0e9d6c..6c4c8fdfaa6 100644 --- a/spec/models/web_hook_spec.rb +++ b/spec/models/web_hook_spec.rb @@ -131,7 +131,7 @@ describe WebHook do PostDestroyer.new(user, post2).recover end - it 'should enqueue the right hooks for user creation events' do + it 'should enqueue the right hooks for user events' do WebHook.expects(:enqueue_hooks).once user @@ -140,6 +140,9 @@ describe WebHook do WebHook.expects(:enqueue_hooks).once user.approve(admin) + + WebHook.expects(:enqueue_hooks).once + UserUpdater.new(admin, user).update(username: 'testing123') end end end diff --git a/spec/phantom_js/smoke_test.js b/spec/phantom_js/smoke_test.js index f703257fa82..1d43de145e8 100644 --- a/spec/phantom_js/smoke_test.js +++ b/spec/phantom_js/smoke_test.js @@ -46,6 +46,7 @@ page.waitFor = function(desc, fn, cb) { if (diff > TIMEOUT) { console.log("FAILED: " + desc + " - " + diff + "ms"); page.render('/tmp/failed.png'); + console.log('Content:' + page.content); cb(false); } else { setTimeout(check, 25); @@ -139,7 +140,7 @@ var runTests = function() { }); test("at least one topic shows up", function() { - return document.querySelector(".topic-list tbody tr"); + return $(".topic-list tbody tr").length; }); execAsync("navigate to 1st topic", 500, function() { @@ -147,7 +148,7 @@ var runTests = function() { }); test("at least one post body", function() { - return document.querySelector(".topic-post"); + return $(".topic-post").length; }); execAsync("click on the 1st user", 500, function() { @@ -157,7 +158,7 @@ var runTests = function() { }); test("user has details", function() { - return document.querySelector("#user-card .names"); + return $("#user-card .names").length; }); exec("open login modal", function() { @@ -165,7 +166,7 @@ var runTests = function() { }); test("login modal is open", function() { - return document.querySelector(".login-modal"); + return $(".login-modal").length; }); exec("type in credentials & log in", function() { @@ -175,7 +176,7 @@ var runTests = function() { }); test("is logged in", function() { - return document.querySelector(".current-user"); + return $(".current-user").length; }); exec("go home", function() { @@ -183,11 +184,11 @@ var runTests = function() { }); test("it shows a topic list", function() { - return document.querySelector(".topic-list"); + return $(".topic-list").length; }); test('we have a create topic button', function() { - return document.querySelector("#create-topic"); + return $("#create-topic").length; }); exec("open composer", function() { @@ -195,7 +196,7 @@ var runTests = function() { }); test('the editor is visible', function() { - return document.querySelector(".d-editor"); + return $(".d-editor").length; }); exec("compose new topic", function() { @@ -209,7 +210,7 @@ var runTests = function() { }); test("updates preview", function() { - return document.querySelector(".d-editor-preview p"); + return $(".d-editor-preview p").length; }); exec("open upload modal", function() { @@ -217,7 +218,7 @@ var runTests = function() { }); test("upload modal is open", function() { - return document.querySelector("#filename-input"); + return $("#filename-input").length; }); // TODO: Looks like PhantomJS 2.0.0 has a bug with `uploadFile` @@ -246,7 +247,7 @@ var runTests = function() { }); test("topic is created", function() { - return document.querySelector(".fancy-title"); + return $(".fancy-title").length; }); exec("click reply button", function() { @@ -254,7 +255,7 @@ var runTests = function() { }); test("composer is open", function() { - return document.querySelector("#reply-control .d-editor-input"); + return $("#reply-control .d-editor-input").length; }); exec("compose reply", function() { diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index c1297809c01..c57a4217040 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -43,6 +43,7 @@ Spork.prefork do config.include Helpers config.include MessageBus config.include RSpecHtmlMatchers + config.include IntegrationHelpers, type: :request config.mock_framework = :mocha config.order = 'random' config.infer_spec_type_from_file_location! @@ -103,9 +104,11 @@ Spork.prefork do # # $redis = DiscourseMockRedis.new # - # disable all observers, enable as needed during specs - # - ActiveRecord::Base.observers.disable :all + PostActionNotifier.disable + SearchIndexer.disable + UserActionCreator.disable + NotificationEmailer.disable + SiteSetting.provider.all.each do |setting| SiteSetting.remove_override!(setting.name) end diff --git a/spec/models/user_email_observer_spec.rb b/spec/services/notification_emailer_spec.rb similarity index 82% rename from spec/models/user_email_observer_spec.rb rename to spec/services/notification_emailer_spec.rb index 013b1db9413..8e44538af3a 100644 --- a/spec/models/user_email_observer_spec.rb +++ b/spec/services/notification_emailer_spec.rb @@ -1,6 +1,10 @@ require 'rails_helper' -describe UserEmailObserver do +describe NotificationEmailer do + + before do + NotificationEmailer.enable + end let(:topic) { Fabricate(:topic) } let(:post) { Fabricate(:post, topic: topic) } @@ -18,8 +22,8 @@ describe UserEmailObserver do shared_examples "enqueue" do it "enqueues a job for the email" do - Jobs.expects(:enqueue_in).with(delay, :user_email, UserEmailObserver::EmailUser.notification_params(notification,type)) - UserEmailObserver.process_notification(notification) + Jobs.expects(:enqueue_in).with(delay, :user_email, NotificationEmailer::EmailUser.notification_params(notification,type)) + NotificationEmailer.process_notification(notification) end context "inactive user" do @@ -27,13 +31,13 @@ describe UserEmailObserver do it "doesn't enqueue a job" do Jobs.expects(:enqueue_in).with(delay, :user_email, has_entry(type: type)).never - UserEmailObserver.process_notification(notification) + NotificationEmailer.process_notification(notification) end it "enqueues a job if the user is staged" do notification.user.staged = true - Jobs.expects(:enqueue_in).with(delay, :user_email, UserEmailObserver::EmailUser.notification_params(notification,type)) - UserEmailObserver.process_notification(notification) + Jobs.expects(:enqueue_in).with(delay, :user_email, NotificationEmailer::EmailUser.notification_params(notification,type)) + NotificationEmailer.process_notification(notification) end end @@ -46,7 +50,7 @@ describe UserEmailObserver do it "doesn't enqueue a job" do Jobs.expects(:enqueue_in).with(delay, :user_email, has_entry(type: type)).never - UserEmailObserver.process_notification(notification) + NotificationEmailer.process_notification(notification) end end @@ -55,7 +59,7 @@ describe UserEmailObserver do it "doesn't enqueue a job" do Post.any_instance.expects(:post_type).returns(Post.types[:small_action]) Jobs.expects(:enqueue_in).with(delay, :user_email, has_entry(type: type)).never - UserEmailObserver.process_notification(notification) + NotificationEmailer.process_notification(notification) end end @@ -68,7 +72,7 @@ describe UserEmailObserver do it "doesn't enqueue a job if the user has mention emails disabled" do notification.user.user_option.update_columns(email_direct: false) Jobs.expects(:enqueue_in).with(delay, :user_email, has_entry(type: type)).never - UserEmailObserver.process_notification(notification) + NotificationEmailer.process_notification(notification) end end @@ -78,7 +82,7 @@ describe UserEmailObserver do it "doesn't enqueue a job if the user has private message emails disabled" do notification.user.user_option.update_columns(email_private_messages: false) Jobs.expects(:enqueue_in).with(delay, :user_email, has_entry(type: type)).never - UserEmailObserver.process_notification(notification) + NotificationEmailer.process_notification(notification) end end @@ -92,8 +96,8 @@ describe UserEmailObserver do it "enqueue a delayed job for users that are online" do notification.user.last_seen_at = 1.minute.ago - Jobs.expects(:enqueue_in).with(delay, :user_email, UserEmailObserver::EmailUser.notification_params(notification,type)) - UserEmailObserver.process_notification(notification) + Jobs.expects(:enqueue_in).with(delay, :user_email, NotificationEmailer::EmailUser.notification_params(notification,type)) + NotificationEmailer.process_notification(notification) end end @@ -140,7 +144,7 @@ describe UserEmailObserver do it "doesn't enqueue a job for a small action" do notification.data_hash["original_post_type"] = Post.types[:small_action] Jobs.expects(:enqueue_in).with(delay, :user_email, has_entry(type: type)).never - UserEmailObserver.process_notification(notification) + NotificationEmailer.process_notification(notification) end end diff --git a/spec/models/post_alert_observer_spec.rb b/spec/services/post_action_notifier_spec.rb similarity index 97% rename from spec/models/post_alert_observer_spec.rb rename to spec/services/post_action_notifier_spec.rb index be6f8c7876c..b04b7c032f4 100644 --- a/spec/models/post_alert_observer_spec.rb +++ b/spec/services/post_action_notifier_spec.rb @@ -1,10 +1,10 @@ require 'rails_helper' require_dependency 'post_destroyer' -describe PostAlertObserver do +describe PostActionNotifier do before do - ActiveRecord::Base.observers.enable :post_alert_observer + PostActionNotifier.enable end let!(:evil_trout) { Fabricate(:evil_trout) } diff --git a/spec/services/post_alerter_spec.rb b/spec/services/post_alerter_spec.rb index 48689faae4f..ff160244f33 100644 --- a/spec/services/post_alerter_spec.rb +++ b/spec/services/post_alerter_spec.rb @@ -63,8 +63,7 @@ describe PostAlerter do context 'edits' do it 'notifies correctly on edits' do - - ActiveRecord::Base.observers.enable :all + PostActionNotifier.enable post = Fabricate(:post, raw: 'I love waffles') @@ -89,7 +88,7 @@ describe PostAlerter do context 'likes' do it 'notifies on likes after an undo' do - ActiveRecord::Base.observers.enable :all + PostActionNotifier.enable post = Fabricate(:post, raw: 'I love waffles') @@ -101,7 +100,7 @@ describe PostAlerter do end it 'notifies on does not notify when never is selected' do - ActiveRecord::Base.observers.enable :all + PostActionNotifier.enable post = Fabricate(:post, raw: 'I love waffles') @@ -110,12 +109,11 @@ describe PostAlerter do PostAction.act(evil_trout, post, PostActionType.types[:like]) - expect(Notification.where(post_number: 1, topic_id: post.topic_id).count).to eq(0) end it 'notifies on likes correctly' do - ActiveRecord::Base.observers.enable :all + PostActionNotifier.enable post = Fabricate(:post, raw: 'I love waffles') diff --git a/spec/services/post_owner_changer_spec.rb b/spec/services/post_owner_changer_spec.rb index b1452d35c45..10fb1cebec1 100644 --- a/spec/services/post_owner_changer_spec.rb +++ b/spec/services/post_owner_changer_spec.rb @@ -63,23 +63,44 @@ describe PostOwnerChanger do let(:p2user) { p2.user } before do - topic.user_id = p1user.id - topic.save! + topic.update!(user_id: p1user.id) - p1user.user_stat.update_attributes(topic_count: 1, post_count: 1, first_post_created_at: p1.created_at, topic_reply_count: 0) - p2user.user_stat.update_attributes(topic_count: 0, post_count: 1, first_post_created_at: p2.created_at, topic_reply_count: 1) + p1user.user_stat.update!( + topic_count: 1, + post_count: 1, + first_post_created_at: p1.created_at, + topic_reply_count: 0 + ) + + p2user.user_stat.update!( + topic_count: 0, + post_count: 1, + first_post_created_at: p2.created_at, + topic_reply_count: 1 + ) UserAction.create!( action_type: UserAction::NEW_TOPIC, user_id: p1user.id, acting_user_id: p1user.id, target_post_id: -1, target_topic_id: p1.topic_id, created_at: p1.created_at ) UserAction.create!( action_type: UserAction::REPLY, user_id: p2user.id, acting_user_id: p2user.id, target_post_id: p2.id, target_topic_id: p2.topic_id, created_at: p2.created_at ) - ActiveRecord::Base.observers.enable :user_action_observer + + UserActionCreator.enable end - subject(:change_owners) { described_class.new(post_ids: [p1.id, p2.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner! } + subject(:change_owners) do + described_class.new( + post_ids: [p1.id, p2.id], + topic_id: topic.id, + new_owner: user_a, + acting_user: editor + ).change_owner! + end it "updates users' topic and post counts" do + PostAction.act(p2user, p1, PostActionType.types[:like]) + expect(p1user.user_stat.reload.likes_received).to eq(1) + change_owners p1user.reload; p2user.reload; user_a.reload @@ -89,11 +110,38 @@ describe PostOwnerChanger do expect(p2user.post_count).to eq(0) expect(user_a.topic_count).to eq(1) expect(user_a.post_count).to eq(2) - expect(p1user.user_stat.first_post_created_at).to eq(nil) - expect(p2user.user_stat.first_post_created_at).to eq(nil) - expect(p1user.user_stat.topic_reply_count).to eq(0) - expect(p2user.user_stat.topic_reply_count).to eq(0) - expect(user_a.user_stat.first_post_created_at).to be_present + + p1_user_stat = p1user.user_stat + + expect(p1_user_stat.first_post_created_at).to eq(nil) + expect(p1_user_stat.topic_reply_count).to eq(0) + expect(p1_user_stat.likes_received).to eq(0) + + p2_user_stat = p2user.user_stat + + expect(p2_user_stat.first_post_created_at).to eq(nil) + expect(p2_user_stat.topic_reply_count).to eq(0) + + user_a_stat = user_a.user_stat + + expect(user_a_stat.first_post_created_at).to be_present + expect(user_a_stat.likes_received).to eq(1) + end + + context 'private message topic' do + let(:topic) { Fabricate(:private_message_topic) } + + it "should update users' counts" do + PostAction.act(p2user, p1, PostActionType.types[:like]) + + change_owners + + expect(p1user.user_stat.likes_received).to eq(0) + + user_a_stat = user_a.user_stat + expect(user_a_stat.first_post_created_at).to be_present + expect(user_a_stat.likes_received).to eq(0) + end end it "updates UserAction records" do diff --git a/spec/services/random_topic_selector_spec.rb b/spec/services/random_topic_selector_spec.rb index d57f5519d2b..18decd73c7f 100644 --- a/spec/services/random_topic_selector_spec.rb +++ b/spec/services/random_topic_selector_spec.rb @@ -23,7 +23,7 @@ describe RandomTopicSelector do end it 'can correctly backfill' do - category = Fabricate(:category) + category = Fabricate(:category, sort_order: 'op_likes') t1 = Fabricate(:topic, category_id: category.id) _t2 = Fabricate(:topic, category_id: category.id, visible: false) _t3 = Fabricate(:topic, category_id: category.id, deleted_at: 1.minute.ago) diff --git a/spec/models/search_observer_spec.rb b/spec/services/search_indexer_spec.rb similarity index 75% rename from spec/models/search_observer_spec.rb rename to spec/services/search_indexer_spec.rb index fccf8612207..74ac1c2b4fb 100644 --- a/spec/models/search_observer_spec.rb +++ b/spec/services/search_indexer_spec.rb @@ -1,13 +1,13 @@ require 'rails_helper' -describe SearchObserver do +describe SearchIndexer do it 'correctly indexes chinese' do SiteSetting.default_locale = 'zh_CN' data = "你好世界" expect(data.split(" ").length).to eq(1) - SearchObserver.update_posts_index(99, "你好世界", "", nil) + SearchIndexer.update_posts_index(99, "你好世界", "", nil) raw_data = PostSearchData.where(post_id: 99).pluck(:raw_data)[0] expect(raw_data.split(' ').length).to eq(2) @@ -16,13 +16,13 @@ describe SearchObserver do it 'correctly indexes a post' do data = "This is a test" - SearchObserver.update_posts_index(99, data, "", nil) + SearchIndexer.update_posts_index(99, data, "", nil) raw_data, locale = PostSearchData.where(post_id: 99).pluck(:raw_data, :locale)[0] expect(raw_data).to eq("This is a test") expect(locale).to eq("en") - SearchObserver.update_posts_index(99, "tester", "", nil) + SearchIndexer.update_posts_index(99, "tester", "", nil) raw_data = PostSearchData.where(post_id: 99).pluck(:raw_data)[0] expect(raw_data).to eq("tester") diff --git a/spec/services/staff_action_logger_spec.rb b/spec/services/staff_action_logger_spec.rb index 676b899dce9..b614faa874b 100644 --- a/spec/services/staff_action_logger_spec.rb +++ b/spec/services/staff_action_logger_spec.rb @@ -369,4 +369,62 @@ describe StaffActionLogger do expect(user_history.action).to eq(UserHistory.actions[:create_category]) end end + + describe 'log_lock_trust_level' do + let(:user) { Fabricate(:user) } + + it "raises an error when argument is missing" do + expect { logger.log_lock_trust_level(nil) }.to raise_error(Discourse::InvalidParameters) + end + + it "creates a new UserHistory record" do + user.trust_level_locked = true + expect { logger.log_lock_trust_level(user) }.to change { UserHistory.count }.by(1) + user_history = UserHistory.last + expect(user_history.action).to eq(UserHistory.actions[:lock_trust_level]) + + user.trust_level_locked = false + expect { logger.log_lock_trust_level(user) }.to change { UserHistory.count }.by(1) + user_history = UserHistory.last + expect(user_history.action).to eq(UserHistory.actions[:unlock_trust_level]) + end + end + + describe 'log_user_activate' do + let(:user) { Fabricate(:user) } + + it "raises an error when argument is missing" do + expect { logger.log_user_activate(nil, nil) }.to raise_error(Discourse::InvalidParameters) + end + + it "creates a new UserHistory record" do + reason = "Staff activated from admin" + expect { + logger.log_user_activate(user, reason) + }.to change { UserHistory.count }.by(1) + user_history = UserHistory.last + expect(user_history.action).to eq(UserHistory.actions[:activate_user]) + expect(user_history.details).to eq(reason) + end + end + + describe '#log_readonly_mode' do + it "creates a new record" do + expect { logger.log_change_readonly_mode(true) }.to change { UserHistory.count }.by(1) + + user_history = UserHistory.last + + expect(user_history.action).to eq(UserHistory.actions[:change_readonly_mode]) + expect(user_history.new_value).to eq('t') + expect(user_history.previous_value).to eq('f') + + expect { logger.log_change_readonly_mode(false) }.to change { UserHistory.count }.by(1) + + user_history = UserHistory.last + + expect(user_history.action).to eq(UserHistory.actions[:change_readonly_mode]) + expect(user_history.new_value).to eq('f') + expect(user_history.previous_value).to eq('t') + end + end end diff --git a/spec/services/user_activator_spec.rb b/spec/services/user_activator_spec.rb index 3a7974983ee..e584189ffd8 100644 --- a/spec/services/user_activator_spec.rb +++ b/spec/services/user_activator_spec.rb @@ -28,14 +28,5 @@ describe UserActivator do expect(user.email_tokens.last.created_at).to be_within_one_second_of(Time.zone.now) end - it "escapes the email in the message" do - user = Fabricate(:user, email: 'eviltrout@example.com') - activator = EmailActivator.new(user, nil, nil, nil) - msg = activator.activate - - expect(msg).to match(/eviltrout@example.com/) - expect(msg).not_to match(//) - end - end end diff --git a/spec/services/user_blocker_spec.rb b/spec/services/user_blocker_spec.rb index b75b5766a79..34c0b99fbdf 100644 --- a/spec/services/user_blocker_spec.rb +++ b/spec/services/user_blocker_spec.rb @@ -58,6 +58,14 @@ describe UserBlocker do SystemMessage.expects(:create).never expect(block_user).to eq(false) end + + it "logs it with context" do + SystemMessage.stubs(:create).returns(Fabricate.build(:post)) + expect { + UserBlocker.block(user, Fabricate(:admin)) + }.to change { UserHistory.count }.by(1) + expect(UserHistory.last.context).to be_present + end end describe 'unblock' do @@ -81,6 +89,12 @@ describe UserBlocker do SystemMessage.expects(:create).never unblock_user end + + it "logs it" do + expect { + unblock_user + }.to change { UserHistory.count }.by(1) + end end describe 'hide_posts' do @@ -104,6 +118,16 @@ describe UserBlocker do expect(post.reload).to_not be_hidden expect(post.topic.reload).to be_visible end + + it "only hides posts from the past 24 hours" do + old_post = Fabricate(:post, user: user, created_at: 2.days.ago) + subject.block + expect(post.reload).to be_hidden + expect(post.topic.reload).to_not be_visible + old_post.reload + expect(old_post).to_not be_hidden + expect(old_post.topic).to be_visible + end end end diff --git a/spec/services/user_destroyer_spec.rb b/spec/services/user_destroyer_spec.rb index e4043e93705..55b94ff3fbd 100644 --- a/spec/services/user_destroyer_spec.rb +++ b/spec/services/user_destroyer_spec.rb @@ -82,7 +82,25 @@ describe UserDestroyer do UserDestroyer.new(admin).destroy(user) expect(QueuedPost.where(user_id: user.id).count).to eq(0) end + end + context "with a directory item record" do + let(:user) { Fabricate(:user) } + let(:admin) { Fabricate(:admin) } + + it "removes the directory item" do + DirectoryItem.create!( + user: user, + period_type: 1, + likes_received: 0, + likes_given: 0, + topics_entered: 0, + topic_count: 0, + post_count: 0 + ) + UserDestroyer.new(admin).destroy(user) + expect(DirectoryItem.where(user_id: user.id).count).to eq(0) + end end context "with a draft" do @@ -146,7 +164,7 @@ describe UserDestroyer do it "deletes topics started by the deleted user" do spammer_topic = Fabricate(:topic, user: @user) - spammer_post = Fabricate(:post, user: @user, topic: spammer_topic) + Fabricate(:post, user: @user, topic: spammer_topic) destroy expect(spammer_topic.reload.deleted_at).not_to eq(nil) expect(spammer_topic.user_id).to eq(nil) @@ -239,12 +257,12 @@ describe UserDestroyer do it "doesn't add ScreenedUrl records by default" do ScreenedUrl.expects(:watch).never - UserDestroyer.new(@admin).destroy(@user, {delete_posts: true}) + UserDestroyer.new(@admin).destroy(@user, delete_posts: true) end it "adds ScreenedUrl records when :block_urls is true" do ScreenedUrl.expects(:watch).with(anything, anything, has_key(:ip_address)).at_least_once - UserDestroyer.new(@admin).destroy(@user, {delete_posts: true, block_urls: true}) + UserDestroyer.new(@admin).destroy(@user, delete_posts: true, block_urls: true) end end diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb index 36863e798d7..5b7c124463e 100644 --- a/spec/support/helpers.rb +++ b/spec/support/helpers.rb @@ -1,4 +1,20 @@ module Helpers + extend ActiveSupport::Concern + + class_methods do + def site_setting(setting_name, value) + original_value = SiteSetting.public_send(setting_name.to_sym) + + self.before do + SiteSetting.public_send("#{setting_name}=", value) + end + + self.after do + SiteSetting.public_send("#{setting_name}=", original_value) + end + end + end + def self.next_seq @next_seq = (@next_seq || 0) + 1 end diff --git a/spec/support/integration_helpers.rb b/spec/support/integration_helpers.rb new file mode 100644 index 00000000000..24331a0761c --- /dev/null +++ b/spec/support/integration_helpers.rb @@ -0,0 +1,9 @@ +module IntegrationHelpers + def sign_in(user) + password = 'somecomplicatedpassword' + user.update!(password: password) + Fabricate(:email_token, confirmed: true, user: user) + post "/session.json", { login: user.username, password: password } + expect(response).to be_success + end +end diff --git a/test/javascripts/acceptance/composer-topic-links-test.js.es6 b/test/javascripts/acceptance/composer-topic-links-test.js.es6 index 98dac6b8409..2ff236abe49 100644 --- a/test/javascripts/acceptance/composer-topic-links-test.js.es6 +++ b/test/javascripts/acceptance/composer-topic-links-test.js.es6 @@ -26,7 +26,7 @@ test("onebox result doesn't include a title", () => { andThen(() => { ok(find('.d-editor-preview').html().trim().indexOf('onebox') > 0, "it pastes the link into the body and previews it"); ok(exists('.d-editor-textarea-wrapper .popup-tip.good'), 'the body is now good'); - equal(find('.title-input input').val(), "no-title.html", "title is from the end of the url"); + equal(find('.title-input input').val(), "http://www.example.com/no-title.html", "title is unchanged"); }); }); diff --git a/test/javascripts/acceptance/group-edit-test.js.es6 b/test/javascripts/acceptance/group-edit-test.js.es6 new file mode 100644 index 00000000000..e4498bf793a --- /dev/null +++ b/test/javascripts/acceptance/group-edit-test.js.es6 @@ -0,0 +1,31 @@ +import { acceptance } from "helpers/qunit-helpers"; + +acceptance("Editing Group", { + loggedIn: true +}); + +test("Editing group", () => { + visit("/groups/discourse/edit"); + + andThen(() => { + ok(find('.group-flair-inputs').length === 1, 'it should display avatar flair inputs'); + ok(find('.group-edit-bio').length === 1, 'it should display group bio input'); + ok(find('.group-edit-full-name').length === 1, 'it should display group full name input'); + ok(find('.group-edit-public').length === 1, 'it should display group public input'); + ok(find('.group-edit-allow-membership-requests').length === 1, 'it should display group allow_membership_requets input'); + ok(find('.group-members-input .item').length === 7, 'it should display group members'); + ok(find('.group-members-input-selector').length === 1, 'it should display input to add group members'); + ok(find('.group-members-input-selector .add[disabled]').length === 1, 'add members button should be disabled'); + }); + + andThen(() => { + ok(find('.group-edit-allow-membership-requests[disabled]').length === 1, 'it should disable group allow_membership_request input'); + }); + + click('.group-edit-public'); + click('.group-edit-allow-membership-requests'); + + andThen(() => { + ok(find('.group-edit-public[disabled]').length === 1, 'it should disable group public input'); + }); +}); diff --git a/test/javascripts/acceptance/groups-logs-test.js.es6 b/test/javascripts/acceptance/group-logs-test.js.es6 similarity index 100% rename from test/javascripts/acceptance/groups-logs-test.js.es6 rename to test/javascripts/acceptance/group-logs-test.js.es6 diff --git a/test/javascripts/acceptance/groups-test.js.es6 b/test/javascripts/acceptance/groups-test.js.es6 index c3578e43d74..baf138e76d0 100644 --- a/test/javascripts/acceptance/groups-test.js.es6 +++ b/test/javascripts/acceptance/groups-test.js.es6 @@ -3,6 +3,46 @@ import { acceptance, logIn } from "helpers/qunit-helpers"; acceptance("Groups"); test("Browsing Groups", () => { + visit("/groups"); + + andThen(() => { + equal(count('.groups-table-row'), 2, 'it displays visible groups'); + equal(find('.group-index-join').length, 1, 'it shows button to join group'); + equal(find('.group-index-request').length, 1, 'it shows button to request for group membership'); + }); + + click('.group-index-join'); + + andThen(() => { + ok(exists('.modal.login-modal'), 'it shows the login modal'); + }); + + click('.login-modal .close'); + + andThen(() => { + ok(invisible('.modal.login-modal'), 'it closes the login modal'); + }); + + click('.group-index-request'); + + andThen(() => { + ok(exists('.modal.login-modal'), 'it shows the login modal'); + }); + + click("a[href='/groups/discourse/members']"); + + andThen(() => { + equal(find('.group-info-name').text().trim(), 'Awesome Team', "it displays the group page"); + }); + + click('.group-index-join'); + + andThen(() => { + ok(exists('.modal.login-modal'), 'it shows the login modal'); + }); +}); + +test("Viewing Group", () => { visit("/groups/discourse"); andThen(() => { @@ -10,62 +50,56 @@ test("Browsing Groups", () => { ok(count('.group-members tr') > 0, "it lists group members"); }); - visit("/groups/discourse/posts"); + click(".nav-pills li a[title='Activity']"); + andThen(() => { ok(count('.user-stream .item') > 0, "it lists stream items"); }); - visit("/groups/discourse/topics"); + click(".group-activity-nav li a[href='/groups/discourse/activity/topics']"); + andThen(() => { ok(count('.user-stream .item') > 0, "it lists stream items"); }); - visit("/groups/discourse/mentions"); + click(".group-activity-nav li a[href='/groups/discourse/activity/mentions']"); + andThen(() => { ok(count('.user-stream .item') > 0, "it lists stream items"); }); - visit("/groups/discourse/messages"); andThen(() => { - ok(find(".nav-stacked li a[title='Messages']").length === 0, 'it should not show messages tab if user is admin'); - ok(find(".nav-stacked li a[title='Logs']").length === 0, 'it should not show Logs tab if user is admin'); + equal( + find(".group-activity li a[href='/groups/discourse/activity/messages']").length, + 0, + 'it should not show messages tab if user is not a group user or admin' + ); + ok(find(".nav-pills li a[title='Edit Group']").length === 0, 'it should not show messages tab if user is not admin'); + ok(find(".nav-pills li a[title='Logs']").length === 0, 'it should not show Logs tab if user is not admin'); ok(count('.user-stream .item') > 0, "it lists stream items"); }); }); -test("Admin Browsing Groups", () => { +test("Admin Viewing Group", () => { logIn(); Discourse.reset(); visit("/groups/discourse"); andThen(() => { - ok(find(".nav-stacked li a[title='Messages']").length === 1, 'it should show messages tab if user is admin'); - ok(find(".nav-stacked li a[title='Logs']").length === 1, 'it should show Logs tab if user is admin'); - equal(find('.group-title').text(), 'Awesome Team', 'it should display the group title'); - equal(find('.group-name').text(), '@discourse', 'it should display the group name'); + ok(find(".nav-pills li a[title='Edit Group']").length === 1, 'it should show edit group tab if user is admin'); + ok(find(".nav-pills li a[title='Logs']").length === 1, 'it should show Logs tab if user is admin'); + + equal(find('.group-info-name').text(), 'Awesome Team', 'it should display the group name'); }); - click('.group-edit-btn'); + click(".nav-pills li a[title='Activity']"); andThen(() => { - ok(find('.group-flair-inputs').length === 1, 'it should display avatar flair inputs'); - ok(find('.edit-group-bio').length === 1, 'it should display group bio input'); - ok(find('.edit-group-title').length === 1, 'it should display group title input'); - ok(find('.edit-group-public').length === 1, 'it should display group public input'); - ok(find('.edit-group-allow-membership-requests').length === 1, 'it should display group allow_membership_requets input'); - }); - - click('.edit-group-public'); - - andThen(() => { - ok(find('.edit-group-allow-membership-requests[disabled]').length === 1, 'it should disable group allow_membership_requets input'); - }); - - click('.edit-group-public'); - click('.edit-group-allow-membership-requests'); - - andThen(() => { - ok(find('.edit-group-public[disabled]').length === 1, 'it should disable group public input'); + equal( + find(".group-activity li a[href='/groups/discourse/activity/messages']").length, + 1, + 'it should show messages tab if user is admin' + ); }); }); diff --git a/test/javascripts/acceptance/login-required-test.js.es6 b/test/javascripts/acceptance/login-required-test.js.es6 index abdb2eea949..4bbec697a41 100644 --- a/test/javascripts/acceptance/login-required-test.js.es6 +++ b/test/javascripts/acceptance/login-required-test.js.es6 @@ -26,19 +26,4 @@ test("redirect", () => { andThen(() => { ok(invisible('.login-modal'), "it closes the login modal"); }); - - click('#search-button'); - andThen(() => { - ok(exists('.login-modal'), "clicking search opens the login modal"); - }); - - click('.modal-header .close'); - andThen(() => { - ok(invisible('.login-modal'), "it closes the login modal"); - }); - - click('#toggle-hamburger-menu'); - andThen(() => { - ok(exists('.login-modal'), "site map opens the login modal"); - }); }); diff --git a/test/javascripts/acceptance/plugin-outlet-connector-class-test.js.es6 b/test/javascripts/acceptance/plugin-outlet-connector-class-test.js.es6 new file mode 100644 index 00000000000..82b34f7ca7c --- /dev/null +++ b/test/javascripts/acceptance/plugin-outlet-connector-class-test.js.es6 @@ -0,0 +1,47 @@ +import { acceptance } from "helpers/qunit-helpers"; +import { extraConnectorClass } from 'discourse/lib/plugin-connectors'; + +const PREFIX = "javascripts/single-test/connectors"; +acceptance("Plugin Outlet - Connector Class", { + setup() { + extraConnectorClass('user-profile-primary/hello', { + actions: { + sayHello() { + this.set('hello', 'hello!'); + } + } + }); + + extraConnectorClass('user-profile-primary/dont-render', { + shouldRender(args) { + return args.model.get('username') !== 'eviltrout'; + } + }); + + Ember.TEMPLATES[`${PREFIX}/user-profile-primary/hello`] = Ember.HTMLBars.compile( + `{{model.username}} + + {{hello}}` + ); + Ember.TEMPLATES[`${PREFIX}/user-profile-primary/dont-render`] = Ember.HTMLBars.compile( + `I'm not rendered!` + ); + }, + + teardown() { + delete Ember.TEMPLATES[`${PREFIX}/user-profile-primary/hello`]; + delete Ember.TEMPLATES[`${PREFIX}/user-profile-primary/dont-render`]; + } +}); + +test("Renders a template into the outlet", assert => { + visit("/users/eviltrout"); + andThen(() => { + assert.ok(find('.user-profile-primary-outlet.hello').length === 1, 'it has class names'); + assert.ok(!find('.user-profile-primary-outlet.dont-render').length, "doesn't render"); + }); + click('.say-hello'); + andThen(() => { + assert.equal(find('.hello-result').text(), 'hello!', 'actions delegate properly'); + }); +}); diff --git a/test/javascripts/acceptance/plugin-outlet-multi-template-test.js.es6 b/test/javascripts/acceptance/plugin-outlet-multi-template-test.js.es6 index 34d5bc00459..0379b2d8e54 100644 --- a/test/javascripts/acceptance/plugin-outlet-multi-template-test.js.es6 +++ b/test/javascripts/acceptance/plugin-outlet-multi-template-test.js.es6 @@ -1,5 +1,5 @@ import { acceptance } from "helpers/qunit-helpers"; -import { clearCache } from 'discourse/helpers/plugin-outlet'; +import { clearCache } from 'discourse/lib/plugin-connectors'; const HELLO = 'javascripts/multi-test/connectors/user-profile-primary/hello'; const GOODBYE = 'javascripts/multi-test/connectors/user-profile-primary/goodbye'; diff --git a/test/javascripts/acceptance/plugin-outlet-single-template-test.js.es6 b/test/javascripts/acceptance/plugin-outlet-single-template-test.js.es6 index 228506e27c9..ee236ed8518 100644 --- a/test/javascripts/acceptance/plugin-outlet-single-template-test.js.es6 +++ b/test/javascripts/acceptance/plugin-outlet-single-template-test.js.es6 @@ -4,9 +4,7 @@ const CONNECTOR = 'javascripts/single-test/connectors/user-profile-primary/hello acceptance("Plugin Outlet - Single Template", { setup() { Ember.TEMPLATES[CONNECTOR] = Ember.HTMLBars.compile( - `{{model.username}} - - {{model.email}}` + `{{model.username}}` ); }, @@ -21,8 +19,4 @@ test("Renders a template into the outlet", assert => { assert.ok(find('.user-profile-primary-outlet.hello').length === 1, 'it has class names'); assert.equal(find('.hello-username').text(), 'eviltrout', 'it renders into the outlet'); }); - click('.hello-check-email'); - andThen(() => { - assert.equal(find('.hello-email').text(), 'eviltrout@example.com', 'actions delegate properly'); - }); }); diff --git a/test/javascripts/acceptance/preferences-test.js.es6 b/test/javascripts/acceptance/preferences-test.js.es6 index b6885400ea4..9c597df2e0a 100644 --- a/test/javascripts/acceptance/preferences-test.js.es6 +++ b/test/javascripts/acceptance/preferences-test.js.es6 @@ -36,6 +36,12 @@ test("about me", () => { test("email", () => { visit("/users/eviltrout/preferences/email"); andThen(() => { - ok(exists("#change_email"), "it has the input element"); + ok(exists("#change-email"), "it has the input element"); + }); + + fillIn("#change-email", 'invalidemail'); + + andThen(() => { + equal(find('.tip.bad').text().trim(), I18n.t('user.email.invalid'), 'it should display invalid email tip'); }); }); diff --git a/test/javascripts/acceptance/raw-plugin-outlet-test.js.es6 b/test/javascripts/acceptance/raw-plugin-outlet-test.js.es6 new file mode 100644 index 00000000000..3611bf1cddd --- /dev/null +++ b/test/javascripts/acceptance/raw-plugin-outlet-test.js.es6 @@ -0,0 +1,23 @@ +import { acceptance } from "helpers/qunit-helpers"; + +const CONNECTOR = 'javascripts/raw-test/connectors/topic-list-tags/lala'; +acceptance("Raw Plugin Outlet", { + setup() { + Discourse.RAW_TEMPLATES[CONNECTOR] = Handlebars.compile( + `{{context.topic.id}}` + ); + }, + + teardown() { + delete Discourse.RAW_TEMPLATES[CONNECTOR]; + } +}); + +test("Renders the raw plugin outlet", assert => { + visit("/"); + andThen(() => { + assert.ok(find('.topic-lala').length > 0, 'it renders the outlet'); + assert.equal(find('.topic-lala:eq(0)').text(), '11557', 'it has the topic id'); + }); +}); + diff --git a/test/javascripts/acceptance/search-full-test.js.es6 b/test/javascripts/acceptance/search-full-test.js.es6 index 99820e7d9d9..47fdbc8bf6e 100644 --- a/test/javascripts/acceptance/search-full-test.js.es6 +++ b/test/javascripts/acceptance/search-full-test.js.es6 @@ -71,27 +71,29 @@ test("open advanced search", assert => { andThen(() => assert.ok(visible('.search-advanced .search-advanced-options'), '"search-advanced-options" is visible')); }); -test("validate population of advanced search", assert => { - visit("/search"); - fillIn('.search input.full-page-search', 'test user:admin #bug group:moderators badge:Reader tags:monkey in:likes in:private in:wiki in:bookmarks status:open after:2016-10-05 min_post_count:10'); - click('.search-advanced-btn'); +// these tests are screwy with the runloop - andThen(() => { - assert.ok(exists('.search-advanced-options span:contains("admin")'), 'has "admin" pre-populated'); - assert.ok(exists('.search-advanced-options .badge-category:contains("bug")'), 'has "bug" pre-populated'); - //assert.ok(exists('.search-advanced-options span:contains("moderators")'), 'has "moderators" pre-populated'); - //assert.ok(exists('.search-advanced-options span:contains("Reader")'), 'has "Reader" pre-populated'); - assert.ok(exists('.search-advanced-options .tag-chooser .tag-monkey'), 'has "monkey" pre-populated'); - assert.ok(exists('.search-advanced-options .in-likes:checked'), 'has "I liked" pre-populated'); - assert.ok(exists('.search-advanced-options .in-private:checked'), 'has "are in my messages" pre-populated'); - assert.ok(exists('.search-advanced-options .in-wiki:checked'), 'has "are wiki" pre-populated'); - assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("I\'ve bookmarked")'), 'has "I\'ve bookmarked" pre-populated'); - assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("are open")'), 'has "are open" pre-populated'); - assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("after")'), 'has "after" pre-populated'); - assert.equal(find('.search-advanced-options #search-post-date').val(), "2016-10-05", 'has "2016-10-05" pre-populated'); - assert.equal(find('.search-advanced-options #search-min-post-count').val(), "10", 'has "10" pre-populated'); - }); -}); +// test("validate population of advanced search", assert => { +// visit("/search"); +// fillIn('.search input.full-page-search', 'test user:admin #bug group:moderators badge:Reader tags:monkey in:likes in:private in:wiki in:bookmarks status:open after:2016-10-05 min_post_count:10'); +// click('.search-advanced-btn'); +// +// andThen(() => { +// assert.ok(exists('.search-advanced-options span:contains("admin")'), 'has "admin" pre-populated'); +// assert.ok(exists('.search-advanced-options .badge-category:contains("bug")'), 'has "bug" pre-populated'); +// //assert.ok(exists('.search-advanced-options span:contains("moderators")'), 'has "moderators" pre-populated'); +// //assert.ok(exists('.search-advanced-options span:contains("Reader")'), 'has "Reader" pre-populated'); +// assert.ok(exists('.search-advanced-options .tag-chooser .tag-monkey'), 'has "monkey" pre-populated'); +// assert.ok(exists('.search-advanced-options .in-likes:checked'), 'has "I liked" pre-populated'); +// assert.ok(exists('.search-advanced-options .in-private:checked'), 'has "are in my messages" pre-populated'); +// assert.ok(exists('.search-advanced-options .in-wiki:checked'), 'has "are wiki" pre-populated'); +// assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("I\'ve bookmarked")'), 'has "I\'ve bookmarked" pre-populated'); +// assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("are open")'), 'has "are open" pre-populated'); +// assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("after")'), 'has "after" pre-populated'); +// assert.equal(find('.search-advanced-options #search-post-date').val(), "2016-10-05", 'has "2016-10-05" pre-populated'); +// assert.equal(find('.search-advanced-options #search-min-post-count').val(), "10", 'has "10" pre-populated'); +// }); +// }); test("escape search term", (assert) => { visit("/search"); diff --git a/test/javascripts/acceptance/topic-test.js.es6 b/test/javascripts/acceptance/topic-test.js.es6 index ea8471d71c5..dd9a9bdc20b 100644 --- a/test/javascripts/acceptance/topic-test.js.es6 +++ b/test/javascripts/acceptance/topic-test.js.es6 @@ -48,3 +48,27 @@ test("Updating the topic title and category", () => { equal(find('.fancy-title').text().trim(), 'this is the new title', 'it displays the new title'); }); }); + +test("Marking a topic as wiki", () => { + server.put('/posts/398/wiki', () => { // eslint-disable-line no-undef + return [ + 200, + { "Content-Type": "application/json" }, + {} + ]; + }); + + visit("/t/internationalization-localization/280"); + + andThen(() => { + ok(find('a.wiki').length === 0, 'it does not show the wiki icon'); + }); + + click('.topic-post:eq(0) button.show-more-actions'); + click('.topic-post:eq(0) button.show-post-admin-menu'); + click('.btn.wiki'); + + andThen(() => { + ok(find('a.wiki').length === 1, 'it shows the wiki icon'); + }); +}); diff --git a/test/javascripts/admin/controllers/admin-user-badges-test.js.es6 b/test/javascripts/admin/controllers/admin-user-badges-test.js.es6 index e4a7aaceb4f..f58845ecfc0 100644 --- a/test/javascripts/admin/controllers/admin-user-badges-test.js.es6 +++ b/test/javascripts/admin/controllers/admin-user-badges-test.js.es6 @@ -20,6 +20,6 @@ test("grantableBadges", function() { }); - not(badgeNames.contains(badgeDisabled), "excludes disabled badges"); + not(badgeNames.includes(badgeDisabled), "excludes disabled badges"); deepEqual(badgeNames, sortedNames, "sorts badges by name"); }); diff --git a/test/javascripts/components/d-editor-test.js.es6 b/test/javascripts/components/d-editor-test.js.es6 index 4fefd8c819b..1a594cd2dae 100644 --- a/test/javascripts/components/d-editor-test.js.es6 +++ b/test/javascripts/components/d-editor-test.js.es6 @@ -760,7 +760,7 @@ componentTest('emoji', { } }); -testCase("replace-text event", function(assert, textarea) { +testCase("replace-text event", function(assert) { this.set('value', "red green blue"); @@ -770,7 +770,96 @@ testCase("replace-text event", function(assert, textarea) { andThen(() => { assert.equal(this.get('value'), 'red yellow blue'); - assert.equal(textarea.selectionStart, 10); - assert.equal(textarea.selectionEnd, 10); }); }); + +(() => { + // Tests to check cursor/selection after replace-text event. + const BEFORE = 'red green blue'; + const NEEDLE = 'green'; + const REPLACE = 'yellow'; + const AFTER = BEFORE.replace(NEEDLE, REPLACE); + + const CASES = [ + { + description: 'cursor at start remains there', + before: [0, 0], + after: [0, 0] + },{ + description: 'cursor before needle becomes cursor before replacement', + before: [BEFORE.indexOf(NEEDLE), 0], + after: [AFTER.indexOf(REPLACE), 0] + },{ + description: 'cursor at needle start + 1 moves behind replacement', + before: [BEFORE.indexOf(NEEDLE) + 1, 0], + after: [AFTER.indexOf(REPLACE) + REPLACE.length, 0] + },{ + description: 'cursor at needle end - 1 stays behind replacement', + before: [BEFORE.indexOf(NEEDLE) + NEEDLE.length - 1, 0], + after: [AFTER.indexOf(REPLACE) + REPLACE.length, 0] + },{ + description: 'cursor behind needle becomes cursor behind replacement', + before: [BEFORE.indexOf(NEEDLE) + NEEDLE.length, 0], + after: [AFTER.indexOf(REPLACE) + REPLACE.length, 0] + },{ + description: 'cursor at end remains there', + before: [BEFORE.length, 0], + after: [AFTER.length, 0] + },{ + description: 'selection spanning needle start becomes selection until replacement start', + before: [BEFORE.indexOf(NEEDLE) - 1, 2], + after: [AFTER.indexOf(REPLACE) - 1, 1] + },{ + description: 'selection spanning needle end becomes selection from replacement end', + before: [BEFORE.indexOf(NEEDLE) + NEEDLE.length - 1, 2], + after: [AFTER.indexOf(REPLACE) + REPLACE.length, 1] + },{ + description: 'selection spanning needle becomes selection spanning replacement', + before: [BEFORE.indexOf(NEEDLE) - 1, NEEDLE.length + 2], + after: [AFTER.indexOf(REPLACE) - 1, REPLACE.length + 2] + },{ + description: 'complete selection remains complete', + before: [0, BEFORE.length], + after: [0, AFTER.length] + } + ]; + + function setSelection(textarea, [start, len]) { + textarea.selectionStart = start; + textarea.selectionEnd = start + len; + } + + function getSelection(textarea) { + const start = textarea.selectionStart; + const end = textarea.selectionEnd; + return [start, end - start]; + } + + function formatTextWithSelection(text, [start, len]) { + return [ + '"', + text.substr(0, start), + '<', + text.substr(start, len), + '>', + text.substr(start+len), + '"', + ].join(''); + } + + for (let i = 0; i < CASES.length; i++) { + const CASE = CASES[i]; + testCase(`replace-text event: ${CASE.description}`, function(assert, textarea) { + this.set('value', BEFORE); + setSelection(textarea, CASE.before); + andThen(() => { + this.container.lookup('app-events:main').trigger('composer:replace-text', 'green', 'yellow'); + }); + andThen(() => { + let expect = formatTextWithSelection(AFTER, CASE.after); + let actual = formatTextWithSelection(this.get('value'), getSelection(textarea)); + assert.equal(actual, expect); + }); + }); + } +})(); diff --git a/test/javascripts/controllers/group-index-test.js.es6 b/test/javascripts/components/group-membership-button-test.js.es6 similarity index 54% rename from test/javascripts/controllers/group-index-test.js.es6 rename to test/javascripts/components/group-membership-button-test.js.es6 index 361439154c9..b1796078d87 100644 --- a/test/javascripts/controllers/group-index-test.js.es6 +++ b/test/javascripts/components/group-membership-button-test.js.es6 @@ -1,14 +1,12 @@ import { currentUser } from "helpers/qunit-helpers"; -moduleFor("controller:group-index"); +moduleFor('component:group-membership-button'); -test("canJoinGroup", function() { +test('canJoinGroup', function() { this.subject().setProperties({ model: { public: false } }); - this.subject().set("currentUser", currentUser()); - equal(this.subject().get("canJoinGroup"), false, "non public group cannot be joined"); this.subject().set("model.public", true); @@ -17,7 +15,7 @@ test("canJoinGroup", function() { this.subject().setProperties({ currentUser: null, model: { public: true } }); - equal(this.subject().get("canJoinGroup"), false, "can't join group when not logged in"); + equal(this.subject().get("canJoinGroup"), true, "can't join group when not logged in"); }); test('canRequestMembership', function() { @@ -37,3 +35,27 @@ test('canRequestMembership', function() { equal(this.subject().get('canRequestMembership'), false); }); + +test('userIsGroupUser', function() { + this.subject().setProperties({ + model: { is_group_user: true } + }); + + equal(this.subject().get('userIsGroupUser'), true); + + this.subject().set('model.is_group_user', false); + + equal(this.subject().get('userIsGroupUser'), false); + + this.subject().setProperties({ model: { id: 1 }, groupUserIds: [1] }); + + equal(this.subject().get('userIsGroupUser'), true); + + this.subject().set('groupUserIds', [3]); + + equal(this.subject().get('userIsGroupUser'), false); + + this.subject().set('groupUserIds', undefined); + + equal(this.subject().get('userIsGroupUser'), false); +}); diff --git a/test/javascripts/fixtures/group-fixtures.js.es6 b/test/javascripts/fixtures/group-fixtures.js.es6 index 55041ac96f4..92ecb7c48be 100644 --- a/test/javascripts/fixtures/group-fixtures.js.es6 +++ b/test/javascripts/fixtures/group-fixtures.js.es6 @@ -4,10 +4,11 @@ export default { "id":47, "automatic":false, "name":"discourse", - "title":"Awesome Team", + "full_name":"Awesome Team", "user_count":8, "alias_level":0, "visible":true, + "public":true, "flair_url": 'fa-adjust', "is_group_owner":true } diff --git a/test/javascripts/fixtures/groups-fixtures.js.es6 b/test/javascripts/fixtures/groups-fixtures.js.es6 new file mode 100644 index 00000000000..1baa42b560e --- /dev/null +++ b/test/javascripts/fixtures/groups-fixtures.js.es6 @@ -0,0 +1,3 @@ +export default { + "/groups.json": {"groups":[{"id":41,"automatic":false,"name":"discourse","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":"","automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":"","bio_cooked":null,"public":true,"allow_membership_requests":false,"full_name":"Awesome Team"},{"id":42,"automatic":false,"name":"Macdonald","user_count":0,"alias_level":99,"visible":true,"automatic_membership_email_domains":"","automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":true,"full_name":null}],"extras":{"group_user_ids":[]},"total_rows_groups":2,"load_more_groups":"/groups?page=1"} +} diff --git a/test/javascripts/helpers/create-pretender.js.es6 b/test/javascripts/helpers/create-pretender.js.es6 index fe1b4d1a294..809aec596b9 100644 --- a/test/javascripts/helpers/create-pretender.js.es6 +++ b/test/javascripts/helpers/create-pretender.js.es6 @@ -113,7 +113,7 @@ export default function() { return response({}); }); - this.put('/users/eviltrout', () => response({ user: {} })); + this.put('/users/eviltrout.json', () => response({ user: {} })); this.get("/t/280.json", () => response(fixturesByUrl['/t/280/1.json'])); this.get("/t/28830.json", () => response(fixturesByUrl['/t/28830/1.json'])); @@ -242,6 +242,10 @@ export default function() { slug: request.params.slug } }); }); + this.get("groups", () => { + return response(200, fixturesByUrl['/groups.json']); + }); + this.get("/groups/discourse/topics.json", () => { return response(200, fixturesByUrl['/groups/discourse/posts.json']); }); diff --git a/test/javascripts/helpers/qunit-helpers.js.es6 b/test/javascripts/helpers/qunit-helpers.js.es6 index d8351405f0c..1fdc796b693 100644 --- a/test/javascripts/helpers/qunit-helpers.js.es6 +++ b/test/javascripts/helpers/qunit-helpers.js.es6 @@ -5,8 +5,10 @@ import siteFixtures from 'fixtures/site-fixtures'; import HeaderComponent from 'discourse/components/site-header'; import { forceMobile, resetMobile } from 'discourse/lib/mobile'; import { resetPluginApi } from 'discourse/lib/plugin-api'; -import { clearCache as clearOutletCache } from 'discourse/helpers/plugin-outlet'; +import { clearCache as clearOutletCache, resetExtraClasses } from 'discourse/lib/plugin-connectors'; import { clearHTMLCache } from 'discourse/helpers/custom-html'; +import { flushMap } from 'discourse/models/store'; + function currentUser() { return Discourse.User.create(sessionFixtures['/session/current.json'].current_user); @@ -44,6 +46,7 @@ function acceptance(name, options) { // For now don't do scrolling stuff in Test Mode HeaderComponent.reopen({examineDockHeader: Ember.K}); + resetExtraClasses(); const siteJson = siteFixtures['site.json'].site; if (options) { if (options.setup) { @@ -77,9 +80,11 @@ function acceptance(name, options) { if (options && options.teardown) { options.teardown.call(this); } + flushMap(); Discourse.User.resetCurrent(); Discourse.Site.resetCurrent(Discourse.Site.create(jQuery.extend(true, {}, fixtures['site.json'].site))); + resetExtraClasses(); clearOutletCache(); clearHTMLCache(); resetPluginApi(); diff --git a/test/javascripts/models/composer-test.js.es6 b/test/javascripts/models/composer-test.js.es6 index 86208aa5843..d7bcf53af7c 100644 --- a/test/javascripts/models/composer-test.js.es6 +++ b/test/javascripts/models/composer-test.js.es6 @@ -248,3 +248,11 @@ test("title placeholder depends on what you're doing", function() { composer = createComposer({action: Composer.PRIVATE_MESSAGE}); equal(composer.get('titlePlaceholder'), 'composer.title_placeholder', "placeholder for private message with topic links enabled"); }); + +test("allows featured link before choosing a category", function() { + Discourse.SiteSettings.topic_featured_link_enabled = true; + Discourse.SiteSettings.allow_uncategorized_topics = false; + let composer = createComposer({action: Composer.CREATE_TOPIC}); + equal(composer.get('titlePlaceholder'), 'composer.title_or_link_placeholder', "placeholder invites you to paste a link"); + ok(composer.get('canEditTopicFeaturedLink'), "can paste link"); +}); diff --git a/test/javascripts/models/post-stream-test.js.es6 b/test/javascripts/models/post-stream-test.js.es6 index 5f825d9fbcc..b0c455e8fa9 100644 --- a/test/javascripts/models/post-stream-test.js.es6 +++ b/test/javascripts/models/post-stream-test.js.es6 @@ -170,7 +170,7 @@ test("toggleParticipant", function() { equal(postStream.get('userFilters.length'), 0, "by default no participants are toggled"); postStream.toggleParticipant(participant.username); - ok(postStream.get('userFilters').contains('eviltrout'), 'eviltrout is in the filters'); + ok(postStream.get('userFilters').includes('eviltrout'), 'eviltrout is in the filters'); postStream.toggleParticipant(participant.username); blank(postStream.get('userFilters'), "toggling the participant again removes them"); @@ -283,7 +283,7 @@ test("identity map", function() { }); test("loadIntoIdentityMap with no data", () => { - buildStream(1234).loadIntoIdentityMap([]).then(result => { + return buildStream(1234).loadIntoIdentityMap([]).then(result => { equal(result.length, 0, 'requesting no posts produces no posts'); }); }); @@ -291,7 +291,7 @@ test("loadIntoIdentityMap with no data", () => { test("loadIntoIdentityMap with post ids", function() { const postStream = buildStream(1234); - postStream.loadIntoIdentityMap([10]).then(function() { + return postStream.loadIntoIdentityMap([10]).then(function() { present(postStream.findLoadedPost(10), "it adds the returned post to the store"); }); }); @@ -327,7 +327,7 @@ test("staging and undoing a new post", function() { equal(stagedPost.get('topic'), topic, "it assigns the topic reference"); equal(stagedPost.get('post_number'), 2, "it is assigned the probable post_number"); present(stagedPost.get('created_at'), "it is assigned a created date"); - ok(postStream.get('posts').contains(stagedPost), "the post is added to the stream"); + ok(postStream.get('posts').includes(stagedPost), "the post is added to the stream"); equal(stagedPost.get('id'), -1, "the post has a magical -1 id"); // Undoing a created post (there was an error) @@ -337,7 +337,7 @@ test("staging and undoing a new post", function() { equal(topic.get('highest_post_number'), 1, "it reverts the highest_post_number"); equal(topic.get('posts_count'), 1, "it reverts the post count"); equal(postStream.get('filteredPostsCount'), 1, "it retains the filteredPostsCount"); - ok(!postStream.get('posts').contains(stagedPost), "the post is removed from the stream"); + ok(!postStream.get('posts').includes(stagedPost), "the post is removed from the stream"); ok(postStream.get('lastAppended'), original, "it doesn't consider undid post lastAppended"); }); @@ -367,7 +367,7 @@ test("staging and committing a post", function() { ok(postStream.get('lastAppended'), original, "staging a post doesn't change the lastAppended"); postStream.commitPost(stagedPost); - ok(postStream.get('posts').contains(stagedPost), "the post is still in the stream"); + ok(postStream.get('posts').includes(stagedPost), "the post is still in the stream"); ok(!postStream.get('loading'), "it is no longer loading"); equal(postStream.get('filteredPostsCount'), 2, "it increases the filteredPostsCount"); diff --git a/test/javascripts/models/result-set-test.js.es6 b/test/javascripts/models/result-set-test.js.es6 index c846fd88720..18c9aa0c80f 100644 --- a/test/javascripts/models/result-set-test.js.es6 +++ b/test/javascripts/models/result-set-test.js.es6 @@ -15,7 +15,7 @@ test('defaults', function() { test('pagination support', function() { const store = createStore(); - store.findAll('widget').then(function(rs) { + return store.findAll('widget').then(function(rs) { equal(rs.get('length'), 2); equal(rs.get('totalRows'), 4); ok(rs.get('loadMoreUrl'), 'has a url to load more'); @@ -36,7 +36,7 @@ test('pagination support', function() { test('refresh support', function() { const store = createStore(); - store.findAll('widget').then(function(rs) { + return store.findAll('widget').then(function(rs) { equal(rs.get('refreshUrl'), '/widgets?refresh=true', 'it has the refresh url'); const promise = rs.refresh(); diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index 69855950146..f82d4b70653 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -30,9 +30,9 @@ //= require sinon-1.7.1 //= require sinon-qunit-1.0.0 -//= require helpers/qunit-helpers //= require helpers/assertions +//= require helpers/qunit-helpers //= require_tree ./fixtures //= require_tree ./lib //= require_tree . diff --git a/test/javascripts/widgets/actions-summary-test.js.es6 b/test/javascripts/widgets/actions-summary-test.js.es6 index 9b7f9cea233..6542d17b12c 100644 --- a/test/javascripts/widgets/actions-summary-test.js.es6 +++ b/test/javascripts/widgets/actions-summary-test.js.es6 @@ -23,7 +23,7 @@ widgetTest('listing actions', { }); widgetTest('undo', { - template: '{{mount-widget widget="actions-summary" args=args undoPostAction="undoPostAction"}}', + template: '{{mount-widget widget="actions-summary" args=args undoPostAction=undoPostAction}}', setup() { this.set('args', { actionsSummary: [ @@ -31,7 +31,7 @@ widgetTest('undo', { ] }); - this.on('undoPostAction', () => this.undid = true); + this.set('undoPostAction', () => this.undid = true); }, test(assert) { assert.equal(this.$('.post-actions .post-action').length, 1); diff --git a/test/javascripts/widgets/header-test.js.es6 b/test/javascripts/widgets/header-test.js.es6 index f3a7b8f9071..71676a0338c 100644 --- a/test/javascripts/widgets/header-test.js.es6 +++ b/test/javascripts/widgets/header-test.js.es6 @@ -35,3 +35,41 @@ widgetTest('sign up / login buttons', { }); } }); + +widgetTest('anon when login required', { + template: '{{mount-widget widget="header" showCreateAccount="showCreateAccount" showLogin="showLogin" args=args}}', + anonymous: true, + + setup() { + this.set('args', { canSignUp: true }); + this.on('showCreateAccount', () => this.signupShown = true); + this.on('showLogin', () => this.loginShown = true); + this.siteSettings.login_required = true; + }, + + test(assert) { + assert.ok(exists('button.login-button')); + assert.ok(exists('button.sign-up-button')); + assert.ok(!exists('#search-button')); + assert.ok(!exists('#toggle-hamburger-menu')); + } +}); + +widgetTest('logged in when login required', { + template: '{{mount-widget widget="header" showCreateAccount="showCreateAccount" showLogin="showLogin" args=args}}', + + setup() { + this.set('args', { canSignUp: true }); + this.on('showCreateAccount', () => this.signupShown = true); + this.on('showLogin', () => this.loginShown = true); + this.siteSettings.login_required = true; + }, + + test(assert) { + assert.ok(!exists('button.login-button')); + assert.ok(!exists('button.sign-up-button')); + assert.ok(exists('#search-button')); + assert.ok(exists('#toggle-hamburger-menu')); + assert.ok(exists('#current-user')); + } +}); diff --git a/test/javascripts/widgets/post-test.js.es6 b/test/javascripts/widgets/post-test.js.es6 index 67886da7689..80b97b548a8 100644 --- a/test/javascripts/widgets/post-test.js.es6 +++ b/test/javascripts/widgets/post-test.js.es6 @@ -17,15 +17,29 @@ widgetTest('basic elements', { }); widgetTest('wiki', { + template: '{{mount-widget widget="post" args=args showHistory="showHistory"}}', + setup() { + this.set('args', { wiki: true, version: 2, canViewEditHistory: true }); + this.on('showHistory', () => this.historyShown = true); + }, + test(assert) { + click('.post-info .wiki'); + andThen(() => { + assert.ok(this.historyShown, 'clicking the wiki icon displays the post history'); + }); + } +}); + +widgetTest('wiki without revision', { template: '{{mount-widget widget="post" args=args editPost="editPost"}}', setup() { - this.set('args', { wiki: true }); + this.set('args', { wiki: true, version: 1, canViewEditHistory: true }); this.on('editPost', () => this.editPostCalled = true); }, test(assert) { - click('.post-info.wiki'); + click('.post-info .wiki'); andThen(() => { - assert.ok(this.editPostCalled, 'clicking the wiki icon edits the post'); + assert.ok(this.editPostCalled, 'clicking wiki icon edits the post'); }); } }); diff --git a/test/javascripts/widgets/topic-participant-test.js.es6 b/test/javascripts/widgets/topic-participant-test.js.es6 new file mode 100644 index 00000000000..fe436524564 --- /dev/null +++ b/test/javascripts/widgets/topic-participant-test.js.es6 @@ -0,0 +1,43 @@ +import { moduleForWidget, widgetTest } from 'helpers/widget-test'; + +moduleForWidget('topic-participant'); + +widgetTest('one post', { + template: '{{mount-widget widget="topic-participant" args=args}}', + + setup() { + this.set('args', { + username: 'test', + avatar_template: 'stubbed', + post_count: 1 + }); + }, + + test(assert) { + assert.ok(exists('a.poster.trigger-user-card')); + assert.ok(!exists('span.post-count'), "don't show count for only 1 post"); + assert.ok(!exists('.avatar-flair'), "no avatar flair"); + } +}); + +widgetTest('many posts, a primary group with flair', { + template: '{{mount-widget widget="topic-participant" args=args}}', + + setup() { + this.set('args', { + username: 'test', + avatar_template: 'stubbed', + post_count: 5, + primary_group_name: 'devs', + primary_group_flair_url: "http://devs.example.com/img/devs.png", + primary_group_flair_bg_color: "222" + }); + }, + + test(assert) { + assert.ok(exists('a.poster.trigger-user-card')); + assert.ok(exists('span.post-count'), "show count for many posts"); + assert.ok(exists('.group-devs a.poster'), "add class for the group outside the link"); + assert.ok(exists('.avatar-flair.avatar-flair-devs'), "show flair with group class"); + } +}); diff --git a/vendor/assets/javascripts/ember-qunit.js b/vendor/assets/javascripts/ember-qunit.js index 759edca9be9..cf41920e2e6 100644 --- a/vendor/assets/javascripts/ember-qunit.js +++ b/vendor/assets/javascripts/ember-qunit.js @@ -111,81 +111,82 @@ var define, requireModule, require, requirejs; }; })(); -define('ember-qunit', ['exports', 'ember-qunit/module-for', 'ember-qunit/module-for-component', 'ember-qunit/module-for-model', 'ember-qunit/test', 'ember-qunit/only', 'ember-test-helpers'], function (exports, moduleFor, moduleForComponent, moduleForModel, test, only, ember_test_helpers) { - +define('ember-qunit', ['exports', 'ember-qunit/module-for', 'ember-qunit/module-for-component', 'ember-qunit/module-for-model', 'ember-qunit/adapter', 'ember-test-helpers', 'qunit'], function (exports, _emberQunitModuleFor, _emberQunitModuleForComponent, _emberQunitModuleForModel, _emberQunitAdapter, _emberTestHelpers, _qunit) { 'use strict'; - - - exports.moduleFor = moduleFor['default']; - exports.moduleForComponent = moduleForComponent['default']; - exports.moduleForModel = moduleForModel['default']; - exports.test = test['default']; - exports.only = only['default']; - exports.setResolver = ember_test_helpers.setResolver; - + exports.module = _qunit.module; + exports.test = _qunit.test; + exports.skip = _qunit.skip; + exports.only = _qunit.only; + exports.moduleFor = _emberQunitModuleFor['default']; + exports.moduleForComponent = _emberQunitModuleForComponent['default']; + exports.moduleForModel = _emberQunitModuleForModel['default']; + exports.setResolver = _emberTestHelpers.setResolver; + exports.QUnitAdapter = _emberQunitAdapter['default']; }); -define('ember-qunit/module-for-component', ['exports', 'ember-qunit/qunit-module', 'ember-test-helpers'], function (exports, qunit_module, ember_test_helpers) { - +define('ember-qunit/adapter', ['exports', 'ember', 'qunit'], function (exports, _ember, _qunit) { + 'use strict'; + + exports['default'] = _ember['default'].Test.Adapter.extend({ + init: function init() { + this.doneCallbacks = []; + }, + + asyncStart: function asyncStart() { + this.doneCallbacks.push(_qunit['default'].config.current.assert.async()); + }, + + asyncEnd: function asyncEnd() { + this.doneCallbacks.pop()(); + }, + + exception: function exception(error) { + _qunit['default'].config.current.assert.ok(false, _ember['default'].inspect(error)); + } + }); +}); +define('ember-qunit/module-for-component', ['exports', './qunit-module', 'ember-test-helpers'], function (exports, _qunitModule, _emberTestHelpers) { 'use strict'; - function moduleForComponent(name, description, callbacks) { - qunit_module.createModule(ember_test_helpers.TestModuleForComponent, name, description, callbacks); - } exports['default'] = moduleForComponent; + function moduleForComponent(name, description, callbacks) { + _qunitModule.createModule(_emberTestHelpers.TestModuleForComponent, name, description, callbacks); + } }); -define('ember-qunit/module-for-model', ['exports', 'ember-qunit/qunit-module', 'ember-test-helpers'], function (exports, qunit_module, ember_test_helpers) { - +define('ember-qunit/module-for-model', ['exports', './qunit-module', 'ember-test-helpers'], function (exports, _qunitModule, _emberTestHelpers) { 'use strict'; - function moduleForModel(name, description, callbacks) { - qunit_module.createModule(ember_test_helpers.TestModuleForModel, name, description, callbacks); - } exports['default'] = moduleForModel; + function moduleForModel(name, description, callbacks) { + _qunitModule.createModule(_emberTestHelpers.TestModuleForModel, name, description, callbacks); + } }); -define('ember-qunit/module-for', ['exports', 'ember-qunit/qunit-module', 'ember-test-helpers'], function (exports, qunit_module, ember_test_helpers) { - +define('ember-qunit/module-for', ['exports', './qunit-module', 'ember-test-helpers'], function (exports, _qunitModule, _emberTestHelpers) { 'use strict'; - function moduleFor(name, description, callbacks) { - qunit_module.createModule(ember_test_helpers.TestModule, name, description, callbacks); - } exports['default'] = moduleFor; -}); -define('ember-qunit/only', ['exports', 'ember-qunit/test-wrapper', 'qunit'], function (exports, testWrapper, qunit) { - - 'use strict'; - - function only(/* testName, expected, callback, async */) { - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; ++_key) { - args[_key] = arguments[_key]; - } - args.unshift(qunit.only); - testWrapper['default'].apply(null, args); + function moduleFor(name, description, callbacks) { + _qunitModule.createModule(_emberTestHelpers.TestModule, name, description, callbacks); } - exports['default'] = only; - }); -define('ember-qunit/qunit-module', ['exports', 'qunit'], function (exports, qunit) { - +define('ember-qunit/qunit-module', ['exports', 'ember', 'qunit'], function (exports, _ember, _qunit) { 'use strict'; exports.createModule = createModule; function beforeEachCallback(callbacks) { - if (typeof callbacks !== 'object') { return; } - if (!callbacks) { return; } + if (typeof callbacks !== 'object') { + return; + } + if (!callbacks) { + return; + } var beforeEach; - if (callbacks.setup) { - beforeEach = callbacks.setup; - delete callbacks.setup; - } - if (callbacks.beforeEach) { beforeEach = callbacks.beforeEach; delete callbacks.beforeEach; @@ -195,16 +196,15 @@ define('ember-qunit/qunit-module', ['exports', 'qunit'], function (exports, quni } function afterEachCallback(callbacks) { - if (typeof callbacks !== 'object') { return; } - if (!callbacks) { return; } + if (typeof callbacks !== 'object') { + return; + } + if (!callbacks) { + return; + } var afterEach; - if (callbacks.teardown) { - afterEach = callbacks.teardown; - delete callbacks.teardown; - } - if (callbacks.afterEach) { afterEach = callbacks.afterEach; delete callbacks.afterEach; @@ -214,129 +214,349 @@ define('ember-qunit/qunit-module', ['exports', 'qunit'], function (exports, quni } function createModule(Constructor, name, description, callbacks) { - var beforeEach = beforeEachCallback(callbacks || description); - var afterEach = afterEachCallback(callbacks || description); + var _beforeEach = beforeEachCallback(callbacks || description); + var _afterEach = afterEachCallback(callbacks || description); var module = new Constructor(name, description, callbacks); - qunit.module(module.name, { - setup: function(assert) { - var done = assert.async(); - return module.setup().then(function() { - if (beforeEach) { - beforeEach.call(module.context, assert); + _qunit.module(module.name, { + beforeEach: function beforeEach() { + var _this = this, + _arguments = arguments; + + // provide the test context to the underlying module + module.setContext(this); + + return module.setup.apply(module, arguments).then(function () { + if (_beforeEach) { + return _beforeEach.apply(_this, _arguments); } - })['finally'](done); + }); }, - teardown: function(assert) { - if (afterEach) { - afterEach.call(module.context, assert); + afterEach: function afterEach() { + var _arguments2 = arguments; + + var result = undefined; + + if (_afterEach) { + result = _afterEach.apply(this, arguments); } - var done = assert.async(); - return module.teardown()['finally'](done); + + return _ember['default'].RSVP.resolve(result).then(function () { + return module.teardown.apply(module, _arguments2); + }); } }); } - }); -define('ember-qunit/test-wrapper', ['exports', 'ember', 'ember-test-helpers'], function (exports, Ember, ember_test_helpers) { - +define('ember-test-helpers', ['exports', 'ember', 'ember-test-helpers/test-module', 'ember-test-helpers/test-module-for-acceptance', 'ember-test-helpers/test-module-for-integration', 'ember-test-helpers/test-module-for-component', 'ember-test-helpers/test-module-for-model', 'ember-test-helpers/test-context', 'ember-test-helpers/test-resolver'], function (exports, _ember, _emberTestHelpersTestModule, _emberTestHelpersTestModuleForAcceptance, _emberTestHelpersTestModuleForIntegration, _emberTestHelpersTestModuleForComponent, _emberTestHelpersTestModuleForModel, _emberTestHelpersTestContext, _emberTestHelpersTestResolver) { 'use strict'; - function testWrapper(qunit /*, testName, expected, callback, async */) { - var callback; - for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; ++_key) { - args[_key - 1] = arguments[_key]; + _ember['default'].testing = true; + + exports.TestModule = _emberTestHelpersTestModule['default']; + exports.TestModuleForAcceptance = _emberTestHelpersTestModuleForAcceptance['default']; + exports.TestModuleForIntegration = _emberTestHelpersTestModuleForIntegration['default']; + exports.TestModuleForComponent = _emberTestHelpersTestModuleForComponent['default']; + exports.TestModuleForModel = _emberTestHelpersTestModuleForModel['default']; + exports.getContext = _emberTestHelpersTestContext.getContext; + exports.setContext = _emberTestHelpersTestContext.setContext; + exports.unsetContext = _emberTestHelpersTestContext.unsetContext; + exports.setResolver = _emberTestHelpersTestResolver.setResolver; +}); +define('ember-test-helpers/-legacy-overrides', ['exports', 'ember', './has-ember-version'], function (exports, _ember, _hasEmberVersion) { + 'use strict'; + + exports.preGlimmerSetupIntegrationForComponent = preGlimmerSetupIntegrationForComponent; + + function preGlimmerSetupIntegrationForComponent() { + var module = this; + var context = this.context; + + this.actionHooks = {}; + + context.dispatcher = this.container.lookup('event_dispatcher:main') || _ember['default'].EventDispatcher.create(); + context.dispatcher.setup({}, '#ember-testing'); + context.actions = module.actionHooks; + + (this.registry || this.container).register('component:-test-holder', _ember['default'].Component.extend()); + + context.render = function (template) { + // in case `this.render` is called twice, make sure to teardown the first invocation + module.teardownComponent(); + + if (!template) { + throw new Error("in a component integration test you must pass a template to `render()`"); + } + if (_ember['default'].isArray(template)) { + template = template.join(''); + } + if (typeof template === 'string') { + template = _ember['default'].Handlebars.compile(template); + } + module.component = module.container.lookupFactory('component:-test-holder').create({ + layout: template + }); + + module.component.set('context', context); + module.component.set('controller', context); + + _ember['default'].run(function () { + module.component.appendTo('#ember-testing'); + }); + + context._element = module.component.element; + }; + + context.$ = function () { + return module.component.$.apply(module.component, arguments); + }; + + context.set = function (key, value) { + var ret = _ember['default'].run(function () { + return _ember['default'].set(context, key, value); + }); + + if (_hasEmberVersion['default'](2, 0)) { + return ret; + } + }; + + context.setProperties = function (hash) { + var ret = _ember['default'].run(function () { + return _ember['default'].setProperties(context, hash); + }); + + if (_hasEmberVersion['default'](2, 0)) { + return ret; + } + }; + + context.get = function (key) { + return _ember['default'].get(context, key); + }; + + context.getProperties = function () { + var args = Array.prototype.slice.call(arguments); + return _ember['default'].getProperties(context, args); + }; + + context.on = function (actionName, handler) { + module.actionHooks[actionName] = handler; + }; + + context.send = function (actionName) { + var hook = module.actionHooks[actionName]; + if (!hook) { + throw new Error("integration testing template received unexpected action " + actionName); + } + hook.apply(module, Array.prototype.slice.call(arguments, 1)); + }; + + context.clearRender = function () { + module.teardownComponent(); + }; + } +}); +define('ember-test-helpers/abstract-test-module', ['exports', './wait', './test-context', 'ember'], function (exports, _wait, _testContext, _ember) { + 'use strict'; + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + // calling this `merge` here because we cannot + // actually assume it is like `Object.assign` + // with > 2 args + var merge = _ember['default'].assign || _ember['default'].merge; + + var _default = (function () { + function _default(name, options) { + _classCallCheck(this, _default); + + this.context = undefined; + this.name = name; + this.callbacks = options || {}; + + this.initSetupSteps(); + this.initTeardownSteps(); } - function wrapper() { - var context = ember_test_helpers.getContext(); + _default.prototype.setup = function setup(assert) { + var _this = this; - var result = callback.apply(context, arguments); + return this.invokeSteps(this.setupSteps, this, assert).then(function () { + _this.contextualizeCallbacks(); + return _this.invokeSteps(_this.contextualizedSetupSteps, _this.context, assert); + }); + }; - function failTestOnPromiseRejection(reason) { - var message; - if (reason instanceof Error) { - message = reason.stack; - if (reason.message && message.indexOf(reason.message) < 0) { - // PhantomJS has a `stack` that does not contain the actual - // exception message. - message = Ember['default'].inspect(reason) + "\n" + message; - } - } else { - message = Ember['default'].inspect(reason); - } - ok(false, message); + _default.prototype.teardown = function teardown(assert) { + var _this2 = this; + + return this.invokeSteps(this.contextualizedTeardownSteps, this.context, assert).then(function () { + return _this2.invokeSteps(_this2.teardownSteps, _this2, assert); + }).then(function () { + _this2.cache = null; + _this2.cachedCalls = null; + }); + }; + + _default.prototype.initSetupSteps = function initSetupSteps() { + this.setupSteps = []; + this.contextualizedSetupSteps = []; + + if (this.callbacks.beforeSetup) { + this.setupSteps.push(this.callbacks.beforeSetup); + delete this.callbacks.beforeSetup; } - Ember['default'].run(function(){ - QUnit.stop(); - Ember['default'].RSVP.Promise.resolve(result)['catch'](failTestOnPromiseRejection)['finally'](QUnit.start); + this.setupSteps.push(this.setupContext); + this.setupSteps.push(this.setupTestElements); + this.setupSteps.push(this.setupAJAXListeners); + + if (this.callbacks.setup) { + this.contextualizedSetupSteps.push(this.callbacks.setup); + delete this.callbacks.setup; + } + }; + + _default.prototype.invokeSteps = function invokeSteps(steps, context, assert) { + steps = steps.slice(); + + function nextStep() { + var step = steps.shift(); + if (step) { + // guard against exceptions, for example missing components referenced from needs. + return new _ember['default'].RSVP.Promise(function (resolve) { + resolve(step.call(context, assert)); + }).then(nextStep); + } else { + return _ember['default'].RSVP.resolve(); + } + } + return nextStep(); + }; + + _default.prototype.contextualizeCallbacks = function contextualizeCallbacks() {}; + + _default.prototype.initTeardownSteps = function initTeardownSteps() { + this.teardownSteps = []; + this.contextualizedTeardownSteps = []; + + if (this.callbacks.teardown) { + this.contextualizedTeardownSteps.push(this.callbacks.teardown); + delete this.callbacks.teardown; + } + + this.teardownSteps.push(this.teardownContext); + this.teardownSteps.push(this.teardownTestElements); + this.teardownSteps.push(this.teardownAJAXListeners); + + if (this.callbacks.afterTeardown) { + this.teardownSteps.push(this.callbacks.afterTeardown); + delete this.callbacks.afterTeardown; + } + }; + + _default.prototype.setupTestElements = function setupTestElements() { + var testEl = document.querySelector('#ember-testing'); + if (!testEl) { + var element = document.createElement('div'); + element.setAttribute('id', 'ember-testing'); + + document.body.appendChild(element); + this.fixtureResetValue = ''; + } else { + this.fixtureResetValue = testEl.innerHTML; + } + }; + + _default.prototype.setupContext = function setupContext(options) { + var context = this.getContext(); + + merge(context, { + dispatcher: null, + inject: {} }); - } + merge(context, options); - if (args.length === 2) { - callback = args.splice(1, 1, wrapper)[0]; - } else { - callback = args.splice(2, 1, wrapper)[0]; - } + this.setToString(); + _testContext.setContext(context); + this.context = context; + }; - qunit.apply(null, args); - } - exports['default'] = testWrapper; + _default.prototype.setContext = function setContext(context) { + this.context = context; + }; + _default.prototype.getContext = function getContext() { + if (this.context) { + return this.context; + } + + return this.context = _testContext.getContext() || {}; + }; + + _default.prototype.setToString = function setToString() { + var _this3 = this; + + this.context.toString = function () { + if (_this3.subjectName) { + return 'test context for: ' + _this3.subjectName; + } + + if (_this3.name) { + return 'test context for: ' + _this3.name; + } + }; + }; + + _default.prototype.setupAJAXListeners = function setupAJAXListeners() { + _wait._setupAJAXHooks(); + }; + + _default.prototype.teardownAJAXListeners = function teardownAJAXListeners() { + _wait._teardownAJAXHooks(); + }; + + _default.prototype.teardownTestElements = function teardownTestElements() { + document.getElementById('ember-testing').innerHTML = this.fixtureResetValue; + + // Ember 2.0.0 removed Ember.View as public API, so only do this when + // Ember.View is present + if (_ember['default'].View && _ember['default'].View.views) { + _ember['default'].View.views = {}; + } + }; + + _default.prototype.teardownContext = function teardownContext() { + var context = this.context; + this.context = undefined; + _testContext.unsetContext(); + + if (context && context.dispatcher && !context.dispatcher.isDestroyed) { + _ember['default'].run(function () { + context.dispatcher.destroy(); + }); + } + }; + + return _default; + })(); + + exports['default'] = _default; }); -define('ember-qunit/test', ['exports', 'ember-qunit/test-wrapper', 'qunit'], function (exports, testWrapper, qunit) { - - 'use strict'; - - function test(/* testName, expected, callback, async */) { - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; ++_key) { - args[_key] = arguments[_key]; - } - args.unshift(qunit.test); - testWrapper['default'].apply(null, args); - } - exports['default'] = test; - -}); -define('ember-test-helpers', ['exports', 'ember', 'ember-test-helpers/test-module', 'ember-test-helpers/test-module-for-component', 'ember-test-helpers/test-module-for-model', 'ember-test-helpers/test-context', 'ember-test-helpers/test-resolver'], function (exports, Ember, TestModule, TestModuleForComponent, TestModuleForModel, test_context, test_resolver) { - - 'use strict'; - - Ember['default'].testing = true; - - exports.TestModule = TestModule['default']; - exports.TestModuleForComponent = TestModuleForComponent['default']; - exports.TestModuleForModel = TestModuleForModel['default']; - exports.getContext = test_context.getContext; - exports.setContext = test_context.setContext; - exports.setResolver = test_resolver.setResolver; - -}); -define('ember-test-helpers/build-registry', ['exports', 'ember'], function (exports, Ember) { +define('ember-test-helpers/build-registry', ['exports', 'ember'], function (exports, _ember) { + /* globals global, self, requirejs, require */ 'use strict'; function exposeRegistryMethodsWithoutDeprecations(container) { - var methods = [ - 'register', - 'unregister', - 'resolve', - 'normalize', - 'typeInjection', - 'injection', - 'factoryInjection', - 'factoryTypeInjection', - 'has', - 'options', - 'optionsForType' - ]; + var methods = ['register', 'unregister', 'resolve', 'normalize', 'typeInjection', 'injection', 'factoryInjection', 'factoryTypeInjection', 'has', 'options', 'optionsForType']; function exposeRegistryMethod(container, method) { if (method in container) { - container[method] = function() { + container[method] = function () { return container._registry[method].apply(container._registry, arguments); }; } @@ -347,18 +567,20 @@ define('ember-test-helpers/build-registry', ['exports', 'ember'], function (expo } } - var Owner = (function() { - if (Ember['default']._RegistryProxyMixin && Ember['default']._ContainerProxyMixin) { - return Ember['default'].Object.extend(Ember['default']._RegistryProxyMixin, Ember['default']._ContainerProxyMixin); + var Owner = (function () { + if (_ember['default']._RegistryProxyMixin && _ember['default']._ContainerProxyMixin) { + return _ember['default'].Object.extend(_ember['default']._RegistryProxyMixin, _ember['default']._ContainerProxyMixin); } - return Ember['default'].Object.extend(); + return _ember['default'].Object.extend(); })(); - exports['default'] = function(resolver) { + exports['default'] = function (resolver) { var fallbackRegistry, registry, container; - var namespace = Ember['default'].Object.create({ - Resolver: { create: function() { return resolver; } } + var namespace = _ember['default'].Object.create({ + Resolver: { create: function create() { + return resolver; + } } }); function register(name, factory) { @@ -369,14 +591,18 @@ define('ember-test-helpers/build-registry', ['exports', 'ember'], function (expo } } - if (Ember['default'].Application.buildRegistry) { - fallbackRegistry = Ember['default'].Application.buildRegistry(namespace); - fallbackRegistry.register('component-lookup:main', Ember['default'].ComponentLookup); + if (_ember['default'].Application.buildRegistry) { + fallbackRegistry = _ember['default'].Application.buildRegistry(namespace); + fallbackRegistry.register('component-lookup:main', _ember['default'].ComponentLookup); - registry = new Ember['default'].Registry({ + registry = new _ember['default'].Registry({ fallback: fallbackRegistry }); + if (_ember['default'].ApplicationInstance && _ember['default'].ApplicationInstance.setupRegistry) { + _ember['default'].ApplicationInstance.setupRegistry(registry); + } + // these properties are set on the fallback registry by `buildRegistry` // and on the primary registry within the ApplicationInstance constructor // but we need to manually recreate them since ApplicationInstance's are not @@ -395,8 +621,8 @@ define('ember-test-helpers/build-registry', ['exports', 'ember'], function (expo exposeRegistryMethodsWithoutDeprecations(container); } else { - container = Ember['default'].Application.buildContainer(namespace); - container.register('component-lookup:main', Ember['default'].ComponentLookup); + container = _ember['default'].Application.buildContainer(namespace); + container.register('component-lookup:main', _ember['default'].ComponentLookup); } // Ember 1.10.0 did not properly add `view:toplevel` or `view:default` @@ -404,18 +630,26 @@ define('ember-test-helpers/build-registry', ['exports', 'ember'], function (expo // // Ember 2.0.0 removed Ember.View as public API, so only do this when // Ember.View is present - if (Ember['default'].View) { - register('view:toplevel', Ember['default'].View.extend()); + if (_ember['default'].View) { + register('view:toplevel', _ember['default'].View.extend()); } // Ember 2.0.0 removed Ember._MetamorphView from the Ember global, so only // do this when present - if (Ember['default']._MetamorphView) { - register('view:default', Ember['default']._MetamorphView); + if (_ember['default']._MetamorphView) { + register('view:default', _ember['default']._MetamorphView); } var globalContext = typeof global === 'object' && global || self; - if (globalContext.DS) { + if (requirejs.entries['ember-data/setup-container']) { + // ember-data is a proper ember-cli addon since 2.3; if no 'import + // 'ember-data'' is present somewhere in the tests, there is also no `DS` + // available on the globalContext and hence ember-data wouldn't be setup + // correctly for the tests; that's why we import and call setupContainer + // here; also see https://github.com/emberjs/data/issues/4071 for context + var setupContainer = require('ember-data/setup-container')['default']; + setupContainer(registry || container); + } else if (globalContext.DS) { var DS = globalContext.DS; if (DS._setupContainer) { DS._setupContainer(registry || container); @@ -434,30 +668,26 @@ define('ember-test-helpers/build-registry', ['exports', 'ember'], function (expo registry: registry, container: container }; - } - + }; }); -define('ember-test-helpers/has-ember-version', ['exports', 'ember'], function (exports, Ember) { - +define('ember-test-helpers/has-ember-version', ['exports', 'ember'], function (exports, _ember) { 'use strict'; - function hasEmberVersion(major, minor) { - var numbers = Ember['default'].VERSION.split('-')[0].split('.'); - var actualMajor = parseInt(numbers[0], 10); - var actualMinor = parseInt(numbers[1], 10); - return actualMajor > major || (actualMajor === major && actualMinor >= minor); - } exports['default'] = hasEmberVersion; + function hasEmberVersion(major, minor) { + var numbers = _ember['default'].VERSION.split('-')[0].split('.'); + var actualMajor = parseInt(numbers[0], 10); + var actualMinor = parseInt(numbers[1], 10); + return actualMajor > major || actualMajor === major && actualMinor >= minor; + } }); -define('ember-test-helpers/test-context', ['exports'], function (exports) { - - 'use strict'; +define("ember-test-helpers/test-context", ["exports"], function (exports) { + "use strict"; exports.setContext = setContext; exports.getContext = getContext; exports.unsetContext = unsetContext; - var __test_context__; function setContext(context) { @@ -471,16 +701,82 @@ define('ember-test-helpers/test-context', ['exports'], function (exports) { function unsetContext() { __test_context__ = undefined; } - }); -define('ember-test-helpers/test-module-for-component', ['exports', 'ember-test-helpers/test-module', 'ember', 'ember-test-helpers/test-resolver'], function (exports, TestModule, Ember, test_resolver) { - +define('ember-test-helpers/test-module-for-acceptance', ['exports', './abstract-test-module', 'ember', './test-context'], function (exports, _abstractTestModule, _ember, _testContext) { 'use strict'; - exports['default'] = TestModule['default'].extend({ - isComponentTestModule: true, + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + + var _default = (function (_AbstractTestModule) { + _inherits(_default, _AbstractTestModule); + + function _default() { + _classCallCheck(this, _default); + + _AbstractTestModule.apply(this, arguments); + } + + _default.prototype.setupContext = function setupContext() { + _AbstractTestModule.prototype.setupContext.call(this, { application: this.createApplication() }); + }; + + _default.prototype.teardownContext = function teardownContext() { + _ember['default'].run(function () { + _testContext.getContext().application.destroy(); + }); + + _AbstractTestModule.prototype.teardownContext.call(this); + }; + + _default.prototype.createApplication = function createApplication() { + var _callbacks = this.callbacks; + var Application = _callbacks.Application; + var config = _callbacks.config; + + var application = undefined; + + _ember['default'].run(function () { + application = Application.create(config); + application.setupForTesting(); + application.injectTestHelpers(); + }); + + return application; + }; + + return _default; + })(_abstractTestModule['default']); + + exports['default'] = _default; +}); +define('ember-test-helpers/test-module-for-component', ['exports', './test-module', 'ember', './has-ember-version', './-legacy-overrides'], function (exports, _testModule, _ember, _hasEmberVersion, _legacyOverrides) { + 'use strict'; + + exports.setupComponentIntegrationTest = _setupComponentIntegrationTest; + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + + var ACTION_KEY = undefined; + if (_hasEmberVersion['default'](2, 0)) { + ACTION_KEY = 'actions'; + } else { + ACTION_KEY = '_actions'; + } + + var isPreGlimmer = !_hasEmberVersion['default'](1, 13); + + var getOwner = _ember['default'].getOwner; + + var _default = (function (_TestModule) { + _inherits(_default, _TestModule); + + function _default(componentName, description, callbacks) { + _classCallCheck(this, _default); - init: function(componentName, description, callbacks) { // Allow `description` to be omitted if (!callbacks && typeof description === 'object') { callbacks = description; @@ -489,30 +785,21 @@ define('ember-test-helpers/test-module-for-component', ['exports', 'ember-test-h callbacks = {}; } + var integrationOption = callbacks.integration; + + _TestModule.call(this, 'component:' + componentName, description, callbacks); + this.componentName = componentName; - if (callbacks.needs || callbacks.unit || callbacks.integration === false) { + if (callbacks.needs || callbacks.unit || integrationOption === false) { this.isUnitTest = true; - } else if (callbacks.integration) { + } else if (integrationOption) { this.isUnitTest = false; } else { - Ember['default'].deprecate( - "the component:" + componentName + " test module is implicitly running in unit test mode, " + - "which will change to integration test mode by default in an upcoming version of " + - "ember-test-helpers. Add `unit: true` or a `needs:[]` list to explicitly opt in to unit " + - "test mode.", - false, - { id: 'ember-test-helpers.test-module-for-component.test-type', until: '0.6.0' } - ); + _ember['default'].deprecate("the component:" + componentName + " test module is implicitly running in unit test mode, " + "which will change to integration test mode by default in an upcoming version of " + "ember-test-helpers. Add `unit: true` or a `needs:[]` list to explicitly opt in to unit " + "test mode.", false, { id: 'ember-test-helpers.test-module-for-component.test-type', until: '0.6.0' }); this.isUnitTest = true; } - if (description) { - this._super.call(this, 'component:' + componentName, description, callbacks); - } else { - this._super.call(this, 'component:' + componentName, callbacks); - } - if (!this.isUnitTest && !this.isLegacy) { callbacks.integration = true; } @@ -520,35 +807,40 @@ define('ember-test-helpers/test-module-for-component', ['exports', 'ember-test-h if (this.isUnitTest || this.isLegacy) { this.setupSteps.push(this.setupComponentUnitTest); } else { - this.callbacks.subject = function() { - throw new Error("component integration tests do not support `subject()`."); + this.callbacks.subject = function () { + throw new Error("component integration tests do not support `subject()`. Instead, render the component as if it were HTML: `this.render('');`. For more information, read: http://guides.emberjs.com/v2.2.0/testing/testing-components/"); }; this.setupSteps.push(this.setupComponentIntegrationTest); this.teardownSteps.unshift(this.teardownComponent); } - if (Ember['default'].View && Ember['default'].View.views) { + if (_ember['default'].View && _ember['default'].View.views) { this.setupSteps.push(this._aliasViewRegistry); this.teardownSteps.unshift(this._resetViewRegistry); } - }, + } - _aliasViewRegistry: function() { - this._originalGlobalViewRegistry = Ember['default'].View.views; + _default.prototype.initIntegration = function initIntegration(options) { + this.isLegacy = options.integration === 'legacy'; + this.isIntegration = options.integration !== 'legacy'; + }; + + _default.prototype._aliasViewRegistry = function _aliasViewRegistry() { + this._originalGlobalViewRegistry = _ember['default'].View.views; var viewRegistry = this.container.lookup('-view-registry:main'); if (viewRegistry) { - Ember['default'].View.views = viewRegistry; + _ember['default'].View.views = viewRegistry; } - }, + }; - _resetViewRegistry: function() { - Ember['default'].View.views = this._originalGlobalViewRegistry; - }, + _default.prototype._resetViewRegistry = function _resetViewRegistry() { + _ember['default'].View.views = this._originalGlobalViewRegistry; + }; - setupComponentUnitTest: function() { + _default.prototype.setupComponentUnitTest = function setupComponentUnitTest() { var _this = this; - var resolver = test_resolver.getResolver(); + var resolver = this.resolver; var context = this.context; var layoutName = 'template:components/' + this.componentName; @@ -561,114 +853,51 @@ define('ember-test-helpers/test-module-for-component', ['exports', 'ember-test-h thingToRegisterWith.injection(this.subjectName, 'layout', layoutName); } - context.dispatcher = this.container.lookup('event_dispatcher:main') || Ember['default'].EventDispatcher.create(); + context.dispatcher = this.container.lookup('event_dispatcher:main') || _ember['default'].EventDispatcher.create(); context.dispatcher.setup({}, '#ember-testing'); - this.callbacks.render = function() { + context._element = null; + + this.callbacks.render = function () { var subject; - Ember['default'].run(function(){ + _ember['default'].run(function () { subject = context.subject(); subject.appendTo('#ember-testing'); }); - _this.teardownSteps.unshift(function() { - Ember['default'].run(function() { - Ember['default'].tryInvoke(subject, 'destroy'); + context._element = subject.element; + + _this.teardownSteps.unshift(function () { + _ember['default'].run(function () { + _ember['default'].tryInvoke(subject, 'destroy'); }); }); }; - this.callbacks.append = function() { - Ember['default'].deprecate( - 'this.append() is deprecated. Please use this.render() or this.$() instead.', - false, - { id: 'ember-test-helpers.test-module-for-component.append', until: '0.6.0' } - ); + this.callbacks.append = function () { + _ember['default'].deprecate('this.append() is deprecated. Please use this.render() or this.$() instead.', false, { id: 'ember-test-helpers.test-module-for-component.append', until: '0.6.0' }); return context.$(); }; - context.$ = function() { + context.$ = function () { this.render(); var subject = this.subject(); return subject.$.apply(subject, arguments); }; - }, + }; - setupComponentIntegrationTest: function() { - var module = this; - var context = this.context; + _default.prototype.setupComponentIntegrationTest = function setupComponentIntegrationTest() { + if (isPreGlimmer) { + return _legacyOverrides.preGlimmerSetupIntegrationForComponent.apply(this, arguments); + } else { + return _setupComponentIntegrationTest.apply(this, arguments); + } + }; - this.actionHooks = {}; - - context.dispatcher = this.container.lookup('event_dispatcher:main') || Ember['default'].EventDispatcher.create(); - context.dispatcher.setup({}, '#ember-testing'); - context.actions = module.actionHooks; - - (this.registry || this.container).register('component:-test-holder', Ember['default'].Component.extend()); - - context.render = function(template) { - if (!template) { - throw new Error("in a component integration test you must pass a template to `render()`"); - } - if (Ember['default'].isArray(template)) { - template = template.join(''); - } - if (typeof template === 'string') { - template = Ember['default'].Handlebars.compile(template); - } - module.component = module.container.lookupFactory('component:-test-holder').create({ - layout: template - }); - - module.component.set('context' ,context); - module.component.set('controller', context); - - Ember['default'].run(function() { - module.component.appendTo('#ember-testing'); - }); - }; - - context.$ = function() { - return module.component.$.apply(module.component, arguments); - }; - - context.set = function(key, value) { - Ember['default'].run(function() { - Ember['default'].set(context, key, value); - }); - }; - - context.setProperties = function(hash) { - Ember['default'].run(function() { - Ember['default'].setProperties(context, hash); - }); - }; - - context.get = function(key) { - return Ember['default'].get(context, key); - }; - - context.getProperties = function() { - var args = Array.prototype.slice.call(arguments); - return Ember['default'].getProperties(context, args); - }; - - context.on = function(actionName, handler) { - module.actionHooks[actionName] = handler; - }; - context.send = function(actionName) { - var hook = module.actionHooks[actionName]; - if (!hook) { - throw new Error("integration testing template received unexpected action " + actionName); - } - hook.apply(module, Array.prototype.slice.call(arguments, 1)); - }; - }, - - setupContext: function() { - this._super.call(this); + _default.prototype.setupContext = function setupContext() { + _TestModule.prototype.setupContext.call(this); // only setup the injection if we are running against a version // of Ember that has `-view-registry:main` (Ember >= 1.12) @@ -677,35 +906,409 @@ define('ember-test-helpers/test-module-for-component', ['exports', 'ember-test-h } if (!this.isUnitTest && !this.isLegacy) { - this.context.factory = function() {}; + this.context.factory = function () {}; } - }, + }; - teardownComponent: function() { + _default.prototype.teardownComponent = function teardownComponent() { var component = this.component; if (component) { - Ember['default'].run(function() { + _ember['default'].run(component, 'destroy'); + this.component = null; + } + }; + + return _default; + })(_testModule['default']); + + exports['default'] = _default; + + function _setupComponentIntegrationTest() { + var module = this; + var context = this.context; + + this.actionHooks = context[ACTION_KEY] = {}; + context.dispatcher = this.container.lookup('event_dispatcher:main') || _ember['default'].EventDispatcher.create(); + context.dispatcher.setup({}, '#ember-testing'); + + var hasRendered = false; + var OutletView = module.container.lookupFactory('view:-outlet'); + var OutletTemplate = module.container.lookup('template:-outlet'); + var toplevelView = module.component = OutletView.create(); + var hasOutletTemplate = !!OutletTemplate; + var outletState = { + render: { + owner: getOwner ? getOwner(module.container) : undefined, + into: undefined, + outlet: 'main', + name: 'application', + controller: module.context, + ViewClass: undefined, + template: OutletTemplate + }, + + outlets: {} + }; + + var element = document.getElementById('ember-testing'); + var templateId = 0; + + if (hasOutletTemplate) { + _ember['default'].run(function () { + toplevelView.setOutletState(outletState); + }); + } + + context.render = function (template) { + if (!template) { + throw new Error("in a component integration test you must pass a template to `render()`"); + } + if (_ember['default'].isArray(template)) { + template = template.join(''); + } + if (typeof template === 'string') { + template = _ember['default'].Handlebars.compile(template); + } + + var templateFullName = 'template:-undertest-' + ++templateId; + this.registry.register(templateFullName, template); + var stateToRender = { + owner: getOwner ? getOwner(module.container) : undefined, + into: undefined, + outlet: 'main', + name: 'index', + controller: module.context, + ViewClass: undefined, + template: module.container.lookup(templateFullName), + outlets: {} + }; + + if (hasOutletTemplate) { + stateToRender.name = 'index'; + outletState.outlets.main = { render: stateToRender, outlets: {} }; + } else { + stateToRender.name = 'application'; + outletState = { render: stateToRender, outlets: {} }; + } + + _ember['default'].run(function () { + toplevelView.setOutletState(outletState); + }); + + if (!hasRendered) { + _ember['default'].run(module.component, 'appendTo', '#ember-testing'); + hasRendered = true; + } + + // ensure the element is based on the wrapping toplevel view + // Ember still wraps the main application template with a + // normal tagged view + context._element = element = document.querySelector('#ember-testing > .ember-view'); + }; + + context.$ = function (selector) { + // emulates Ember internal behavor of `this.$` in a component + // https://github.com/emberjs/ember.js/blob/v2.5.1/packages/ember-views/lib/views/states/has_element.js#L18 + return selector ? _ember['default'].$(selector, element) : _ember['default'].$(element); + }; + + context.set = function (key, value) { + var ret = _ember['default'].run(function () { + return _ember['default'].set(context, key, value); + }); + + if (_hasEmberVersion['default'](2, 0)) { + return ret; + } + }; + + context.setProperties = function (hash) { + var ret = _ember['default'].run(function () { + return _ember['default'].setProperties(context, hash); + }); + + if (_hasEmberVersion['default'](2, 0)) { + return ret; + } + }; + + context.get = function (key) { + return _ember['default'].get(context, key); + }; + + context.getProperties = function () { + var args = Array.prototype.slice.call(arguments); + return _ember['default'].getProperties(context, args); + }; + + context.on = function (actionName, handler) { + module.actionHooks[actionName] = handler; + }; + + context.send = function (actionName) { + var hook = module.actionHooks[actionName]; + if (!hook) { + throw new Error("integration testing template received unexpected action " + actionName); + } + hook.apply(module.context, Array.prototype.slice.call(arguments, 1)); + }; + + context.clearRender = function () { + _ember['default'].run(function () { + toplevelView.setOutletState({ + render: { + owner: module.container, + into: undefined, + outlet: 'main', + name: 'application', + controller: module.context, + ViewClass: undefined, + template: undefined + }, + outlets: {} + }); + }); + }; + } +}); +define('ember-test-helpers/test-module-for-integration', ['exports', 'ember', './abstract-test-module', './test-resolver', './build-registry', './has-ember-version', './-legacy-overrides', './test-module-for-component'], function (exports, _ember, _abstractTestModule, _testResolver, _buildRegistry, _hasEmberVersion, _legacyOverrides, _testModuleForComponent) { + 'use strict'; + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + + var ACTION_KEY = undefined; + if (_hasEmberVersion['default'](2, 0)) { + ACTION_KEY = 'actions'; + } else { + ACTION_KEY = '_actions'; + } + + var isPreGlimmer = !_hasEmberVersion['default'](1, 13); + + var _default = (function (_AbstractTestModule) { + _inherits(_default, _AbstractTestModule); + + function _default() { + _classCallCheck(this, _default); + + _AbstractTestModule.apply(this, arguments); + this.resolver = this.callbacks.resolver || _testResolver.getResolver(); + } + + _default.prototype.initSetupSteps = function initSetupSteps() { + this.setupSteps = []; + this.contextualizedSetupSteps = []; + + if (this.callbacks.beforeSetup) { + this.setupSteps.push(this.callbacks.beforeSetup); + delete this.callbacks.beforeSetup; + } + + this.setupSteps.push(this.setupContainer); + this.setupSteps.push(this.setupContext); + this.setupSteps.push(this.setupTestElements); + this.setupSteps.push(this.setupAJAXListeners); + this.setupSteps.push(this.setupComponentIntegrationTest); + + if (_ember['default'].View && _ember['default'].View.views) { + this.setupSteps.push(this._aliasViewRegistry); + } + + if (this.callbacks.setup) { + this.contextualizedSetupSteps.push(this.callbacks.setup); + delete this.callbacks.setup; + } + }; + + _default.prototype.initTeardownSteps = function initTeardownSteps() { + this.teardownSteps = []; + this.contextualizedTeardownSteps = []; + + if (this.callbacks.teardown) { + this.contextualizedTeardownSteps.push(this.callbacks.teardown); + delete this.callbacks.teardown; + } + + this.teardownSteps.push(this.teardownContainer); + this.teardownSteps.push(this.teardownContext); + this.teardownSteps.push(this.teardownAJAXListeners); + this.teardownSteps.push(this.teardownComponent); + + if (_ember['default'].View && _ember['default'].View.views) { + this.teardownSteps.push(this._resetViewRegistry); + } + + this.teardownSteps.push(this.teardownTestElements); + + if (this.callbacks.afterTeardown) { + this.teardownSteps.push(this.callbacks.afterTeardown); + delete this.callbacks.afterTeardown; + } + }; + + _default.prototype.setupContainer = function setupContainer() { + var resolver = this.resolver; + var items = _buildRegistry['default'](resolver); + + this.container = items.container; + this.registry = items.registry; + + if (_hasEmberVersion['default'](1, 13)) { + var thingToRegisterWith = this.registry || this.container; + var router = resolver.resolve('router:main'); + router = router || _ember['default'].Router.extend(); + thingToRegisterWith.register('router:main', router); + } + }; + + _default.prototype.setupContext = function setupContext() { + var subjectName = this.subjectName; + var container = this.container; + + var factory = function factory() { + return container.lookupFactory(subjectName); + }; + + _AbstractTestModule.prototype.setupContext.call(this, { + container: this.container, + registry: this.registry, + factory: factory, + register: function register() { + var target = this.registry || this.container; + return target.register.apply(target, arguments); + } + }); + + var context = this.context; + + if (_ember['default'].setOwner) { + _ember['default'].setOwner(context, this.container.owner); + } + + if (_ember['default'].inject) { + var keys = (Object.keys || _ember['default'].keys)(_ember['default'].inject); + keys.forEach(function (typeName) { + context.inject[typeName] = function (name, opts) { + var alias = opts && opts.as || name; + _ember['default'].run(function () { + _ember['default'].set(context, alias, context.container.lookup(typeName + ':' + name)); + }); + }; + }); + } + + // only setup the injection if we are running against a version + // of Ember that has `-view-registry:main` (Ember >= 1.12) + if (this.container.lookupFactory('-view-registry:main')) { + (this.registry || this.container).injection('component', '_viewRegistry', '-view-registry:main'); + } + }; + + _default.prototype.setupComponentIntegrationTest = function setupComponentIntegrationTest() { + if (isPreGlimmer) { + return _legacyOverrides.preGlimmerSetupIntegrationForComponent.apply(this, arguments); + } else { + return _testModuleForComponent.setupComponentIntegrationTest.apply(this, arguments); + } + }; + + _default.prototype.teardownComponent = function teardownComponent() { + var component = this.component; + if (component) { + _ember['default'].run(function () { component.destroy(); }); } - } - }); + }; + _default.prototype.teardownContainer = function teardownContainer() { + var container = this.container; + _ember['default'].run(function () { + container.destroy(); + }); + }; + + // allow arbitrary named factories, like rspec let + + _default.prototype.contextualizeCallbacks = function contextualizeCallbacks() { + var callbacks = this.callbacks; + var context = this.context; + + this.cache = this.cache || {}; + this.cachedCalls = this.cachedCalls || {}; + + var keys = (Object.keys || _ember['default'].keys)(callbacks); + var keysLength = keys.length; + + if (keysLength) { + for (var i = 0; i < keysLength; i++) { + this._contextualizeCallback(context, keys[i], context); + } + } + }; + + _default.prototype._contextualizeCallback = function _contextualizeCallback(context, key, callbackContext) { + var _this = this; + var callbacks = this.callbacks; + var factory = context.factory; + + context[key] = function (options) { + if (_this.cachedCalls[key]) { + return _this.cache[key]; + } + + var result = callbacks[key].call(callbackContext, options, factory()); + + _this.cache[key] = result; + _this.cachedCalls[key] = true; + + return result; + }; + }; + + _default.prototype._aliasViewRegistry = function _aliasViewRegistry() { + this._originalGlobalViewRegistry = _ember['default'].View.views; + var viewRegistry = this.container.lookup('-view-registry:main'); + + if (viewRegistry) { + _ember['default'].View.views = viewRegistry; + } + }; + + _default.prototype._resetViewRegistry = function _resetViewRegistry() { + _ember['default'].View.views = this._originalGlobalViewRegistry; + }; + + return _default; + })(_abstractTestModule['default']); + + exports['default'] = _default; }); -define('ember-test-helpers/test-module-for-model', ['exports', 'ember-test-helpers/test-module', 'ember'], function (exports, TestModule, Ember) { +define('ember-test-helpers/test-module-for-model', ['exports', './test-module', 'ember'], function (exports, _testModule, _ember) { + /* global DS, require, requirejs */ // added here to prevent an import from erroring when ED is not present 'use strict'; - exports['default'] = TestModule['default'].extend({ - init: function(modelName, description, callbacks) { + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + + var _default = (function (_TestModule) { + _inherits(_default, _TestModule); + + function _default(modelName, description, callbacks) { + _classCallCheck(this, _default); + + _TestModule.call(this, 'model:' + modelName, description, callbacks); + this.modelName = modelName; - this._super.call(this, 'model:' + modelName, description, callbacks); - this.setupSteps.push(this.setupModel); - }, + } - setupModel: function() { + _default.prototype.setupModel = function setupModel() { var container = this.container; var defaultSubject = this.defaultSubject; var callbacks = this.callbacks; @@ -713,38 +1316,57 @@ define('ember-test-helpers/test-module-for-model', ['exports', 'ember-test-helpe var adapterFactory = container.lookupFactory('adapter:application'); if (!adapterFactory) { - adapterFactory = DS.JSONAPIAdapter || DS.FixtureAdapter; + if (requirejs.entries['ember-data/adapters/json-api']) { + adapterFactory = require('ember-data/adapters/json-api')['default']; + } + + // when ember-data/adapters/json-api is provided via ember-cli shims + // using Ember Data 1.x the actual JSONAPIAdapter isn't found, but the + // above require statement returns a bizzaro object with only a `default` + // property (circular reference actually) + if (!adapterFactory || !adapterFactory.create) { + adapterFactory = DS.JSONAPIAdapter || DS.FixtureAdapter; + } var thingToRegisterWith = this.registry || this.container; thingToRegisterWith.register('adapter:application', adapterFactory); } - callbacks.store = function(){ + callbacks.store = function () { var container = this.container; - var store = container.lookup('service:store') || container.lookup('store:main'); - return store; + return container.lookup('service:store') || container.lookup('store:main'); }; if (callbacks.subject === defaultSubject) { - callbacks.subject = function(options) { + callbacks.subject = function (options) { var container = this.container; - return Ember['default'].run(function() { + return _ember['default'].run(function () { var store = container.lookup('service:store') || container.lookup('store:main'); return store.createRecord(modelName, options); }); }; } - } - }); + }; + return _default; + })(_testModule['default']); + + exports['default'] = _default; }); -define('ember-test-helpers/test-module', ['exports', 'ember', 'ember-test-helpers/test-context', 'klassy', 'ember-test-helpers/test-resolver', 'ember-test-helpers/build-registry', 'ember-test-helpers/has-ember-version', 'ember-test-helpers/wait'], function (exports, Ember, test_context, klassy, test_resolver, buildRegistry, hasEmberVersion, wait) { - +define('ember-test-helpers/test-module', ['exports', 'ember', './abstract-test-module', './test-resolver', './build-registry', './has-ember-version'], function (exports, _ember, _abstractTestModule, _testResolver, _buildRegistry, _hasEmberVersion) { 'use strict'; - exports['default'] = klassy.Klass.extend({ - init: function(subjectName, description, callbacks) { + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + + var _default = (function (_AbstractTestModule) { + _inherits(_default, _AbstractTestModule); + + function _default(subjectName, description, callbacks) { + _classCallCheck(this, _default); + // Allow `description` to be omitted, in which case it should // default to `subjectName` if (!callbacks && typeof description === 'object') { @@ -752,53 +1374,50 @@ define('ember-test-helpers/test-module', ['exports', 'ember', 'ember-test-helper description = subjectName; } + _AbstractTestModule.call(this, description || subjectName, callbacks); + this.subjectName = subjectName; this.description = description || subjectName; - this.name = description || subjectName; - this.callbacks = callbacks || {}; + this.resolver = this.callbacks.resolver || _testResolver.getResolver(); if (this.callbacks.integration && this.callbacks.needs) { throw new Error("cannot declare 'integration: true' and 'needs' in the same module"); } if (this.callbacks.integration) { - if (this.isComponentTestModule) { - this.isLegacy = (callbacks.integration === 'legacy'); - this.isIntegration = (callbacks.integration !== 'legacy'); - } else { - if (callbacks.integration === 'legacy') { - throw new Error('`integration: \'legacy\'` is only valid for component tests.'); - } - this.isIntegration = true; - } - + this.initIntegration(callbacks); delete callbacks.integration; } this.initSubject(); this.initNeeds(); - this.initSetupSteps(); - this.initTeardownSteps(); - }, + } - initSubject: function() { + _default.prototype.initIntegration = function initIntegration(options) { + if (options.integration === 'legacy') { + throw new Error('`integration: \'legacy\'` is only valid for component tests.'); + } + this.isIntegration = true; + }; + + _default.prototype.initSubject = function initSubject() { this.callbacks.subject = this.callbacks.subject || this.defaultSubject; - }, + }; - initNeeds: function() { + _default.prototype.initNeeds = function initNeeds() { this.needs = [this.subjectName]; if (this.callbacks.needs) { this.needs = this.needs.concat(this.callbacks.needs); delete this.callbacks.needs; } - }, + }; - initSetupSteps: function() { + _default.prototype.initSetupSteps = function initSetupSteps() { this.setupSteps = []; this.contextualizedSetupSteps = []; if (this.callbacks.beforeSetup) { - this.setupSteps.push( this.callbacks.beforeSetup ); + this.setupSteps.push(this.callbacks.beforeSetup); delete this.callbacks.beforeSetup; } @@ -808,17 +1427,17 @@ define('ember-test-helpers/test-module', ['exports', 'ember', 'ember-test-helper this.setupSteps.push(this.setupAJAXListeners); if (this.callbacks.setup) { - this.contextualizedSetupSteps.push( this.callbacks.setup ); + this.contextualizedSetupSteps.push(this.callbacks.setup); delete this.callbacks.setup; } - }, + }; - initTeardownSteps: function() { + _default.prototype.initTeardownSteps = function initTeardownSteps() { this.teardownSteps = []; this.contextualizedTeardownSteps = []; if (this.callbacks.teardown) { - this.contextualizedTeardownSteps.push( this.callbacks.teardown ); + this.contextualizedTeardownSteps.push(this.callbacks.teardown); delete this.callbacks.teardown; } @@ -829,203 +1448,176 @@ define('ember-test-helpers/test-module', ['exports', 'ember', 'ember-test-helper this.teardownSteps.push(this.teardownAJAXListeners); if (this.callbacks.afterTeardown) { - this.teardownSteps.push( this.callbacks.afterTeardown ); + this.teardownSteps.push(this.callbacks.afterTeardown); delete this.callbacks.afterTeardown; } - }, + }; - setup: function() { - var self = this; - return self.invokeSteps(self.setupSteps).then(function() { - self.contextualizeCallbacks(); - return self.invokeSteps(self.contextualizedSetupSteps, self.context); - }); - }, - - teardown: function() { - var self = this; - return self.invokeSteps(self.contextualizedTeardownSteps, self.context).then(function() { - return self.invokeSteps(self.teardownSteps); - }).then(function() { - self.cache = null; - self.cachedCalls = null; - }); - }, - - invokeSteps: function(steps, _context) { - var context = _context; - if (!context) { - context = this; - } - steps = steps.slice(); - function nextStep() { - var step = steps.shift(); - if (step) { - // guard against exceptions, for example missing components referenced from needs. - return new Ember['default'].RSVP.Promise(function(ok) { - ok(step.call(context)); - }).then(nextStep); - } else { - return Ember['default'].RSVP.resolve(); - } - } - return nextStep(); - }, - - setupContainer: function() { + _default.prototype.setupContainer = function setupContainer() { if (this.isIntegration || this.isLegacy) { this._setupIntegratedContainer(); } else { this._setupIsolatedContainer(); } - }, + }; - setupContext: function() { + _default.prototype.setupContext = function setupContext() { var subjectName = this.subjectName; var container = this.container; - var factory = function() { + var factory = function factory() { return container.lookupFactory(subjectName); }; - test_context.setContext({ - container: this.container, + _AbstractTestModule.prototype.setupContext.call(this, { + container: this.container, registry: this.registry, - factory: factory, - dispatcher: null, - register: function() { + factory: factory, + register: function register() { var target = this.registry || this.container; return target.register.apply(target, arguments); - }, - inject: {} + } }); - var context = this.context = test_context.getContext(); - - if (Ember['default'].setOwner) { - Ember['default'].setOwner(context, this.container.owner); + if (_ember['default'].setOwner) { + _ember['default'].setOwner(this.context, this.container.owner); } - if (Ember['default'].inject) { - var keys = (Object.keys || Ember['default'].keys)(Ember['default'].inject); - keys.forEach(function(typeName) { - context.inject[typeName] = function(name, opts) { - var alias = (opts && opts.as) || name; - Ember['default'].set(context, alias, context.container.lookup(typeName + ':' + name)); + this.setupInject(); + }; + + _default.prototype.setupInject = function setupInject() { + var module = this; + var context = this.context; + + if (_ember['default'].inject) { + var keys = (Object.keys || _ember['default'].keys)(_ember['default'].inject); + + keys.forEach(function (typeName) { + context.inject[typeName] = function (name, opts) { + var alias = opts && opts.as || name; + _ember['default'].run(function () { + _ember['default'].set(context, alias, module.container.lookup(typeName + ':' + name)); + }); }; }); } - }, + }; - setupTestElements: function() { - if (Ember['default'].$('#ember-testing').length === 0) { - Ember['default'].$('
    ').appendTo(document.body); - } - }, - - setupAJAXListeners: function() { - wait._setupAJAXHooks(); - }, - - teardownSubject: function() { + _default.prototype.teardownSubject = function teardownSubject() { var subject = this.cache.subject; if (subject) { - Ember['default'].run(function() { - Ember['default'].tryInvoke(subject, 'destroy'); + _ember['default'].run(function () { + _ember['default'].tryInvoke(subject, 'destroy'); }); } - }, + }; - teardownContainer: function() { + _default.prototype.teardownContainer = function teardownContainer() { var container = this.container; - Ember['default'].run(function() { + _ember['default'].run(function () { container.destroy(); }); - }, + }; - teardownContext: function() { - var context = this.context; - this.context = undefined; - test_context.unsetContext(); - - if (context.dispatcher && !context.dispatcher.isDestroyed) { - Ember['default'].run(function() { - context.dispatcher.destroy(); - }); - } - }, - - teardownTestElements: function() { - Ember['default'].$('#ember-testing').empty(); - - // Ember 2.0.0 removed Ember.View as public API, so only do this when - // Ember.View is present - if (Ember['default'].View && Ember['default'].View.views) { - Ember['default'].View.views = {}; - } - }, - - teardownAJAXListeners: function() { - wait._teardownAJAXHooks(); - }, - - defaultSubject: function(options, factory) { + _default.prototype.defaultSubject = function defaultSubject(options, factory) { return factory.create(options); - }, + }; // allow arbitrary named factories, like rspec let - contextualizeCallbacks: function() { - var _this = this; + + _default.prototype.contextualizeCallbacks = function contextualizeCallbacks() { var callbacks = this.callbacks; - var context = this.context; - var factory = context.factory; + var context = this.context; this.cache = this.cache || {}; this.cachedCalls = this.cachedCalls || {}; - var keys = (Object.keys || Ember['default'].keys)(callbacks); + var keys = (Object.keys || _ember['default'].keys)(callbacks); + var keysLength = keys.length; - for (var i = 0, l = keys.length; i < l; i++) { - (function(key) { - - context[key] = function(options) { - if (_this.cachedCalls[key]) { return _this.cache[key]; } - - var result = callbacks[key].call(_this, options, factory()); - - _this.cache[key] = result; - _this.cachedCalls[key] = true; - - return result; - }; - - })(keys[i]); + if (keysLength) { + var deprecatedContext = this._buildDeprecatedContext(this, context); + for (var i = 0; i < keysLength; i++) { + this._contextualizeCallback(context, keys[i], deprecatedContext); + } } - }, + }; - _setupContainer: function(isolated) { - var resolver = test_resolver.getResolver(); + _default.prototype._contextualizeCallback = function _contextualizeCallback(context, key, callbackContext) { + var _this = this; + var callbacks = this.callbacks; + var factory = context.factory; - var items = buildRegistry['default'](!isolated ? resolver : Object.create(resolver, { + context[key] = function (options) { + if (_this.cachedCalls[key]) { + return _this.cache[key]; + } + + var result = callbacks[key].call(callbackContext, options, factory()); + + _this.cache[key] = result; + _this.cachedCalls[key] = true; + + return result; + }; + }; + + /* + Builds a version of the passed in context that contains deprecation warnings + for accessing properties that exist on the module. + */ + + _default.prototype._buildDeprecatedContext = function _buildDeprecatedContext(module, context) { + var deprecatedContext = Object.create(context); + + var keysForDeprecation = Object.keys(module); + + for (var i = 0, l = keysForDeprecation.length; i < l; i++) { + this._proxyDeprecation(module, deprecatedContext, keysForDeprecation[i]); + } + + return deprecatedContext; + }; + + /* + Defines a key on an object to act as a proxy for deprecating the original. + */ + + _default.prototype._proxyDeprecation = function _proxyDeprecation(obj, proxy, key) { + if (typeof proxy[key] === 'undefined') { + Object.defineProperty(proxy, key, { + get: function get() { + _ember['default'].deprecate('Accessing the test module property "' + key + '" from a callback is deprecated.', false, { id: 'ember-test-helpers.test-module.callback-context', until: '0.6.0' }); + return obj[key]; + } + }); + } + }; + + _default.prototype._setupContainer = function _setupContainer(isolated) { + var resolver = this.resolver; + + var items = _buildRegistry['default'](!isolated ? resolver : Object.create(resolver, { resolve: { - value: function() {} + value: function value() {} } })); this.container = items.container; this.registry = items.registry; - if (hasEmberVersion['default'](1, 13)) { + if (_hasEmberVersion['default'](1, 13)) { var thingToRegisterWith = this.registry || this.container; var router = resolver.resolve('router:main'); - router = router || Ember['default'].Router.extend(); + router = router || _ember['default'].Router.extend(); thingToRegisterWith.register('router:main', router); } - }, + }; - _setupIsolatedContainer: function() { - var resolver = test_resolver.getResolver(); + _default.prototype._setupIsolatedContainer = function _setupIsolatedContainer() { + var resolver = this.resolver; this._setupContainer(true); var thingToRegisterWith = this.registry || this.container; @@ -1037,24 +1629,24 @@ define('ember-test-helpers/test-module', ['exports', 'ember', 'ember-test-helper } if (!this.registry) { - this.container.resolver = function() {}; + this.container.resolver = function () {}; } - }, + }; - _setupIntegratedContainer: function() { + _default.prototype._setupIntegratedContainer = function _setupIntegratedContainer() { this._setupContainer(); - } + }; - }); + return _default; + })(_abstractTestModule['default']); + exports['default'] = _default; }); define('ember-test-helpers/test-resolver', ['exports'], function (exports) { - 'use strict'; exports.setResolver = setResolver; exports.getResolver = getResolver; - var __resolver__; function setResolver(resolver) { @@ -1062,17 +1654,23 @@ define('ember-test-helpers/test-resolver', ['exports'], function (exports) { } function getResolver() { - if (__resolver__ == null) throw new Error('you must set a resolver with `testResolver.set(resolver)`'); + if (__resolver__ == null) { + throw new Error('you must set a resolver with `testResolver.set(resolver)`'); + } + return __resolver__; } - }); -define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, Ember) { +define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, _ember) { + /* globals self */ 'use strict'; exports._teardownAJAXHooks = _teardownAJAXHooks; exports._setupAJAXHooks = _setupAJAXHooks; + exports['default'] = wait; + + var jQuery = _ember['default'].$; var requests; function incrementAjaxPendingRequests(_, xhr) { @@ -1080,7 +1678,7 @@ define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, Ember } function decrementAjaxPendingRequests(_, xhr) { - for (var i = 0;i < requests.length;i++) { + for (var i = 0; i < requests.length; i++) { if (xhr === requests[i]) { requests.splice(i, 1); } @@ -1088,6 +1686,10 @@ define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, Ember } function _teardownAJAXHooks() { + if (!jQuery) { + return; + } + jQuery(document).off('ajaxSend', incrementAjaxPendingRequests); jQuery(document).off('ajaxComplete', decrementAjaxPendingRequests); } @@ -1095,18 +1697,44 @@ define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, Ember function _setupAJAXHooks() { requests = []; + if (!jQuery) { + return; + } + jQuery(document).on('ajaxSend', incrementAjaxPendingRequests); jQuery(document).on('ajaxComplete', decrementAjaxPendingRequests); } + var _internalCheckWaiters; + if (_ember['default'].__loader.registry['ember-testing/test/waiters']) { + _internalCheckWaiters = _ember['default'].__loader.require('ember-testing/test/waiters').checkWaiters; + } + + function checkWaiters() { + if (_internalCheckWaiters) { + return _internalCheckWaiters(); + } else if (_ember['default'].Test.waiters) { + if (_ember['default'].Test.waiters.any(function (_ref) { + var context = _ref[0]; + var callback = _ref[1]; + return !callback.call(context); + })) { + return true; + } + } + + return false; + } + function wait(_options) { var options = _options || {}; var waitForTimers = options.hasOwnProperty('waitForTimers') ? options.waitForTimers : true; var waitForAJAX = options.hasOwnProperty('waitForAJAX') ? options.waitForAJAX : true; + var waitForWaiters = options.hasOwnProperty('waitForWaiters') ? options.waitForWaiters : true; - return new Ember['default'].RSVP.Promise(function(resolve) { - var watcher = self.setInterval(function() { - if (waitForTimers && (Ember['default'].run.hasScheduledTimers() || Ember['default'].run.currentRunLoop)) { + return new _ember['default'].RSVP.Promise(function (resolve) { + var watcher = self.setInterval(function () { + if (waitForTimers && (_ember['default'].run.hasScheduledTimers() || _ember['default'].run.currentRunLoop)) { return; } @@ -1114,188 +1742,34 @@ define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, Ember return; } + if (waitForWaiters && checkWaiters()) { + return; + } + // Stop polling self.clearInterval(watcher); // Synchronously resolve the promise - Ember['default'].run(null, resolve); + _ember['default'].run(null, resolve); }, 10); }); } - exports['default'] = wait; - }); -define('klassy', ['exports'], function (exports) { +define("qunit", ["exports"], function (exports) { + /* globals QUnit */ - 'use strict'; + "use strict"; - /** - Extend a class with the properties and methods of one or more other classes. - - When a method is replaced with another method, it will be wrapped in a - function that makes the replaced method accessible via `this._super`. - - @method extendClass - @param {Object} destination The class to merge into - @param {Object} source One or more source classes - */ - var extendClass = function(destination) { - var sources = Array.prototype.slice.call(arguments, 1); - var source; - - for (var i = 0, l = sources.length; i < l; i++) { - source = sources[i]; - - for (var p in source) { - if (source.hasOwnProperty(p) && - destination[p] && - typeof destination[p] === 'function' && - typeof source[p] === 'function') { - - /* jshint loopfunc:true */ - destination[p] = - (function(destinationFn, sourceFn) { - var wrapper = function() { - var prevSuper = this._super; - this._super = destinationFn; - - var ret = sourceFn.apply(this, arguments); - - this._super = prevSuper; - - return ret; - }; - wrapper.wrappedFunction = sourceFn; - return wrapper; - })(destination[p], source[p]); - - } else { - destination[p] = source[p]; - } - } - } - }; - - // `subclassing` is a state flag used by `defineClass` to track when a class is - // being subclassed. It allows constructors to avoid calling `init`, which can - // be expensive and cause undesirable side effects. - var subclassing = false; - - /** - Define a new class with the properties and methods of one or more other classes. - - The new class can be based on a `SuperClass`, which will be inserted into its - prototype chain. - - Furthermore, one or more mixins (object that contain properties and/or methods) - may be specified, which will be applied in order. When a method is replaced - with another method, it will be wrapped in a function that makes the previous - method accessible via `this._super`. - - @method defineClass - @param {Object} SuperClass A base class to extend. If `mixins` are to be included - without a `SuperClass`, pass `null` for SuperClass. - @param {Object} mixins One or more objects that contain properties and methods - to apply to the new class. - */ - var defineClass = function(SuperClass) { - var Klass = function() { - if (!subclassing && this.init) { - this.init.apply(this, arguments); - } - }; - - if (SuperClass) { - subclassing = true; - Klass.prototype = new SuperClass(); - subclassing = false; - } - - if (arguments.length > 1) { - var extendArgs = Array.prototype.slice.call(arguments, 1); - extendArgs.unshift(Klass.prototype); - extendClass.apply(Klass.prototype, extendArgs); - } - - Klass.constructor = Klass; - - Klass.extend = function() { - var args = Array.prototype.slice.call(arguments, 0); - args.unshift(Klass); - return defineClass.apply(Klass, args); - }; - - return Klass; - }; - - /** - A base class that can be extended. - - @example - - ```javascript - var CelestialObject = Klass.extend({ - init: function(name) { - this._super(); - this.name = name; - this.isCelestialObject = true; - }, - greeting: function() { - return 'Hello from ' + this.name; - } - }); - - var Planet = CelestialObject.extend({ - init: function(name) { - this._super.apply(this, arguments); - this.isPlanet = true; - }, - greeting: function() { - return this._super() + '!'; - }, - }); - - var earth = new Planet('Earth'); - - console.log(earth instanceof Klass); // true - console.log(earth instanceof CelestialObject); // true - console.log(earth instanceof Planet); // true - - console.log(earth.isCelestialObject); // true - console.log(earth.isPlanet); // true - - console.log(earth.greeting()); // 'Hello from Earth!' - ``` - - @class Klass - */ - var Klass = defineClass(null, { - init: function() {} - }); - - exports.Klass = Klass; - exports.defineClass = defineClass; - exports.extendClass = extendClass; - -}); -define('qunit', ['exports'], function (exports) { - - 'use strict'; - - /* globals test:true */ - - var module = QUnit.module; - var test = QUnit.test; - var skip = QUnit.skip; - var only = QUnit.only; - - exports['default'] = QUnit; - - exports.module = module; - exports.test = test; - exports.skip = skip; - exports.only = only; + var _module = QUnit.module; + exports.module = _module; + var test = QUnit.test; + exports.test = test; + var skip = QUnit.skip; + exports.skip = skip; + var only = QUnit.only; + exports.only = only; + exports["default"] = QUnit; }); define("ember", ["exports"], function(__exports__) { __exports__["default"] = window.Ember; diff --git a/vendor/gems/discourse_imgur/lib/discourse_imgur/locale/server.ur.yml b/vendor/gems/discourse_imgur/lib/discourse_imgur/locale/server.ur.yml index 34a02275ebb..58bc9735bcb 100644 --- a/vendor/gems/discourse_imgur/lib/discourse_imgur/locale/server.ur.yml +++ b/vendor/gems/discourse_imgur/lib/discourse_imgur/locale/server.ur.yml @@ -1,22 +1,8 @@ # encoding: utf-8 # -# This file contains content for the server portion of Discourse used by Ruby +# Never edit this file. It will be overwritten when translations are pulled from Transifex. # -# To work with us on translations, see: +# To work with us on translations, join this project: # https://www.transifex.com/projects/p/discourse-org/ -# -# This is a "source" file, which is used by Transifex to get translations for other languages. -# After this file is changed, it needs to be pushed by a maintainer to Transifex: -# -# tx push -s -# -# Read more here: https://meta.discourse.org/t/contribute-a-translation-to-discourse/14882 -# -# To validate this YAML file after you change it, please paste it into -# http://yamllint.com/ -ur: - site_settings: - enable_imgur: "Enable imgur api for uploading, don't host files locally" - imgur_client_id: "Your imgur.com client ID, required for image upload to function" - imgur_client_secret: "Your imgur.com client secret. Not currently required for image upload to function, but may be at some point." +ur: {}