diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03f4e109c7..04a646d9d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: target: ["PLUGINS", "CORE"] os: [ubuntu-latest] ruby: ["2.6"] - postgres: ["10"] + postgres: ["12"] redis: ["4.x"] services: @@ -64,9 +64,17 @@ jobs: - name: Setup packages if: env.BUILD_TYPE != 'LINT' run: | + sudo apt-get update sudo apt-get -yqq install postgresql-client libpq-dev gifsicle jpegoptim optipng jhead wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/master/image/base/install-pngquant | sudo sh + - name: Update imagemagick + if: env.BUILD_TYPE == 'BACKEND' + run: | + wget https://raw.githubusercontent.com/discourse/discourse_docker/master/image/base/install-imagemagick + chmod +x install-imagemagick + sudo ./install-imagemagick + - name: Setup redis uses: shogo82148/actions-setup-redis@v1 if: env.BUILD_TYPE != 'LINT' diff --git a/.rubocop.yml b/.rubocop.yml index d46296cf88..b7edfe4894 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,2 +1,9 @@ inherit_gem: rubocop-discourse: default.yml + +# Still work to do in ensuring we don't link old files +Discourse/NoAddReferenceOrAliasesActiveRecordMigration: + Enabled: false + +Discourse/NoResetColumnInformationInMigrations: + Enabled: true diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index b22e221ed4..cb867e5604 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -29,5 +29,3 @@ Javascript Ruby Rails - Copyright (c) 2005-2013 David Heinemeier Hansson, Rails Core Team contributors (MIT) - - Thin - Copyright (c) 2012-2013 Marc-Andre Cournoyer diff --git a/Gemfile b/Gemfile index b708152130..4d809fda20 100644 --- a/Gemfile +++ b/Gemfile @@ -178,7 +178,7 @@ end group :development do gem 'ruby-prof', require: false, platform: :mri gem 'bullet', require: !!ENV['BULLET'] - gem 'better_errors', platform: :mri + gem 'better_errors', platform: :mri, require: !!ENV['BETTER_ERRORS'] gem 'binding_of_caller' gem 'yaml-lint' gem 'annotate' @@ -250,4 +250,4 @@ gem 'webpush', require: false gem 'colored2', require: false gem 'maxminddb' -gem 'rails_failover', require: false, git: 'https://github.com/discourse/rails_failover' +gem 'rails_failover', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 2870d86e7b..4862c4a3be 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,11 +1,3 @@ -GIT - remote: https://github.com/discourse/rails_failover - revision: 66602aa73785851b81c506f0023d3c2a2e40de0a - specs: - rails_failover (0.4.0) - activerecord (~> 6.0) - railties (~> 6.0) - GEM remote: https://rubygems.org/ specs: @@ -51,10 +43,10 @@ GEM annotate (3.1.1) activerecord (>= 3.2, < 7.0) rake (>= 10.4, < 14.0) - ast (2.4.0) + ast (2.4.1) aws-eventstream (1.1.0) - aws-partitions (1.322.0) - aws-sdk-core (3.96.1) + aws-partitions (1.329.0) + aws-sdk-core (3.99.1) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.239.0) aws-sigv4 (~> 1.1) @@ -66,11 +58,11 @@ GEM aws-sdk-core (~> 3, >= 3.96.1) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.1) - aws-sdk-sns (1.23.0) - aws-sdk-core (~> 3, >= 3.71.0) + aws-sdk-sns (1.25.1) + aws-sdk-core (~> 3, >= 3.99.0) aws-sigv4 (~> 1.1) - aws-sigv4 (1.1.3) - aws-eventstream (~> 1.0, >= 1.0.2) + aws-sigv4 (1.2.0) + aws-eventstream (~> 1, >= 1.0.2) barber (0.12.2) ember-source (>= 1.0, < 3.1) execjs (>= 1.2, < 3) @@ -104,7 +96,7 @@ GEM css_parser (1.7.1) addressable debug_inspector (0.0.3) - diff-lcs (1.3) + diff-lcs (1.4.1) diffy (3.3.0) discourse-ember-source (3.12.2.0) discourse_image_optim (0.26.2) @@ -129,7 +121,7 @@ GEM railties (>= 3.1) ember-source (2.18.2) erubi (1.9.0) - excon (0.73.0) + excon (0.75.0) execjs (2.7.0) exifr (1.3.6) fabrication (2.21.1) @@ -142,7 +134,7 @@ GEM rake-compiler fast_xs (0.8.0) fastimage (2.1.7) - ffi (1.13.0) + ffi (1.13.1) flamegraph (0.9.5) fspath (3.1.2) gc_tracer (1.5.1) @@ -181,8 +173,8 @@ GEM logstash-event (1.2.02) logstash-logger (0.26.1) logstash-event (~> 1.2) - logster (2.8.0) - loofah (2.5.0) + logster (2.9.0) + loofah (2.6.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) lru_redux (1.1.0) @@ -205,7 +197,7 @@ GEM ffi (~> 1.9) minitest (5.14.1) mocha (1.11.2) - mock_redis (0.23.0) + mock_redis (0.24.0) msgpack (1.3.3) multi_json (1.14.1) multi_xml (0.6.0) @@ -248,7 +240,7 @@ GEM omniauth-twitter (1.4.0) omniauth-oauth (~> 1.1) rack - onebox (1.9.28.3) + onebox (1.9.29) addressable (~> 2.7.0) htmlentities (~> 4.3) multi_json (~> 1.11) @@ -257,11 +249,11 @@ GEM sanitize openssl-signature_algorithm (0.4.0) optimist (3.0.1) - parallel (1.19.1) - parallel_tests (2.32.0) + parallel (1.19.2) + parallel_tests (3.0.0) parallel - parser (2.7.1.3) - ast (~> 2.4.0) + parser (2.7.1.4) + ast (~> 2.4.1) pg (1.2.3) progress (3.5.2) pry (0.13.1) @@ -288,6 +280,9 @@ GEM nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) + rails_failover (0.5.2) + activerecord (~> 6.0) + railties (~> 6.0) rails_multisite (2.3.0) activerecord (> 5.0, < 7) railties (> 5.0, < 7) @@ -310,7 +305,7 @@ GEM msgpack (>= 0.4.3) optimist (>= 3.0.0) rchardet (1.8.0) - redis (4.1.4) + redis (4.2.1) redis-namespace (1.7.0) redis (>= 3.0.4) regexp_parser (1.7.1) @@ -353,21 +348,21 @@ GEM json-schema (~> 2.2) railties (>= 3.1, < 7.0) rtlit (0.0.5) - rubocop (0.85.1) + rubocop (0.86.0) parallel (~> 1.10) parser (>= 2.7.0.1) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.7) rexml - rubocop-ast (>= 0.0.3) + rubocop-ast (>= 0.0.3, < 1.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 2.0) rubocop-ast (0.0.3) parser (>= 2.7.0.1) - rubocop-discourse (2.1.2) + rubocop-discourse (2.2.0) rubocop (>= 0.69.0) rubocop-rspec (>= 1.39.0) - rubocop-rspec (1.39.0) + rubocop-rspec (1.40.0) rubocop (>= 0.68.1) ruby-prof (1.4.1) ruby-progressbar (1.10.1) @@ -376,7 +371,7 @@ GEM nokogiri (>= 1.6.0) rubyzip (2.3.0) safe_yaml (1.0.5) - sanitize (5.1.0) + sanitize (5.2.1) crass (~> 1.0.2) nokogiri (>= 1.8.0) nokogumbo (~> 2.0) @@ -526,7 +521,7 @@ DEPENDENCIES rack (= 2.2.2) rack-mini-profiler rack-protection - rails_failover! + rails_failover rails_multisite railties (= 6.0.3.1) rake diff --git a/app/assets/javascripts/admin/controllers/admin-permalinks.js b/app/assets/javascripts/admin/controllers/admin-permalinks.js index 177bb4148d..23c47f5739 100644 --- a/app/assets/javascripts/admin/controllers/admin-permalinks.js +++ b/app/assets/javascripts/admin/controllers/admin-permalinks.js @@ -22,6 +22,16 @@ export default Controller.extend({ this.model.unshiftObject(arg); }, + copyUrl(pl) { + let linkElement = document.querySelector(`#admin-permalink-${pl.id}`); + let textArea = document.createElement("textarea"); + textArea.value = linkElement.textContent; + document.body.appendChild(textArea); + textArea.select(); + document.execCommand("Copy"); + textArea.remove(); + }, + destroy: function(record) { return bootbox.confirm( I18n.t("admin.permalink.delete_confirm"), diff --git a/app/assets/javascripts/admin/templates/components/permalink-form.hbs b/app/assets/javascripts/admin/templates/components/permalink-form.hbs index 1f5d1c06f2..8792d78734 100644 --- a/app/assets/javascripts/admin/templates/components/permalink-form.hbs +++ b/app/assets/javascripts/admin/templates/components/permalink-form.hbs @@ -12,6 +12,7 @@ content=permalinkTypes value=permalinkType onChange=(action (mut permalinkType)) + class="permalink-type" }} {{text-field diff --git a/app/assets/javascripts/admin/templates/customize.hbs b/app/assets/javascripts/admin/templates/customize.hbs index d017abe67f..cafafd1285 100644 --- a/app/assets/javascripts/admin/templates/customize.hbs +++ b/app/assets/javascripts/admin/templates/customize.hbs @@ -1,13 +1,13 @@ {{#admin-nav}} - {{nav-item route="adminCustomizeThemes" label="admin.customize.theme.title"}} - {{nav-item route="adminCustomize.colors" label="admin.customize.colors.title"}} - {{nav-item route="adminSiteText" label="admin.site_text.title"}} - {{nav-item route="adminCustomizeEmailTemplates" label="admin.customize.email_templates.title"}} - {{nav-item route="adminCustomizeEmailStyle" label="admin.customize.email_style.title"}} - {{nav-item route="adminUserFields" label="admin.user_fields.title"}} - {{nav-item route="adminEmojis" label="admin.emoji.title"}} - {{nav-item route="adminPermalinks" label="admin.permalink.title"}} - {{nav-item route="adminEmbedding" label="admin.embedding.title"}} + {{nav-item route="adminCustomizeThemes" label="admin.customize.theme.title" class="admin-customize-themes"}} + {{nav-item route="adminCustomize.colors" label="admin.customize.colors.title" class="admin-customize-colors"}} + {{nav-item route="adminSiteText" label="admin.site_text.title" class="admin-customize-site-text"}} + {{nav-item route="adminCustomizeEmailTemplates" label="admin.customize.email_templates.title" class="admin-customize-email-templates"}} + {{nav-item route="adminCustomizeEmailStyle" label="admin.customize.email_style.title" class="admin-customize-email-styles"}} + {{nav-item route="adminUserFields" label="admin.user_fields.title" class="admin-customize-user-fields"}} + {{nav-item route="adminEmojis" label="admin.emoji.title" class="admin-customize-emojis"}} + {{nav-item route="adminPermalinks" label="admin.permalink.title" class="admin-customize-permalinks"}} + {{nav-item route="adminEmbedding" label="admin.embedding.title" class="admin-customize-embedding"}} {{/admin-nav}}
diff --git a/app/assets/javascripts/admin/templates/permalinks.hbs b/app/assets/javascripts/admin/templates/permalinks.hbs index 1424e530b9..a66151140a 100644 --- a/app/assets/javascripts/admin/templates/permalinks.hbs +++ b/app/assets/javascripts/admin/templates/permalinks.hbs @@ -21,7 +21,7 @@ {{#each model as |pl|}} - {{pl.url}} + {{d-button title="admin.permalink.copy_to_clipboard" icon="far-clipboard" action=(action "copyUrl" pl)}} {{pl.url}} {{#if pl.topic_id}} {{pl.topic_title}} @@ -42,7 +42,7 @@ {{pl.external_url}} {{/if}} - + {{d-button action=(action "destroy") actionParam=pl icon="far-trash-alt" class="btn-danger"}} diff --git a/app/assets/javascripts/admin/templates/user-index.hbs b/app/assets/javascripts/admin/templates/user-index.hbs index df9a6e196f..62e500f805 100644 --- a/app/assets/javascripts/admin/templates/user-index.hbs +++ b/app/assets/javascripts/admin/templates/user-index.hbs @@ -514,7 +514,7 @@
{{i18n "admin.groups.custom"}}
- {{admin-group-selector + {{group-chooser content=availableGroups value=customGroupIdsBuffer labelProperty="name" diff --git a/app/assets/javascripts/discourse/app/components/d-textarea.js b/app/assets/javascripts/discourse/app/components/d-textarea.js new file mode 100644 index 0000000000..a3979bd2ce --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/d-textarea.js @@ -0,0 +1,5 @@ +import TextArea from "@ember/component/text-area"; + +export default TextArea.extend({ + attributeBindings: ["aria-label"] +}); diff --git a/app/assets/javascripts/discourse/app/components/text-field.js b/app/assets/javascripts/discourse/app/components/text-field.js index f9c13ec4d3..c61d0e7023 100644 --- a/app/assets/javascripts/discourse/app/components/text-field.js +++ b/app/assets/javascripts/discourse/app/components/text-field.js @@ -12,7 +12,8 @@ export default TextField.extend({ "autocapitalize", "autofocus", "maxLength", - "dir" + "dir", + "aria-label" ], init() { diff --git a/app/assets/javascripts/discourse/app/components/topic-progress.js b/app/assets/javascripts/discourse/app/components/topic-progress.js index 3f927bd78c..bf0f5cb3bf 100644 --- a/app/assets/javascripts/discourse/app/components/topic-progress.js +++ b/app/assets/javascripts/discourse/app/components/topic-progress.js @@ -180,7 +180,7 @@ export default Component.extend({ this.set("docked", isDocked); const $replyArea = $("#reply-control .reply-area"); - if ($replyArea && $replyArea.length > 0 && wrapperDir === "left") { + if ($replyArea && $replyArea.length > 0) { $wrapper.css(wrapperDir, `${$replyArea.offset().left}px`); } else { $wrapper.css(wrapperDir, "1em"); diff --git a/app/assets/javascripts/discourse/app/controllers/composer.js b/app/assets/javascripts/discourse/app/controllers/composer.js index 3ca2b70f36..569338907e 100644 --- a/app/assets/javascripts/discourse/app/controllers/composer.js +++ b/app/assets/javascripts/discourse/app/controllers/composer.js @@ -1040,7 +1040,7 @@ export default Controller.extend({ const keyPrefix = this.model.action === "edit" ? "post.abandon_edit" : "post.abandon"; - let promise = new Promise(resolve => { + let promise = new Promise((resolve, reject) => { if (this.get("model.hasMetaData") || this.get("model.replyDirty")) { bootbox.dialog(I18n.t(keyPrefix + ".confirm"), [ { @@ -1052,8 +1052,10 @@ export default Controller.extend({ if (differentDraft) { this.model.clearState(); this.close(); + resolve(); } - resolve(); + + reject(); } }, { diff --git a/app/assets/javascripts/discourse/app/controllers/history.js b/app/assets/javascripts/discourse/app/controllers/history.js index b368a283fb..b2bbe94d0f 100644 --- a/app/assets/javascripts/discourse/app/controllers/history.js +++ b/app/assets/javascripts/discourse/app/controllers/history.js @@ -60,6 +60,11 @@ export default Controller.extend(ModalFunctionality, { ); }, + @discourseComputed("previousVersion") + revertToRevisionText(revision) { + return I18n.t("post.revisions.controls.revert", { revision }); + }, + refresh(postId, postVersion) { this.set("loading", true); @@ -261,9 +266,10 @@ export default Controller.extend(ModalFunctionality, { this.set("bodyDiff", html); } else { const opts = { - features: { editHistory: true }, + features: { editHistory: true, historyOneboxes: true }, whiteListed: { - editHistory: { custom: (tag, attr) => attr === "class" } + editHistory: { custom: (tag, attr) => attr === "class" }, + historyOneboxes: ["header", "article", "div[style]"] } }; diff --git a/app/assets/javascripts/discourse/app/controllers/publish-page.js b/app/assets/javascripts/discourse/app/controllers/publish-page.js index f6c864682a..58059d027c 100644 --- a/app/assets/javascripts/discourse/app/controllers/publish-page.js +++ b/app/assets/javascripts/discourse/app/controllers/publish-page.js @@ -35,6 +35,7 @@ export default Controller.extend(ModalFunctionality, StateHelpers, { this.state === States.existing ); }), + showUnpublish: computed("state", function() { return this.state === States.existing || this.state === States.unpublishing; }), @@ -95,7 +96,7 @@ export default Controller.extend(ModalFunctionality, StateHelpers, { this.set("state", States.saving); return this.publishedPage - .update({ slug: this.publishedPage.slug }) + .update(this.publishedPage.getProperties("slug", "public")) .then(() => { this.set("state", States.existing); this.model.set("publishedPage", this.publishedPage); @@ -110,11 +111,17 @@ export default Controller.extend(ModalFunctionality, StateHelpers, { startNew() { this.setProperties({ state: States.new, - publishedPage: this.store.createRecord("published_page", { - id: this.model.id, - slug: this.model.slug - }) + publishedPage: this.store.createRecord( + "published_page", + this.model.getProperties("id", "slug", "public") + ) }); this.checkSlug(); + }, + + @action + onChangePublic(isPublic) { + this.publishedPage.set("public", isPublic); + this.publish(); } }); diff --git a/app/assets/javascripts/discourse/app/initializers/mobile.js b/app/assets/javascripts/discourse/app/initializers/mobile.js index b0708fca85..d219ce5ca0 100644 --- a/app/assets/javascripts/discourse/app/initializers/mobile.js +++ b/app/assets/javascripts/discourse/app/initializers/mobile.js @@ -1,7 +1,5 @@ -import { later } from "@ember/runloop"; import Mobile from "discourse/lib/mobile"; import { setResolverOption } from "discourse-common/resolver"; -import { isAppWebview, postRNWebviewMessage } from "discourse/lib/utilities"; // Initializes the `Mobile` helper object. export default { @@ -16,14 +14,5 @@ export default { site.set("isMobileDevice", Mobile.isMobileDevice); setResolverOption("mobileView", Mobile.mobileView); - - if (isAppWebview()) { - later(() => { - postRNWebviewMessage( - "headerBg", - $(".d-header").css("background-color") - ); - }, 500); - } } }; diff --git a/app/assets/javascripts/discourse/app/initializers/webview-background.js b/app/assets/javascripts/discourse/app/initializers/webview-background.js new file mode 100644 index 0000000000..e24db7d65e --- /dev/null +++ b/app/assets/javascripts/discourse/app/initializers/webview-background.js @@ -0,0 +1,20 @@ +import { later } from "@ember/runloop"; +import { isAppWebview, postRNWebviewMessage } from "discourse/lib/utilities"; + +// Send bg color to webview so iOS status bar matches site theme +export default { + name: "webview-background", + after: "inject-objects", + + initialize() { + if (isAppWebview()) { + later(() => { + const header = document.querySelectorAll(".d-header")[0]; + if (header) { + const styles = window.getComputedStyle(header); + postRNWebviewMessage("headerBg", styles.backgroundColor); + } + }, 500); + } + } +}; diff --git a/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js b/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js index 29cfaaf9d2..f887d2eb87 100644 --- a/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js +++ b/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js @@ -355,7 +355,8 @@ export default { this.container.lookup("controller:topic").togglePinnedState(); }, - goToPost() { + goToPost(event) { + preventKeyboardEvent(event); this.appEvents.trigger("topic:keyboard-trigger", { type: "jump" }); }, diff --git a/app/assets/javascripts/discourse/app/lib/url.js b/app/assets/javascripts/discourse/app/lib/url.js index 499b5d745c..ae73638a70 100644 --- a/app/assets/javascripts/discourse/app/lib/url.js +++ b/app/assets/javascripts/discourse/app/lib/url.js @@ -30,7 +30,8 @@ const SERVER_SIDE_ONLY = [ /^\/admin\/upgrade$/, /^\/logs($|\/)/, /^\/admin\/logs\/watched_words\/action\/[^\/]+\/download$/, - /^\/pub\// + /^\/pub\//, + /^\/invites\// ]; export function rewritePath(path) { diff --git a/app/assets/javascripts/discourse/app/lib/utilities.js b/app/assets/javascripts/discourse/app/lib/utilities.js index 92fa344134..cee9ce5faf 100644 --- a/app/assets/javascripts/discourse/app/lib/utilities.js +++ b/app/assets/javascripts/discourse/app/lib/utilities.js @@ -25,6 +25,10 @@ export function translateSize(size) { } export function escapeExpression(string) { + if (!string) { + return ""; + } + // don't escape SafeStrings, since they're already safe if (string instanceof Handlebars.SafeString) { return string.toString(); diff --git a/app/assets/javascripts/discourse/app/models/nav-item.js b/app/assets/javascripts/discourse/app/models/nav-item.js index bf41bdde66..49c0ad37b4 100644 --- a/app/assets/javascripts/discourse/app/models/nav-item.js +++ b/app/assets/javascripts/discourse/app/models/nav-item.js @@ -71,11 +71,16 @@ const NavItem = EmberObject.extend({ return mode + name.replace(" ", "-"); }, - @discourseComputed("name", "category", "topicTrackingState.messageCount") - count(name, category) { + @discourseComputed( + "name", + "category", + "tagId", + "topicTrackingState.messageCount" + ) + count(name, category, tagId) { const state = this.topicTrackingState; if (state) { - return state.lookupCount(name, category); + return state.lookupCount(name, category, tagId); } } }); diff --git a/app/assets/javascripts/discourse/app/models/site.js b/app/assets/javascripts/discourse/app/models/site.js index 8e6b8f2d2c..0481485a9f 100644 --- a/app/assets/javascripts/discourse/app/models/site.js +++ b/app/assets/javascripts/discourse/app/models/site.js @@ -132,7 +132,9 @@ Site.reopenClass(Singleton, { // The current singleton will retrieve its attributes from the `PreloadStore`. createCurrent() { const store = Discourse.__container__.lookup("service:store"); - return store.createRecord("site", PreloadStore.get("site")); + const siteAttributes = PreloadStore.get("site"); + siteAttributes["isReadOnly"] = PreloadStore.get("isReadOnly"); + return store.createRecord("site", siteAttributes); }, create() { diff --git a/app/assets/javascripts/discourse/app/models/topic-tracking-state.js b/app/assets/javascripts/discourse/app/models/topic-tracking-state.js index ee18ed4287..2875f2a519 100644 --- a/app/assets/javascripts/discourse/app/models/topic-tracking-state.js +++ b/app/assets/javascripts/discourse/app/models/topic-tracking-state.js @@ -408,7 +408,7 @@ const TopicTrackingState = EmberObject.extend({ return new Set(result); }, - countCategoryByState(fn, categoryId) { + countCategoryByState(fn, categoryId, tagId) { const subcategoryIds = this.getSubCategoryIds(categoryId); return _.chain(this.states) .filter(fn) @@ -416,17 +416,18 @@ const TopicTrackingState = EmberObject.extend({ topic => topic.archetype !== "private_message" && !topic.deleted && - (!categoryId || subcategoryIds.has(topic.category_id)) + (!categoryId || subcategoryIds.has(topic.category_id)) && + (!tagId || (topic.tags && topic.tags.indexOf(tagId) > -1)) ) .value().length; }, - countNew(categoryId) { - return this.countCategoryByState(isNew, categoryId); + countNew(categoryId, tagId) { + return this.countCategoryByState(isNew, categoryId, tagId); }, - countUnread(categoryId) { - return this.countCategoryByState(isUnread, categoryId); + countUnread(categoryId, tagId) { + return this.countCategoryByState(isUnread, categoryId, tagId); }, countTags(tags) { @@ -462,10 +463,14 @@ const TopicTrackingState = EmberObject.extend({ return counts; }, - countCategory(category_id) { + countCategory(category_id, tagId) { let sum = 0; Object.values(this.states).forEach(topic => { - if (topic.category_id === category_id && !topic.deleted) { + if ( + topic.category_id === category_id && + !topic.deleted && + (!tagId || (topic.tags && topic.tags.indexOf(tagId) > -1)) + ) { sum += topic.last_read_post_number === null || topic.last_read_post_number < topic.highest_post_number @@ -476,23 +481,24 @@ const TopicTrackingState = EmberObject.extend({ return sum; }, - lookupCount(name, category) { + lookupCount(name, category, tagId) { if (name === "latest") { return ( - this.lookupCount("new", category) + this.lookupCount("unread", category) + this.lookupCount("new", category, tagId) + + this.lookupCount("unread", category, tagId) ); } let categoryId = category ? get(category, "id") : null; if (name === "new") { - return this.countNew(categoryId); + return this.countNew(categoryId, tagId); } else if (name === "unread") { - return this.countUnread(categoryId); + return this.countUnread(categoryId, tagId); } else { const categoryName = name.split("/")[1]; if (categoryName) { - return this.countCategory(categoryId); + return this.countCategory(categoryId, tagId); } } }, diff --git a/app/assets/javascripts/discourse/app/models/topic.js b/app/assets/javascripts/discourse/app/models/topic.js index 4f5305fec6..b4a69c33c7 100644 --- a/app/assets/javascripts/discourse/app/models/topic.js +++ b/app/assets/javascripts/discourse/app/models/topic.js @@ -430,8 +430,11 @@ const Topic = RestModel.extend({ return this.firstPost().then(firstPost => { const toggleBookmarkOnServer = () => { if (bookmark) { - return firstPost.toggleBookmark().then(() => { + return firstPost.toggleBookmark().then(opts => { this.set("bookmarking", false); + if (opts.closedWithoutSaving) { + return; + } return this.afterTopicBookmarked(firstPost); }); } else { diff --git a/app/assets/javascripts/discourse/app/models/user.js b/app/assets/javascripts/discourse/app/models/user.js index 0f67d613b2..f4482fa6e8 100644 --- a/app/assets/javascripts/discourse/app/models/user.js +++ b/app/assets/javascripts/discourse/app/models/user.js @@ -595,7 +595,7 @@ const User = RestModel.extend({ ); } - if (!isEmpty(json.user.groups)) { + if (!isEmpty(json.user.groups) && !isEmpty(json.user.group_users)) { const groups = []; for (let i = 0; i < json.user.groups.length; i++) { @@ -770,6 +770,7 @@ const User = RestModel.extend({ this.setProperties({ email: result.email, secondary_emails: result.secondary_emails, + unconfirmed_emails: result.unconfirmed_emails, associated_accounts: result.associated_accounts }); } diff --git a/app/assets/javascripts/discourse/app/templates/components/categories-only.hbs b/app/assets/javascripts/discourse/app/templates/components/categories-only.hbs index 787968d3d5..e030adc4a3 100644 --- a/app/assets/javascripts/discourse/app/templates/components/categories-only.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/categories-only.hbs @@ -11,6 +11,7 @@ {{#each categories as |c|}} + {{plugin-outlet name="category-list-above-each-category" connectorTagName="" tagName="" args=(hash category=c)}} {{category-title-link category=c}} diff --git a/app/assets/javascripts/discourse/app/templates/components/composer-title.hbs b/app/assets/javascripts/discourse/app/templates/components/composer-title.hbs index a8483595de..c29ed22187 100644 --- a/app/assets/javascripts/discourse/app/templates/components/composer-title.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/composer-title.hbs @@ -3,6 +3,7 @@ id="reply-title" maxLength=titleMaxLength placeholderKey=composer.titlePlaceholder + aria-label=(I18n composer.titlePlaceholder) disabled=disabled autocomplete="discourse"}} diff --git a/app/assets/javascripts/discourse/app/templates/components/d-editor.hbs b/app/assets/javascripts/discourse/app/templates/components/d-editor.hbs index 0c7cdebded..5528aeb669 100644 --- a/app/assets/javascripts/discourse/app/templates/components/d-editor.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/d-editor.hbs @@ -33,12 +33,13 @@
{{conditional-loading-spinner condition=loading}} - {{textarea + {{d-textarea autocomplete="discourse" tabindex=tabindex value=value class="d-editor-input" placeholder=placeholderTranslated + aria-label=placeholderTranslated disabled=disabled input=change}} {{popup-input-tip validation=validation}} diff --git a/app/assets/javascripts/discourse/app/templates/components/future-date-input.hbs b/app/assets/javascripts/discourse/app/templates/components/future-date-input.hbs index 6e6b117e08..43c7e421e0 100644 --- a/app/assets/javascripts/discourse/app/templates/components/future-date-input.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/future-date-input.hbs @@ -11,10 +11,13 @@ includeWeekend=includeWeekend includeFarFuture=includeFarFuture includeMidFuture=includeMidFuture + includeNow=includeNow clearable=clearable - none="topic.auto_update_input.none" onChangeInput=onChangeInput onChange=(action (mut selection)) + options=(hash + none="topic.auto_update_input.none" + ) }}
{{/unless}} diff --git a/app/assets/javascripts/discourse/app/templates/components/user-info.hbs b/app/assets/javascripts/discourse/app/templates/components/user-info.hbs index fe6c7823fe..ced515393c 100644 --- a/app/assets/javascripts/discourse/app/templates/components/user-info.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/user-info.hbs @@ -15,6 +15,7 @@
{{format-username @user.username}} {{this.name}} + {{plugin-outlet name="after-user-name" connectorTagName="span" args=(hash user=user)}}
{{@user.title}}
@@ -25,3 +26,5 @@ {{/if}}
+ +{{plugin-outlet name="after-user-info" args=(hash user=user)}} diff --git a/app/assets/javascripts/discourse/app/templates/composer.hbs b/app/assets/javascripts/discourse/app/templates/composer.hbs index 672d5d2d01..e8dbfc8fff 100644 --- a/app/assets/javascripts/discourse/app/templates/composer.hbs +++ b/app/assets/javascripts/discourse/app/templates/composer.hbs @@ -10,7 +10,7 @@ messageCount=messageCount addLinkLookup=(action "addLinkLookup")}} {{#if model.viewOpenOrFullscreen}} -
+
{{plugin-outlet name="composer-open" args=(hash model=model)}}
@@ -100,7 +100,7 @@
{{/if}} - {{plugin-outlet name="composer-fields" args=(hash model=model)}} + {{plugin-outlet name="composer-fields" args=(hash model=model showPreview=showPreview)}} {{/unless}}
diff --git a/app/assets/javascripts/discourse/app/templates/mobile/components/categories-only.hbs b/app/assets/javascripts/discourse/app/templates/mobile/components/categories-only.hbs index 04cf4d8578..e42372b29c 100644 --- a/app/assets/javascripts/discourse/app/templates/mobile/components/categories-only.hbs +++ b/app/assets/javascripts/discourse/app/templates/mobile/components/categories-only.hbs @@ -1,6 +1,7 @@ {{#if categories}}
{{#each categories as |c|}} + {{plugin-outlet name="category-list-above-each-category" connectorTagName="" tagName="" args=(hash category=c)}}
diff --git a/app/assets/javascripts/discourse/app/templates/mobile/list/topic-list-item.hbr b/app/assets/javascripts/discourse/app/templates/mobile/list/topic-list-item.hbr index 6c4663b83d..34abdbf429 100644 --- a/app/assets/javascripts/discourse/app/templates/mobile/list/topic-list-item.hbr +++ b/app/assets/javascripts/discourse/app/templates/mobile/list/topic-list-item.hbr @@ -23,6 +23,7 @@ {{~#if topic.featured_link~}} {{~topic-featured-link topic~}} {{~/if~}} + {{~raw-plugin-outlet name="topic-list-after-title"}} {{~#if topic.unseen~}}   {{~/if~}} diff --git a/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs b/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs index 615ae16b07..d3811ac9ab 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs @@ -9,7 +9,7 @@ {{/if}}
- {{input id="bookmark-name" value=model.name name="bookmark-name" class="bookmark-name" placeholder=(i18n "post.bookmarks.name_placeholder")}} + {{input id="bookmark-name" value=model.name name="bookmark-name" class="bookmark-name" enter=(action "saveAndClose") placeholder=(i18n "post.bookmarks.name_placeholder")}} {{d-button icon="cog" action=(action "toggleOptionsPanel") class="bookmark-options-button"}}
diff --git a/app/assets/javascripts/discourse/app/templates/modal/history.hbs b/app/assets/javascripts/discourse/app/templates/modal/history.hbs index 528f5a8bf3..f86f98a046 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/history.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/history.hbs @@ -128,7 +128,7 @@ {{/if}} {{#if displayRevert}} - {{d-button action=(action "revertToVersion") icon="undo" label="post.revisions.controls.revert" class="btn-danger" disabled=loading}} + {{d-button action=(action "revertToVersion") icon="undo" translatedLabel=revertToRevisionText class="btn-danger" disabled=loading}} {{/if}} {{#if displayHide}} diff --git a/app/assets/javascripts/discourse/app/templates/modal/ignore-duration-with-username.hbs b/app/assets/javascripts/discourse/app/templates/modal/ignore-duration-with-username.hbs index 29a8c0f215..379f8bc893 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/ignore-duration-with-username.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/ignore-duration-with-username.hbs @@ -12,7 +12,7 @@ includeWeekend=true includeDateTime=false includeMidFuture=true - includeFarFuture=false + includeFarFuture=true onChangeInput=(action (mut ignoredUntil)) }}

{{i18n "user.user_notifications.ignore_duration_note"}}

diff --git a/app/assets/javascripts/discourse/app/templates/modal/ignore-duration.hbs b/app/assets/javascripts/discourse/app/templates/modal/ignore-duration.hbs index 33db2479db..8cb1e0baa8 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/ignore-duration.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/ignore-duration.hbs @@ -5,7 +5,7 @@ includeWeekend=true includeDateTime=false includeMidFuture=true - includeFarFuture=false + includeFarFuture=true onChangeInput=(action (mut ignoredUntil)) }}

{{i18n "user.user_notifications.ignore_duration_note"}}

diff --git a/app/assets/javascripts/discourse/app/templates/modal/publish-page.hbs b/app/assets/javascripts/discourse/app/templates/modal/publish-page.hbs index 712682fe74..9cd9a56087 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/publish-page.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/publish-page.hbs @@ -6,8 +6,29 @@

{{i18n "topic.publish_page.description"}}

- - {{text-field value=publishedPage.slug onChange=(action "checkSlug") onChangeImmediate=(action "startCheckSlug") disabled=existing class="publish-slug"}} +
+ + {{text-field + value=publishedPage.slug + onChange=(action "checkSlug") + onChangeImmediate=(action "startCheckSlug") + disabled=existing + class="publish-slug" + }} +
+ +
+ + +

+ {{input + type="checkbox" + checked=publishedPage.public + click=(action "onChangePublic" value="target.checked") + }} + {{i18n "topic.publish_page.public_description"}} +

+
@@ -40,14 +61,15 @@
diff --git a/app/views/layouts/publish.html.erb b/app/views/layouts/publish.html.erb index 4a249e8f32..4a428eb9e1 100644 --- a/app/views/layouts/publish.html.erb +++ b/app/views/layouts/publish.html.erb @@ -6,6 +6,8 @@ <%= render partial: "common/discourse_publish_stylesheet" %> + <%= theme_lookup("header") %> <%= yield %> + <%= theme_lookup("footer") %> diff --git a/app/views/users_email/show_confirm_new_email.html.erb b/app/views/users_email/show_confirm_new_email.html.erb index ba5102e13d..d5a49bc3cb 100644 --- a/app/views/users_email/show_confirm_new_email.html.erb +++ b/app/views/users_email/show_confirm_new_email.html.erb @@ -46,11 +46,11 @@ <% elsif @show_security_key %> <%= hidden_field_tag 'security_key_challenge', @security_key_challenge, id: 'security-key-challenge' %> <%= hidden_field_tag 'second_factor_method', UserSecondFactor.methods[:security_key] %> - <%= hidden_field_tag 'security_key_allowed_credential_ids', @security_key_allowed_credential_ids, id: 'security-key-allowed-credential-ids' %> + <%= hidden_field_tag 'security_key_allowed_credential_ids', @security_key_allowed_credential_ids.join(","), id: 'security-key-allowed-credential-ids' %>

<%= t('login.security_key_authenticate') %>

<%= t('login.security_key_description') %>

- <%= button_tag t('login.security_key_authenticate'), id: 'submit-security-key' %> + <%= button_tag t('login.security_key_authenticate'), id: 'submit-security-key', class: 'btn btn-primary' %>

<% if @show_second_factor %> @@ -77,9 +77,11 @@ <%end%> <% end%> - <%= preload_script "ember_jquery" %> <%= preload_script "locales/#{I18n.locale}" %> - <%= preload_script "locales/i18n" %> + <%- if ExtraLocalesController.client_overrides_exist? %> + <%= preload_script_url ExtraLocalesController.url('overrides') %> + <%- end %> + <%= preload_script 'ember_jquery' %> <%= preload_script "discourse/app/lib/webauthn" %> <%= preload_script "confirm-new-email/confirm-new-email" %> <%= preload_script "confirm-new-email/bootstrap" %> diff --git a/config/application.rb b/config/application.rb index a93c86c258..6120831f6d 100644 --- a/config/application.rb +++ b/config/application.rb @@ -27,14 +27,6 @@ require_relative '../lib/discourse_plugin_registry' require_relative '../lib/plugin_gem' -if ENV['ACTIVE_RECORD_RAILS_FAILOVER'] - require 'rails_failover/active_record' -end - -if ENV['REDIS_RAILS_FAILOVER'] - require 'rails_failover/redis' -end - # Global config require_relative '../app/models/global_setting' GlobalSetting.configure! @@ -51,6 +43,14 @@ if ENV['SKIP_DB_AND_REDIS'] == '1' GlobalSetting.skip_redis = true end +if !GlobalSetting.skip_db? + require 'rails_failover/active_record' +end + +if !GlobalSetting.skip_redis? + require 'rails_failover/redis' +end + require 'pry-rails' if Rails.env.development? if defined?(Bundler) diff --git a/config/discourse_defaults.conf b/config/discourse_defaults.conf index b2b2aff03e..b714d8161e 100644 --- a/config/discourse_defaults.conf +++ b/config/discourse_defaults.conf @@ -59,6 +59,8 @@ db_replica_host = # port running replica db server, defaults to 5432 if not set db_replica_port = +db_advisory_locks = true + # hostname running the forum hostname = "www.example.com" diff --git a/config/initializers/001-redis.rb b/config/initializers/001-redis.rb index d11303a9d5..3957d626b2 100644 --- a/config/initializers/001-redis.rb +++ b/config/initializers/001-redis.rb @@ -4,3 +4,7 @@ if Rails.env.development? && ENV['DISCOURSE_FLUSH_REDIS'] puts "Flushing redis (development mode)" Discourse.redis.flushdb end + +# Pending https://github.com/MiniProfiler/rack-mini-profiler/pull/450 and +# upgrade to Sidekiq 6.1 +Redis.exists_returns_integer = true diff --git a/config/initializers/002-rails_failover.rb b/config/initializers/002-rails_failover.rb index 54692b7f82..40809c14cd 100644 --- a/config/initializers/002-rails_failover.rb +++ b/config/initializers/002-rails_failover.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -if ENV["REDIS_RAILS_FAILOVER"] +if defined?(RailsFailover::Redis) message_bus_keepalive_interval = nil RailsFailover::Redis.on_failover do @@ -14,9 +14,15 @@ if ENV["REDIS_RAILS_FAILOVER"] Discourse.request_refresh! MessageBus.keepalive_interval = message_bus_keepalive_interval end + + if Rails.logger.respond_to? :chained + RailsFailover::Redis.logger = Rails.logger.chained.first + end end -if ENV["ACTIVE_RECORD_RAILS_FAILOVER"] +if defined?(RailsFailover::ActiveRecord) + return unless Rails.configuration.active_record_rails_failover + if Rails.configuration.multisite if ActiveRecord::Base.current_role == ActiveRecord::Base.reading_role RailsMultisite::ConnectionManagement.default_connection_handler = @@ -43,31 +49,13 @@ if ENV["ACTIVE_RECORD_RAILS_FAILOVER"] end end - module Discourse - PG_FORCE_READONLY_MODE_KEY ||= 'readonly_mode:postgres_force' - - READONLY_KEYS.push(PG_FORCE_READONLY_MODE_KEY) - - def self.enable_pg_force_readonly_mode - Discourse.redis.set(PG_FORCE_READONLY_MODE_KEY, 1) - Sidekiq.pause!("pg_failover") if !Sidekiq.paused? - MessageBus.publish(readonly_channel, true) - Site.clear_anon_cache! - true - end - - def self.disable_pg_force_readonly_mode - result = Discourse.redis.del(PG_FORCE_READONLY_MODE_KEY) - Sidekiq.unpause! - MessageBus.publish(readonly_channel, false) - result > 0 - end - end - RailsFailover::ActiveRecord.register_force_reading_role_callback do - Discourse.redis.exists( + Discourse.redis.exists?( Discourse::PG_READONLY_MODE_KEY, Discourse::PG_FORCE_READONLY_MODE_KEY ) + rescue => e + Rails.logger.warn "#{e.class} #{e.message}: #{e.backtrace.join("\n")}" + false end end diff --git a/config/initializers/100-quiet_logger.rb b/config/initializers/100-quiet_logger.rb index ad8e1798b9..6c7e11db62 100644 --- a/config/initializers/100-quiet_logger.rb +++ b/config/initializers/100-quiet_logger.rb @@ -8,7 +8,8 @@ module DiscourseRackQuietAssetsLogger def call(env) override = false if (env['PATH_INFO'].index("/assets/") == 0) || - (env['PATH_INFO'].index("mini-profiler-resources") == 0) + (env['PATH_INFO'].index("mini-profiler-resources") == 0) || + (env['PATH_INFO'].index("/srv/status") == 0) if ::Logster::Logger === Rails.logger override = true Rails.logger.override_level = Logger::ERROR diff --git a/config/initializers/100-sidekiq.rb b/config/initializers/100-sidekiq.rb index 892380708d..6d6e0ddb3a 100644 --- a/config/initializers/100-sidekiq.rb +++ b/config/initializers/100-sidekiq.rb @@ -70,7 +70,12 @@ if Sidekiq.server? scheduler_hostname = ENV["UNICORN_SCHEDULER_HOSTNAME"] if !scheduler_hostname || scheduler_hostname.split(',').include?(Discourse.os_hostname) - MiniScheduler.start(workers: GlobalSetting.mini_scheduler_workers) + begin + MiniScheduler.start(workers: GlobalSetting.mini_scheduler_workers) + rescue MiniScheduler::DistributedMutex::Timeout + sleep 5 + retry + end end end end diff --git a/config/initializers/200-first_middlewares.rb b/config/initializers/200-first_middlewares.rb index 5fada923cd..2467202d6e 100644 --- a/config/initializers/200-first_middlewares.rb +++ b/config/initializers/200-first_middlewares.rb @@ -24,12 +24,10 @@ if Rails.configuration.multisite # Multisite needs to be first, because the request tracker and message bus rely on it Rails.configuration.middleware.unshift RailsMultisite::Middleware, RailsMultisite::DiscoursePatches.config Rails.configuration.middleware.delete ActionDispatch::Executor -end -if ENV["ACTIVE_RECORD_RAILS_FAILOVER"] - if Rails.configuration.multisite + if defined?(RailsFailover::ActiveRecord) && Rails.configuration.active_record_rails_failover Rails.configuration.middleware.insert_after(RailsMultisite::Middleware, RailsFailover::ActiveRecord::Middleware) - else - Rails.configuration.middleware.insert_before(MessageBus::Rack::Middleware, RailsFailover::ActiveRecord::Middleware) end +elsif defined?(RailsFailover::ActiveRecord) && Rails.configuration.active_record_rails_failover + Rails.configuration.middleware.insert_before(MessageBus::Rack::Middleware, RailsFailover::ActiveRecord::Middleware) end diff --git a/config/locales/client.ar.yml b/config/locales/client.ar.yml index 4c1a70a7e1..72083bc0f9 100644 --- a/config/locales/client.ar.yml +++ b/config/locales/client.ar.yml @@ -835,6 +835,8 @@ ar: title: "تغيير اسم المستخدم" taken: "عذرا، اسم المستخدم غير متاح." invalid: "اسم المستخدم غير صالح. يمكنه احتواء احرف و ارقام انجليزية فحسب" + add_email: + add: "أضف" change_email: title: "غيّر البريد الإلكتروني" taken: "عذرا، البريد الإلكتروني غير متوفر." @@ -853,6 +855,8 @@ ar: instructions: "سيتم وضع صورة الخلفية في المنتصف بعرض 590px" email: title: "البريد الإلكتروني" + primary_label: "الأساسي" + update_email: "غيّر البريد الإلكتروني" ok: "سنرسل لك بريدا للتأكيد" invalid: "من فضلك أدخل بريدا إلكترونيا صالحا" authenticated: "تم توثيق بريدك الإلكتروني بواسطة %{provider}" @@ -2041,7 +2045,6 @@ ar: last: "آخر مراجعة" hide: "أخفِ المراجعة" show: "أظهر المراجعة" - revert: "ارجع إلى هذه المراجعة" edit_wiki: "عدل الwiki" edit_post: "عدل المنشور" displays: @@ -2641,7 +2644,7 @@ ar: total: "مجموع الوقت الكلي" no_data: "لا توجد بيانات للعرض" filters: - file-extension: + file_extension: label: إمتداد الملف group: label: المجموعة diff --git a/config/locales/client.be.yml b/config/locales/client.be.yml index 982c44fc43..0ce957b9a9 100644 --- a/config/locales/client.be.yml +++ b/config/locales/client.be.yml @@ -479,6 +479,8 @@ be: title: "Змена імя карыстальніка" taken: "Выбачайце, гэтае імя карыстальніка ўжо занятае." invalid: "Такое імя карыстальніка не падыйдзе. Яно павінна ўтрымліваць толькі лічбы і літары" + add_email: + add: "дадаць" change_email: title: "Змяненне адрасы электроннай пошты" taken: "Выбачайце, гэты адрас не даступны." @@ -493,6 +495,8 @@ be: title: "Фон вашай візітоўкі" email: title: "Электронная пошта" + primary_label: "асноўнай" + update_email: "Змяненне адрасы электроннай пошты" invalid: "Калі ласка, увядзіце верны email" associated_accounts: title: "Асацыяваныя аккаўнты" @@ -1024,6 +1028,8 @@ be: error: "Пры пераносе паведамленняў да гэтай тэмы адбылася памылка." move_to_new_message: radio_label: "новае паведамленне" + publish_page: + public: "грамадскага" change_timestamp: title: "Змяніць метку часу" action: "змяніць метку часу" @@ -1059,7 +1065,6 @@ be: last: "Апошняя рэвізія" hide: " Схаваць рэвізію" show: "Паказаць рэвізію" - revert: "Адкат да гэтай рэвізіі" displays: inline: title: "Адлюстраваць паведамленне з улучанымі дадаткамі і выдаленнямі." diff --git a/config/locales/client.bg.yml b/config/locales/client.bg.yml index efc23c459e..22b381d063 100644 --- a/config/locales/client.bg.yml +++ b/config/locales/client.bg.yml @@ -811,6 +811,8 @@ bg: title: "Смяна на потребителското име." taken: "Съжаляваме, това потребителско име е заето." invalid: "Потребителското име не е валидно. Трябва да включва само цифри и букви" + add_email: + add: "добавяне" change_email: title: "Смяна на Имейла" taken: "Съжаляваме, този имейл адрес не е свободен." @@ -829,6 +831,8 @@ bg: instructions: "Фонът ще бъде центриран и ще има дължина 590 пиксела." email: title: "Имейл" + primary_label: "главен" + update_email: "Смяна на Имейла" instructions: "Не е публичен" ok: "Ще Ви изпратим имейл за потвърждение." invalid: "Моля, въведете валиден имейл адрес" @@ -1656,6 +1660,7 @@ bg: radio_label: "Ново Съобщение" publish_page: title: "Публикуване на страници" + public: "Публични" change_owner: action: "смени собственика" error: "Възникна грешка при смяната на собственика" @@ -1797,7 +1802,6 @@ bg: last: "Последна ревизия" hide: "Скрий ревизията" show: "Покажи ревизията" - revert: "Връщане към тази редакция" edit_wiki: "Редактиране на Wiki" edit_post: "Редактиране на публикацията" displays: diff --git a/config/locales/client.bs_BA.yml b/config/locales/client.bs_BA.yml index 70d0af662d..0eda001731 100644 --- a/config/locales/client.bs_BA.yml +++ b/config/locales/client.bs_BA.yml @@ -779,7 +779,6 @@ bs_BA: all: "Sve" read: "Učitaj" unread: "Nepročitanih" - ignore_duration_title: "Zanemari tajmer" ignore_duration_username: "Ime" ignore_duration_when: "Trajanje:" ignore_duration_save: "Zanemari" @@ -992,6 +991,8 @@ bs_BA: confirm: "Da li ste apsolutno sigurni da želite promijeniti svoje korisničko ime?" taken: "Nažalost, to korisničko ime je zauzeto." invalid: "To korisničko ime nije validno. Mora sadržavati samo brojeve i slova" + add_email: + add: "Dodaj" change_email: title: "Promijeni Email" taken: "Nažalost, taj email nije dostupan." @@ -1018,8 +1019,10 @@ bs_BA: title: "Email" primary: "Primarni Email" secondary: "Sekundari Emailovi" - no_secondary: "Nema sekundarnih emailova" + primary_label: "primary" + update_email: "Promijeni Email" sso_override_instructions: "E-pošta se može ažurirati od SSO provajdera." + no_secondary: "Nema sekundarnih emailova" instructions: "Nikada nije prikazan javnosti." ok: "Izgleda dobro. Poslat ćemo email sa potvrdom." invalid: "Molimo vas da unesete validnu email adresu." @@ -1305,8 +1308,6 @@ bs_BA: enabled: "Ovaj sajt je u read only mod-u: Dozvoljeno je čitati. Možete nastaviti sa pregledom, ali odgovaranje na objave, lajkanje i ostale akcije su isključene za sada." login_disabled: "Ulogovanje je isključeno jer je sajt u read only načinu rada." logout_disabled: "Odjava je isključena sve dok je sajt u read only tj. samo čitanje je dozvoljeno načinu rada." - logs_error_rate_notice: - reached_hour_MF: "{realtivna starost} - {stopa, množina, jedna {# pogreška / sat} ostala {# errors / hour}} dostigla je granicu postavljanja stranice {granica, množina, jednu {# error / hour} druge {# errors / hour}}." learn_more: "saznaj više..." all_time: "ukupno" all_time_desc: "ukupno kreiranih tema" @@ -2229,6 +2230,8 @@ bs_BA: title: "Spoji izabrane postove" action: "spoji izabrane postove" error: "Desila se greška prilikom spajanja označenih objava." + publish_page: + public: "Javno" change_owner: title: "Change Owner" action: "change ownership" @@ -2431,7 +2434,6 @@ bs_BA: last: "Last revision" hide: "Hide revision" show: "Show revision" - revert: "Vratite se na ovu reviziju" edit_wiki: "Promjni Wiki" edit_post: "Promjeni Post" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -3099,7 +3101,7 @@ bs_BA: more: 'Pretraživanje dnevnika' disabled: 'Izvješće o pretraživanju trendova je onemogućeno. Omogućite upite pretraživanja dnevnika za prikupljanje podataka.' filters: - file-extension: + file_extension: label: Ekstenzija datoteke group: label: Grupa diff --git a/config/locales/client.ca.yml b/config/locales/client.ca.yml index 1387fda522..a998e6335e 100644 --- a/config/locales/client.ca.yml +++ b/config/locales/client.ca.yml @@ -734,7 +734,6 @@ ca: all: "Tot" read: "Llegit" unread: "No llegits" - ignore_duration_title: "Ignora el temporitzador" ignore_duration_username: "Nom d'usuari " ignore_duration_when: "Duració:" ignore_duration_save: "Ignora" @@ -942,6 +941,8 @@ ca: confirm: "Esteu del tot segur que voleu canviar el nom d'usuari?" taken: "Aquest nom d'usuari ja està agafat." invalid: "El nom d'usuari no és vàlid. Ha d'incloure només xifres i lletres." + add_email: + add: "afegeix" change_email: title: "Canvi de correu" taken: "Aquest correu electrònic no està disponible." @@ -969,8 +970,10 @@ ca: title: "Correu electrònic" primary: "Adreça de correu primària" secondary: "Adreces de correu secundàries" - no_secondary: "Sense adreces de correu secundàries" + primary_label: "primari" + update_email: "Canvi de correu" sso_override_instructions: "L'adreça de correu es pot actualitzar des d'un proveïdor SSO" + no_secondary: "Sense adreces de correu secundàries" instructions: "No es mostra mai en públic." ok: "Us enviarem un correu electrònic de confirmació" invalid: "Introduïu una adreça vàlida de correu electrònic" @@ -1249,7 +1252,7 @@ ca: login_disabled: "S'ha desactivat l'inici de sessió mentre aquest lloc web es trobi en mode només de lectura." logout_disabled: "S'ha desactivat el tancament de sessió mentre aquest lloc web es trobi en mode només de lectura." logs_error_rate_notice: - reached_hour_MF: "{relativeAge} - {rate, plural, one {# error/hora} other {# errors/hora} s'ha arribat al límit de configuració del lloc web de {limit, plural, one {# error/hora} other {# errors/hora}}." + reached_hour_MF: "{relativeAge} - {rate, plural, one {# error/hora} other {# errors/hora}} s'ha arribat al límit de configuració del lloc web de {limit, plural, one {# error/hora} other {# errors/hora}}." reached_minute_MF: "{relativeAge} - {rate, plural, one {# error/minut} other {# errors/minut}} s'ha arribat al límit de configuració del lloc web de {limit, plural, one {# error/minut} other {# errors/minut}}." exceeded_hour_MF: "{relativeAge}{rate, plural, one {# error/hora} other {# errors/hora}} s'ha superat el límit de la configuració del lloc web de {limit, plural, one {# error/hora} other {# errors/hora}}." exceeded_minute_MF: "{relativeAge}{rate, plural, one {# error/minut} other {# errors/minut}} s'ha superat el límit de la configuració del lloc web de {limit, plural, one {# error/minut} other {# errors/minut}}." @@ -2161,6 +2164,8 @@ ca: title: "Combina les publicacions seleccionades" action: "combina les publicacions seleccionades" error: "Hi ha hagut un error en unir les publicacions seleccionades." + publish_page: + public: "Públic" change_owner: title: "Canvia el propietari" action: "canvia la propietat" @@ -2355,7 +2360,6 @@ ca: last: "Darrera revisió" hide: "Amaga la revisió" show: "Mostra la revisió" - revert: "Reverteix a aquesta revisió" edit_wiki: "Edita Wiki" edit_post: "Edita publicació" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -2988,7 +2992,7 @@ ca: more: 'Cerca de registres (logs)' disabled: 'El report de cerca de tendències està desactivat. Habiliteu les consultes de cerca de registres per a recopilar dades.' filters: - file-extension: + file_extension: label: Extensió de fitxer group: label: Grup diff --git a/config/locales/client.cs.yml b/config/locales/client.cs.yml index b2f81bc439..91283d1a47 100644 --- a/config/locales/client.cs.yml +++ b/config/locales/client.cs.yml @@ -800,6 +800,8 @@ cs: confirm: "Jste si naprosto jisti, že chcete změnit své uživatelské jméno?" taken: "Toto uživatelské jméno je již zabrané." invalid: "Uživatelské jméno je neplatné. Musí obsahovat pouze písmena a číslice." + add_email: + add: "přidat" change_email: title: "Změnit emailovou adresu" taken: "Tato emailová adresa není k dispozici." @@ -820,6 +822,8 @@ cs: title: "Emailová adresa" primary: "Hlavní email" secondary: "Záložní emailové adresy" + primary_label: "primární" + update_email: "Změnit emailovou adresu" no_secondary: "Žádné záložní emailové adresy" instructions: "Nikdy nebude zveřejněno." ok: "Pro potvrzení vám pošleme email." @@ -1943,6 +1947,8 @@ cs: title: "Sluč vybrané příspěvky" action: "sluč vybrané příspěvky" error: "Během slučování vybraných příspěvků došlo k chybě." + publish_page: + public: "Veřejné" change_owner: title: "Změnit vlastníka" action: "změnit autora" @@ -2142,7 +2148,6 @@ cs: last: "Poslední revize" hide: "Schovejte revizi" show: "Zobrazte revizi" - revert: "Vrátit se k této revizi" edit_wiki: "Upravit Wiki" edit_post: "upravit příspěvek" displays: diff --git a/config/locales/client.da.yml b/config/locales/client.da.yml index 165c033d9d..1adeb84089 100644 --- a/config/locales/client.da.yml +++ b/config/locales/client.da.yml @@ -730,7 +730,6 @@ da: all: "Alle" read: "Læste" unread: "Ulæst" - ignore_duration_title: "Ignorér timer" ignore_duration_username: "Brugernavn" ignore_duration_when: "Varighed:" ignore_duration_save: "Ignorér" @@ -936,6 +935,8 @@ da: confirm: "Er du helt sikker på, at du vil ændre dit brugernavn?" taken: "Beklager, det brugernavn er optaget." invalid: "Det brugernavn er ugyldigt. Det må kun bestå af bogstaver og tal." + add_email: + add: "tilføj" change_email: title: "Skift e-mail-adresse" taken: "Beklager, den e-mail-adresse er optaget af en anden bruger." @@ -956,8 +957,10 @@ da: title: "E-mail" primary: "Primær email" secondary: "Sekundære emails" - no_secondary: "Ingen sekundære emails" + primary_label: "Primær" + update_email: "Skift e-mail-adresse" sso_override_instructions: "Email kan opdateres fra SSO-udbyderen." + no_secondary: "Ingen sekundære emails" instructions: "Vis aldrig offentligt" ok: "Vi vil sende dig en bekræftelses email" invalid: "Indtast venligst en gyldig email adresse" @@ -1233,11 +1236,6 @@ da: enabled: "Dette website kan kun læses lige nu. Fortsæt endelig med at kigge, men der kan ikke svares, likes eller andet indtil videre." login_disabled: "Log in er deaktiveret midlertidigt, da forummet er i \"kun læsnings\" tilstand." logout_disabled: "Log ud er deaktiveret mens websitet er i læs kun tilstand" - logs_error_rate_notice: - reached_hour_MF: "{relativeAge} - {rate, plural, en {# error / hour} anden {# fejl / time}} nåede indstillingsgrænsen på {limit, plural, en {# error / hour} anden {# fejl / hour}}." - reached_minute_MF: "{relativeAge} - {rate, plural, en {# error / minute} other {# fejl / minut}} nåede indstillingsgrænsen på {limit, plural, en {# error / minute} anden {# fejl / minut}}." - exceeded_hour_MF: "{relativeAge} - {rate, plural, en {# error / hour} other {# error / hour}} har overskredet indstillingsgræsen på {limit, plural, en {# error / hour} anden {# error / hour}}." - exceeded_minute_MF: "{relativeAge} - {rate, plural, en {# error / minute} anden {# fejl / minut}} overskredet indstillingsgrænsen på {limit, plural, en {# error / minute} anden {# fejl / minut}}." learn_more: "Læs mere…" all_time: "i alt" all_time_desc: "emner oprettet i alt" @@ -2126,6 +2124,8 @@ da: title: "Flet valgte indlæg" action: "flet valgte indlæg" error: "Der opstod en fejl med at flette de valgte indlæg." + publish_page: + public: "Offentlig" change_owner: title: "Skift ejer" action: "skift ejerskab" @@ -2315,7 +2315,6 @@ da: last: "Sidste udgave" hide: "Skjul udgave" show: "Vis udgave" - revert: "Gå tilbage til denne udgave" edit_wiki: "Ret Wiki" edit_post: "Ret Indlæg" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -2939,7 +2938,7 @@ da: more: 'Søg logfiler' disabled: 'Rapport over søge tendenser er deaktiveret. Aktivér log søgeforespørgelser for at indsamle data.' filters: - file-extension: + file_extension: label: Filtypenavn group: label: Gruppe diff --git a/config/locales/client.de.yml b/config/locales/client.de.yml index 535d412514..489e39d71f 100644 --- a/config/locales/client.de.yml +++ b/config/locales/client.de.yml @@ -291,6 +291,8 @@ de: tomorrow_with_time: "morgen um %{time}" at_time: "um %{date_time}" existing_reminder: "Es gibt eine Erinnerung für dieses Lesezeichen, die versendet werden wird" + copy_codeblock: + copied: "kopiert!" drafts: resume: "Fortsetzen" remove: "Entfernen" @@ -679,6 +681,9 @@ de: flair_color_placeholder: "(Optoinal) Hex-Farbwert" flair_preview_icon: "Vorschau-Icon" flair_preview_image: "Vorschaubild" + flair_type: + icon: "Wähle ein Symbol" + image: "Lade ein Bild hoch" user_action_groups: "1": "Abgegebene Likes" "2": "Erhaltene Likes" @@ -758,7 +763,6 @@ de: all: "Alle" read: "Gelesen" unread: "Ungelesen" - ignore_duration_title: "Zeitschaltuhr ignorieren" ignore_duration_username: "Benutzername" ignore_duration_when: "Dauer:" ignore_duration_save: "Ignorieren" @@ -973,6 +977,8 @@ de: confirm: "Bist du dir ganz sicher, dass du deinen Benutzernamen ändern möchtest?" taken: "Der Benutzername ist bereits vergeben." invalid: "Der Benutzernamen ist nicht zulässig. Er darf nur Zahlen und Buchstaben enthalten." + add_email: + add: "Hinzufügen" change_email: title: "E-Mail-Adresse ändern" taken: "Entschuldige, diese E-Mail-Adresse ist nicht verfügbar." @@ -1001,8 +1007,10 @@ de: title: "E-Mail" primary: "Primäre E-Mail-Adresse" secondary: "Weitere E-Mail-Adressen" - no_secondary: "Keine weiteren E-Mail-Adressen" + primary_label: "erste" + update_email: "E-Mail-Adresse ändern" sso_override_instructions: "E-Mail kann vom SSO-Provider aktualisiert werden." + no_secondary: "Keine weiteren E-Mail-Adressen" instructions: "Nie öffentlich gezeigt." ok: "Wir senden dir zur Bestätigung eine E-Mail" invalid: "Bitte gib eine gültige E-Mail-Adresse ein" @@ -1164,12 +1172,15 @@ de: account_age_days: "Konto-Alter in Tagen" links_tab: "Links" link_created_at: "Erstellt" + link_redemption_stats: "Rücknahmen" link_groups: Gruppen create: "Einladung versenden" + copy_link: "Link kopieren" generate_link: "Einladungslink kopieren" link_generated: "Der Einladungslink wurde erfolgreich generiert!" valid_for: "Der Einladungslink ist nur für die Adresse %{email} gültig" single_user: "Einzelbenutzer" + multiple_user: "Mehrere Benutzer" invite_link: success: "Der Einladungslink wurde erfolgreich generiert!" bulk_invite: @@ -2211,6 +2222,8 @@ de: title: "Ausgewählte Beiträge zusammenführen" action: "ausgewählte Beiträge zusammenführen" error: "Es gab einen Fehler beim Zusammenführen der ausgewählten Beiträge." + publish_page: + public: "Öffentlich" change_owner: title: "Eigentümer ändern" action: "Eigentümer ändern" @@ -2411,7 +2424,6 @@ de: last: "Letzte Überarbeitung" hide: "Überarbeitung verstecken" show: "Überarbeitung anzeigen" - revert: "Diese Überarbeitung wiederherstellen" edit_wiki: "Bearbeite Wiki" edit_post: "Bearbeite Beitrag" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -3067,7 +3079,7 @@ de: more: 'Suchprotokoll' disabled: 'Der Bericht über beliebte Suchen ist deaktiviert. Aktiviere Suchanfragen protokollieren, um die Daten zu erheben.' filters: - file-extension: + file_extension: label: Dateiendung group: label: Gruppe diff --git a/config/locales/client.el.yml b/config/locales/client.el.yml index 97356cf7d9..c0c9b07b2b 100644 --- a/config/locales/client.el.yml +++ b/config/locales/client.el.yml @@ -662,6 +662,8 @@ el: title: "Αλλαγή Ονόματος Χρήστη" taken: "Λυπούμαστε, αυτό το όνομα χρήστη χρησιμοποιείται ήδη." invalid: "Αυτό το όνομα χρήστη δεν είναι έγκυρο. Θα πρέπει να αποτελείται μόνο από αριθμούς και γράμματα" + add_email: + add: "προσθήκη" change_email: title: "Αλλαγή διεύθυνσης Email" taken: "Λυπούμαστε, αυτή η διεύθυνση email δεν είναι διαθέσιμη." @@ -680,6 +682,8 @@ el: instructions: "Οι εικόνες στο φόντο θα κεντραρίζονται και το προκαθορισμένο πλάτος τους είναι 590px." email: title: "Email" + primary_label: "κύριο" + update_email: "Αλλαγή διεύθυνσης Email" ok: "Για επιβεβαίωση θα σου στείλουμε ένα email" invalid: "Παρακαλώ δώσε μία έγκυρη διεύθυνση email" authenticated: "Η διεύθυνση email σου ταυτοποιήθηκε από τον πάροχο %{provider}" @@ -1616,6 +1620,8 @@ el: title: "Συγχώνευσε Επιλεγμένες Αναρτήσεις" action: "συγχώνευσε επιλεγμένες αναρτήσεις" error: "Προέκυψε σφάλμα κατά τη συγχώνευση των επιλεγμένων αναρτήσεων." + publish_page: + public: "Δημόσια" change_owner: action: "αλλαγή ιδιοκτήτη" error: "Παρουσιάστηκε ένα σφάλμα κατά την αλλαγή του ιδιοκτήτη των αναρτήσεων." @@ -1758,7 +1764,6 @@ el: last: "Τελευταία αναθεώρηση" hide: "Κρύψε την αναθεώρηση" show: "Εμφάνισε την αναθεώρηση" - revert: "Επιστροφή σε αυτήν την αναθεώρηση" edit_wiki: "Επεξεργασία του Βίκι" edit_post: "Επεξεργασία Ανάρτησης" displays: diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 104edd8793..0045b41d07 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -847,7 +847,7 @@ en: all: "All" read: "Read" unread: "Unread" - ignore_duration_title: "Ignore Timer" + ignore_duration_title: "Ignore User" ignore_duration_username: "Username" ignore_duration_when: "Duration:" ignore_duration_save: "Ignore" @@ -1131,7 +1131,8 @@ en: set_primary: "Set Primary Email" destroy: "Remove Email" add_email: "Add Alternate Email" - ssDestroy_override_instructions: "Email can be updated from SSO provider." + sso_override_instructions: "Email can be updated from SSO provider." + no_secondary: "No secondary emails" instructions: "Never shown to the public." ok: "We will email you to confirm" required: "Please enter an email address" @@ -2225,6 +2226,7 @@ en: time_frame_required: Please select a time frame auto_update_input: none: "Select a timeframe" + now: "Now" later_today: "Later today" tomorrow: "Tomorrow" later_this_week: "Later this week" @@ -2512,11 +2514,14 @@ en: publish: "Publish" description: "When a topic is published as a page, its URL can be shared and it will displayed with custom styling." slug: "Slug" + public: "Public" + public_description: "People can see the page even if the associated topic is private." publish_url: "Your page has been published at:" topic_published: "Your topic has been published at:" preview_url: "Your page will be published at:" invalid_slug: "Sorry, you can't publish this page." unpublish: "Unpublish" + update: "Update" unpublished: "Your page has been unpublished and is no longer accessible." publishing_settings: "Publishing Settings" @@ -2598,6 +2603,7 @@ en: one: "%{count} Reply" other: "%{count} Replies" + unknown_user: "(unknown/deleted user)" has_likes_title: one: "%{count} person liked this post" other: "%{count} people liked this post" @@ -2744,7 +2750,7 @@ en: last: "Last revision" hide: "Hide revision" show: "Show revision" - revert: "Revert to this revision" + revert: "Revert to revision %{revision}" edit_wiki: "Edit Wiki" edit_post: "Edit Post" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -4754,8 +4760,9 @@ en: category_id: "Category ID" category_title: "Category" tag_name: "Tag name" - external_url: "External URL" + external_url: "External or Relative URL" destination: "Destination" + copy_to_clipboard: "Copy Permalink to Clipboard" delete_confirm: Are you sure you want to delete this permalink? form: label: "New:" diff --git a/config/locales/client.es.yml b/config/locales/client.es.yml index b90248cf8b..e313e4b8f6 100644 --- a/config/locales/client.es.yml +++ b/config/locales/client.es.yml @@ -767,7 +767,6 @@ es: all: "Todo" read: "Leídos" unread: "Sin leer" - ignore_duration_title: "Temporizador de ignorado" ignore_duration_username: "Nombre de usuario" ignore_duration_when: "Duración:" ignore_duration_save: "Ignorar" @@ -989,6 +988,8 @@ es: confirm: "¿Estás completamente seguro de que quieres cambiar tu nombre de usuario?" taken: "Lo sentimos, ese nombre de usuario ya se encuentra en uso." invalid: "Este nombre de usuario no es válido. Este solo puede incluir números y letras" + add_email: + add: "añadir" change_email: title: "Cambiar correo electrónico" taken: "Lo sentimos, ese correo electrónico no está disponible." @@ -1019,8 +1020,10 @@ es: title: "Correo electrónico" primary: "Correo electrónico principal" secondary: "Correos electrónicos secundarios" - no_secondary: "Sin correos electrónicos secundarios" + primary_label: "primario" + update_email: "Cambiar correo electrónico" sso_override_instructions: "El correo electrónico puede actualizarse desde el proveedor de SSO." + no_secondary: "Sin correos electrónicos secundarios" instructions: "Nunca se mostrará al público." ok: "Te enviaremos un correo electrónico para confirmar" required: "Por favor, introduce un correo electrónico" @@ -2253,6 +2256,7 @@ es: publish: "Publicar" description: "Cuando un tema se publica como página su URL se puede compartir y se mostrará con estilos personalizados." slug: "Slug" + public: "Público" publish_url: "La página se ha publicado en:" topic_published: "El tema se ha publicado en:" preview_url: "La página será publicada en:" @@ -2464,7 +2468,6 @@ es: last: "Última revisión" hide: "Ocultar revisión." show: "Mostrar revisión." - revert: "Volver a esta revisión" edit_wiki: "Editar wiki" edit_post: "Editar publicación" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -3149,13 +3152,13 @@ es: more: 'Buscar registros' disabled: 'El reporte de tendencias de búsqueda está desactivado. Activa la opción registrar consultas de búsquedas para recolectar datos.' filters: - file-extension: + file_extension: label: Extensión del archivo group: label: Grupo category: label: Categoría - include-subcategories: + include_subcategories: label: "Incluir subcategoría" commits: latest_changes: "Cambios recientes: ¡por favor, actualiza a menudo!" diff --git a/config/locales/client.et.yml b/config/locales/client.et.yml index e2478f0ade..433f36a760 100644 --- a/config/locales/client.et.yml +++ b/config/locales/client.et.yml @@ -704,6 +704,8 @@ et: title: "Muuda kasutajanime" taken: "Vabandust, see kasutajanimi on võetud." invalid: "Selline kasutajanimi ei ole lubatud. Kasutada tohib ainult numbreid ja tähti" + add_email: + add: "lisa" change_email: title: "Muuda meiliaadressi" taken: "Vabandust, see meiliaadress ei ole saadaval." @@ -723,6 +725,8 @@ et: title: "Meiliaadress" primary: "Peamine e-post" secondary: "Teine e-post" + primary_label: "primaarne" + update_email: "Muuda meiliaadressi" no_secondary: "Teist e-posti pole" instructions: "Ära näita kunagi avalikkusele." ok: "Saadame sulle kinnituseks meili" @@ -1686,6 +1690,8 @@ et: title: "Ühenda valitud postitused" action: "ühenda valitud postitused" error: "Valitud postituste ühendamisel tekkis viga." + publish_page: + public: "Avalik" change_owner: title: "Muuda omanikku" action: "muuda omanikku" @@ -1832,7 +1838,6 @@ et: last: "Viimane redaktsioon" hide: "Peida redaktsioon" show: "Näita redaktsiooni" - revert: "Ennista selleks redaktsiooniks" edit_wiki: "Muuda wikit" edit_post: "Muuda postitust" displays: diff --git a/config/locales/client.fa_IR.yml b/config/locales/client.fa_IR.yml index eb44b2c1ed..f752e174f6 100644 --- a/config/locales/client.fa_IR.yml +++ b/config/locales/client.fa_IR.yml @@ -758,7 +758,6 @@ fa_IR: all: "همه" read: "خواندن" unread: "خوانده‌ نشده‌" - ignore_duration_title: "از زمانسنج صرف نظر کن" ignore_duration_username: "نام‌کاربری" ignore_duration_when: "مدت زمان:" ignore_duration_save: "چشم پوشی" @@ -972,6 +971,8 @@ fa_IR: confirm: "مطمئنید میخواهید نام کاربری خود را تغییر دهید؟" taken: "متأسفیم، آن نام کاربری قبلا گرفته شده است." invalid: "آن نام کاربری نامعتبر است. تنها باید عددها و حرف‌ها را در بر بگیرد." + add_email: + add: "اضافه کردن" change_email: title: "تغییر ایمیل" taken: "متأسفیم، آن ایمیل در دسترس نیست." @@ -995,8 +996,10 @@ fa_IR: title: "ایمیل" primary: "آدرس ایمیل اصلی" secondary: "آدرس ایمیل ثانویه" - no_secondary: "بدون ایمیل ثانویه" + primary_label: "اصلی" + update_email: "تغییر ایمیل" sso_override_instructions: "ایمیل را میتوانید از طریق SSO به روزرسانی کنید" + no_secondary: "بدون ایمیل ثانویه" instructions: "هرگز به عموم نمایش داده نخواهد شد" ok: "برای تایید ایمیلی برایتان ارسال خواهیم کرد." required: "لطفا یک آدرس ایمیل وارد کنید" @@ -2168,6 +2171,7 @@ fa_IR: error: "خطایی در ادغام نوشته‌های انتخاب شده رخ داده است." publish_page: publish: "انتشار" + public: "عمومی" publish_url: "صفحه شما منتشر شده در:" topic_published: "مبحث شما منتشر شده در:" preview_url: "صفحه شما منتشر خواهد شد در:" @@ -2350,7 +2354,6 @@ fa_IR: last: "بازبینی آخر" hide: "مخفی کردن بازبینی" show: "نمایش بازبینی" - revert: "بازگشت به این بازبینی" edit_wiki: "ویرایش دانشنامه" edit_post: "ویرایش نوشته" comparing_previous_to_current_out_of_total: "%{previous}%{icon}%{current}/%{total}" diff --git a/config/locales/client.fi.yml b/config/locales/client.fi.yml index 4c30f26f67..dd1ebb927d 100644 --- a/config/locales/client.fi.yml +++ b/config/locales/client.fi.yml @@ -770,7 +770,6 @@ fi: all: "Kaikki" read: "Luetut" unread: "Lukematta" - ignore_duration_title: "Estoajastin" ignore_duration_username: "Käyttäjätunnus" ignore_duration_when: "Kesto:" ignore_duration_save: "Sivuuta" @@ -876,7 +875,9 @@ fi: admin_delete: "Poista" users: "Käyttäjät" muted_users: "Vaimennetut" + muted_users_instructions: "Älä näytä ilmoituksia tai vastaanota yksityisviestejä näiltä käyttäjiltä." ignored_users: "Sivuutettu" + ignored_users_instructions: "Älä näytä näiden käyttäjien viestejä, näytä heiltä ilmoituksia äläkä vastaanota heiltä yksityisviestejä." tracked_topics_link: "Näytä" automatically_unpin_topics: "Poista kiinnitetyn ketjun kiinnitys automaattisesti, kun olen selannut sen loppuun." apps: "Sovellukset" @@ -994,6 +995,9 @@ fi: confirm: "Oletko aivan varma että haluat vaihtaa käyttäjänimesi?" taken: "Pahoittelut, tuo nimi on jo käytössä." invalid: "Käyttäjätunnus ei kelpaa. Siinä saa olla ainoastaan numeroita ja kirjaimia." + add_email: + title: "Lisää sähköpostiosoite" + add: "lisää" change_email: title: "Vaihda sähköposti" taken: "Pahoittelut, tämä sähköpostiosoite ei ole saatavilla." @@ -1023,6 +1027,15 @@ fi: title: "Sähköposti" primary: "Ensisijainen sähköpostiosoite" secondary: "Toissijaiset sähköpostiosoitteet" + primary_label: "ensisijainen väri" + unconfirmed_label: "vahvistamaton" + resend_label: "lähetä vahvistussähköposti uudelleen" + resending_label: "lähetetään..." + resent_label: "sähköposti lähetetty" + update_email: "Vaihda sähköposti" + set_primary: "Aseta ensisijainen sähköpostiosoite" + destroy: "Poista sähköpostiosoite" + add_email: "Lisää vaihtoehtoinen sähköpostiosoite" no_secondary: "Ei toissijaisia sähköpostiosoitteita" instructions: "Ei tule julkiseksi." ok: "Lähetämme sinulle sähköpostin varmistukseksi." @@ -1176,6 +1189,7 @@ fi: expired: "Tämä kutsu on rauennut." rescind: "Poista" rescinded: "Kutsu poistettu" + rescind_all: "Poista vanhentuneet kutsut" rescinded_all: "Kaikki vanhentuneet kutsut poistettu!" rescind_all_confirm: "Haluatko varmasti poistaa kaikki vanhentuneet kutsut?" reinvite: "Lähetä kutsu uudestaan" @@ -1186,18 +1200,29 @@ fi: time_read: "Lukuaika" days_visited: "Päiviä vierailtu" account_age_days: "Tilin ikä päivissä" + source: "Kutsuttiin tavalla" links_tab: "Linkit" + links_tab_with_count: "Linkit (%{count})" + link_url: "Linkki" link_created_at: "Luotu" link_groups: Ryhmät + link_expires_at: Vanhenee create: "Lähetä kutsu" + copy_link: "Kopioi linkki" generate_link: "Kopioi kutsulinkki" link_generated: "Kutsulinkki luotiin onnistuneesti!" valid_for: "Kutsulinkki on käypä tälle sähköpostiosoitteelle: %{email}" single_user: "Yksittäinen käyttäjä" + multiple_user: "Useita käyttäjiä" invite_link: + title: "Kutsulinkki" success: "Kutsulinkki luotiin onnistuneesti!" + error: "Kutsulinkin luominen epäonnistui" + max_redemptions_allowed_label: "Kuinka moni voi enintään liittyä tämä linkin avulla?" + expires_at: "Koska tämä linkki vanhenee?" bulk_invite: none: "Et ole kutsunut vielä ketään tänne. Voit lähettää yksittäisiä kutsuja tai kutsua joukon ihmisiä kerralla lataamalla CSV-tiedoston." + text: "Massakutsu" success: "Tiedoston lähettäminen onnistui. Saat viestin, kun prosessi on valmis." error: "Pahoittelut, tiedoston tulee olla CSV-muodossa." confirmation_message: "Olet lähettämässä kutsun kaikkiin sähköpostiosoitteisiin, jotka lähettämässäsi tiedostossa on." @@ -1688,6 +1713,9 @@ fi: message: one: "Uusi yksityisviesti" other: "%{count} uutta yksityisviestiä" + high_priority: + one: "%{count} korkean prioriteetin ilmoitus" + other: "%{count} lukematonta korkean prioriteetin ilmoitusta" title: "ilmoitukset @nimeen viittauksista, vastauksista omiin viesteihin ja ketjuihin, viesteistä ym." none: "Ilmoitusten lataaminen ei onnistunut." empty: "Ilmoituksia ei löydetty." @@ -1996,6 +2024,7 @@ fi: time_frame_required: Valitse ajanjakso auto_update_input: none: "Valitse ajanjakso" + now: "Nyt" later_today: "Myöhemmin tänään" tomorrow: "Huomenna" later_this_week: "Myöhemmin tällä viikolla" @@ -2255,6 +2284,18 @@ fi: publish_page: title: "Sivujulkaisu" publish: "Julkaise" + description: "Kun ketju julkaistaan sivuna, sen verkko-osoitteen voi jakaa ja se näytetään erityisellä tavalla muotoiltuna." + slug: "Polkutunnus" + public: "Julkinen" + public_description: "Ihmiset näkevät sivun, vaikka siihen liittyvä ketju olisi yksityinen." + publish_url: "Sivusi julkaistiin osoitteessa:" + topic_published: "Ketjusi julkaistiin osoitteessa;" + preview_url: "Sivusi julkaistaan osoitteessa:" + invalid_slug: "Pahoittelut, et voi julkaista tätä sivua." + unpublish: "Peru julkaisu" + update: "Päivitä" + unpublished: "Sivusi julkaisu peruttiin, sille ei ole enää pääsyä." + publishing_settings: "Julkaisuasetukset" change_owner: title: "Vaihda omistajaa" action: "muokkaa omistajuutta" @@ -2263,6 +2304,9 @@ fi: instructions: one: "Valitse uusi omistaja käyttäjän @%{old_user} viestille." other: "Valitse uusi omistaja käyttäjän @%{old_user} %{count} viestille." + instructions_without_old_user: + one: "Valitse uusi omistaja viestille" + other: "Valitse uusi omistaja %{count} viestille" change_timestamp: title: "Muuta aikaleimaa..." action: "muuta aikaleimaa" @@ -2456,7 +2500,7 @@ fi: last: "Viimeinen revisio" hide: "Piilota revisio" show: "Näytä revisio" - revert: "Palaa tähän revisioon" + revert: "Palaa revisioon %{revision}" edit_wiki: "Muokkaa wikiä" edit_post: "Muokkaa viestiä" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -2483,13 +2527,19 @@ fi: button: "HTML" bookmarks: create: "Luo kirjanmerkki" + edit: "Muokkaa kirjanmerkkiä" created: "Luotu" updated: "Päivitetty" name: "Nimi" + name_placeholder: "Mitä varten kirjanmerkki on?" + set_reminder: "Muistuta minua" actions: delete_bookmark: name: "Poista kirjanmerkki" description: "Poistaa kirjanmerkin profiilistasi ja kumoaa kaikki kirjanmerkkiin liittyvät muistutukset" + edit_bookmark: + name: "Muokkaa kirjanmerkkiä" + description: "Muokkaa kirjanmerkin nimeä tai säädä muistutuksen päivämäärää ja kellonaikaa" category: can: "voivat… " none: "(ei aluetta)" @@ -2550,6 +2600,7 @@ fi: email_in_disabled_click: 'ota käyttöön "email in" asetus.' mailinglist_mirror: "Alue jäljittelee postituslistaa" show_subcategory_list: "Näytä lista tytäralueista ketjujen yläpuolella tällä alueella." + read_only_banner: "Banneriteksti joka näytetään, jos käyttäjä ei voi aloittaa ketjua tälle alueelle:" num_featured_topics: "Kuinka monta ketjua näytetään Keskustelualueet-sivulla:" subcategory_num_featured_topics: "Kuinka monta ketjua näytetään emoalueen sivulla:" all_topics_wiki: "Tee uusista ketjuista wiki-viestejä oletuksena." @@ -2619,6 +2670,9 @@ fi: moderation: "Valvonta" appearance: "Ulkoasu" email: "Sähköposti" + list_filters: + all: "kaikki ketjut" + none: "ei tytäralueita" flagging: title: "Kiitos avustasi yhteisön hyväksi!" action: "Liputa viesti" @@ -2794,6 +2848,8 @@ fi: this_month: "Kuukausi" this_week: "Viikko" today: "Tänään" + other_periods: "katso kuumat:" + browser_update: 'Valitettavasti selaimesi on liian vanha eikä siksi toimi tällä sivustolla. Päivitä selaimesi niin voit katsella nykyaikaisia sisältöjä, kirjautua sisään ja vastata.' permission_types: full: "Luoda / Vastata / Nähdä" create_post: "Vastata / Nähdä" @@ -2849,6 +2905,18 @@ fi: title: "Kirjoittaminen" return: "%{shortcut} Palaa viestikenttään" fullscreen: "%{shortcut} Koko ruudun kirjoitustila" + bookmarks: + title: "Kirjanmerkit" + later_today: "%{shortcut} Myöhemmin tänään" + later_this_week: "%{shortcut} Myöhemmin tällä viikolla " + tomorrow: "%{shortcut} Huomenna" + next_week: "%{shortcut} Ensi viikolla" + next_month: "%{shortcut} Ensi kuussa" + next_business_week: "%{shortcut} Ensi viikon alussa" + next_business_day: "%{shortcut} Seuraavana arkipäivänä" + custom: "%{shortcut} Valitse päivämäärä ja kellonaika" + none: "%{shortcut} Ei muistutusta" + delete: "%{shortcut} Poista kirjanmerkk" actions: title: "Toiminnot" bookmark_topic: "%{shortcut} Aseta kirjanmerkkeihin/poista" @@ -2871,6 +2939,10 @@ fi: print: "%{shortcut} Tulosta ketju" defer: "%{shortcut} Lykkää ketjua" topic_admin_actions: "%{shortcut} Avaa ketjun ylläpitotyökalut" + search_menu: + title: "Hakuvalikko" + prev_next: "%{shortcut} Siirry valinnassa ylös ja alas" + insert_url: "%{shortcut} Lisää valittu avoinna olevaan viestieditoriin" badges: earned_n_times: one: "Ansaitsi tämän ansiomerkin yhden kerran" @@ -3106,6 +3178,7 @@ fi: view_table: "taulukko" view_graph: "graafi" refresh_report: "Päivitä raportti" + dates: "Päivämäärät (UTC)" groups: "Kaikki ryhmät" disabled: "Raportti ei ole käytössä" totals_for_sample: "Otos yhteensä" @@ -3116,12 +3189,14 @@ fi: more: 'Hakulokit' disabled: 'Trendaavat haut eivät ole käytössä. Kerää dataa ottamalla käyttöön asetus log search queries.' filters: - file-extension: + file_extension: label: Tiedostomuoto group: label: Ryhmä category: label: Alue + include_subcategories: + label: "Sisällytä tytäralueet" commits: latest_changes: "Viimeisimmät muutokset: päivitä usein!" by: "käyttäjältä" @@ -3166,6 +3241,7 @@ fi: effects: Vaikutukset trust_levels_none: "Ei mitään" automatic_membership_email_domains: "Käyttäjä, joka rekisteröityy sähköpostiverkkotunnuksella joka täsmää tähän luetteloon, liitetään ryhmään automaattisesti:" + automatic_membership_user_count: "%{count} käyttäjällä on joku uusista sähköposti-verkkotunnuksista; heidät lisätään ryhmään." primary_group: "Aseta automaattisesti ensisijaiseksi ryhmäksi" name_placeholder: "Ryhmän nimi, ei välilyöntejä, samat säännöt kuin käyttäjänimillä" primary: "Ensisijainen ryhmä" @@ -3277,6 +3353,9 @@ fi: notification_event: name: "Ilmoitustapahtuma" details: "Kun käyttäjä saa ilmoituksen syötteeseensä." + user_badge_event: + name: "Ansiomerkinmyöntämistapahtuma" + details: "Kun käyttäjä saa ansiomerkin." delivery_status: title: "Toimituksen tila" inactive: "Ei toiminnassa" @@ -3426,6 +3505,7 @@ fi: theme_name: "Teeman nimi" component_name: "Komponentin nimi" themes_intro: "Aloita valitsemalla olemassa oleva teema tai asenna uusi." + themes_intro_emoji: "naistaiteilijaemoji" beginners_guide_title: "Aloittelijan opas Discourse-teemojen käyttämiseen" developers_guide_title: "Kehittäjän opas Discourse-teemoihin" browse_themes: "Selaile yhteisön kehittämiä teemoja" @@ -4014,9 +4094,27 @@ fi: delete: "Poista käyttäjä" merge: prompt: + title: "Siirrä & poista %{username}" + description: | +

Valitse uusi omistaja käyttäjän @%{username}'s sisälölle.

+ +

Kaikki ketjunaloitukset, viestit, yksityisviestit ja muu käyttäjän @%{username} luoma sisältö siirtyvät.

+ target_username_placeholder: "Uuden omistajan käyttäjänim" + transfer_and_delete: "Siirrä & poista %{username}" cancel: "Peru" confirmation: + title: "Siirrä & poista %{username}" + description: | +

Kaikki käyttäjän @%{username}'s sisältö siirretään käyttäjän @%{targetUsername} nimiin. Kun sisältö on siirretty, käyttäjän @%{username}'s tili poistetaan.

+ +

Tätä ei voi peruuttaa!

+ +

Jatka kirjoittamalla: %{text}

+ text: "siirrä käyttäjä @%{username} käyttäjälle @%{targetUsername}" + transfer_and_delete: "Siirrä & poista %{username}" cancel: "Peru" + merging_user: "Yhdistetään käyttäjää..." + merge_failed: "Käyttäjien yhdistäminen epäonnistui." delete_forbidden_because_staff: "Ylläpitäjiä ja valvojia ei voi poistaa." delete_posts_forbidden_because_staff: "Ylläpitäjien ja valvojien kaikkia viestejä ei voi poistaa." delete_forbidden: @@ -4060,6 +4158,7 @@ fi: threshold_reached: "Vastaanotettiin liian monta palautusta tästä sähköpostiosoiteesta" trust_level_change_failed: "Käyttäjän luottamustason vaihtamisessa tapahtui virhe." suspend_modal_title: "Hyllytä käyttäjä" + confirm_cancel_penalty: "Oletko varma, että haluat pyyhkiä rangaistuksen?" trust_level_2_users: "Käyttäjät luottamustasolla 2" trust_level_3_requirements: "Luottamustaso 3 vaatimukset" trust_level_locked_tip: "luottamustaso on lukittu, järjestelmä ei ylennä tai alenna käyttäjää" @@ -4202,6 +4301,8 @@ fi: modal_description: "Haluatko tämän muutoksen vaikuttavan takautuvasti? Tämä muuttaa kaikkien %{count} olemassa olevan käyttäjän käyttäjäasetusta." modal_yes: "Kyllä" modal_no: "Ei, muutosta sovellettakoon vain tästedes" + simple_list: + add_item: "Lisää asia..." badges: title: Ansiomerkit new_badge: Uusi ansiomerkki @@ -4273,6 +4374,7 @@ fi: with_time: "%{username} %{time}" badge_intro: title: "Aloita valitsemalla olemassa oleva ansiomerkki tai luomalla uusi" + emoji: "naisopiskelijaemoji" what_are_badges_title: "Mitä ansiomerkit ovat?" badge_query_examples_title: "Esimerkkejä ansiomerkin tietokantakyselyistä" mass_award: @@ -4280,6 +4382,8 @@ fi: description: Myönnä sama ansiomerkki useille käyttäjille samalla kertaa. no_badge_selected: Aloita valitsemalla ansiomerkki. perform: "Myönnä ansiomerkki käyttäjille" + upload_csv: "Lataa CSV, jossa on joko käyttäjien sähköpostiosoitteet tai käyttäjänimet" + aborted: "Lataa CSV, jossa on joko käyttäjien sähköpostiosoitteet tai käyttäjänimet" success: CSV tuli perille ja käyttäjät saavat ansiomerkkinsä pian. replace_owners: Poista ansiomerkki aiemmilta omistajilta emoji: @@ -4290,6 +4394,7 @@ fi: name: "Nimi" group: "Ryhmä" image: "Kuva" + alt: "mukautetun emojin esikatselu" delete_confirm: "Oletko varma, että haluat poistaa emojin :%{name}:?" embedding: get_started: "Jos haluat upottaa Discoursen toiselle sivustolle, aloita lisäämällä isäntä." diff --git a/config/locales/client.fr.yml b/config/locales/client.fr.yml index fbb00145bc..5de8a0c9a9 100644 --- a/config/locales/client.fr.yml +++ b/config/locales/client.fr.yml @@ -568,7 +568,7 @@ fr: profile: title: Profil interaction: - title: Intéraction + title: Interaction posting: Contribution notification: Notification membership: @@ -668,7 +668,7 @@ fr: description: "Vous serez notifié de chaque nouvelle réponse dans chaque message, et le nombre de nouvelles réponses sera affiché." watching_first_post: title: "Surveiller les nouveaux sujets" - description: "Vous serez averti de nouveaux messages dans ce groupe mais pas de réponses aux messages." + description: "Vous serez averti des nouveaux messages dans ce groupe mais pas des réponses aux messages." tracking: title: "Suivre" description: "Vous serez notifié si quelqu'un vous mentionne ou vous répond, et le nombre de nouvelles réponses sera affiché." @@ -770,7 +770,6 @@ fr: all: "Toutes" read: "Temps de lecture" unread: "Non lus" - ignore_duration_title: "Ignorer la planification" ignore_duration_username: "Nom d'utilisateur" ignore_duration_when: "Durée :" ignore_duration_save: "Ignorer" @@ -806,7 +805,7 @@ fr: notifications: "Notifications" statistics: "Statistiques" desktop_notifications: - label: "Notifications actives" + label: "Notifications instantanées" not_supported: "Les notifications ne sont pas supportées sur ce navigateur. Désolé." perm_default: "Activer les notifications" perm_denied_btn: "Permission refusée" @@ -876,9 +875,9 @@ fr: admin_delete: "Supprimer" users: "Utilisateurs" muted_users: "Silencieux" - muted_users_instructions: "Ignorer toutes les notifications et messages privés provenant de ces utilisateurs." + muted_users_instructions: "Ignorer toutes les notifications et messages directs provenant de ces utilisateurs." ignored_users: "Ignorés" - ignored_users_instructions: "Ignorer tous les billets, notifications et messages privés provenant de ces utilisateurs." + ignored_users_instructions: "Ignorer tous les messages, notifications et messages directs provenant de ces utilisateurs." tracked_topics_link: "Afficher" automatically_unpin_topics: "Désépingler automatiquement les sujets quand j'arrive à la fin." apps: "Applications" @@ -996,6 +995,9 @@ fr: confirm: "Êtes-vous sûr de vouloir modifier votre nom d'utilisateur ?" taken: "Désolé, ce nom d'utilisateur est déjà pris." invalid: "Ce nom d'utilisateur est invalide. Il ne doit être composé que de lettres et de chiffres." + add_email: + title: "Ajouter une adresse courriel" + add: "ajouter" change_email: title: "Modifier l'adresse courriel" taken: "Désolé, cette adresse courriel est indisponible." @@ -1026,8 +1028,17 @@ fr: title: "Courriel" primary: "Adresse courriel principale" secondary: "Adresses courriel secondaires" - no_secondary: "Aucune adresse courriel secondaire" + primary_label: "primaire" + unconfirmed_label: "non confirmée" + resend_label: "renvoyer le courriel d'activation" + resending_label: "envoi en cours…" + resent_label: "courriel envoyé" + update_email: "Modifier l'adresse courriel" + set_primary: "Définir comme adresse courriel principale" + destroy: "Supprimer l'adresse courriel" + add_email: "Ajouter une adresse courriel alternative" sso_override_instructions: "Le courriel peut être mis à jour à partir du fournisseur SSO." + no_secondary: "Aucune adresse courriel secondaire" instructions: "Jamais visible publiquement." ok: "Nous vous enverrons un courriel de confirmation" required: "Veuillez entrer une adresse courriel" @@ -2019,6 +2030,7 @@ fr: time_frame_required: Veuillez sélectionner un intervalle de temps auto_update_input: none: "Sélectionner un intervalle de temps" + now: "Maintenant" later_today: "Plus tard aujourd'hui" tomorrow: "Demain" later_this_week: "Plus tard cette semaine" @@ -2033,7 +2045,7 @@ fr: one_year: "Une année" forever: "Toujours" pick_date_and_time: "Sélectionner une date et heure" - set_based_on_last_post: "Fermer par rapport au dernier message" + set_based_on_last_post: "Fermer selon le dernier message" publish_to_category: title: "Planifier la publication" temp_open: @@ -2280,11 +2292,14 @@ fr: publish: "Publier" description: "Lorsqu'un sujet est publié comme page, son URL peut être partagée et il sera affiché avec un style personnalisé." slug: "Identifiant" + public: "Public" + public_description: "Les utilisateurs peuvent voir cette page même si le sujet associé est privé." publish_url: "Votre page a été publiée sur :" topic_published: "Votre sujet a été publié sur :" preview_url: "Votre page sera publiée sur :" invalid_slug: "Désolé, vous ne pouvez pas publier cette page." unpublish: "Annuler la publication" + update: "Mettre à jour" unpublished: "La publication de votre page a été annulée et elle n'est plus accessible." publishing_settings: "Paramètres de publication" change_owner: @@ -2491,7 +2506,7 @@ fr: last: "Dernière révision" hide: "Masquer la révision" show: "Afficher la révision" - revert: "Revenir à cette révision" + revert: "Revenir à la révision %{revision}" edit_wiki: "Modifier le wiki" edit_post: "Modifier le message" comparing_previous_to_current_out_of_total: "%{previous} %{icon}%{current} / %{total}" @@ -3187,13 +3202,13 @@ fr: more: 'Journal des recherches' disabled: 'Rapport sur les tendances de recherche désactivé. Activez la journalisation des recherches pour collecter des données.' filters: - file-extension: + file_extension: label: Extension de fichier group: label: Groupe category: label: Catégorie - include-subcategories: + include_subcategories: label: "Inclure les sous-catégories" commits: latest_changes: "Dernières modifications : veuillez mettre à jour régulièrement !" @@ -3212,7 +3227,7 @@ fr: bulk_add: title: "Ajouter au groupe en masse" complete_users_not_added: "Ces utilisateurs n'ont pas été ajoutés (vérifiez qu'ils ont un compte) :" - paste: "Coller une liste de nom d'utilisateur ou courriel, un par ligne :" + paste: "Coller une liste de noms d'utilisateurs ou de courriels, un par ligne :" add_members: as_owner: "Rendre des utilisateurs propriétaires de ce groupe" manage: @@ -3891,6 +3906,9 @@ fr: override_upload_secure_status: "passer outre le statut de téléchargement sécurisé" page_published: "page publiée" page_unpublished: "publication de la page annulée" + add_email: "ajouter une adresse courriel" + update_email: "mettre à jour une adresse courriel" + destroy_email: "supprimer une adresse courriel" screened_emails: title: "Courriels sous surveillance" description: "Lorsque quelqu'un essaye de créer un nouveau compte, les adresses courriel suivantes seront vérifiées et l'inscription sera bloquée, ou une autre action sera réalisée." diff --git a/config/locales/client.gl.yml b/config/locales/client.gl.yml index e69e86f5ae..33841359e9 100644 --- a/config/locales/client.gl.yml +++ b/config/locales/client.gl.yml @@ -9,8 +9,8 @@ gl: js: number: format: - separator: "." - delimiter: "," + separator: "," + delimiter: "." human: storage_units: format: "%n %u" @@ -27,7 +27,10 @@ gl: millions: "%{number}M" dates: time: "h:mm a" + time_with_zone: "HH:mm (z)" + time_short_day: "ddd, HH:mm" timeline_date: "MMM YYYY" + long_no_year: "D MMM, HH:mm" long_no_year_no_time: "D MMM" full_no_year_no_time: "D MMMM" long_with_year: "D MMM, YYYY h:mm a" @@ -88,6 +91,12 @@ gl: x_days: one: "Hai %{count} día" other: "Hai %{count} días" + x_months: + one: "Hai %{count} mes" + other: "Hai %{count} meses" + x_years: + one: "Hai %{count} ano" + other: "Hai %{count} anos" later: x_days: one: "%{count} día despois" @@ -102,10 +111,15 @@ gl: next_month: "Mes seguinte" placeholder: data share: + topic_html: 'Tema: %{topicTitle}' post: "publicación %{postNumber}" close: "pechar" + twitter: "Compartir esta ligazón no Twitter" + facebook: "Compartir esta ligazón no Facebook" + email: "Enviar esta ligazón por correo electrónico" action_codes: - public_topic: "fixo esta publicación pública no %{when}" + public_topic: "fixo este tema público o %{when}" + private_topic: "fixo este tema unha mensaxe persoal o %{when}" split_topic: "este tema dividiuse o %{when}" invited_user: "convidou a %{who} %{when}" invited_group: "invitou %{who} o %{when}" @@ -129,6 +143,7 @@ gl: visible: enabled: "listado o %{when}" disabled: "retirado da lista o %{when}" + topic_admin_menu: "accións do tema" 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." themes: default_description: "Predeterminado" @@ -139,13 +154,19 @@ gl: ap_south_1: "Asia Pacífico (Mumbai)" ap_southeast_1: "Asia Pacífico (Singapur)" ap_southeast_2: "Asia Pacífico (Sidney)" - cn_north_1: "China (Beijing)" - eu_central_1: "EU (Frankfurt)" - eu_west_1: "EU (Irlanda)" - eu_west_2: "EU (Londres)" - us_east_1: "EE.UU. Leste (N. Virxinia)" - us_west_1: "EE.UU. Oeste (N. California)" - us_west_2: "EE.UU. Oeste (Oregón)" + ca_central_1: "O Canadá (Central)" + cn_north_1: "A China (Beijing)" + cn_northwest_1: "A China (Ningxia)" + eu_central_1: "UE (Frankfurt)" + eu_north_1: "UE (Estocolmo)" + eu_west_1: "UE (Irlanda)" + eu_west_2: "UE (Londres)" + eu_west_3: "UE (París)" + sa_east_1: "América do Sur (São Paulo)" + us_east_1: "EUA Leste (Virxinia N.)" + us_east_2: "EUA Leste (Ohio)" + us_west_1: "EUA Oeste (N. California)" + us_west_2: "EUA Oeste (Oregón)" edit: "editar o título e a categoría deste tema" expand: "Expandir" not_implemented: "Sentímolo pero esta funcionalidade non se implementou aínda." @@ -167,9 +188,11 @@ gl: other: "ligazóns" faq: "FAQ" guidelines: "Directrices" - privacy_policy: "Normas de confidencialidade" - privacy: "Confidencialidade" + privacy_policy: "Política de privacidade" + privacy: "Privacidade" tos: "Termos do servizo" + rules: "Regras" + conduct: "Código de conduta" mobile_view: "Visualización móbil" desktop_view: "Visualización en escritorio" you: "Ti" @@ -183,11 +206,16 @@ gl: every_hour: "cada hora" daily: "diariamente" weekly: "semanalmente" + every_month: "cada mes" + every_six_months: "cada seis meses" max_of_count: "máx. de %{count}" alternation: "ou" character_count: one: "%{count} carácter" other: "%{count} caracteres" + related_messages: + title: "Mensaxes relacionadas" + see_all: 'Ver todas as mensaxes de @%{username}...' suggested_topics: title: "Temas suxeridos" pm_title: "Mensaxes suxeridas" @@ -200,6 +228,8 @@ gl: moderators: "Moderadores" stat: all_time: "Todos" + last_7_days: "Últimos 7" + last_30_days: "Últimos 30" like_count: "Gústames" topic_count: "Temas" post_count: "Publicacións" @@ -214,13 +244,42 @@ gl: bookmark: "Preme para engadir aos marcadores a publicación inicial deste tema" unbookmark: "Preme para retirar todos os marcadores deste tema" bookmarks: + created: "marcaches esta publicación%{name}" + not_bookmarked: "marcar esta publicación" remove: "Eliminar marcador" + delete: "Eliminar marcador" + confirm_clear: "Confirmas o borrado de todos os marcadores deste tema?" save: "Gardar" + list_permission_denied: "Non tes permiso para ver os marcadores deste usuario." + reminders: + at_desktop: "A vindeira vez que estea no meu ordenador" + later_today: "Hoxe, máis tarde" + next_business_day: "O vindeiro día laborable" + tomorrow: "Mañá" + next_week: "A vindeira semana" + start_of_next_business_week: "O vindeiro luns" + next_month: "O vindeiro mes" + custom: "Personalizar data e hora" + today_with_time: "hoxe á(s) %{time}" + tomorrow_with_time: "mañá á(s) %{time}" + at_time: "á(s) %{date_time}" + copy_codeblock: + copied: "copiado!" drafts: + resume: "Continuar" remove: "Eliminar" abandon: yes_value: "Si, abandonar" no_value: "Non, seguir" + topic_count_latest: + one: "Ver %{count} tema novo ou actualizado" + other: "Ver %{count} temas novos ou actualizados" + topic_count_unread: + one: "Ver %{count} tema sen ler" + other: "Ver %{count} temas sen ler" + topic_count_new: + one: "Ver %{count} tema novo" + other: "Ver %{count} temas novos" preview: "previsualizar" cancel: "cancelar" save: "Gardar cambios" @@ -228,52 +287,137 @@ gl: saved: "Gardado!" upload: "Actualizar" uploading: "Actualizando..." + uploading_filename: "Actualizando: %{filename}..." + clipboard: "portapapeis" uploaded: "Actualizado!" pasting: "A pegar..." enable: "Activar" disable: "Desactivar" + continue: "Continuar" undo: "Desfacer" revert: "Reverter" failed: "Fallou" + switch_to_anon: "Entrar no Modo anónimo" + switch_from_anon: "Saír do Modo anónimo" banner: close: "Desbotar este báner." edit: "Editar este báner »" + pwa: + install_banner: "Queres instalar %{title} neste dispositivo?" choose_topic: none_found: "Non se atoparon temas." + title: + search: "Buscar un tema" + placeholder: "escribe o título do tema, url ou id aquí" + choose_message: + none_found: "Non se atoparon mensaxes." + title: + search: "Buscar unha mensaxe" + placeholder: "escribe o título da mensaxe, url ou id aquí" review: + order_by: "Ordenar por" + in_reply_to: "en resposta a" explain: + formula: "Fórmula" + subtotal: "Subtotal" total: "Total" + trust_level_bonus: + name: "nivel de confianza" + claim_help: + claimed_by_other: "Este elemento só pode revisalo %{username}." + awaiting_approval: "Agardando aprobación" delete: "Eliminar" settings: + saved: "Gardado" save_changes: "Gardar os cambios" title: "Axustes" + moderation_history: "Historial de moderación" + view_all: "Ver todos" + grouped_by_topic: "Agrupados por tema" + none: "Non hai elementos para revisar." + view_pending: "ver pendentes" + topic_has_pending: + one: "Este tema ten %{count} publicación agardando aprobación" + other: "Este tema ten %{count} publicacións agardando aprobación" + title: "Revisar" topic: "Tema:" filtered_user: "Usuario" + show_all_topics: "buscar todos os temas" + deleted_post: "(publicación eliminada)" + deleted_user: "(usuario eliminado)" user: + bio: "Biografía" + website: "Sitio web" username: "Nome do usuario" email: "Correo electrónico" name: "Nome" + fields: "Campos" topics: topic: "Tema" + reviewable_count: "Número" + deleted: "[Tema eliminado]" + original: "(tema orixinal)" + details: "detalles" + unique_users: + one: "%{count} usuario" + other: "%{count} usuarios" + replies: + one: "%{count} resposta" + other: "%{count} respostas" edit: "Editar" save: "Gardar" cancel: "Cancelar" + new_topic: "A aprobación deste elemento creará un tema novo" filters: + all_categories: "(todas as categorías)" + type: + title: "Tipo" + all: "(todos os tipos)" + minimum_score: "Puntuación mínima:" refresh: "Actualizar" + status: "Estado" category: "Categoría" + orders: + score: "Puntuación" + priority: + title: "Prioridade mínima" + low: "(calquera)" + medium: "Media" + high: "Alta" + conversation: + view_full: "ver conversa completa" scores: + score: "Puntuación" date: "Data" + type: "Tipo" + status: "Estado" + submitted_by: "Enviado por" + reviewed_by: "Revisado por" statuses: pending: title: "Pendente" + approved: + title: "Aprobado" rejected: title: "Rexeitado" + ignored: + title: "Ignorado" + deleted: + title: "Eliminado" + all: + title: "(todo)" types: + reviewable_flagged_post: + title: "Publicación denunciada" + flagged_by: "Denunciado por" reviewable_user: title: "Usuario" approval: title: "A publicación necesita aprobación" description: "Recibimos a túa nova publicación pero cómpre que sexa aprobada por un moderador antes de aparecer. Ten paciencia." + pending_posts: + one: "Tes %{count} publicación pendente." + other: "Tes %{count} publicacións pendentes." ok: "De acordo" user_action: user_posted_topic: "%{user} publicou o tema" @@ -294,6 +438,7 @@ gl: title: "Usuarios" likes_given: "Dados" likes_received: "Recibidos" + topics_entered: "Vistos" topics_entered_long: "Temas vistos" time_read: "Tempo de lectura" topic_count: "Temas" @@ -305,56 +450,127 @@ gl: days_visited_long: "Días visitados" posts_read: "Lidas" posts_read_long: "Publicacións lidas" + last_updated: "Última actualización:" total_rows: one: "Un usuario" other: "%{count} usuarios" + group_histories: + actions: + change_group_setting: "Cambiar axustes do grupo" + add_user_to_group: "Engadir usuario" + remove_user_from_group: "Eliminar usuario" + remove_user_as_group_owner: "Revogar propietario" groups: + member_added: "Engadido" + add_members: + title: "Engadir membros" + usernames: "Nomes de usuario" requests: + title: "Peticións" reason: "Razón" + accept: "Aceptar" + accepted: "aceptado" + deny: "Denegar" + denied: "denegado" manage: + title: "Xestionar" name: "Nome" + full_name: "Nome completo" + add_members: "Engadir membros" delete_member_confirm: "Queres eliminar a «%{username}» do grupo «%{group}»?" profile: title: Perfil interaction: posting: Publicación + notification: Notificación + membership: + access: Acceso logs: title: "Rexistros" when: "Cando" action: "Acción" + target_user: "Usuario obxectivo" subject: "Asunto" details: "Detalles" from: "De" to: "A" + public_admission: "Permitir que os usuarios se unan ao grupo libremente (require un grupo visible ao público)" + public_exit: "Permitir que os usuarios abandonen o grupo libremente" + empty: + posts: "Non hai publicacións de membros deste grupo." + members: "Non hai membros neste grupo." + mentions: "Non hai mencións neste grupo." + messages: "Non hai mensaxes para este grupo." + topics: "Non hai temas de membros deste grupo." + logs: "Non hai rexistros para este grupo." add: "Engadir" + join: "Unirse" + leave: "Abandonar" + request: "Petición" message: "Mensaxe" + confirm_leave: "Confirmas o abandono deste grupo?" + membership_request: + submit: "Enviar petición" + title: "Petición para unirse a%{group_name}" + reason: "Permitir que os propietarios do grupo coñezan os motivos polos que pertences a este grupo" name: "Nome" + group_name: "Nome do grupo" user_count: "Usuarios" + bio: "Acerca do grupo" selector_placeholder: "escribe o nome do usuario" owner: "propietario" index: title: "Grupos" + all: "Todos os grupos" + empty: "Non hai grupos visibles." + filter: "Filtrar por tipo de grupo" + owner_groups: "Grupos dos que son propietario" + close_groups: "Grupos pechados" + automatic_groups: "Grupos automáticos" automatic: "Automático" + closed: "Pechado" + public: "Público" + private: "Privado" + public_groups: "Grupos públicos" + automatic_group: Grupo automático + close_group: Pechar grupo my_groups: "Os meus grupos" + group_type: "Tipo de grupo" is_group_user: "Membro" + is_group_owner: "Propietario" + title: + one: "Grupo" + other: "Grupos" activity: "Actividade" members: title: "Membros" + filter_placeholder_admin: "nome de usuario ou correo electrónico" filter_placeholder: "nome do usuario" + remove_member: "Eliminar membro" + remove_member_description: "Eliminar a %{username} deste grupo" + remove_owner: "Eliminar como propietario" + remove_owner_description: "Eliminar a %{username} como propietario deste grupo" + owner: "Propietario" + forbidden: "Non tes permiso para ver os membros" topics: "Temas" posts: "Publicacións" mentions: "Mencións" messages: "Mensaxes" + notification_level: "Nivel de notificación predeterminado para mensaxes do grupo" alias_levels: + messageable: "Que pode enviar mensaxes a este grupo?" nobody: "Ninguén" only_admins: "Só administradores" mods_and_admins: "Só moderadores e administradores" members_mods_and_admins: "Só membros do grupo, moderadores e administradores" + owners_mods_and_admins: "Só os propietarios, moderadores e administradores do grupo" everyone: "Todos" notifications: watching: title: "Ver" description: "Notificaráseche cada publicación nova en cada mensaxe e amosarase o número de novas respostas." + watching_first_post: + description: "Recibirás notificacións das novas mensaxes deste grupo pero non das súas respostas." tracking: title: "Seguimento" description: "Notificaráseche se alguén menciona o teu @nome ou che responde e tamén aparecerá o número de novas respostas." @@ -363,6 +579,13 @@ gl: description: "Notificaráseche se alguén menciona o teu @nome ou che responde." muted: title: "Silenciado" + description: "Non recibirás notificación ningunha sobre as mensaxes deste grupo." + flair_upload_description: "Usar imaxes cadradas cun tamaño mínimo de 20 x 20 px." + flair_preview_icon: "Previsualizar icona" + flair_preview_image: "Previsualizar imaxe" + flair_type: + icon: "Seleccionar unha icona" + image: "Subir unha imaxe" user_action_groups: "1": "Gústames dados" "2": "Gústames recibidos" @@ -376,6 +599,7 @@ gl: "12": "Enviar elementos" "13": "Caixa de entrada" "14": "Pendente" + "15": "Borradores" categories: all: "todas as categorías" all_subcategories: "todo" @@ -394,6 +618,16 @@ gl: latest_by: "últimos de" toggle_ordering: "trocar o control de ordenación" subcategories: "Subcategorías" + topic_sentence: + one: "%{count} tema" + other: "%{count} temas" + topic_stat_sentence_week: + one: "%{count} tema novo na última semana." + other: "%{count} temas novos na última semana." + topic_stat_sentence_month: + one: "%{count} tema novo no último mes" + other: "%{count} temas novos no último mes" + n_more: "Categorías (%{count} máis)..." ip_lookup: title: Busca do enderezo IP hostname: Nome do servidor @@ -409,37 +643,52 @@ gl: topics_entered: "temas introducidos" post_count: "# publicacións" confirm_delete_other_accounts: "Confirma que quere eliminar estas contas?" + copied: "copiado" user_fields: none: "(seleccione unha opción)" + required: 'Introduce un valor para "%{name}"' user: said: "%{username}:" profile: "Perfil" mute: "Silenciar" edit: "Editar preferencias" download_archive: + button_text: "Descargar todo" confirm: "Confirmas a descarga das túas publicacións?" + success: "Iniciouse a descarga, notificarémosche cunha mensaxe o remate do proceso." rate_limit_error: "Só se poden descargar as publicacións unha vez por día. Téntao de novo mañá." new_private_message: "Nova mensaxe" private_message: "Mensaxe" private_messages: "Mensaxes" user_notifications: filters: + filter_by: "Filtrar por" all: "Todo" read: "Lidos" unread: "Sen ler" ignore_duration_username: "Nome do usuario" + ignore_duration_when: "Duración:" ignore_duration_save: "Ignorar" + ignore_no_users: "Non tes usuarios ignorados." + ignore_option: "Ignorado" + ignore_option_title: "Non recibirás notificacións relacionadas con este usuario e todos os seus temas e respostas permanecerán ocultos." + add_ignored_user: "Engadir..." mute_option: "Silenciado" + mute_option_title: "Non recibirás notificación ningunha relacionada con este usuario." normal_option: "Normal" activity_stream: "Actividade" preferences: "Preferencias" feature_topic_on_profile: + open_search: "Seleccionar un novo tema" + title: "Seleccionar un tema" + search_label: "Buscar tema polo título" save: "Gardar" clear: title: "Borrar" expand_profile: "Expandir" bookmarks: "Marcadores" bio: "Verbo de min" + timezone: "Fuso horario" invited_by: "Convidado por" trust_level: "Nivel de confianza" notifications: "Notificacións" @@ -457,13 +706,20 @@ gl: external_links_in_new_tab: "Abrir todas as ligazóns externas nunha nova lapela" enable_quoting: "Activar as comiñas de resposta para o texto realzado" change: "cambiar" + featured_topic: "Tema destacado" moderator: "%{user} é moderador" admin: "%{user} é administrador" moderator_tooltip: "Este usuario é un moderador" admin_tooltip: "Este usuario é un administrador" + silenced_tooltip: "Este usuario está silenciado" suspended_notice: "Este usuario está suspendido até o %{date}." + suspended_permanently: "Este usuario está suspendido" suspended_reason: "Razón:" github_profile: "Github" + email_activity_summary: "Resumo da actividade" + mailing_list_mode: + individual: "Enviar un correo electrónico por cada nova publicación" + tag_settings: "Etiquetas" watched_tags: "Visto" tracked_tags: "Seguido" muted_tags: "Silenciado" @@ -477,8 +733,12 @@ gl: admin_delete: "Eliminar" users: "Usuarios" muted_users: "Silenciado" + ignored_users: "Ignorado" tracked_topics_link: "Amosar" automatically_unpin_topics: "Despegar os temas automaticamente cando alcance o fondo." + revoke_access: "Revogar acceso" + theme: "Tema" + staged: "Transitorio" staff_counters: flags_given: "denuncias útiles" flagged_posts: "publicacións denunciadas" @@ -496,53 +756,96 @@ gl: move_to_archive: "Arquivo" failed_to_move: "Produciuse un fallo ao mover as mensaxes seleccionadas (quizais a rede está caída)" select_all: "Seleccionar todo" + tags: "Etiquetas" preferences_nav: + account: "Conta" profile: "Perfil" emails: "Correos electrónicos" notifications: "Notificacións" categories: "Categorías" users: "Usuarios" + tags: "Etiquetas" + interface: "Interface" change_password: success: "(correo enviado)" in_progress: "(enviando o correo)" error: "(erro)" + emoji: "bloquear emoji" action: "Enviar correo para restabelecer o contrasinal" set_password: "Estabelecer o contrasinal" + choose_new: "Elixir un novo contrasinal" + choose: "Elixir un contrasinal" second_factor_backup: regenerate: "Rexenerar" disable: "Desactivar" enable: "Activar" + copy_to_clipboard: "Copiar ao portapapeis" + copy_to_clipboard_error: "Erro ao copiar os datos ao portapapeis" + copied_to_clipboard: "Copiado ao portapapeis" second_factor: + title: "Autenticación de dobre factor" + forgot_password: "Esqueciches o contrasinal?" + confirm_password_description: "Confirma o teu contrasinal para continuar" name: "Nome" + label: "Código" + show_key_description: "Inserir manualmente" disable: "Desactivar" save: "Gardar" edit: "Editar" security_key: + register: "Rexistrarse" save: "Gardar" change_about: title: "Cambiar «Verbo de min»" + error: "Produciuse un erro ao cambiar este valor." change_username: title: "Cambiar o nome do usuario" + confirm: "Confirmas o cambio do teu nome de usuario?" taken: "Sentímolo pero este nome xa está en uso." invalid: "Este usuario é incorrecto. Só pode contar números e letras." + add_email: + title: "Engadir correo electrónico" + add: "engadir" change_email: title: "Cambiar o correo electrónico" taken: "Sentímolo pero este correo non está dispoñíbel." error: "Produciuse un erro cambiando o correo electrónico. Quizais ese enderezo xa está en uso." success: "Enviamos un correo electrónico a ese enderezo. Sigue as instrucións de confirmación." + success_staff: "Enviamos un correo electrónico ao teu enderezo actual. Sigue as instrucións de confirmación." change_avatar: title: "Cambia a foto do perfil" + gravatar: "%{gravatarName}, baseado en" + gravatar_title: "Cambia o teu avatar no sitio web de %{gravatarName}" + gravatar_failed: "Non atopamos ningún %{gravatarName} con ese enderezo de correo electrónico." + refresh_gravatar_title: "Actualiza o teu %{gravatarName}" letter_based: "Imaxe do perfil asignada polo sistema" uploaded_avatar: "Imaxe personalizada" uploaded_avatar_empty: "Engadir unha imaxe personalizada" upload_title: "Envía a túa imaxe" image_is_not_a_square: "Aviso: recortamos a túa imaxe; a largura e a altura eran distintas." + change_profile_background: + title: "Cabeceira do perfil" + instructions: "As cabeceiras dos perfís centraranse e terán unha largura predeterminada de 1110 px." change_card_background: title: "Fondo das fichas dos usuarios" instructions: "As imaxes dos fondos centraranse e terán unha largura predeterminada de 590px." + change_featured_topic: + title: "Tema destacado" email: title: "Correo electrónico" + primary: "Correo electrónico principal" + secondary: "Correos electrónicos secundarios" + primary_label: "primario" + unconfirmed_label: "sen confirmar" + resend_label: "reenviar correo de confirmación" + resending_label: "enviando..." + resent_label: "correo electrónico enviado" + update_email: "Cambiar o correo electrónico" + destroy: "Eliminar correo electrónico" + add_email: "Engadir correo electrónico alternativo" + no_secondary: "Sen correos electrónicos secundarios" ok: "Enviarémosche un correo electrónico para confirmar" + required: "Escribe un enderezo de correo electrónico" invalid: "Introduce un enderezo de correo electrónico correcto" authenticated: "O teu enderezo de correo electrónico foi autenticado por %{provider}" frequency_immediately: "Enviarémosche un correo-e axiña se non liches sobre o que che estamos a enviar." @@ -550,11 +853,20 @@ gl: one: "Só che eviaremos un correo-e se non te vimos no último minuto." other: "Só che eviaremos un correo-e se non te vimos nos últimos %{count} minutos." associated_accounts: + title: "Contas asociadas" + connect: "Conectar" revoke: "Revogar" cancel: "Cancelar" + not_connected: "(sen conectar)" + confirm_modal_title: "Conectar a conta de %{provider}" + confirm_description: + account_specific: "Usarase a túa conta \"%{account_description}\" de %{provider} para a autenticación." + generic: "Usarase a túa conta de %{provider} para a autenticación." name: title: "Nome" + instructions: "o teu nome completo (opcional)" instructions_required: "Nome completo" + required: "Escribe un nome" too_short: "O nome é curto de mais" ok: "O nome parece correcto" username: @@ -562,19 +874,30 @@ gl: short_instructions: "A xente pode mencionarte como @%{username}" available: "O nome de usuario está dispoñíbel" not_available: "Non dispoñíbel. Tentar %{suggestion}?" + not_available_no_suggestion: "Non dispoñible" too_short: "O nome do usuario é curto de máis" too_long: "O nome do usuario é longo de máis" checking: "Comprobando a dispoñibilidade do nome do usuario..." prefilled: "O correo electrónico coincide co nome do usuario rexistrado" + required: "Escribe un nome de usuario" locale: title: "Idioma da interface" instructions: "Idioma da interface do usuario. Cambiará cando actualices a páxina." default: "(predeterminado)" password_confirmation: title: "O contrasinal outra vez" + invite_code: + title: "Código de convite" + instructions: "O rexistro da conta require un código de convite" auth_tokens: + title: "Dispositivos usados recentemente" ip: "IP" details: "Detalles" + not_you: "Non es ti?" + show_all: "Amosar todos (%{count})" + show_few: "Amosar menos" + was_this_you: "Fuches ti?" + was_this_you_description: "Se non fuches ti, recomendamos que cambies o teu contrasinal e saias da sesión." last_posted: "Última publicación" last_emailed: "Últimos envíos por correo-e" last_seen: "Visto" @@ -584,7 +907,13 @@ gl: website: "Sitio web" email_settings: "Correo electrónico" text_size: + title: "Tamaño do texto" + smaller: "Máis pequeno" normal: "Normal" + larger: "Máis grande" + largest: "Enorme" + title_count_mode: + notifications: "Novas notificacións" like_notification_frequency: title: "Notificar cando reciba gústames" always: "Sempre" @@ -601,6 +930,8 @@ gl: every_hour: "cada hora" daily: "diariamente" weekly: "semanalmente" + every_month: "cada mes" + every_six_months: "cada seis meses" email_level: title: "Enviar un correo electrónico cando alguén me cite, responda a unha das miñas publicacións, mencione o meu @nome_do_usuario ou me convide a un tema." always: "sempre" @@ -632,6 +963,7 @@ gl: search: "escribir para buscar convites..." title: "Convites" user: "Usuario convidado" + none: "Non hai convites que amosar." truncated: one: "Amosando o primeiro convite." other: "Amosando os primeiros %{count} convites." @@ -647,18 +979,40 @@ gl: expired: "Este convite caducou." rescind: "Eliminar" rescinded: "Convite eliminado" + rescind_all: "Eliminar os convites caducados" + rescinded_all: "Todos os convites caducados foron eliminados" + rescind_all_confirm: "Confirmas a eliminación de todos os convites caducados?" reinvite: "Reenviar convite" + reinvite_all: "Reenviar todos os convites" + reinvite_all_confirm: "Confirmas o reenvío de todos os convites?" reinvited: "Convite reenviado" + reinvited_all: "Todos os convites foron reenviados" time_read: "Tempo de lectura" days_visited: "Días visitado" account_age_days: "Tempo da conta en días" links_tab: "Ligazóns" + links_tab_with_count: "Ligazóns (%{count})" + link_url: "Ligazón" link_created_at: "Creado" link_groups: Grupos + link_expires_at: Caduca create: "Enviar convite" + copy_link: "Copiar ligazón" generate_link: "Copiar a ligazón do convite" + link_generated: "A ligazón do convite xerouse correctamente" + valid_for: "A ligazón do convite só é válida para este enderezo de correo electrónico: %{email}" + invite_link: + title: "Ligazón do convite" + success: "A ligazón do convite xerouse correctamente" + error: "Produciuse un erro ao xerar esta ligazón de convite" + max_redemptions_allowed_label: "Cantas persoas poden rexistrarse con esta ligazón?" + expires_at: "Cando caduca a ligazón deste convite?" bulk_invite: + none: "Aínda non convidaches a ninguén. Podes enviar convites individuais ou en grupo se subes un ficheiro CSV." + text: "Convite en grupo" success: "O ficheiro enviouse correctamente, notificaráseche por mensaxe cando remate o proceso." + error: "O ficheiro ten que ter formato CSV." + confirmation_message: "Vas enviar por correo electrónico convites a todos os que están no ficheiro que subiches." password: title: "Contrasinal" too_short: "O teu contrasinal é demasiado curto." @@ -666,17 +1020,47 @@ gl: same_as_username: "O contrasinal é igual ao nome do usuario." same_as_email: "O contrasinal é igual ao correo electrónico." ok: "O contrasinal semella bo." + instructions: "como mínimo %{count} caracteres" + required: "Escribe un contrasinal" summary: title: "Resumo" stats: "Estatísticas" time_read: "tempo de lectura" + recent_time_read: "tempo de lectura recente" + topic_count: + one: "tema creado" + other: "temas creados" + post_count: + one: "publicación creada" + other: "publicacións creadas" + likes_received: + one: "recibido" + other: "recibidos" + topics_entered: + one: "tema visto" + other: "temas vistos" + posts_read: + one: "publicación lida" + other: "publicacións lidas" + bookmark_count: + one: "marcador" + other: "marcadores" top_replies: "Respostas destacadas" + no_replies: "Aínda sen respostas." more_replies: "Máis respostas" top_topics: "Temas destacados" + no_topics: "Aínda sen temas." more_topics: "Máis temas" top_badges: "Insignias principais" + no_badges: "Aínda sen insignias." more_badges: "Máis insignias" + top_links: "Ligazóns destacadas" + no_links: "Aínda sen ligazóns." + most_liked_by: "Con máis Gústames de" most_liked_users: "Con máis Gústames" + most_replied_to_users: "Con máis respostas a" + no_likes: "Aínda sen Gústames." + top_categories: "Categorías destacadas" topics: "Temas" replies: "Respostas" ip_address: @@ -688,8 +1072,10 @@ gl: header_title: "perfil, mensaxes, marcadores e preferencias" title: title: "Título" + none: "(ningún)" primary_group: title: "Grupo primario" + none: "(ningunha)" filters: all: "Todo" stream: @@ -719,6 +1105,7 @@ gl: fixed: "Cargar páxina" modal: close: "pechar" + dismiss_error: "Desbotar erro" close: "Pechar" assets_changed_confirm: "Este sitio acaba de actualizarse. Queres recargar a páxina para ter a última versión?" logout: "Fuches desconectado." @@ -729,6 +1116,8 @@ gl: login_disabled: "Cando o sitio está no modo de só-lectura, desactívase o inicio de sesión." logout_disabled: "O peche de sesión desactívase mentres o sitio está en modo de só lectura." learn_more: "saber máis..." + all_time: "total" + all_time_desc: "total de temas creados" year: "ano" year_desc: "temas creados nos últimos 365 días" month: "mes" @@ -739,7 +1128,12 @@ gl: first_post: Publicación inicial mute: Silenciar unmute: Non silenciar + last_post: Publicado + local_time: "Hora local" time_read: Lidos + time_read_recently: " Recentemente%{time_read}" + time_read_tooltip: "Tempo de lectura total %{time_read}" + time_read_recently_tooltip: "Tempo de lectura total%{time_read} (%{recent_time_read} nos últimos 60 días)" last_reply_lowercase: última resposta replies_lowercase: one: resposta @@ -749,6 +1143,7 @@ gl: hide_session: "Lembrarmo mañá" hide_forever: "non grazas" hidden_for_session: "De acordo, preguntareicho mañá. Tamén podes usar «Iniciar sesión» para crear unha conta." + intro: "Ola! Semella que gozas coa discusión pero aínda non abriches ningunha conta." summary: enabled_description: "Estás vendo un resumo deste tema: as publicacións máis interesantes determinadas pola comunidade" description: "Hai %{replyCount} respostas." @@ -762,6 +1157,9 @@ gl: disable: "Amosar as publicacións eliminadas" private_message_info: title: "Mensaxe" + invite: "Convidar a outros..." + edit: "Engadir ou eliminar..." + leave_message: "Confirmas o abandono desta mensaxe?" remove_allowed_user: "Confirmas a eliminación de %{name} desta mensaxe?" remove_allowed_group: "Confirmas a eliminación de %{name} desta mensaxe?" email: "Correo electrónico" @@ -772,6 +1170,7 @@ gl: trust_level: "Nivel de confianza" search_hint: "nome do usuario, correo-e ou enderezo IP" create_account: + disclaimer: "Ao rexistrarte, aceptas a política de privacidade e as condicións do servizo." title: "Crear unha conta nova" failed: "Algo foi mal, quizais este correo electrónico xa está rexistrado, tenta coa ligazón de «Esquecín o contrasinal»." forgot_password: @@ -781,21 +1180,41 @@ gl: reset: "Restabelecer contrasinal" complete_username: "Se unha conta corresponde ao nome de usuario %{username}, deberas recibir en breve un correo-e coas instrucións sobre como restabelecer o teu contrasinal." complete_email: "Se unha conta coincide con %{email}, deberías recibir en breve un correo-e con instrucións sobre como restabelecer o teu contrasinal." + complete_username_found: "Atopamos unha conta co mesmo nome de usuario %{username}. Deberas recibir en breve un correo electrónico coas instrucións sobre como restabelecer o teu contrasinal." + complete_email_found: "Atopamos unha conta que coincide con %{email}. Deberas recibir en breve un correo electrónico coas instrucións sobre como restablecer o teu contrasinal." complete_username_not_found: "Ningunha conta coincide co nome do usuario %{username}" complete_email_not_found: "Ningunha conta coincide co %{email}" + help: "Non recibiches o correo electrónico? Comproba primeiro o correo non desexado.

Non lembras o enderezo de correo electrónico que usaches? Escribe un enderezo de correo electrónico e comprobaremos se está rexistrado.

No caso de que xa non teñas acceso ao enderezo de correo electrónico rexistrado na conta, ponte en contacto co noso atento equipo.

" button_ok: "De acordo" + button_help: "Axuda" email_login: + link_label: "Enviarme por correo electrónico unha ligazón de inicio de sesión" + button_label: "con correo electrónico" + emoji: "bloquear emoji" + complete_username: "Se unha conta corresponde ao nome de usuario %{username}, deberas recibir en breve un correo electrónico cunha ligazón de inicio de sesión." + complete_email: "Se unha conta corresponde a %{email}, deberas recibir en breve unha ligazón de inicio de sesión." + complete_username_found: "Atopamos unha conta que co nome de usuario %{username}, deberas recibir en breve un correo electrónico cunha ligazón de inicio de sesión." + complete_email_found: "Atopamos unha conta que corresponde a %{email}, deberas recibir en breve un correo electrónico cunha ligazón de inicio de sesión." complete_username_not_found: "Ningunha conta coincide co nome do usuario %{username}" complete_email_not_found: "Ningunha conta coincide co %{email}" confirm_title: "Continuar a %{site_name}" + logging_in_as: "Iniciar sesión como %{email}" + confirm_button: Finalizar inicio de sesión login: title: "Iniciar sesión" username: "Usuario" password: "Contrasinal" + second_factor_title: "Autenticación de dobre factor" + second_factor_description: "Escribe o código de autenticación da aplicación" + second_factor_backup: "Iniciar sesión cun código de copia de seguranza" + second_factor_backup_title: "Copia de seguranza de dobre factor" + second_factor_backup_description: "Escribe un dos códigos de copia de seguranza" + security_key_alternative: "Tentalo doutro xeito" email_placeholder: "correo electrónico ou nome de usuario" caps_lock_warning: " Bloqueo de maiúsculas activado" error: "Erro descoñecido" rate_limit: "Por favor, agarda antes de tentalo outra vez." + blank_username: "Escribe o teu correo electrónico ou nome de usuario." blank_username_or_password: "Introduce o teu correo electrónico ou nome de usuario e o contrasinal." reset_password: "Restabelecer contrasinal" logging_in: "Iniciando sesión..." @@ -808,10 +1227,17 @@ gl: not_allowed_from_ip_address: "Non podes acceder desde este enderezo IP." admin_not_allowed_from_ip_address: "Non podes acceder como administrador desde este enderezo IP." resend_activation_email: "Preme aquí para enviar outro correo de activación." + omniauth_disallow_totp: "A túa conta ten habilitada a autenticación de dobre factor. Inicia sesión co teu contrasinal." + resend_title: "Reenviar correo electrónico de activación" + change_email: "Cambiar enderezo de correo electrónico" + provide_new_email: "Escribe un enderezo novo e reenviarémosche a el o correo electrónico de confirmación." + submit_new_email: "Actualizar enderezo de correo electrónico" sent_activation_email_again: "Enviamos outro correo-e de activación a %{currentEmail}. Pode tardar uns minutos en chegar; asegúrate de revisar o cartafol do spam." + sent_activation_email_again_generic: "Enviamos outro correo electrónico de activación. Pode tardar uns minutos en chegar; asegúrate de revisar o cartafol do spam." to_continue: "Por favor, inicia sesión" preferences: "Precisas iniciar sesión para cambiar as túas preferencias de usuario." forgot: "Non lembro os detalles da miña conta" + not_approved: "A túa conta non foi aínda aprobada. Notificaráseche por correo electrónico cando poidas iniciar a sesión." google_oauth2: name: "Google" title: "co Google" @@ -819,37 +1245,95 @@ gl: name: "Twitter" title: "co Twitter" instagram: + name: "Instagram" title: "con Instagram" facebook: + name: "Facebook" title: "co Facebook" github: + name: "GitHub" title: "co GitHub" + discord: + name: "Discord" + title: "co Discord" + second_factor_toggle: + backup_code: "Usar no seu lugar un código de copia de seguranza" invites: + accept_title: "Convite" + emoji: "emoji de sobre" welcome_to: "Benvido/a a %{site_name}!" + invited_by: "Recibiches o convite de:" + your_email: "O enderezo de correo electrónico da túa conta é %{email}." + accept_invite: "Aceptar convite" + success: "A túa conta acaba de ser creada e tes a sesión iniciada." name_label: "Nome" password_label: "Estabelecer o contrasinal" + optional_description: "(opcional)" password_reset: continue: "Continuar a %{site_name}" emoji_set: apple_international: "Apple/Internacional" google: "Google" twitter: "Twitter" + emoji_one: "JoyPixels (antes EmojiOne)" + win10: "Win10" + google_classic: "Google Classic" + facebook_messenger: "Facebook Messenger" + category_page_style: + categories_only: "Só categorías" + categories_with_featured_topics: "Categorías con temas destacados" + categories_and_latest_topics: "Categorías e últimos temas" + categories_and_top_topics: "Categorías e temas destacados" shortcut_modifier_key: shift: "Maiús." ctrl: "Ctrl" alt: "Alt" conditional_loading_section: loading: Cargando... + category_row: + topic_count: "%{count} temas nesta categoría" + select_kit: + default_header_text: Seleccionar... + no_content: Non se atoparon coincidencias + filter_placeholder: Buscar... + filter_placeholder_with_any: Buscar ou crear... + create: "Crear: '%{content}'" + max_content_reached: + one: "Só podes seleccionar %{count} elemento." + other: "Só podes seleccionar %{count} elementos." + min_content_not_reached: + one: "Selecciona como mínimo %{count} elemento." + other: "Selecciona como mínimo %{count} elementos." + invalid_selection_length: "A selección debe ter como mínimo %{count} caracteres." date_time_picker: from: De to: A emoji_picker: + filter_placeholder: Buscar emoji + animals_&_nature: Animais e natureza + food_&_drink: Comida e bebida + activities: Actividades + objects: Obxectos + symbols: Símbolos flags: Denuncias + recent: Usados recentemente + default_tone: Sen ton de pel + light_tone: Ton de pel claro + dark_tone: Ton de pel escuro + default: Emojis personalizados + shared_drafts: + title: "Borradores compartidos" + notice: "Este tema só é visíbel para aqueles que poden ver a categoría %{category}." + destination_category: "Categoría de destino" + publish: "Publicar borrador compartido" + confirm_publish: "Confirmas a publicación deste borrador?" + publishing: "Publicando tema..." composer: emoji: "Emoji :)" more_emoji: "máis..." options: "Opcións" whisper: "bisbar" + unlist: "retirado da lista" blockquote_text: "Citación" add_warning: "Este é un aviso oficial." toggle_whisper: "Cambiar Bisbar" @@ -857,12 +1341,16 @@ gl: saved_local_draft_tip: "gardado localmente" similar_topics: "O teu tema é semellante a..." drafts_offline: "borradores sen conexión" + reference_topic_title: "RE: %{title}" error: title_missing: "O título é obrigatorio" title_too_short: "O título debe ter alomenos %{min} caracteres" title_too_long: "O título non debe ter máis de %{max} caracteres" + post_missing: "A publicación non pode estar baleira" post_length: "A publicación debe ter alomenos %{min} caracteres" + try_like: "Probaches o botón %{heart}?" category_missing: "Debes seleccionar unha categoría" + tags_missing: "Debes seleccionar como mínimo %{count} etiquetas" save_edit: "Gardar a edición" reply_original: "Responder no tema orixinal" reply_here: "Responder aquí" @@ -870,14 +1358,21 @@ gl: cancel: "Cancelar" create_topic: "Crear tema" create_pm: "Mensaxe" + create_shared_draft: "Crear borrador compartido" + edit_shared_draft: "Editar borrador compartido" title: "Ou preme Ctrl+Intro" users_placeholder: "Engadir un usuario" title_placeholder: "Sobre que trata a discusión nunha soa frase?" + title_or_link_placeholder: "Escribe o título ou pega unha ligazón aquí" edit_reason_placeholder: "por que estás editando?" + topic_featured_link_placeholder: "Escribe a ligazón amosada co título." + remove_featured_link: "Elimina a ligazón do tema." reply_placeholder: "Escribe aquí. Usa Markdown, BBCode ou HTML para formatar. Arrastra ou pega imaxes." + reply_placeholder_choose_category: "Selecciona unha categoría antes de escribir aquí." view_new_post: "Ver a nova publicación." saving: "Gardando" saved: "Gardado!" + saved_draft: "A publicación do borrador está en proceso. Toca para continuar." uploading: "Enviando..." show_preview: "amosar visualización »" hide_preview: "« ocultar previsualización" @@ -890,37 +1385,109 @@ gl: link_description: "introducir a descrición da ligazón aquí" link_dialog_title: "Inserir hiperligazón" link_optional_text: "título opcional" + link_url_placeholder: "Copia un URL ou escríbeo para buscar temas." quote_title: "Citación" quote_text: "Citación" code_title: "Texto preformatado" code_text: "Texto preformatado cun sangrado de 4 espazos" + paste_code_text: "Escribe un título ou pégao aquí" upload_title: "Enviar" upload_description: "introducir a descrición do envío aquí" olist_title: "Lista numerada" ulist_title: "Lista con símbolos" list_item: "Elemento da lista" help: "Axuda para edición con Markdown" + collapse: "minimizar o panel de composición" + open: "abrir o panel de composición" + abandon: "pechar o panel de composición e desbotar o borrador" modal_ok: "De acordo" modal_cancel: "Cancelar" cant_send_pm: "Sentímolo pero non podes enviar unha mensaxe a %{username}." + yourself_confirm: + title: "Esqueciches engadir destinatarios?" + body: "Polo momento esta mensaxe só a recibes ti." admin_options_title: "Axustes do equipo para este tema" composer_actions: reply: Responder + draft: Borrador edit: Editar + reply_to_post: + label: "Responder á publicación %{postNumber} de %{postUsername}" + desc: Responder a unha publicación específica + reply_as_new_topic: + label: Responder como tema ligado + desc: Crear un novo tema ligado a este tema + reply_as_private_message: + label: Nova mensaxe + desc: Crear unha nova mensaxe persoal create_topic: label: "Novo tema" + shared_draft: + label: "Borrador compartido" notifications: + tooltip: + regular: + one: "%{count} notificación sen ver" + other: "%{count} notificacións sen ver" + message: + one: "%{count} mensaxe sen ler" + other: "%{count} mensaxes sen ler" title: "notificacións das mencións ao teu @nome, respostas ás túas publicacións e temas, mensaxes, etc" none: "Non é posíbel cargar as notificacións neste intre" + empty: "Non se atoparon notificacións." + post_approved: "A túa publicación foi aprobada" + reviewable_items: "elementos que requiren revisión" + mentioned: "%{username} %{description}" + group_mentioned: "%{username} %{description}" + quoted: "%{username} %{description}" + bookmark_reminder: "%{username} %{description}" + replied: "%{username} %{description}" + posted: "%{username} %{description}" + edited: "%{username} %{description}" + liked: "%{username} %{description}" + liked_2: "%{username}, %{username2} %{description}" + liked_many: + one: "%{username}, %{username2} e %{count} máis %{description}" + other: "%{username}, %{username2} e %{count} máis %{description}" + liked_consolidated: "%{username} %{description}" + private_message: "%{username} %{description}" + invited_to_private_message: "

%{username} %{description}" + invited_to_topic: "%{username} %{description}" + invitee_accepted: "%{username} aceptou o teu convite" + linked: "%{username} %{description}" + topic_reminder: "%{username} %{description}" + watching_first_post: "Novo tema %{description}" + group_message_summary: + one: "%{count} mensaxe na caixa %{group_name}" + other: "%{count} mensaxes na caixa %{group_name}" popup: mentioned: '%{username} mencionoute en "%{topic}" - %{site_title}' group_mentioned: '%{username} mencionoute en "%{topic}" - %{site_title}' quoted: '%{username} citoute en "%{topic}" - %{site_title}' replied: '%{username} respondeute en "%{topic}" - %{site_title}' posted: '%{username} publicou en "%{topic}" - %{site_title}' + private_message: '%{username} enviouche unha mensaxe persoal en "%{topic}" - %{site_title}' linked: '%{username} ligou a túa publicación desde "%{topic}" - %{site_title}' + watching_first_post: '%{username} creou un tema novo "%{topic}" - %{site_title}' + confirm_title: "Notificacións habilitadas - %{site_title}" + confirm_body: "Perfecto! As notificacións están habilitadas." + custom: "Notificación de %{username} en %{site_title}" titles: + mentioned: "mencionado" + replied: "nova resposta" + quoted: "citado" + edited: "editado" + liked: "novo gústame" + private_message: "nova mensaxe privada" + invited_to_private_message: "convidado a unha mensaxe privada" + invitee_accepted: "convite aceptado" + posted: "nova publicación" + granted_badge: "insignia concedida" + invited_to_topic: "convidado ao tema" + group_mentioned: "grupo mencionado" watching_first_post: "novo tema" + liked_consolidated: "novos gústames" + post_approved: "publicación aprobada" upload_selector: title: "Engadir unha imaxe" title_with_attachments: "Engadir imaxe ou ficheiro" @@ -939,23 +1506,49 @@ gl: sort_by: "Ordenar por" relevance: "Relevancia" latest_post: "Últimas publicacións" + latest_topic: "Último tema" most_viewed: "Máis vistos" most_liked: "Con máis Gústames" select_all: "Seleccionar todo" clear_all: "Borrar todo" + too_short: "O teu termo de busca é curto de máis" title: "buscar temas, publicacións, usuarios ou categorías" + full_page_title: "buscar temas ou publicacións" no_results: "Non se atoparon resultados." no_more_results: "Non se atoparon máis resultados." searching: "Buscando..." post_format: "#%{post_number} de %{username}" + results_page: "Buscar resultados para '%{term}'" + more_results: "Hai máis resultados. Restrinxe os criterios da busca." + cant_find: "Non atopas o que buscas?" + start_new_topic: "Se cadra queres comezar un novo tema?" + or_search_google: "Ou proba a buscar con Google:" + search_google: "Proba a buscar con Google:" search_google_button: "Google" + search_google_title: "Buscar neste sitio" context: user: "Buscar publicacións de @%{username}" + category: "Buscar na categoría #%{category}" + tag: "Buscar a etiqueta #%{tag}" topic: "Buscar neste tema" private_messages: "Buscar mensaxes" advanced: + title: Busca avanzada posted_by: label: Publicado por + in_group: + label: No grupo + with_badge: + label: Con insignia + filters: + label: Devolver só temas/publicacións... + title: Coincidencia só no título + private: Nas miñas mensaxes + images: incluír imaxe(s) + all_tags: Todas as etiquetas anteriores + post: + time: + label: Publicado hamburger_menu: "ir a outra lista de temas ou categoría" new_item: "novo" go_back: "volver" @@ -983,6 +1576,11 @@ gl: selected: one: "Seleccionaches un tema." other: "Seleccionaches %{count} temas." + change_tags: "Substituír etiquetas" + append_tags: "Anexar etiquetas" + choose_new_tags: "Selecciona novas etiquetas para estes temas:" + choose_append_tags: "Selecciona novas etiquetas para anexar a estes temas:" + changed_tags: "As etiquetas deses temas cambiaron." none: unread: "Non tes temas sen ler." new: "Non tes novos temas." @@ -1005,8 +1603,12 @@ gl: top: "Non hai máis temas destacados." bookmarks: "Non hai máis temas marcados." topic: + filter_to: + one: "%{count} publicación no tema" + other: "%{count} publicacións no tema" create: "Novo tema" create_long: "Crear un novo tema" + open_draft: "Abrir borrador" private_message: "Iniciar unha mensaxe" archive_message: help: "Mover mensaxes ao arquivo" @@ -1018,6 +1620,9 @@ gl: title: "Editar" defer: title: "Pospor" + remove_from_profile: + help: "Eliminar a ligazón a este tema do teu perfil de usuario" + title: "Eliminar do perfil" list: "Temas" new: "novo tema" unread: "sen ler" @@ -1056,6 +1661,7 @@ gl: toggle_information: "cambiar detalles do tema" read_more_in_category: "Queres ler máis? explora outros temas en %{catLink} ou %{latestLink}." read_more: "Queres ler máis? %{catLink} ou %{latestLink}." + group_join: "Debes unirte ao grupo \"%{name}\" para ver este tema" read_more_MF: "Hai { UNREAD, plural, =0 {} one { 1 sen ler } other { # sen ler } } { NEW, plural, =0 {} one { {BOTH, select, true{e} false { } other{}} 1 novo topic} other { {BOTH, select, true{e} false { } other{}} # novos topics} } restantes, ou {CATEGORY, select, true {explora outros temas en {catLink}} false {{latestLink}} other {}}" browse_all_categories: Explorar todas as categorías view_latest_topics: ver últimos temas @@ -1063,24 +1669,64 @@ gl: jump_reply_up: ir a unha resposta anterior jump_reply_down: ir a unha resposta posterior deleted: "Eliminouse o tema" + topic_status_update: + num_of_hours: "Número de horas:" + num_of_days: "Número de días:" + auto_update_input: + now: "Agora" + later_today: "Hoxe, máis tarde" + tomorrow: "Mañá" + this_weekend: "Esta fin de semana" + next_week: "A vindeira semana" + two_weeks: "Dúas semanas" + next_month: "O vindeiro mes" + two_months: "Dous meses" + three_months: "Tres meses" + four_months: "Catro meses" + six_months: "Seis meses" + one_year: "Un ano" + pick_date_and_time: "Escolle unha data e hora" + temp_open: + title: "Abrir temporalmente" + auto_reopen: + title: "Abrir automaticamente o tema" + temp_close: + title: "Pechar temporalmente" auto_close: + title: "Pechar automaticamente o tema" error: "Introduce un valor correcto." based_on_last_post: "Non pechar até que a última publicación do tema teña alomenos este tempo." + auto_delete: + title: "Eliminar automaticamente o tema" + auto_delete_replies: + title: "Eliminar automaticamente respostas" status_update_notice: + auto_open: "Este tema abrirase automaticamente en %{timeLeft}." auto_close: "Este tema pechará automaticamente en %{timeLeft}." + auto_publish_to_category: "Este tema publicarase en #%{categoryName} en %{timeLeft}." auto_close_based_on_last_post: "Este tema pechará %{duration} despois da última resposta." + auto_delete: "Este tema eliminarase automaticamente en %{timeLeft}." + auto_delete_replies: "As respostas a este tema eliminaranse automaticamente en %{duration}." auto_close_title: "Axustes do peche automático" + timeline: + back: "Atrás" + back_description: "Volver á última publicación sen ler" + replies_short: "%{current} / %{total}" progress: title: progreso do tema go_top: "principio" go_bottom: "final" go: "ir" jump_bottom: "ir á última publicación" + jump_prompt: "ir a..." + jump_prompt_of: "de %{count} publicacións" + jump_prompt_long: "Ir a..." jump_bottom_with_number: "ir á publicación %{post_number}" jump_prompt_or: "ou" total: publicacións totais current: publicación actual notifications: + title: cambiar a frecuencia coa que recibes notificacións sobre este tema reasons: "3_6": "Recibirás notificacións porque estás vendo esta categoría." "3_5": "Recibirás notificacións porque comezaches a ver este tema automaticamente." @@ -1144,11 +1790,17 @@ gl: help: "Borra o estado Pegado deste tema para que non apareza na banda superior da lista de temas." share: title: "Compartir" + extended_title: "Compartir unha ligazón" help: "compartir unha ligazón a este tema" + print: + title: "Imprimir" flag_topic: title: "Denunciar" help: "denunciar privadamente este tema para revisalo ou enviar unha notificación privada sobre el" success_message: "Denunciaches o tema correctamente." + make_public: + title: "Converter en tema público" + choose_category: "Selecciona unha categoría para o tema público:" feature_topic: title: "Destacar este tema" pin: "Facer que este tema apareza no alto da categoría %{categoryLink} até" @@ -1176,12 +1828,14 @@ gl: no_banner_exists: "Non hai tema para o báner." banner_exists: "Hai actualmente un tema para o báner." inviting: "Convidando..." + automatically_add_to_groups: "Este convite tamén inclúe o acceso a estes grupos:" invite_private: title: "Convidar á mensaxe" email_or_username: "Nome do usuario ou correo-e do convidado" email_or_username_placeholder: "correo electrónico e nome do usuario" action: "Convidar" success: "Convidamos este usuario a participar nesta mensaxe." + success_group: "Convidamos este grupo a participar nesta mensaxe." error: "Sentímolo pero houbo un erro convidando este usuario." group_name: "nome do grupo" controls: "Controis do tema" @@ -1200,15 +1854,21 @@ gl: success_email: "Enviamos un convite a %{emailOrUsername}. Notificarémosche cando utilice a invitación. Mira a lapela de convites na túa páxina de usuario para facer un seguimento das túas invitacións." success_username: "Convidamos este usuario a participar neste tema." error: "Sentímolo, non foi posíbel convidar esta persoa. Quizais xa foi convidada? (os convites teñen un límite)" + success_existing_email: "Xa existe un usuario co correo electrónico %{emailOrUsername}. Convidamos este usuario a participar neste tema." login_reply: "Inicia sesión para responder" filters: n_posts: one: "Unha publicación" other: "%{count} publicacións" cancel: "Eliminar filtro" + move_to: + title: "Mover a" + action: "mover a" + error: "Produciuse un erro ao mover as publicacións." split_topic: title: "Mover ao tema novo" action: "mover ao tema novo" + topic_name: "Título do tema novo" radio_label: "Novo tema" error: "Produciuse un erro movendo as publicacións ao novo tema." instructions: @@ -1218,15 +1878,32 @@ gl: title: "Mover a un tema existente" action: "mover a un tema existente" error: "Produciuse un erro movendo publicacións nese tema." + radio_label: "Tema existente" instructions: one: "Selecciona o tema ao que queres mover esta publicación." other: "Selecciona o tema ao que queres mover estas %{count} publicacións." move_to_new_message: + message_title: "Título da nova mensaxe" radio_label: "Nova mensaxe" + participants: "Participantes" + move_to_existing_message: + radio_label: "Mensaxe existente" + participants: "Participantes" + publish_page: + title: "Publicación da páxina" + publish: "Publicar" + public: "Público" + invalid_slug: "Sentímolo pero non podes publicar esta páxina." + update: "Actualizar" + publishing_settings: "Axustes da publicación" change_owner: + title: "Cambiar propietario" action: "cambiar propiedade" error: "Produciuse un erro cambiando a propiedade das publicacións." placeholder: "nome do usuario do novo propietario" + instructions_without_old_user: + one: "Selecciona un novo propietario para a publicación" + other: "Selecciona un novo propietario para as %{count} publicacións" change_timestamp: action: "cambiar a marca data/hora" invalid_timestamp: "A marca data/hora non pode ser no futuro." @@ -1277,6 +1954,7 @@ 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, o ficheiro que tentas subir non está autorizado (extensións permitidas: %{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." @@ -1313,6 +1991,7 @@ gl: convert_to_moderator: "Engadir cor do Equipo" revert_to_regular: "Eliminar cor do Equipo" rebake: "Reconstruír HTML" + publish_page: "Publicación da páxina" unhide: "Non ocultar" change_owner: "Cambiar propietario" grant_badge: "Conceder insignia" @@ -1348,26 +2027,55 @@ gl: last: "Última revisión" hide: "Ocultar revisión" show: "Amosar revisión" - revert: "Reverter a esta revisión" + edit_wiki: "Editar wiki" + edit_post: "Editar publicación" displays: inline: title: "Amosar o resultado coas adicións e eliminacións inseridas" + button: "HTML" side_by_side: title: "Amosar o resultado coas diferenzas comparadas" + button: "HTML" side_by_side_markdown: title: "Amosar a fonte crúa coas diferenzas comparadas" + raw_email: + displays: + text_part: + button: "Texto" + html_part: + button: "HTML" bookmarks: + create: "Crear marcador" + edit: "Editar marcador" created: "Creado" name: "Nome" + actions: + delete_bookmark: + name: "Eliminar marcador" + edit_bookmark: + name: "Editar marcador" category: can: "podes… " none: "(sen categoría)" all: "Todas as categorías" edit: "Editar" + edit_dialog_title: "Editar: %{categoryName}" view: "Ver os Temas na Categoría" general: "Xeral" settings: "Axustes" topic_template: "Modelo para o tema" + tags: "Etiquetas" + tags_allowed_tags: "Restrinxir estas etiquetas a esta categoría:" + tags_allowed_tag_groups: "Restrinxir estes grupos de etiquetas a esta categoría:" + tags_placeholder: "lista de etiquetas permitidas (opcional)" + tags_tab_description: "As etiquetas e os grupos de etiquetas anteriores só estarán dispoñíbeis nesta categoría e outras que as inclúan. Non poderán usarse noutras categorías." + tag_groups_placeholder: "lista de grupos de etiquetas permitidos (opcional)" + manage_tag_groups_link: "Xestiona aquí os grupos de etiquetas." + allow_global_tags_label: "Permitir tamén outras etiquetas" + tag_group_selector_placeholder: "Grupo de etiquetas (opcional)" + required_tag_group_description: "Requirir que os novos temas teñan etiquetas dun grupo de etiquetas:" + min_tags_from_required_group_label: "Número de etiquetas:" + required_tag_group_label: "Grupo de etiquetas:" delete: "Eliminar categoría" create: "Nova categoría" create_long: "Crear unha nova categoría" @@ -1406,6 +2114,7 @@ gl: default_position: "Posición predeterminada" position_disabled: "As categorías amosaranse en orde de actividade. Para controlar a orde das categorías nas listas." position_disabled_click: 'activar o axuste «fixed category positions».' + minimum_required_tags: "Número mínimo de etiquetas requiridas nun tema:" parent: "Categoría pai" notifications: watching: @@ -1422,6 +2131,8 @@ gl: options: normal: "Normal" ignore: "Ignorar" + low: "Baixa" + high: "Alta" sort_options: likes: "Gústames" views: "Vistas" @@ -1429,6 +2140,8 @@ gl: activity: "Actividade" category: "Categoría" created: "Creado" + sort_ascending: "Ascendente" + sort_descending: "Descendente" settings_sections: general: "Xeral" email: "Correo electrónico" @@ -1462,6 +2175,10 @@ gl: clicks: one: "Un clic" other: "%{count} clics" + post_links: + title: + one: "%{count} máis" + other: "%{count} máis" topic_statuses: warning: help: "Este é un aviso oficial." @@ -1512,6 +2229,7 @@ gl: history: "Historial" changed_by: "por %{author}" raw_email: + title: "Correo electrónico entrante" not_available: "Non dispoñíbel." categories_list: "Lista de categorías" filters: @@ -1537,7 +2255,7 @@ gl: other: "(%{count}) sen ler" help: "temas con publicacións sen ler que estás vendo ou seguindo" lower_title_with_count: - one: "Unha sen ler" + one: "%{count} sen ler" other: "%{count} sen ler" new: lower_title_with_count: @@ -1588,7 +2306,15 @@ gl: readonly: "Ver" lightbox: download: "descargar" + previous: "Anterior (tecla de frecha cara á esquerda)" + next: "Seguinte (tecla de frecha cara á dereita)" + close: "Pechar (Esc)" + content_load_error: 'O contido non puido cargarse.' + image_load_error: 'A imaxe non puido cargarse.' keyboard_shortcuts_help: + shortcut_delimiter_or: "%{shortcut1} ou %{shortcut2}" + shortcut_delimiter_slash: "%{shortcut1}/%{shortcut2}" + shortcut_delimiter_space: "%{shortcut1} %{shortcut2}" title: "Atallos do teclado" jump_to: title: "Ir a" @@ -1641,6 +2367,7 @@ gl: badges: title: Insignias select_badge_for_title: Selecciona insignia para usar como o teu título + none: "(ningún)" badge_grouping: getting_started: name: Comezar @@ -1653,7 +2380,26 @@ gl: posting: name: Publicación tagging: + all_tags: "Todas as etiquetas" + other_tags: "Outras etiquetas" + selector_all_tags: "todas as etiquetas" + selector_no_tags: "sen etiquetas" + changed: "etiquetas cambiadas:" + tags: "Etiquetas" + choose_for_topic: "etiquetas opcionais" + default_info: "Esta etiqueta non se restrinxe a ningunha categoría e non ten sinónimos." + category_restricted: "Esta etiqueta restrínxese ás categorías ás que non tes permiso para acceder." + synonyms: "Sinónimos" + add_synonyms_label: "Engadir sinónimos:" add_synonyms: "Engadir" + remove_synonym: "Eliminar sinónimo" + delete_tag: "Eliminar etiqueta" + delete_confirm_no_topics: "Confirmas a eliminación desta etiqueta?" + rename_instructions: "Selecciona un novo nome para a etiqueta:" + sort_by: "Ordenar por:" + manage_groups: "Xestionar grupos de etiquetas" + manage_groups_description: "Estabelecer grupos para organizar etiquetas" + delete_unused: "Eliminar etiquetas sen usar" cancel_delete_unused: "Cancelar" notifications: watching: @@ -1665,8 +2411,20 @@ gl: muted: title: "Silenciado" groups: + title: "Etiquetar grupos" + about: "Engade etiquetas aos grupos para xestionalos con maior facilidade." + new: "Novo grupo" + tags_label: "Etiquetas neste grupo:" + tags_placeholder: "etiquetas" + parent_tag_placeholder: "Opcional" + new_name: "Novo grupo de etiquetas" + name_placeholder: "Nome do grupo de etiquetas" save: "Gardar" delete: "Eliminar" + confirm_delete: "Confirmas a eliminación deste grupo de etiquetas?" + everyone_can_use: "Todos poden usar as etiquetas" + usable_only_by_staff: "As etiquetas son visíbeis para todos, pero só o equipo pode usalas" + visible_only_to_staff: "As etiquetas só son visíbeis para o equipo" topics: none: unread: "Non tes temas sen ler." @@ -1684,6 +2442,7 @@ gl: top: "Non hai máis temas destacados." bookmarks: "Non hai máis temas marcados." footer_nav: + back: "Atrás" share: "Compartir" dismiss: "Desbotar" admin_js: @@ -1695,6 +2454,8 @@ gl: remove_muted_tags_from_latest: always: "sempre" never: "nunca" + reports: + title: "Lista dos informes dispoñíbeis" dashboard: title: "Panel" version: "Versión" @@ -1719,28 +2480,49 @@ gl: backups: "Copias de seguranza" traffic_short: "Tráfico" traffic: "Peticións web de aplicativos" + page_views: "Visualizacións de páxinas" + page_views_short: "Visualizacións de páxinas" show_traffic_report: "Amosar o informe detallado do tráfico" + moderators_activity: Actividade dos moderadores + whats_new_in_discourse: Novidades en Discourse + all_reports: "Todos os informes" general_tab: "Xeral" security_tab: "Seguranza" + reports_tab: "Informes" + not_found_error: Sentímolo pero o informe non existe + filter_reports: Filtrar informes reports: today: "Hoxe" yesterday: "Onte" + last_7_days: "Últimos 7" + last_30_days: "Últimos 30" all_time: "Todos" 7_days_ago: "Hai 7 días" 30_days_ago: "Hai 30 días" all: "Todo" view_table: "táboa" - refresh_report: "Actualiza informe" + refresh_report: "Actualizar informe" groups: "Todos os grupos" + disabled: "Este informe está deshabilitado" filters: group: label: Grupo category: label: Categoría + include_subcategories: + label: "Incluír subcategorías" commits: latest_changes: "Últimos cambios: por favor, actualiza a miúdo." by: "por" groups: + new: + title: "Novo grupo" + create: "Crear" + name: + checking: "Comprobando a dispoñibilidade do nome do grupo..." + available: "O nome do grupo está dispoñíbel" + not_available: "O nome do grupo non está dispoñíbel" + blank: "O nome do grupo non pode quedar baleiro" bulk_add: title: "Engadir ao grupo en bloque" paste: "Pegar unha lista de nomes de usuario ou correos-e, un por liña:" @@ -1749,11 +2531,19 @@ gl: email: Correo electrónico incoming_email: "Personalizar enderezos de correo-e entrantes" incoming_email_placeholder: "introducir enderezos de correo-e" + visibility: Visibilidade visibility_levels: + title: "Quen pode ver este grupo?" public: "Todos" + owners: "Propietarios do grupo" + description: "Os administradores poden ver todos os grupos." + members_visibility_levels: + title: "Quen pode ver os membros deste grupo?" + description: "Os administradores poden ver os membros de todos os grupos." membership: automatic: Automático trust_levels_title: "Nivel de confianza automático concedido aos membros cando son engadidos:" + effects: Efectos trust_levels_none: "Ningún" automatic_membership_email_domains: "Os usuarios que se rexistraron cun dominio de correo electrónico que coincida exactamente con algún da lista engadiranse automaticamente a este grupo:" primary_group: "Estabelecer automaticamente como grupo primario" @@ -1772,6 +2562,7 @@ gl: add: "Engadir" custom: "Personalizar" automatic: "Automático" + default_title: "Título predeterminado" group_owners: Propietarios add_owners: Engadir propietarios api: @@ -1785,15 +2576,31 @@ gl: all_users: "Todos os usuarios" show_details: Detalles description: Descrición + no_description: (sen descrición) + user_mode: Nivel de usuario + user_placeholder: Escribe un nome de usuario save: Gardar + continue: Continuar web_hooks: + create: "Crear" save: "Gardar" destroy: "Eliminar" description: "Descrición" + controls: "Controis" + go_back: "Volver á lista" active: "Activo" delivery_status: failed: "Fallou" events: + none: "Non hai eventos relacionados." + incoming: + one: "Hai un evento novo." + other: "Hai %{count} eventos novos." + completed_in: + one: "Completado nun %{count} segundo." + other: "Completado en %{count} segundos." + request: "Petición" + headers: "Cabeceiras" body: "Corpo" timestamp: "Creado" actions: "Accións" @@ -1829,6 +2636,7 @@ gl: label: "Enviar" title: "Subir unha copia de seguranza a esta instancia" uploading: "Enviando..." + uploading_progress: "Actualizando... %{progress}%" error: "Produciuse un erro durante o envío de «%{filename}»: %{message}" operations: is_running: "Estase executando unha operación..." @@ -1841,6 +2649,7 @@ gl: label: "Copia de seguranza" title: "Crear unha copia de seguranza" confirm: "Confirmas a execución dunha nova copia de seguranza?" + without_uploads: "Si (non incluír actualizacións)" download: label: "Descargar" destroy: @@ -1877,10 +2686,14 @@ gl: save: "Gardar" new: "Novo" new_style: "Novo estilo" + install: "Instalar" delete: "Eliminar" color: "Cor" opacity: "Opacidade" copy: "Copiar" + copy_to_clipboard: "Copiar ao portapapeis" + copied_to_clipboard: "Copiado ao portapapeis" + copy_to_clipboard_error: "Erro ao copiar os datos ao portapapeis" email_templates: title: "Correo electrónico" subject: "Asunto" @@ -1890,20 +2703,37 @@ gl: revert: "Reverter os cambios" revert_confirm: "Confirmas a reversión dos cambios?" theme: + theme: "Tema" + theme_name: "Nome do tema" + customize_desc: "Personalizar:" + title: "Temas" + create: "Crear" + create_type: "Tipo" create_name: "Nome" edit: "Editar" + update_confirm_yes: "Si, continuar coa actualización" mobile: "Móbil" settings: "Axustes" + translations: "Traducións" + show_advanced: "Mostrar campos avanzados" + hide_advanced: "Ocultar campos avanzados" + and_x_more: "e %{count} máis." upload: "Enviar" + install: "Instalar" installed: "Instalado" + install_popular: "Destacados" about_theme: "Sobre" enable: "Activar" disable: "Desactivar" + check_for_updates: "Buscar actualizacións" + updating: "Actualizando..." add: "Engadir" scss: text: "CSS" header: text: "Cabeceira" + after_header: + text: "Despois da cabeceira" footer: text: "Pé de páxina" embedded_scss: @@ -1933,7 +2763,7 @@ gl: name: "cuaternario" description: "Ligazóns de navegación" header_background: - name: "Fondo da cabeceira" + name: "fondo da cabeceira" description: "Cor do fondo na cabeceira do sitio." header_primary: name: "cabeceira primaria" @@ -1951,12 +2781,19 @@ gl: name: "gústame" description: "Cor do botón Gústame." email_style: + title: "Estilo de correo electrónico" + heading: "Personalizar estilo de correo electrónico" + html: "Modelo HTML" css: "CSS" email: title: "Correos electrónicos" settings: "Axustes" templates: "Modelos" preview_digest: "Previsualización do compendio" + advanced_test: + email: "Mensaxe orixinal" + run: "Executar proba" + text: "Corpo de texto seleccionado" sending_test: "Enviando correo-e de proba..." error: "ERRO - %{server_error}" test_error: "Produciuse un problema enviando o correo-e de proba. Revisa os teus axustes de correo electrónico, comproba que o teu host non está bloqueando as conexións de correo e téntao de novo." @@ -1972,13 +2809,18 @@ gl: test_email_address: "enderezo de correo-e de proba" send_test: "Enviar correo-e de proba" sent_test: "enviado!" - delivery_method: "Metodo de entrega" + delivery_method: "Método de entrega" preview_digest_desc: "Previsualiza o contido dos correos-e compendio enviados a usuarios inactivos." refresh: "Actualizar" + send_digest_label: "Enviar este resultado a:" + send_digest: "Enviar" + sending_email: "Enviando correo electrónico..." format: "Formato" html: "html" text: "texto" + html_preview: "Previsualización do contido do correo electrónico" last_seen_user: "Último usuario visto:" + no_result: "Non se atoparon resultados para o resumo." reply_key: "Tecla para responder" skipped_reason: "Saltar razón" incoming_emails: @@ -1991,6 +2833,7 @@ gl: modal: title: "Detalles dos correos-e entrantes" error: "Erro" + headers: "Cabeceiras" subject: "Asunto" body: "Corpo" rejection_message: "Correo-e de rexeitamento" @@ -2008,6 +2851,15 @@ gl: address_placeholder: "nome@exemplo.com" type_placeholder: "compendio, rexistro..." reply_key_placeholder: "tecla para responder" + moderation_history: + no_results: "Non hai ningún historial de moderación dispoñible." + actions: + delete_user: "Usuario eliminado" + suspend_user: "Usuario suspendido" + silence_user: "Usuario silenciado" + delete_post: "Publicación eliminada" + delete_topic: "Tema eliminado" + post_approved: "Publicación aprobada" logs: title: "Rexistros" action: "Acción" @@ -2026,6 +2878,7 @@ gl: do_nothing: "non facer nada" staff_actions: all: "todo" + filter: "Filtrar:" title: "Accións do equipo" clear_filters: "Amosar todo" staff_user: "Usuario" @@ -2046,13 +2899,18 @@ gl: change_trust_level: "cambiar nivel de confianza" change_username: "cambiar nome do usuario" change_site_setting: "cambiar axuste do sitio" + change_theme: "cambiar tema" + delete_theme: "eliminar tema" change_site_text: "cambiar o texto do sitio" suspend_user: "suspender usuario" unsuspend_user: "non suspender usuario" + removed_suspend_user: "suspender usuario (eliminado)" + removed_unsuspend_user: "non suspender usuario (eliminado)" grant_badge: "conceder insignia" revoke_badge: "revogar insignia" check_email: "comprobar correo-e" delete_topic: "eliminar tema" + recover_topic: "recuperar tema" delete_post: "eliminar publicación" impersonate: "suplantar" anonymize_user: "facer o usuario anónimo" @@ -2060,10 +2918,45 @@ gl: change_category_settings: "cambiar axustes da categoría" delete_category: "eliminar categoría" create_category: "crear categoría" + silence_user: "silenciar usuario" + unsilence_user: "non silenciar usuario" + removed_silence_user: "silenciar usuario (eliminado)" + removed_unsilence_user: "non silenciar usuario (eliminado)" grant_admin: "conceder administración" revoke_admin: "revogar administración" grant_moderation: "conceder moderación" revoke_moderation: "revogar moderación" + backup_create: "crear copia de seguranza" + deleted_tag: "etiqueta eliminada" + deleted_unused_tags: "etiquetas sen usar eliminadas" + revoke_email: "revogar correo electrónico" + lock_trust_level: "bloquear o nivel de confianza" + unlock_trust_level: "desbloquear o nivel de confianza" + activate_user: "activar usuario" + deactivate_user: "desactivar usuario" + change_readonly_mode: "cambiar modo de só lectura" + backup_download: "descargar copia de seguranza" + reviewed_post: "publicación revisada" + post_locked: "publicación bloqueada" + post_edit: "edición da publicación" + post_unlocked: "publicación desbloqueada" + check_personal_message: "comprobar mensaxe persoal" + disabled_second_factor: "deshabilitar autenticación de dobre factor" + topic_published: "tema publicado" + post_approved: "publicación aprobada" + post_rejected: "publicación rexeitada" + create_badge: "crear insignia" + change_badge: "cambiar insignia" + delete_badge: "eliminar insignia" + entity_export: "exportar entidade" + change_name: "cambiar nome" + approve_user: "usuario aprobado" + revoke_title: "revogar título" + change_title: "cambiar título" + page_published: "páxina publicada" + page_unpublished: "páxina sen publicar" + add_email: "engadir correo electrónico" + update_email: "actualizar correo electrónico" screened_emails: title: "Correos-e controlados" description: "Cando alguén tente crear unha nova conta, comprobaranse os seguintes enderezos de correo electrónico e bloquearase o rexistro ou se tomará outra medida." @@ -2095,19 +2988,41 @@ gl: text: "Agrupar" title: "Crea unha nova subrede de entradas para bloquear se hai cando menos «min_ban_entries_for_roll_up» entradas." search_logs: + title: "Buscar rexistros" + term: "Termo" + searches: "Buscas" + click_through_rate: "CTR" types: + all_search_types: "todos os tipos de busca" header: "Cabeceira" + full_page: "Páxina completa" logster: title: "Rexistros de erros" watched_words: + search: "buscar" clear_filter: "Borrar" + show_words: "amosar palabras" + one_word_per_line: "Unha palabra por liña" download: Descargar clear_all: Borrar todo + word_count: + one: "%{count} palabra" + other: "%{count} palabras" actions: block: "Bloquear" + require_approval: "Requirir aprobación" flag: "Denunciar" + action_descriptions: + require_approval: "As publicacións que conteñan estas palabras requiren a aprobación do equipo antes de ser visíbeis." form: + label: "Palabra nova:" + placeholder_regexp: "expresión regular" add: "Engadir" + exists: "Xa existe" + upload: "Engadir desde ficheiro" + test: + found_matches: "Coincidencias atopadas:" + no_matches: "Non se atoparon coincidencias" impersonate: title: "Suplantar" help: "Usar esta ferramenta para suplantar unha conta de usuario co obxecto de detectar e corrixir erros. Deberás saír da sesión ao rematar." @@ -2120,11 +3035,14 @@ gl: not_found: "Sentímolo pero o nome do usuario non existe no sistema." id_not_found: "Sentímolo pero o usuario non existe no sistema." show_emails: "Amosar correos-e" + hide_emails: "Ocultar correos electrónicos" nav: new: "Novo" active: "Activo" staff: "Equipo" suspended: "Suspendido" + silenced: "Silenciado" + staged: "Transitorio" approved: "Aprobado?" titles: active: "Usuarios activos" @@ -2138,7 +3056,9 @@ gl: staff: "Equipo" admins: "Usuarios administradores" moderators: "Moderadores" + silenced: "Usuarios silenciados" suspended: "Usuarios suspendidos" + staged: "Usuarios transitorios" not_verified: "Sen verificar" check_email: title: "Amosar o enderezo de correo-e deste usuario" @@ -2148,10 +3068,28 @@ gl: unsuspend_failed: "Algo foi mal levantando a suspensión deste usuario %{error}" suspend_duration: "Canto tempo estará suspendido o usuario?" suspend_reason_label: "Cal é o motivo da suspensión? Este texto será visíbel para todo o mundo na páxina do perfil deste usuario e amosaráselle ao usuario cando tente iniciar sesión. Procura ser breve." + suspend_reason_hidden_label: "Cal é o motivo da suspensión? Este texto amosaráselle ao usuario cando tente iniciar sesión. Procura ser breve." suspend_reason: "Razón" + suspend_reason_placeholder: "Razón da suspensión" + suspend_message: "Mensaxe de correo electrónico" + suspend_message_placeholder: "Podes achegar máis información sobre a suspensión e enviarlla por correo electrónico ao usuario." suspended_by: "Suspendido por" silence_reason: "Razón" + silenced_by: "Silenciado por" + silence_modal_title: "Silenciar usuario" + silence_message: "Mensaxe de correo electrónico" + silence_message_placeholder: "(deixar baleiro para enviar mensaxe predeterminada)" + suspended_until: "(até %{until})" + cant_suspend: "Este usuario non pode estar suspendido." delete_all_posts: "Eliminar todas as publicacións" + delete_posts_progress: "Eliminando publicacións..." + delete_posts_failed: "Produciuse un erro ao eliminar as publicacións." + penalty_post_actions: "Que queres facer coa publicación asociada?" + penalty_post_delete: "Eliminar a publicación" + penalty_post_delete_replies: "Eliminar a publicación e todas as respostas" + penalty_post_edit: "Editar a publicación" + silence: "Silenciar" + silenced: "Silenciado?" moderator: "Moderador?" admin: "Administrador?" suspended: "Suspendido?" @@ -2159,23 +3097,29 @@ gl: show_admin_profile: "Administración" show_public_profile: "Amosar o perfil público" impersonate: "Suplantar" + action_logs: "Rexistros de accións" ip_lookup: "Busca de IP" log_out: "Saír da sesión" logged_out: "O usuario foi desconectado en todos os dispositivos" revoke_admin: "Revogar administrador" grant_admin: "Facer administrador" + grant_admin_confirm: "Enviamos un correo electrónico para verificar o novo administrador. Ábreo e sigue as instrucións." revoke_moderation: "Revogar moderación" grant_moderation: "Conceder moderación" unsuspend: "Non suspender" suspend: "Suspender" + show_flags_received: "Mostrar denuncias recibidas" + flags_received_by: "Denuncias que recibiu %{username}" + flags_received_none: "Este usuario non recibiu ningunha denuncia." reputation: Reputación permissions: Permisos activity: Actividade - like_count: Gústames dados / Recibidos + like_count: Gústames dados / recibidos last_100_days: "nos últimos 100 días" private_topics_count: Temas privados posts_read_count: Publicacións lidas post_count: Publicacións creadas + second_factor_enabled: Habilitada a autenticación de dobre factor topics_entered: Temas vistos flags_given_count: Denuncias dadas flags_received_count: Denuncias recibidas @@ -2193,6 +3137,7 @@ gl: delete: "Eliminar usuario" merge: prompt: + target_username_placeholder: "Nome de usuario do novo propietario" cancel: "Cancelar" confirmation: cancel: "Cancelar" @@ -2209,6 +3154,7 @@ gl: other: "Non é posíbel eliminar todas as publicacións porque o usuario ten máis de %{count} publicacións. (delete_all_posts_max)" delete_and_block: "Eliminar e bloquear este correo-e e enderezo IP" delete_dont_block: "Só eliminar" + deleting_user: "Eliminando usuario..." deleted: "Eliminouse o usuario." delete_failed: "Produciuse un erro eliminando este usuario. Asegúrate que se eliminan todas as publicacións antes de tentar eliminar o usuario." send_activation_email: "Enviar correo-e de activación" @@ -2231,6 +3177,9 @@ gl: unlock_trust_level: "Desbloquear o nivel de confianza" tl3_requirements: title: "Requerimentos para o nivel 3 de confianza" + table_title: + one: "No último día:" + other: "Nos últimos %{count} días:" value_heading: "Valor" requirement_heading: "Requirimento" visits: "Visitas" @@ -2246,6 +3195,8 @@ gl: likes_received: "Gústames recibidos" likes_received_days: "Gústames recibidos: por días" likes_received_users: "Gústames recibidos: usuarios" + suspended: "Suspendido (os últimos 6 meses)" + silenced: "Silenciado (os últimos 6 meses)" qualifies: "Cumpre os requisitos para o nivel de confianza 3." does_not_qualify: "Non cumpre os requisitos para o nivel de confianza 3." will_be_promoted: "Será promocionado pronto." @@ -2293,12 +3244,14 @@ gl: site_text: description: "Podes personalizar calquera texto do teu foro. Comeza por buscar debaixo:" search: "Busca o texto que queres editar" + title: "Texto" edit: "editar" revert: "Reverter os cambios" revert_confirm: "Confirmas a reversión dos cambios?" go_back: "Volver á busca" recommended: "Recomendamos personalizar o seguinte texto para axeitalo ás túas necesidades:" show_overriden: "Amosar só os cambios" + more_than_50_results: "Hai máis de 50 resultados. Restrinxe a busca." settings: show_overriden: "Amosar só os cambios" reset: "restabelecer" @@ -2306,12 +3259,17 @@ gl: site_settings: title: "Axustes" no_results: "Non se atoparon resultados." + more_than_30_results: "Hai máis de 30 resultados. Restrinxe a busca ou selecciona unha categoría." clear_filter: "Borrar" add_url: "engadir URL" add_host: "engadir host" + add_group: "engadir grupo" uploaded_image_list: + label: "Editar lista" + empty: "Aínda non hai imaxes. Sube unha." upload: label: "Enviar" + title: "Subir imaxe(s)" categories: all_results: "Todo" required: "Obrigatorio" @@ -2335,11 +3293,14 @@ gl: login: "Iniciar sesión" plugins: "Plugins" user_preferences: "Preferencias do usuario" + tags: "Etiquetas" search: "Buscar" groups: "Grupos" dashboard: "Panel" default_categories: modal_yes: "Si" + simple_list: + add_item: "Engadir elemento..." badges: title: Insignias new_badge: Nova insignia @@ -2348,6 +3309,7 @@ gl: badge: Insignia display_name: Nome público description: Descrición + long_description: Descrición longa badge_type: Tipo de insignia badge_grouping: Grupo badge_groupings: @@ -2405,6 +3367,16 @@ gl: with_post: "%{username} para publicación en %{link}" with_post_time: "%{username} para publicación en %{link} o %{time}" with_time: "%{username} o %{time}" + badge_intro: + title: "Selecciona unha insignia existente ou crea unha nova para comezar" + what_are_badges_title: "Que son as insignias?" + badge_query_examples_title: "Exemplos de consulta de insignias" + mass_award: + description: Concede a mesma insignia a varios usuarios á vez. + no_badge_selected: Selecciona unha insignia para comezar. + perform: "Conceder insignia a usuarios" + upload_csv: Actualizar un CSV con correos electrónicos ou nomes de usuario + replace_owners: Retirar a insignia dos propietarios anteriores emoji: title: "Emoji" help: "Engade novo emoji que estará dispoñíbel para todos. (Suxestión: arrastra e solta múltiples ficheiros dunha vez)" @@ -2413,6 +3385,7 @@ gl: name: "Nome" group: "Grupo" image: "Imaxe" + alt: "previsualizar emoji personalizado" delete_confirm: "Confirmas a eliminación do emoji :%{name}:?" embedding: get_started: "Se queres encaixar o Discourse noutro sitio web, comeza engadindo o seu host." @@ -2420,6 +3393,7 @@ gl: sample: "Usa o seguinte código HTML no teu sitio para crear e encaixar temas do Discourse. Substitúe REPLACE_ME pola URL canónica da páxina que recibe o encaixado. " title: "Encaixado" host: "Hosts permitidos" + class_name: "Nome da clase" edit: "editar" category: "Publicación a categoría" add_host: "Engadir host" @@ -2442,25 +3416,40 @@ gl: category_id: "ID da categoría" category_title: "Categoría" external_url: "URL externa" + destination: "Destino" delete_confirm: "Confirmas a eliminación desta ligazón permanente?" form: label: "Novo:" add: "Engadir" filter: "Buscar (URLou URL externa)" reseed: + action: + label: "Substituír texto..." + title: "Substituír o texto das categorías e temas coas traducións" modal: + title: "Substituír texto" + subtitle: "Substituír o texto das categorías e temas xerados polo sistema coas últimas traducións" categories: "Categorías" topics: "Temas" + replace: "Substituír" wizard_js: wizard: done: "Feito" + back: "Atrás" + next: "Seguinte" + step: "%{current} de %{total}" upload: "Enviar" uploading: "Actualizando..." upload_error: "Sentímolo pero produciuse un erro enviando a publicación. Téntao de novo." + quit: "Pode que logo" invites: + add_user: "engadir" + none_added: "Non convidaches a ninguén do equipo. Confirmas que queres continuar?" roles: admin: "Administración" moderator: "Moderador" + regular: "Usuario normal" previews: + topic_title: "Tema de discusión" share_button: "Compartir" reply_button: "Responder" diff --git a/config/locales/client.he.yml b/config/locales/client.he.yml index f4aa2c933a..3c243ca61d 100644 --- a/config/locales/client.he.yml +++ b/config/locales/client.he.yml @@ -850,7 +850,7 @@ he: all: "הכל" read: "נקרא" unread: "לא-נקראו" - ignore_duration_title: "מתזמן התעלמות" + ignore_duration_title: "התעלמות ממשתמש" ignore_duration_username: "שם משתמש" ignore_duration_when: "משך:" ignore_duration_save: "התעלמות" @@ -1076,6 +1076,9 @@ he: confirm: "האם את/ה בטוח/ה שברצונך לשנות את שם המשתמש/ת שלך?" taken: "סליחה, שם המשתמש הזה תפוס." invalid: "שם המשתמש אינו תקין. עליו לכלול רק אותיות באנגלית ומספרים." + add_email: + title: "הוסף דוא\"ל" + add: "הוספה" change_email: title: "שנה דואר אלקטרוני" taken: "סליחה, הכתובת הזו אינה זמינה." @@ -1106,8 +1109,17 @@ he: title: "דואר אלקטרוני" primary: "כתובת דוא״ל ראשית" secondary: "כתובות דוא״ל משניות" - no_secondary: "אין כתובות דוא״ל משניות" + primary_label: "ראשי" + unconfirmed_label: "לא מאושר" + resend_label: "שליחת הודעת אימות בדוא״ל מחדש" + resending_label: "שולח..." + resent_label: "דוא\"ל נשלח" + update_email: "שנה דואר אלקטרוני" + set_primary: "הגדר כתובת דוא\"ל ראשית" + destroy: "הסר דוא\"ל" + add_email: "הוסף דוא\"ל חלופי" sso_override_instructions: "ניתן לעדכן את כתובת הדוא״ל דרך ספק ה־SSO." + no_secondary: "אין כתובות דוא״ל משניות" instructions: "לעולם לא מוצג לציבור." ok: "נשלח אליכם דואר אלקטרוני לאישור" required: "נא למלא כתובת דוא״ל" @@ -1280,6 +1292,7 @@ he: links_tab_with_count: "קישורים (%{count})" link_url: "קישור" link_created_at: "נוצר" + link_redemption_stats: "ניצולים" link_groups: קבוצות link_expires_at: תפוגה create: "שלח הזמנה" @@ -2156,6 +2169,7 @@ he: time_frame_required: נא לבחור מסגרת זמנים auto_update_input: none: "נא לבחור טווח זמן" + now: "כעת" later_today: "בהמשך היום" tomorrow: "מחר" later_this_week: "בהמשך השבוע" @@ -2433,11 +2447,14 @@ he: publish: "פרסום" description: "כאשר נושא מפורסם כעמוד, ניתן לשתף את הכתובת שלו והיא תוצג בסגנון עצמאי." slug: "מזהה ייצוגי" + public: "ציבורי" + public_description: "אנשים יכולים לראות את העמוד אפילו אם הנושא המשויך הוא פרטי." publish_url: "העמוד שלך פורסם ב־:" topic_published: "הנושא שלך פורסם ב־:" preview_url: "העמוד שלך יפורסם ב־:" invalid_slug: "אין לך אפשרות לפרסם את העמוד הזה, עמך הסליחה." unpublish: "משיכת הפרסום" + update: "עדכון" unpublished: "פרסום העמוד שלך נמשך ואין זמין עוד." publishing_settings: "הגדרות פרסום" change_owner: @@ -2525,6 +2542,7 @@ he: two: "%{count} תגובות" many: "%{count} תגובות" other: "%{count} תגובות" + unknown_user: "(משתמש לא ידוע/נמחק)" has_likes_title: one: "מישהו אחד אהב את התגובה הזו" two: "%{count} אנשים אהבו את התגובה הזו" @@ -2680,7 +2698,7 @@ he: last: "מהדורה אחרונה" hide: "הסתרת שינויים" show: "הצגת שינויים" - revert: "חזרה לגרסה זו" + revert: "החזרה לגרסה %{revision}" edit_wiki: "עריכת וויקי" edit_post: "עריכת פוסט" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -3426,13 +3444,13 @@ he: more: 'חיפוש ביומנים' disabled: 'דוח מגמות חיפושים מנוטרל. יש להפעיל שאילתות חיפוש ביומן כדי לאסוף נתונים.' filters: - file-extension: + file_extension: label: סיומת קובץ group: label: קבוצה category: label: קטגוריה - include-subcategories: + include_subcategories: label: "לכלול תת־קטגוריות" commits: latest_changes: "שינויים אחרונים: בבקשה עדכן תכופות!" @@ -4136,6 +4154,9 @@ he: override_upload_secure_status: "דריסת מצב העלאה בטוח" page_published: "העמוד פורסם" page_unpublished: "פרסום העמוד נמשך" + add_email: "הוסף דוא\"ל" + update_email: "עדכן דוא\"ל" + destroy_email: "מחק דוא\"ל" screened_emails: title: "הודעות דואר מסוננות" description: "כשמישהו מנסה ליצור חשבון חדש, כתובות הדואר האלקטרוני הבאות ייבדקו וההרשמה תחסם או שיבוצו פעולות אחרות." @@ -4693,8 +4714,9 @@ he: category_id: "מזהה לקטגוריה" category_title: "קטגוריה" tag_name: "שם תגית" - external_url: "כתובת חיצונית" + external_url: "כתובת חיצונית או יחסית" destination: "יעד" + copy_to_clipboard: "העתקת קישור קבוע ללוח" delete_confirm: " להסיר את הקישור הקבוע?" form: label: "חדש:" diff --git a/config/locales/client.hu.yml b/config/locales/client.hu.yml index d7fa242236..c32e6af2f6 100644 --- a/config/locales/client.hu.yml +++ b/config/locales/client.hu.yml @@ -717,7 +717,6 @@ hu: all: "Mind" read: "Olvasás" unread: "Olvasatlan" - ignore_duration_title: "Időzítő figyelmen kívül hagyása" ignore_duration_username: "Felhasználónév" ignore_duration_when: "Időtartam:" ignore_duration_save: "Ignorál" @@ -898,6 +897,8 @@ hu: confirm: "Biztosan meg szeretnéd változtatni a felhasználónevedet?" taken: "Sajnos ez a felhasználónév már foglalt." invalid: "Ez a felhasználónév érvénytelen. Csak számokat és betűket kell tartalmaznia." + add_email: + add: "hozzáadás" change_email: title: "E-mail cím módosítása" taken: "Sajnos az e-mail cím nem érhető el." @@ -918,6 +919,8 @@ hu: title: "E-mail" primary: "Elsődleges Email" secondary: "Másodlagos Emailek" + primary_label: "Elsődleges" + update_email: "E-mail cím módosítása" no_secondary: "Nincsenek másodlagos emailek" ok: " Jóváhagyás végett e-mailt fogunk küldeni" invalid: "Kérünk adj meg egy érvényes e-mail címet" @@ -1832,6 +1835,8 @@ hu: merge_posts: title: "Kiválasztott bejegyzések összevonása" action: "kiválasztott bejegyzések összevonása" + publish_page: + public: "Nyilvános" change_owner: title: "Tulajdonosváltás" action: "tulajdonjog módosítása" diff --git a/config/locales/client.hy.yml b/config/locales/client.hy.yml index 90a58e9344..499022e046 100644 --- a/config/locales/client.hy.yml +++ b/config/locales/client.hy.yml @@ -736,7 +736,6 @@ hy: all: "Ամբողջը" read: "Կարդացած" unread: "Չկարդացած" - ignore_duration_title: "Անտեսված Օգտատեր" ignore_duration_username: "Օգտանուն" ignore_duration_when: "Տևողությունը." ignore_duration_save: "Անտեսել" @@ -957,6 +956,8 @@ hy: confirm: "Դուք միանշանակ համոզվա՞ծ եք, որ ցանկանում եք փոփոխել Ձեր օգտանունը:" taken: "Ներողություն, այդ օգտանունը զբաղված է:" invalid: "Այդ օգտանունն անվավեր է: Այն պետք է պարունակի միայն թվեր և տառեր:" + add_email: + add: "ավելացնել" change_email: title: "Փոփոխել Էլ. Հասցեն" taken: "Ներողություն, այդ էլ. հասցեն հասանելի չէ:" @@ -987,8 +988,10 @@ hy: title: "Էլ. հասցե" primary: "Հիմնական Էլ. հասցե" secondary: "Երկրորդական Էլ. հասցեներ" - no_secondary: "Երկրորդական էլ. հասցեներ չկան" + primary_label: "հիմնական" + update_email: "Փոփոխել Էլ. Հասցեն" sso_override_instructions: "Էլ. հասցեն կարող է թարմացվել SSO մատակարարից:" + no_secondary: "Երկրորդական էլ. հասցեներ չկան" instructions: "Երբեք չի ցուցադրվում հանրությանը" ok: "Հաստատման համար մենք Ձեզ կուղարկենք էլ. նամակ" invalid: "Խնդրում ենք մուտքագրել վավեր էլ. հասցե" @@ -2205,6 +2208,7 @@ hy: title: "Էջի Հրատարակում" publish: "Հրատարակել" description: "Երբ թեման հրապարակվում է որպես էջ, դրա URL- ն կարող է համընդհանուր տարածվել և պատկերվել օգտատերերի խմբագրմամբ: " + public: "Հանրային" publish_url: "Ձեր էջը հրապարակվել է այս հասցեով՝ " topic_published: "Ձեր թեման հրապարակվել է՝" preview_url: "Ձեր էջը կհրապարակվի այս հասցեով՝" @@ -2401,7 +2405,6 @@ hy: last: "Վերջին խմբագրությունը" hide: "Թաքցնել խմբագրությունը" show: "Ցուցադրել խմբագրությունը" - revert: "Վերադարձնել այս խմբագրությանը" edit_wiki: "Խմբագրել Wiki-ն" edit_post: "Խմբագրել Գրառումը" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -3080,13 +3083,13 @@ hy: more: 'Որոնման գրառումներ' disabled: 'Առաջատար որոնման հաշվետվությունն անջատված է: Միացրեք գրառումների որոնման հարցումները՝ տվյալներ հավաքելու համար:' filters: - file-extension: + file_extension: label: Ֆայլի ընդլայնում group: label: Խումբ category: label: Կատեգորիա - include-subcategories: + include_subcategories: label: "Ներառել Ենթակատեգորիաներ" commits: latest_changes: "Վերջին փոփոխությունները. խնդրում ենք ավելի հաճախ թարմացնել!" diff --git a/config/locales/client.id.yml b/config/locales/client.id.yml index 6daee6f6ff..1b6e4b3943 100644 --- a/config/locales/client.id.yml +++ b/config/locales/client.id.yml @@ -669,7 +669,6 @@ id: all: "Semua" read: "Dibaca" unread: "Belum dibaca" - ignore_duration_title: "Abaikan Timer" ignore_duration_username: "Nama Pengguna" ignore_duration_when: "Durasi:" ignore_duration_save: "Abaikan" @@ -844,6 +843,7 @@ id: title: "Surel" primary: "Email Utama" secondary: "Email Sekunder" + update_email: "Ganti Alamat Surel" no_secondary: "Tidak ada email sekunder" instructions: "Jangan pernah tunjukkan ke publik." ok: "Kami akan mengirimkan surel kepada anda untuk konfirmasi" @@ -1392,6 +1392,8 @@ id: error: "Ada kesalahan dalam memindahkan posting sebagai topik baru" move_to_new_message: radio_label: "Pesan Baru" + publish_page: + public: "Umum" change_owner: placeholder: "username pemilik yang baru" post: diff --git a/config/locales/client.it.yml b/config/locales/client.it.yml index 46e2fe4619..3f1cf97050 100644 --- a/config/locales/client.it.yml +++ b/config/locales/client.it.yml @@ -451,6 +451,7 @@ it: category: "Categoria" orders: score: "Punteggio" + score_asc: "Punteggio (inverso)" created_at: "Creato il" created_at_asc: "Data creazione (inversa)" priority: @@ -769,7 +770,6 @@ it: all: "Tutti" read: "Letti" unread: "Non letti" - ignore_duration_title: "Ignora Timer" ignore_duration_username: "Nome utente" ignore_duration_when: "Durata:" ignore_duration_save: "Ignora" @@ -875,7 +875,9 @@ it: admin_delete: "Cancella" users: "Utenti" muted_users: "Silenziati" + muted_users_instructions: "Elimina tutte le notifiche e i PM da questi utenti." ignored_users: "Ignorato" + ignored_users_instructions: "Elimina tutti i post, le notifiche e i PM da questi utenti." tracked_topics_link: "Mostra" automatically_unpin_topics: "Spunta automaticamente gli argomenti quando arrivi in fondo." apps: "Applicazioni" @@ -993,6 +995,9 @@ it: confirm: "Sei sicuro di voler davvero cambiare il tuo nome utente?" taken: "Spiacenti, questo nome utente è già riservato." invalid: "Nome utente non valido: usa solo lettere e cifre" + add_email: + title: "Aggiungi email" + add: "aggiungi" change_email: title: "Cambia email" taken: "Spiacenti, questa email non è disponibile." @@ -1023,8 +1028,17 @@ it: title: "Email" primary: "Email principale" secondary: "Email secondaria" - no_secondary: "Nessuna email secondaria" + primary_label: "primario" + unconfirmed_label: "non confermata" + resend_label: "Reinvia email di conferma" + resending_label: "invio in corso..." + resent_label: "email inviata" + update_email: "Cambia email" + set_primary: "Imposta email principale" + destroy: "Rimuovi email" + add_email: "Aggiungi email alternativa" sso_override_instructions: "L'email può essere aggiornata dal provider SSO." + no_secondary: "Nessuna email secondaria" instructions: "Mai mostrato pubblicamente" ok: "Ti invieremo una email di conferma" required: "Inserisci un indirizzo email" @@ -1177,6 +1191,7 @@ it: expired: "L'invito è scaduto." rescind: "Rimuovi" rescinded: "Invito revocato" + rescind_all: "Rimuovi inviti scaduti" rescinded_all: "Tutti gli inviti scaduti sono stati rimossi!" rescind_all_confirm: "Sei sicuro di voler rimuovere tutti gli inviti scaduti?" reinvite: "Rinvia Invito" @@ -1187,18 +1202,30 @@ it: time_read: "Ora di Lettura" days_visited: "Giorni Frequenza" account_age_days: "Età dell'utente in giorni" + source: "Invitato via" links_tab: "Collegamenti" + links_tab_with_count: "Link (%{count})" + link_url: "Link" link_created_at: "Creazione" + link_redemption_stats: "Redemptions" link_groups: Gruppi + link_expires_at: Scadenza create: "Invia Invito" + copy_link: "Copia link" generate_link: "Copia il collegamento di invito" link_generated: "Collegamento di invito generato con successo!" valid_for: "Questo collegamento di invito è valido solamente per il seguente indirizzo email: %{email}" single_user: "Utente Singolo" + multiple_user: "Utenti multipli" invite_link: + title: "Link di invito" success: "Collegamento di invito generato con successo!" + error: "Si è verificato un errore durante la generazione del link di invito" + max_redemptions_allowed_label: "Quante persone sono autorizzate a registrarsi utilizzando questo link?" + expires_at: "Quando scadrà questo link di invito?" bulk_invite: none: "Non hai ancora invitato nessuno. Puoi inviare degli inviti individuali o più persone alla volta caricando un file CSV." + text: "Inviti di gruppo" success: "Il file è stato caricato con successo, riceverai un messaggio di notifica quando il processo sarà completato." error: "Spiacenti, il file deve essere in formato CSV." confirmation_message: "Stai per inviare un invito via email a tutti gli indirizzi inclusi nel file caricato." @@ -1316,11 +1343,6 @@ it: Cominciamo la discussione! {currentTopics, plural, one {C'è # argomento} other {Ci sono# argomenti}}. I visitatori hanno bisogno di più per leggere e rispondere: – consigliamo almeno {requiredTopics, plural, one {# argomento} other {# argomenti}}. Solo lo staff può vedere questo messaggio. too_few_posts_notice_MF: >- Cominciamo la discussione! {currentPosts, plural, one {C'è # messaggio} other {Ci sono # messaggi}}. I visitatori hanno bisogno di più per leggere e rispondere: – consigliamo almeno {requiredPosts, plural, one {# messaggio} other {# messaggi}}. Solo lo staff può vedere questo messaggio. - logs_error_rate_notice: - reached_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} altro {# errors/hour}} il limite impostato di {limit, plural, one {# error/hour} altro {# errors/hour}}." - reached_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} altro {# errors/minute}} raggiunto il limite impostato di {limit, plural, one {# error/minute} altro {# errors/minute}}." - exceeded_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} altro {# errors/hour}} superato il limite impostato di {limit, plural, one {# error/hour} altro {# errors/hour}}." - exceeded_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} altro {# errors/minute}} superato il limite impostato di {limit, plural, one {# error/minute} other {# errors/minute}}." learn_more: "per saperne di più..." all_time: "totale" all_time_desc: "totale argomenti creati" @@ -2261,6 +2283,7 @@ it: publish: "Pubblica" description: "Quando un argomento viene pubblicato come pagina, l'URL può essere condiviso e verrà visualizzato con uno stile personalizzato." slug: "Abbreviazione" + public: "Pubblico" publish_url: "La tua pagina è stata pubblicata su:" topic_published: "Il tuo argomento è stato pubblicato su:" preview_url: "La tua pagina sarà pubblicata su:" @@ -2472,7 +2495,6 @@ it: last: "Ultima revisione" hide: "Nascondi revisione" show: "Mostra revisione" - revert: "Ritorna a questa revisione" edit_wiki: "Modifica Wiki" edit_post: "Modifica Messaggio" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -2580,6 +2602,7 @@ it: sort_order: "Lista Argomenti Ordinata Per:" default_view: "Lista Argomenti Predefinita:" default_top_period: "Periodo Predefinito Argomenti Di Punta:" + default_list_filter: "Filtro predefinito della lista:" allow_badges_label: "Permetti l'assegnazione di distintivi in questa categoria" edit_permissions: "Modifica Permessi" reviewable_by_group: "Oltre che dallo staff, i messaggi e le segnalazioni in questa categoria possono essere revisionati da:" @@ -2642,6 +2665,9 @@ it: moderation: "Moderazione" appearance: "Aspetto" email: "Email" + list_filters: + all: "tutti gli argomenti" + none: "nessuna sottocategoria" flagging: title: "Grazie per aiutarci a mantenere la nostra comunità civile!" action: "Segnala Messaggio" @@ -3156,13 +3182,13 @@ it: more: 'Cerca nei log' disabled: 'Il rapporto sulle ricerche di tendenza è disabilitato. Attiva l''opzione log search queries per iniziare a raccogliere i dati.' filters: - file-extension: + file_extension: label: Estensione file group: label: Gruppo category: label: Categoria - include-subcategories: + include_subcategories: label: "Includi Sottocategorie" commits: latest_changes: "Ultime modifiche: per favore aggiorna spesso!" @@ -3860,6 +3886,9 @@ it: override_upload_secure_status: "sovrascrivere stato caricamento sicuro" page_published: "pagina pubblicata" page_unpublished: "pagina non pubblicata" + add_email: "aggiungi email" + update_email: "aggiorna email" + destroy_email: "distruggi 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." @@ -4276,6 +4305,8 @@ it: modal_description: "Desideri applicare questa modifica storicamente? Questo cambierà le preferenze per %{count} utenti esistenti." modal_yes: "Sì" modal_no: "No, applica le modifiche solo da adesso in avanti" + simple_list: + add_item: "Aggiungi elemento..." badges: title: Distintivi new_badge: Nuovo Distintivo @@ -4402,6 +4433,7 @@ it: post_title: "Messaggio" category_id: "ID della categoria" category_title: "Categoria" + tag_name: "Nome etichetta" external_url: "URL esterna" destination: "Destinazione" delete_confirm: "Sei sicuro di voler cancellare questo collegamento permanente?" diff --git a/config/locales/client.ja.yml b/config/locales/client.ja.yml index b4c366f65b..fd9bf678da 100644 --- a/config/locales/client.ja.yml +++ b/config/locales/client.ja.yml @@ -815,6 +815,8 @@ ja: confirm: "ユーザー名を変更してもよろしいですか?" taken: "このユーザー名は既に使われています。" invalid: "このユーザー名は無効です。英数字のみ利用可能です。" + add_email: + add: "追加" change_email: title: "メールアドレスを変更" taken: "このメールアドレスは既に使われています。" @@ -835,6 +837,8 @@ ja: title: "メールアドレス" primary: "主要なメールアドレス" secondary: "その他のメールアドレス" + primary_label: "プライマリー" + update_email: "メールアドレスを変更" no_secondary: "その他のメールアドレスはありません" instructions: "他人に公開はされません" ok: "確認用メールを送信します" @@ -1818,6 +1822,8 @@ ja: title: "選択した投稿を統合" action: "選択した投稿を統合" error: "選択した投稿の統合に失敗しました。" + publish_page: + public: "公開" change_owner: action: "オーナーシップを変更" error: "オーナーの変更ができませんでした。" @@ -1947,7 +1953,6 @@ ja: last: "最後のリビジョン" hide: "リビジョンを隠す" show: "リビジョンを表示" - revert: "このリビジョンに戻す" edit_wiki: "Wikiを編集" edit_post: "投稿を編集" displays: diff --git a/config/locales/client.ko.yml b/config/locales/client.ko.yml index aead8849b5..8231c3e0e2 100644 --- a/config/locales/client.ko.yml +++ b/config/locales/client.ko.yml @@ -709,7 +709,6 @@ ko: all: "모두" read: "읽기" unread: "읽지 않은 글" - ignore_duration_title: "타이머 무시" ignore_duration_username: "아이디" ignore_duration_when: "지속:" ignore_duration_save: "무시" @@ -923,6 +922,8 @@ ko: confirm: "정말로 아이디를 변경 하시겠습니까?" taken: "죄송합니다. 이미 사용 중인 아이디입니다." invalid: "아이디가 잘못되었습니다. 숫자와 문자를 포함해야합니다." + add_email: + add: "추가" change_email: title: "이메일 변경" taken: "죄송합니다. 해당 이메일은 사용 할 수 없습니다." @@ -953,8 +954,9 @@ ko: title: "이메일" primary: "기본 이메일" secondary: "보조 이메일" + primary_label: "주요" + update_email: "이메일 변경" no_secondary: "보조 이메일이 없습니다" - sso_override_instructions: "SSO 제공자로부터 이메일을 업데이트 할 수 있습니다." instructions: "절대로 공개되지 않습니다." ok: "내 이메일로 확인 메일이 전송됩니다." invalid: "유효한 이메일 주소를 입력해주세요." @@ -1225,17 +1227,10 @@ ko: enabled: "이 사이트는 현재 읽기전용 모드입니다. 브라우징은 가능하지만, 댓글달기, 좋아요 등 다른 행위들은 현재 비활성화 되어있습니다." login_disabled: "사이트가 읽기 전용모드로 되면서 로그인은 비활성화되었습니다." logout_disabled: "사이트가 읽기 전용모드일 때 로그아웃은 비활성화됩니다." - too_few_topics_and_posts_notice_MF: >- - 토론을 시작 합시다 ! 이 {currentTopics, plural, one {# 주제} other은 {입니다 # 주제}}과 {currentPosts, plural, one {# 포스트} other {# 포스트}}. 방문객들은 읽고 댓글을 올리려면 더 필요 - 우리는 적어도 {requiredTopics, plural, one {# 주제} other {# 주제}}과 {requiredPosts, plural, one {# 포스트} other {# 게시물}} 좋습니다. 직원 만이 메시지를 볼 수 있습니다. too_few_topics_notice_MF: >- 토론을 시작 합시다 ! {currentTopics, plural, one {is # topic} other {are # topics}}가 있습니다. 방문자는 더 읽고 답장해야합니다. 적어도 {requiredTopics, plural, one { # topic} other { # topics}}을 (를) 권장합니다. 직원 만이 메시지를 볼 수 있습니다. too_few_posts_notice_MF: >- 토론을 시작 합시다 ! {currentPosts, plural, one {is # post} other {are # posts}}가 있습니다. 방문자는 더 읽고 답장해야합니다. – {requiredPosts, plural, one { # post} other { # posts}} 이상을 권장합니다. 직원 만이 메시지를 볼 수 있습니다. - logs_error_rate_notice: - reached_hour_MF: "{relativeAge}{rate, plural, one {# error / hour} other {# errors / hour}}의 사이트 설정 한계 {a0cd0dadb4f0b0b0f0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0d0" - reached_minute_MF: "{relativeAge}{rate, plural, one {# error / minute} other {# errors / minute}}의 사이트 설정 한계 {a0cd0d0b0f0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b2" - exceeded_hour_MF: "{relativeAge}{rate, plural, one {# 오류 / 시간}}" - exceeded_minute_MF: "{relativeAge} - {a07e6f5c6cb6z485z0, plural, one {# 오류 / 분}} {0/0 {0/0} {0} {0} {0} {0} {0} {0} {0} {0} {0} {0} 0 {0}" learn_more: "더 배우기" all_time: "총" all_time_desc: "총 토픽" @@ -2134,6 +2129,7 @@ ko: publish: "게시" description: "주제가 페이지로 게시되면 해당 URL을 공유 할 수 있으며 사용자 정의 스타일과 함께 표시됩니다." slug: "강타" + public: "공개" publish_url: "귀하의 페이지는 다음 위치에 게시되었습니다." topic_published: "귀하의 주제는 다음 위치에 게시되었습니다." preview_url: "귀하의 페이지는 다음 위치에 게시됩니다." @@ -2307,7 +2303,6 @@ ko: last: "최신판" hide: "편집 기록 가리기" show: "편집 기록 보기" - revert: "이 수정본으로 되돌리기" edit_wiki: "Wiki 편집" edit_post: "포스트 편집" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -2951,14 +2946,10 @@ ko: more: '검색 로그' disabled: '인기 검색 보고서가 비활성화되었습니다. 로그 검색 쿼리 를 사용하여 데이터를 수집하십시오.' filters: - file-extension: - label: 파일 확장자 group: label: 그룹 category: label: 카테고리 - include-subcategories: - label: "하위 카테고리 포함" commits: latest_changes: "최근 변경 사항: 자주 업데이트하십시오!" by: "에 의해" diff --git a/config/locales/client.lt.yml b/config/locales/client.lt.yml index 52ad59f808..b5137cc15c 100644 --- a/config/locales/client.lt.yml +++ b/config/locales/client.lt.yml @@ -756,6 +756,8 @@ lt: title: "Keisti vartotojo vardą" taken: "Atsiprašome, šis vartotojo vardas užimtas." invalid: "Šis vartotojo vardas yra neteisingas. Jame turi būti tik skaičiai ir raidės" + add_email: + add: "pridėti" change_email: title: "Keisti el. paštą" taken: "Atsiprašome, šis el. paštas negalimas." @@ -775,6 +777,8 @@ lt: title: "El. paštas" primary: "Pagrindinis el. Paštas" secondary: "Antriniai el. Paštai" + primary_label: "pirminė" + update_email: "Keisti el. paštą" no_secondary: "Antrinių el. Paštų nėra" instructions: "Nebus rodomas viešai." ok: "Mes jums atsiųsime patvirtinimo elektroninį laišką" @@ -1709,6 +1713,8 @@ lt: merge_posts: title: "Sulieti pasirinktus įrašus" action: "sulieti pasirinktus įrašus" + publish_page: + public: "Vieša" change_owner: action: "pakeisti valdymo teises" error: "Įvyko klaida keičiant įrašų valdymo teisę." diff --git a/config/locales/client.lv.yml b/config/locales/client.lv.yml index b23f8da4e2..a2c2f03318 100644 --- a/config/locales/client.lv.yml +++ b/config/locales/client.lv.yml @@ -679,6 +679,8 @@ lv: title: "Mainīt lietotājvārdu" taken: "Atvainojiet, šis lietotājvārds ir aizņemts." invalid: "Šis lietotājvārds ir nederīgs. Izmantojiet tikai ciparus un burtus" + add_email: + add: "Pievienot" change_email: title: "Mainīt e-pastu" taken: "Atvainojiet, šis e-pasts nav pieejams." @@ -696,6 +698,7 @@ lv: instructions: "Fona attēli būs centrēti un ar noklusējuma platumu 590px." email: title: "E-pasts" + update_email: "Mainīt e-pastu" ok: "Mēs jums nosūtīsim apstiprinājuma e-pastu" invalid: "Lūdzu ievadiet derīgu e-pasta adresi" authenticated: "Jūsu e-pastu autentificēja %{provider}" @@ -1609,6 +1612,8 @@ lv: title: "Apvienot izvēlētos ierakstus" action: "apvienot izvēlētos ierakstus" error: "Apvienojot izvēlētos ierakstus, notika kļūda." + publish_page: + public: "Publisks" change_owner: action: "nomainīt īpašnieku" error: "Mainot ierakstu īpašnieku, notika kļūda." @@ -1754,7 +1759,6 @@ lv: last: "Pēdējā versija" hide: "Paslēpt versiju" show: "Parādīt versiju" - revert: "Atgriezties pie šīs versijas" edit_wiki: "Rediģēt wiki" edit_post: "Rediģēt ierakstu" displays: diff --git a/config/locales/client.nb_NO.yml b/config/locales/client.nb_NO.yml index 0a00bb7bb0..3d08b7031f 100644 --- a/config/locales/client.nb_NO.yml +++ b/config/locales/client.nb_NO.yml @@ -808,6 +808,8 @@ nb_NO: confirm: "Er du helt sikker på at du ønsker å endre brukernavnet ditt?" taken: "Beklager, det brukernavnet er tatt." invalid: "Det brukernavnet er ugyldig. Det kan bare inneholde nummer og bokstaver." + add_email: + add: "legg til" change_email: title: "Endre e-postadresse" taken: "Beklager, den e-postadressen er ikke tilgjengelig." @@ -828,6 +830,8 @@ nb_NO: title: "E-post" primary: "Primær e-post" secondary: "Sekundære e-poster" + primary_label: "primær" + update_email: "Endre e-postadresse" no_secondary: "Ingen sekundære e-poster" instructions: "Vises aldri offentlig" ok: "Vi sender deg en e-post for å bekrefte" @@ -1868,6 +1872,8 @@ nb_NO: title: "Slå sammen valgte innlegg" action: "slå sammen valgte innlegg" error: "Feil ved fletting av valgte innlegg." + publish_page: + public: "Offentlig" change_owner: action: "Endre eierskap" error: "Det oppstod en feil ved endring av eierskap til innleggene." @@ -2037,7 +2043,6 @@ nb_NO: last: "Siste versjon" hide: "Skjul versjon" show: "Vis versjon" - revert: "Gå tilbake til denne versjonen" edit_wiki: "Rediger wiki" edit_post: "Rediger innlegg" displays: diff --git a/config/locales/client.nl.yml b/config/locales/client.nl.yml index 14615a4794..5f97971659 100644 --- a/config/locales/client.nl.yml +++ b/config/locales/client.nl.yml @@ -770,7 +770,7 @@ nl: all: "Alle" read: "Gelezen" unread: "Ongelezen" - ignore_duration_title: "Negeertimer" + ignore_duration_title: "Gebruiker negeren" ignore_duration_username: "Gebruikersnaam" ignore_duration_when: "Tijdsduur:" ignore_duration_save: "Negeren" @@ -996,6 +996,9 @@ nl: confirm: "Weet u absoluut zeker dat u uw gebruikersnaam wilt wijzigen?" taken: "Sorry, maar die gebruikersnaam is al in gebruik." invalid: "Die gebruikersnaam is ongeldig. Hij mag alleen cijfers en letters bevatten." + add_email: + title: "E-mailadres toevoegen" + add: "toevoegen" change_email: title: "E-mailadres wijzigen" taken: "Sorry, dat e-mailadres is niet beschikbaar." @@ -1026,8 +1029,17 @@ nl: title: "E-mail" primary: "Primair e-mailadres" secondary: "Extra e-mailadressen" - no_secondary: "Geen extra e-mailadressen" + primary_label: "primaire" + unconfirmed_label: "onbevestigd" + resend_label: "bevestigingsmail opnieuw verzenden" + resending_label: "verzenden..." + resent_label: "e-mail verzonden" + update_email: "E-mailadres wijzigen" + set_primary: "Primair e-mailadres instellen" + destroy: "E-mailadres verwijderen" + add_email: "Alternatief e-mailadres toevoegen" sso_override_instructions: "E-mailadres kan vanaf SSO-provider worden bijgewerkt." + no_secondary: "Geen extra e-mailadressen" instructions: "Nooit openbaar zichtbaar." ok: "We sturen een e-mail ter bevestiging" required: "Voer een e-mailadres in" @@ -2016,6 +2028,7 @@ nl: time_frame_required: Selecteer een tijdsbestek auto_update_input: none: "Selecteer een tijdsbestek" + now: "Nu" later_today: "Later vandaag" tomorrow: "Morgen" later_this_week: "Later deze week" @@ -2277,11 +2290,14 @@ nl: publish: "Publiceren" description: "Wanneer een topic als een pagina wordt gepubliceerd, kan de URL ervan worden gedeeld en wordt deze met aangepaste stijlen weergegeven." slug: "Slug" + public: "Openbaar" + public_description: "Mensen kunnen de pagina ook zien als het gekoppelde topic privé is." publish_url: "Uw pagina is gepubliceerd op:" topic_published: "Uw topic is gepubliceerd op:" preview_url: "Uw pagina wordt gepubliceerd op:" invalid_slug: "Sorry, u kunt deze pagina niet publiceren." unpublish: "Publicatie ongedaan maken" + update: "Bijwerken" unpublished: "Uw pagina is niet meer gepubliceerd en niet meer toegankelijk." publishing_settings: "Publicatie-instellingen" change_owner: @@ -2355,6 +2371,7 @@ nl: has_replies: one: "%{count} antwoord" other: "%{count} antwoorden" + unknown_user: "(onbekende/verwijderde gebruiker)" has_likes_title: one: "%{count} persoon heeft dit bericht geliket" other: "%{count} personen hebben dit bericht geliket" @@ -2488,7 +2505,7 @@ nl: last: "Laatste revisie" hide: "Revisie verbergen" show: "Revisie tonen" - revert: "Terugkeren naar deze revisie" + revert: "Terugkeren naar revisie %{revision}" edit_wiki: "Wiki bewerken" edit_post: "Bericht bewerken" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -3180,13 +3197,13 @@ nl: more: 'Zoeklogboeken' disabled: 'Rapport voor populaire zoekopdrachten is uitgeschakeld. Schakel zoekopdrachten registreren in om gegevens te verzamelen.' filters: - file-extension: + file_extension: label: Bestandsextensie group: label: Groep category: label: Categorie - include-subcategories: + include_subcategories: label: "Subcategorieën bijvoegen" commits: latest_changes: "Laatste wijzigingen: werk regelmatig bij!" @@ -3544,7 +3561,7 @@ nl: and_x_more: "en nog %{count}." collapse: Samenvouwen uploads: "Uploads" - no_uploads: "U kunt aan uw thema gerelateerde assets uploaden zoals fonts en afbeeldingen" + no_uploads: "U kunt aan uw thema gerelateerde assets uploaden, zoals lettertypen en afbeeldingen" add_upload: "Upload toevoegen" upload_file_tip: "Kies een asset om te uploaden (png, woff2, etc...)" variable_name: "SCSS-variabelenaam:" @@ -3884,6 +3901,9 @@ nl: override_upload_secure_status: "status beveiligd uploaden negeren" page_published: "pagina gepubliceerd" page_unpublished: "pagina niet gepubliceerd" + add_email: "e-mailadres toevoegen" + update_email: "e-mailadres bijwerken" + destroy_email: "e-mailadres verwijderen" screened_emails: title: "Gecontroleerde e-mails" description: "Als iemand een nieuwe account probeert aan te maken, worden de volgende e-mailadressen gecontroleerd en de registratie geblokkeerd, of een andere actie uitgevoerd." @@ -4429,8 +4449,9 @@ nl: category_id: "Categorie-ID" category_title: "Categorie" tag_name: "Tagnaam" - external_url: "Externe URL" + external_url: "Externe of relatieve URL" destination: "Bestemming" + copy_to_clipboard: "Permalink naar klembord kopiëren" delete_confirm: "Weet u zeker dat u deze permalink wilt verwijderen?" form: label: "Nieuw:" diff --git a/config/locales/client.pl_PL.yml b/config/locales/client.pl_PL.yml index 8334b8cefe..8df96c03bf 100644 --- a/config/locales/client.pl_PL.yml +++ b/config/locales/client.pl_PL.yml @@ -829,7 +829,6 @@ pl_PL: all: "Wszystkie" read: "Przeczytane" unread: "Nieprzeczytane" - ignore_duration_title: "Ignoruj licznik" ignore_duration_username: "Nazwa użytkownika" ignore_duration_when: "Oczekiwanie" ignore_duration_save: "Ignoruj" @@ -1043,6 +1042,8 @@ pl_PL: confirm: "Czy jesteś absolutnie pewien że chcesz zmienić swoją nazwę użytkownika?" taken: "Przykro nam, ale ta nazwa jest zajęta." invalid: "Ta nazwa jest niepoprawna. Powinna zawierać jedynie liczby i litery." + add_email: + add: "dodaj" change_email: title: "Zmień adres email" taken: "Przykro nam, ale ten adres email nie jest dostępny." @@ -1073,8 +1074,10 @@ pl_PL: title: "Email" primary: "Podstawowy adres email" secondary: "Drugorzędne adresy email" - no_secondary: "Brak drugorzędnych adresów email" + primary_label: "podstawowy" + update_email: "Zmień adres email" sso_override_instructions: "E-mail można zaktualizować od dostawcy SSO." + no_secondary: "Brak drugorzędnych adresów email" instructions: "Nie będzie publicznie widoczny." ok: "Otrzymasz potwierdzenie emailem" invalid: "Podaj poprawny adres email" @@ -1376,17 +1379,6 @@ pl_PL: enabled: "Strona jest w trybie tylko-do-odczytu. Możesz nadal przeglądać serwis, ale operacje takie jak postowanie, lajkowanie i inne są wyłączone." login_disabled: "Logowanie jest zablokowane, gdy strona jest w trybie tylko do odczytu." logout_disabled: "Wylogowanie jest zablokowane gdy strona jest w trybie tylko do odczytu." - too_few_topics_and_posts_notice_MF: >- - Rozpocznijmy dyskusję! Jest {currentTopics, liczba mnoga, jeden {jest # tematem} inny {are # topics}} i {currentPosts, liczba mnoga, jeden { # post} inne { # posty}}. Odwiedzający potrzebują więcej do przeczytania i odpowiedzi - zalecamy co najmniej {wymaganeTopiki, liczba mnoga, jeden { # temat} inne { # tematy}} i {wymaganePosty, liczba mnoga, jeden { # post} inne { # posty}}. Tylko pracownicy mogą zobaczyć tę wiadomość. - too_few_topics_notice_MF: >- - Rozpocznijmy dyskusję! Jest {currentTopics, liczba mnoga, jeden {is # topic} other {are # topics}}. Odwiedzający potrzebują więcej do przeczytania i udzielenia odpowiedzi - zalecamy co najmniej {wymaganeTopiki, liczba mnoga, jeden { # temat} inny { # tematy}}. Tylko pracownicy mogą zobaczyć tę wiadomość. - too_few_posts_notice_MF: >- - Rozpocznijmy dyskusję! Jest {currentPosts, liczba mnoga, jeden {is # post} other {are # posts}}. Odwiedzający potrzebują więcej do przeczytania i odpowiedzi - zalecamy co najmniej {wymaganePosty, liczba mnoga, jeden { # post} inny { # posty}}. Tylko pracownicy mogą zobaczyć tę wiadomość. - logs_error_rate_notice: - reached_hour_MF: "{relativeAge} - {stopa, liczba mnoga, jeden {# błąd / godzina} inne {# błędy / godzina}} osiągnęła limit ustawienia witryny w wysokości {limit, liczba mnoga, jeden {# błąd / godzina} inne {# błędy / godzina}}." - reached_minute_MF: "{relativeAge} - {stopa, liczba mnoga, jeden {# błąd / minuta} inna {# błędy / minuta}} osiągnęła limit ustawienia witryny w wysokości {limit, liczba mnoga, jeden {# błąd / minuta} inne {# błędy / minuta}}." - exceeded_hour_MF: "{relativeAge} - {stopa, liczba mnoga, jeden {# błąd / godzina} inny {# błędy / godzina}} przekroczył limit ustawienia witryny o {limit, liczba mnoga, jeden {# błąd / godzina} inne {# błędy / godzina}}." - exceeded_minute_MF: "{relativeAge} - {stopa, liczba mnoga, jeden {# błąd / minuta} inna {# błędy / minuta}} przekroczyła limit ustawienia witryny o {limit, liczba mnoga, jeden {# błąd / minuta} inne {# błędy / minuta}}." learn_more: "dowiedz się więcej…" all_time: "łącznie" all_time_desc: "łącznie utworzonych tematów" @@ -2361,6 +2353,8 @@ pl_PL: title: "Scal wybrane posty" action: "scal wybrane posty" error: "Wystąpił błąd podczas łączenia wybranych postów" + publish_page: + public: "Publiczna" change_owner: title: "Zmiana właściciela" action: "zmień właściciela" @@ -2563,7 +2557,6 @@ pl_PL: last: "Ostatnia wersja" hide: "Ukryj tę wersję" show: "Pokaż tę wersję" - revert: "Przywróć do tej wersji" edit_wiki: "Edytuj Wiki" edit_post: "Edytuj wpis" displays: @@ -2782,12 +2775,6 @@ pl_PL: help: "Temat jest niewidoczny: nie będzie wyświetlany na listach tematów a dostęp do niego można uzyskać jedynie poprzez link bezpośredni" posts: "Wpisy" posts_long: "jest %{number} wpisów w tym temacie" - posts_likes_MF: | - Ten temat ma {count, plural, one {1 reply} other {# replies}} {ratio, select - low{odpowiedzi z dużą ilością lajk'ów w poście} - med{odpowiedzi z bardzo dużą ilością lajk'ów w poście} - high{odpowiedzi z ekstremalnie dużą ilością lajk'ów w poście} - other{}} original_post: "Oryginalny wpis" views: "Odsłony" views_lowercase: @@ -3204,7 +3191,7 @@ pl_PL: trending_search: more: 'Logi wyszukiwania' filters: - file-extension: + file_extension: label: Rozszerzenie pliku group: label: Grupa diff --git a/config/locales/client.pt.yml b/config/locales/client.pt.yml index ed641a74af..c8bc0b9fc2 100644 --- a/config/locales/client.pt.yml +++ b/config/locales/client.pt.yml @@ -776,6 +776,8 @@ pt: confirm: "Tem a certeza absoluta que pretende alterar o seu nome de utilizador?" taken: "Pedimos desculpa, esse nome de utilizador já está a ser utilizado." invalid: "Esse nome de utilizador é inválido. Deve conter apenas números e letras." + add_email: + add: "adicionar" change_email: title: "Alterar Email" taken: "Pedimos desculpa, esse email não está disponível." @@ -796,6 +798,8 @@ pt: title: "Email" primary: "Email Principal" secondary: "Emails Secundários" + primary_label: "primária" + update_email: "Alterar Email" no_secondary: "Não existem emails secundários" ok: "Enviar-lhe-emos um email para confirmar" invalid: "Por favor introduza um endereço de email válido" @@ -1874,8 +1878,8 @@ pt: radio_label: "Novo Tópico" error: "Ocorreu um erro ao mover as publicações para um novo tópico." instructions: - one: "Está prestes a criar um novo tópico e populá-lo com a publicação que selecionou." - other: "Está prestes a criar um novo tópico e populá-lo com as %{count} publicações que selecionou." + one: "Está prestes a criar um novo tópico e a incorporar a publicação que selecionou." + other: "Está prestes a criar um novo tópico e a incorporar %{count}publicações que selecionou." merge_topic: title: "Mover para Tópico Existente" action: "mover para tópico existente" @@ -1898,7 +1902,9 @@ pt: merge_posts: title: "Juntar Publicações Selecionadas" action: "juntar publicações selecionadas" - error: "Ocorreu um erro ao juntar os tópicos selecionados." + error: "Ocorreu um erro ao juntar as publicações selecionadas." + publish_page: + public: "Público" change_owner: action: "mudar titularidade" error: "Ocorreu um erro na mudança de dono das publicações." @@ -1929,7 +1935,7 @@ pt: quote_reply: "Citar" edit_reason: "Motivo:" post_number: "publicação %{number}" - last_edited_on: "publicação editada pela última vez em" + last_edited_on: "última edição da publicação em" reply_as_new_topic: "Responder com novo Tópico" continue_discussion: "Continuar a discussão de %{postLink}:" follow_quote: "ir para a publicação citada" @@ -1953,8 +1959,8 @@ pt: one: "você e %{count} outra pessoa gostaram desta publicação" other: "você e %{count} outras pessoas gostaram desta publicação" errors: - create: "Pedimos desculpa, ocorreu um erro ao criar a sua publicação. Por favor, tente novamente." - edit: "Pedimos desculpa, ocorreu um erro ao editar a sua publicação. Por favor, tente novamente." + create: "Desculpe, ocorreu um erro ao criar a sua publicação. Por favor, tente novamente." + edit: "Desculpe, ocorreu um erro ao editar a sua publicação. Por favor, tente novamente." upload: "Pedimos desculpa, ocorreu um erro ao carregar esse ficheiro. Por favor, tente novamente." too_many_uploads: "Pedimos desculpa, só pode carregar um ficheiro de cada vez." upload_not_authorized: "Pedimos desculpa, o ficheiro que está a tentar carregar não está autorizado (extensões autorizadas: %{authorized_extensions})." @@ -1967,7 +1973,7 @@ pt: confirm: "Tem a certeza que deseja abandonar a sua publicação?" no_value: "Não, manter" yes_value: "Sim, abandonar" - via_email: "esta publicação chegou por email" + via_email: "esta publicação chegou por ''e-mail''" via_auto_generated_email: "esta publicação chegou via um email gerado automaticamente" whisper: "esta publicação é um susurro privado para os moderadores" wiki: @@ -1977,7 +1983,7 @@ pt: few_likes_left: "Obrigado por partilhar o amor! Restam-lhe apenas um gostos para hoje." controls: reply: "começar a compor uma resposta a este tópico" - like: "gostar deste tópico" + like: "gostar desta publicação" has_liked: "gostou desta publicação" undo_like: "desfazer gosto" edit: "editar esta publicação" @@ -2031,7 +2037,6 @@ pt: last: "Última revisão" hide: "Esconder revisão" show: "Mostrar revisão" - revert: "Reverter para esta revisão" edit_wiki: "Editar Wiki" edit_post: "Editar Publicação" displays: @@ -2145,7 +2150,7 @@ pt: notify_action: "Mensagem" official_warning: "Aviso Oficial" delete_spammer: "Eliminar Spammer" - delete_confirm_MF: "Está prestes a eliminar {POSTS, plural, one {1 publicação} outras {# publicações}} e {TOPICS, plural, one {1 tópico} outros {# tópicos}} deste utilizador, remover a conta do mesmo, bloquear registos a partir do endereço de IP {ip_address} correspondente, e adicionar o endereço de e-mail {email} dos mesmos a uma lista negra permanente. Tem a certeza que este utilizador é de facto um spammer?" + delete_confirm_MF: "Está prestes a eliminar {POSTS, plural, one {1 publicação} other {# publicações}} e {TOPICS, plural, one {1 tópico} other {# tópicos}} deste utilizador, remover a conta do mesmo, bloquear registos a partir do endereço de IP {ip_address} correspondente, e adicionar o endereço de e-mail {email} dos mesmos a uma lista negra permanente. Tem a certeza que este utilizador é de facto um spammer?" yes_delete_spammer: "Sim, Eliminar Spammer" ip_address_missing: "(N/A)" hidden_email_address: "(escondido)" @@ -2951,7 +2956,7 @@ pt: allow: "Permitir" screened_urls: title: "URLs Filtrados" - description: "Os URLs listados aqui foram usados em publicações de utilizadores que foram identificados como spammers." + description: "Os URLs listados aqui foram utilizados nas publicações dos utilizadores que foram identificados como ''spammers''." url: "URL" domain: "Domínio" screened_ips: @@ -3088,7 +3093,7 @@ pt: one: "Não é possível eliminar todas as publicações. Algumas publicações existem há mais de %{count} dia. (A configuração delete_user_max_post_age.)" other: "Não é possível eliminar todas as publicações. Algumas publicações existem há mais de %{count} dias. (A configuração delete_user_max_post_age.)" cant_delete_all_too_many_posts: - one: "Não é possível eliminar todas as publicações porque o utilizador tem mais de %{count} publicações. (delete_all_posts_max)" + one: "Não é possível eliminar todas as publicações porque o utilizador tem mais de %{count} publicação. (delete_all_posts_max)" other: "Não é possível eliminar todas as publicações porque o utilizador tem mais de %{count} publicações. (delete_all_posts_max)" delete_and_block: "Eliminar e bloquear este e-mail e endereço de IP" delete_dont_block: "Apenas eliminar" diff --git a/config/locales/client.pt_BR.yml b/config/locales/client.pt_BR.yml index ca30f525cb..c4a9ea46ff 100644 --- a/config/locales/client.pt_BR.yml +++ b/config/locales/client.pt_BR.yml @@ -767,7 +767,6 @@ pt_BR: all: "Tudo" read: "Lido" unread: "Não lidas" - ignore_duration_title: "Ignorar Temporizador" ignore_duration_username: "Nome de Usuário" ignore_duration_when: "Duração:" ignore_duration_save: "Ignorar" @@ -991,6 +990,9 @@ pt_BR: confirm: "Você tem certeza absoluta de que deseja alterar seu nome de usuário?" taken: "Desculpe, este nome de usuário já está sendo usado." invalid: "Este nome de usuário é inválido. Ele deve conter apenas números e letras" + add_email: + title: "Adicione o e-mail" + add: "adicionar" change_email: title: "Alterar E-mail" taken: "Desculpe, este e-mail não está disponível." @@ -1021,8 +1023,11 @@ pt_BR: title: "E-mail" primary: "E-mail Primário" secondary: "E-mails Secundários" - no_secondary: "Nenhum e-mail secundário" + primary_label: "primário" + unconfirmed_label: "não confirmado" + update_email: "Alterar E-mail" sso_override_instructions: "E-mail pode ser atualizado do provedor de SSO." + no_secondary: "Nenhum e-mail secundário" instructions: "Nunca visível publicamente." ok: "Nós enviaremos um e-mail para confirmar" required: "Por favor preencha um endereço de e-mail" @@ -2262,6 +2267,7 @@ pt_BR: publish: "Publicar" description: "Quando um tópico é publicado como uma página, sua URL pode ser compartilhada e ela será exibida com um estilo personalizado." slug: "Slug" + public: "Público" publish_url: "Sua página foi publicada em:" topic_published: "Seu tópico foi publicado em:" preview_url: "Sua página será publicada em:" @@ -2473,7 +2479,6 @@ pt_BR: last: "Última revisão" hide: "Esconder revisão" show: "Exibir revisão" - revert: "Reverter para esta revisão" edit_wiki: "Editar Wiki" edit_post: "Editar Postagem" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -3161,13 +3166,13 @@ pt_BR: more: 'Registros de pesquisa' disabled: 'O relatório de pesquisa em alta está desativado. Habilitar consultas de pesquisa de registro para coletar dados.' filters: - file-extension: + file_extension: label: Extensão de arquivo group: label: Grupo category: label: Categoria - include-subcategories: + include_subcategories: label: "Incluir subcategorias" commits: latest_changes: "Últimas atualizações: atualize com frequência!" diff --git a/config/locales/client.ro.yml b/config/locales/client.ro.yml index 320f35da3c..19b89eff81 100644 --- a/config/locales/client.ro.yml +++ b/config/locales/client.ro.yml @@ -735,6 +735,8 @@ ro: confirm: "Ești absolut sigur că vrei să-ți schimbi numele de utilizator?" taken: "Acest nume de utilizator este deja folosit." invalid: "Acest nume de utilizator este invalid. Trebuie să includă doar cifre și litere." + add_email: + add: "adaugă" change_email: title: "Schimbă email" taken: "Această adresă există deja în baza de date." @@ -753,6 +755,8 @@ ro: instructions: "Fundalul va fi centrat şi va avea o dimensiune standard de 590px." email: title: "Email" + primary_label: "primar" + update_email: "Schimbă email" ok: "Îți vom trimite un email pentru confirmare." invalid: "Introduceți o adresă de email validă." authenticated: "Emailul a fost autentificat de către %{provider}." @@ -1728,6 +1732,8 @@ ro: title: "Comasează postările selectate" action: "comasează postările selectate" error: "A apărut o eroare la comasarea postărilor selectate." + publish_page: + public: "Public" change_owner: action: "Schimbă autorul" error: "A apărut o eroare la schimbarea autorului postărilor." @@ -1901,7 +1907,6 @@ ro: last: "Ultima revizie" hide: "Ascunde revizia" show: "Afișează revizia" - revert: "Restaurează această revizie" edit_post: "Modifică postarea" displays: inline: diff --git a/config/locales/client.ru.yml b/config/locales/client.ru.yml index aeffc76ecd..58798e1c21 100644 --- a/config/locales/client.ru.yml +++ b/config/locales/client.ru.yml @@ -528,7 +528,7 @@ ru: medium: "Средний" high: "Высокий" conversation: - view_full: "просмотреть полный разговор" + view_full: "Просмотреть всё обсуждение" scores: about: "Оценка рассчитывается на основе уровня доверия сообщающего, точности его предыдущих жалоб и приоритета сообщения." score: "Оценка" @@ -779,7 +779,7 @@ ru: "15": "Черновики" categories: all: "Все разделы" - all_subcategories: "все" + all_subcategories: "Все" no_subcategory: "Вне подразделов" category: "Раздел" category_list: "Показать список разделов" @@ -850,7 +850,7 @@ ru: all: "Все" read: "Прочитанные" unread: "Непрочитанные" - ignore_duration_title: "Игнорировать таймер" + ignore_duration_title: "Игнорировать пользователя" ignore_duration_username: "Псевдоним" ignore_duration_when: "Продолжительность:" ignore_duration_save: "Игнорировать" @@ -956,7 +956,9 @@ ru: admin_delete: "Удалить" users: "Пользователи" muted_users: "Выключено" + muted_users_instructions: "Игнорировать все уведомления и личные сообщения от этих пользователей." ignored_users: "Игнорировать" + ignored_users_instructions: "Игнорировать все сообщения, уведомления и личные сообщения от этих пользователей." tracked_topics_link: "Показать" automatically_unpin_topics: "Автоматически откреплять темы после прочтения" apps: "Приложения" @@ -1074,6 +1076,9 @@ ru: confirm: "Вы абсолютно действительно хотите изменить свое имя пользователя?" taken: "Этот псевдоним уже занят." invalid: "Псевдоним должен состоять только из цифр и латинских букв" + add_email: + title: "Добавить E-mail" + add: "добавить" change_email: title: "Изменить E-mail" taken: "Этот e-mail недоступен." @@ -1104,8 +1109,17 @@ ru: title: "E-mail" primary: "Основной адрес электронной почты" secondary: "Дополнительный адрес электронной почты" - no_secondary: "Нет дополнительного адреса электронной почты" + primary_label: "основной" + unconfirmed_label: "неподтвержденный" + resend_label: "Отправить заново подтверждение по e-mail" + resending_label: "отправка..." + resent_label: "e-mail отправлен" + update_email: "Изменить E-mail" + set_primary: "Указать как основной E-mail" + destroy: "Удалить E-mail" + add_email: "Добавить дополнительный E-mail" sso_override_instructions: "E-mail может быть переопределен от поставщика SSO." + no_secondary: "Нет дополнительного адреса электронной почты" instructions: "Не будет опубликован." ok: "Мы вышлем вам письмо для подтверждения" required: "Пожалуйста, введите email" @@ -1262,6 +1276,7 @@ ru: expired: "Это приглашение истекло." rescind: "Отозвать" rescinded: "Приглашение отозвано" + rescind_all: "Удалить просроченные приглашения" rescinded_all: "Все просроченные приглашения удалены!" rescind_all_confirm: "Вы действительно хотите удалить все просроченные приглашения?" reinvite: "Повторить приглашение" @@ -1272,18 +1287,30 @@ ru: time_read: "Времени читал" days_visited: "Дней посещал" account_age_days: "Дней с момента регистрации" + source: "Способ отправки приглашения" links_tab: "Ссылки" + links_tab_with_count: "Ссылки (%{count})" + link_url: "Ссылка" link_created_at: "Создано" - link_groups: Групп + link_redemption_stats: "Принятые приглашения" + link_groups: Группы + link_expires_at: Истекает create: "Отправить приглашение" + copy_link: "Копировать ссылку" generate_link: "Скопировать ссылку для приглашений" link_generated: "Пригласительная ссылка успешно создана!" valid_for: "Пригласительная ссылка действительна только для этого email: %{email}" - single_user: "Отдельный пользователь" + single_user: "Приглашение единичного пользователя" + multiple_user: "Приглашение нескольких пользователей" invite_link: - success: "Пригласительная ссылка успешно создана!" + title: "Ссылка на приглашение" + success: "Ссылка на приглашение успешно создана!" + error: "Произошла ошибка при создании ссылки на приглашение" + max_redemptions_allowed_label: "Сколько человек могут зарегистрироваться по этой ссылке?" + expires_at: "Когда истечет срок действия этой ссылки?" bulk_invite: none: "Вы ещё никого не приглашали сюда. Отправьте индивидуальные приглашения или пригласите несколько людей за раз, загрузив файл CSV." + text: "Массовое приглашение" success: "Файл успешно загружен, вы получите сообщение, когда процесс будет завершен." error: "Извините, но файл должен быть в формате CSV." confirmation_message: "Вы собираетесь отправить приглашения по электронной почте всем в загруженном файле." @@ -1418,10 +1445,10 @@ ru: too_few_posts_notice_MF: >- Давайте приступим к обсуждению! Есть {currentPosts, plural, one {# сообщение} few {# сообщения} other {# сообщений}}. Пользователи должны больше читать и отвечать – мы рекомендуем, по крайней мере {requiredPosts, plural, one {# сообщение} few {# сообщения} other {# сообщений}}. Только сотрудники могут видеть это сообщение. logs_error_rate_notice: - reached_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} или {# errors/hour}} достигнут предел настройки сайта {limit, plural, one {# error/hour} или {# errors/hour}}." - reached_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} или {# errors/minute}} достигнут предел настройки сайта {limit, plural, one {# error/minute} или {# errors/minute}}." - exceeded_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} или {# errors/hour}} достигнут предел настройки сайта {limit, plural, one {# error/hour} или {# errors/hour}}." - exceeded_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} или {# errors/minute}} превышен лимит настроек сайта {limit, plural, one {# error/minute} или {# errors/minute}}." + reached_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} other {# errors/hour}} достигнут предел настройки сайта {limit, plural, one {# error/hour} other {# errors/hour}}." + reached_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} other {# errors/minute}} достигнут предел настройки сайта {limit, plural, one {# error/minute} other {# errors/minute}}." + exceeded_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} other {# errors/hour}} превышен лимит настроек сайта {limit, plural, one {# error/hour} other {# errors/hour}}." + exceeded_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} other {# errors/minute}} превышен лимит настроек сайта {limit, plural, one {# error/minute} other {# errors/minute}}." learn_more: "подробнее..." all_time: "всего" all_time_desc: "всего создано тем" @@ -2142,6 +2169,7 @@ ru: time_frame_required: "Пожалуйста, выберите временные рамки" auto_update_input: none: "Выбор таймфрейма" + now: "Сейчас" later_today: "Сегодня, но позже" tomorrow: "Завтра" later_this_week: "Позже на этой неделе" @@ -2418,12 +2446,15 @@ ru: title: "Публикация страниц" publish: "Публиковать" description: "Когда тема публикуется в виде страницы, ее URL-адрес может быть предоставлен для общего доступа, и она будет отображаться с пользовательским стилем." - slug: "Slug" + slug: "Слаг (текстовый идентификатор)" + public: "Опубликованная страница" + public_description: "Пользователи могут видеть страницу, даже если соответствующая тема является закрытой." publish_url: "Ваша страница была опубликована по адресу:" - topic_published: "Ваша тема была опубликована на:" + topic_published: "Ваша тема была опубликована по адресу:" preview_url: "Ваша страница будет опубликована по адресу:" invalid_slug: "Извините, вы не можете опубликовать эту страницу." unpublish: "Отменить публикацию" + update: "Обновить" unpublished: "Публикация страницы была отменена и более недоступна по указанному ранее адресу." publishing_settings: "Настройки публикации" change_owner: @@ -2511,6 +2542,7 @@ ru: few: "%{count} ответа" many: "%{count} ответов" other: "%{count} ответов" + unknown_user: "(неизвестный/удалённый пользователь)" has_likes_title: one: "Это сообщение понравилось %{count} человеку" few: "Это сообщение понравилось %{count} людям" @@ -2666,7 +2698,7 @@ ru: last: "Последняя версия" hide: "Скрыть редакцию" show: "Показать редакцию" - revert: "Откат до этой версии" + revert: "Откат до версии %{revision}" edit_wiki: "Редактировать Wiki" edit_post: "Редактировать запись" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -2837,6 +2869,9 @@ ru: moderation: "Модерация" appearance: "Внешний вид" email: "Email" + list_filters: + all: "все темы" + none: "без подразделов" flagging: title: "Спасибо за вашу помощь в поддержании порядка!" action: "Пожаловаться на сообщение" @@ -3409,13 +3444,13 @@ ru: more: 'Поисковые логи' disabled: 'Отчет о поисковых запросов отключен. Включить журнал поисковых запросов для сбора данных.' filters: - file-extension: + file_extension: label: Расширение файла group: label: Группа category: label: Раздел - include-subcategories: + include_subcategories: label: "Включая подразделы" commits: latest_changes: "Обновления в репозитории Github" @@ -4119,6 +4154,9 @@ ru: override_upload_secure_status: "перезаписать защищенный статус загрузки" page_published: "страница опубликована" page_unpublished: "публикация страницы отменена" + add_email: "добавить e-mail" + update_email: "обновить e-mail" + destroy_email: "уничтожить e-mail" screened_emails: title: "Почтовые адреса" description: "Когда кто-то создаёт новую учётную запись, указанный пользователем почтовый адрес проверяется на соответствие с указанным ниже списком, и в случае совпадения регистрация блокируется или производятся другие дополнительные действия." @@ -4545,6 +4583,8 @@ ru: modal_description: "Хотели бы вы применить это изменение исторически? Это изменит настройки для %{count} существующих пользователей." modal_yes: "Да" modal_no: "Нет, только применить изменения в будущем" + simple_list: + add_item: "Добавить элемент..." badges: title: Награды new_badge: Новая награда @@ -4674,8 +4714,9 @@ ru: category_id: "Номер раздела" category_title: "Раздел" tag_name: "Имя тега" - external_url: "Внешняя ссылка" + external_url: "Внешняя или относительная ссылка" destination: "Назначения" + copy_to_clipboard: "Скопировать ссылку в буфер обмена" delete_confirm: "Удалить эту постоянную ссылку?" form: label: "Новая постоянная ссылка:" diff --git a/config/locales/client.sk.yml b/config/locales/client.sk.yml index 53d6fbe725..ade96e1502 100644 --- a/config/locales/client.sk.yml +++ b/config/locales/client.sk.yml @@ -790,6 +790,8 @@ sk: confirm: "Ste si naozaj istý(á), že si chcete zmeniť vaše užívateľské meno?" taken: "Ľutujeme, toto používateľské meno je obsadené." invalid: "Toto používateľské meno nie je platné. Musí obsahovať iba znaky a čísla." + add_email: + add: "pridať" change_email: title: "Zmeniť email" taken: "Ľutujeme, tento email nie je k dispozícii." @@ -810,6 +812,8 @@ sk: title: "Email" primary: "Primárny e-mail" secondary: "Sekundárne e-maily" + primary_label: "primárny" + update_email: "Zmeniť email" no_secondary: "Žiadne sekundárne e-maily" ok: "Pošleme vám email pre potvrdenie" invalid: "Zadajte prosím platný email" @@ -1696,6 +1700,8 @@ sk: merge_posts: title: "Spojiť označené príspevky" action: "spojiť označené príspevky" + publish_page: + public: "Verejné" change_owner: action: "zmeň vlastníka" error: "Nastala chyba pri zmene vlastníka príspevkov." diff --git a/config/locales/client.sl.yml b/config/locales/client.sl.yml index c8abd2ae59..6c6d38bede 100644 --- a/config/locales/client.sl.yml +++ b/config/locales/client.sl.yml @@ -744,7 +744,6 @@ sl: all: "Vsi" read: "Čas branja" unread: "Neprebrane" - ignore_duration_title: "Prezri opomnik" ignore_duration_username: "Uporabniško ime" ignore_duration_when: "Trajanje:" ignore_duration_save: "Prezri" @@ -932,6 +931,8 @@ sl: confirm: "Ali ste prepričani, da želite zamenjati vaše uporabniško ime?" taken: "Oprostite, to uporabniško ime je zasedeno." invalid: "Uporabniško ime ni pravilno. Vsebuje lahko samo črke in številke. Preslednica in posebni znaki niso dovoljeni." + add_email: + add: "dodaj" change_email: title: "Spremeni e-naslov" taken: "Ta e-naslov ni na voljo." @@ -952,8 +953,9 @@ sl: title: "E-naslov" primary: "E-naslov" secondary: "Dodatni e-naslovi" - no_secondary: "Ni dodatnih e-naslovov" + update_email: "Spremeni e-naslov" sso_override_instructions: "E-naslov se lahko spremeni pri SSO ponudniku." + no_secondary: "Ni dodatnih e-naslovov" instructions: "se nikoli ne prikaže javno" ok: "Poslali vam bomo e-sporočilo za potrditev." invalid: "Vnesite veljaven e-naslov." @@ -2191,6 +2193,8 @@ sl: title: "Združi izbrane prispevke" action: "združi izbrane prispevke" error: "Med združevanjem izbranih prispevkov je prišlo do napake." + publish_page: + public: "Javno" change_owner: title: "Spremeni lastnika" action: "spremeni lastnika" @@ -2408,7 +2412,6 @@ sl: last: "Zadnja verzija" hide: "Skrij verzije" show: "Prikaži verzije" - revert: "Povrni to verzijo" edit_wiki: "Uredi wiki" edit_post: "Uredi prispevek" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -3076,7 +3079,7 @@ sl: trending_search: more: 'Dnevnik iskanj' filters: - file-extension: + file_extension: label: Pripona datoteke group: label: Skupina diff --git a/config/locales/client.sq.yml b/config/locales/client.sq.yml index e37fe9701c..f6924bad5d 100644 --- a/config/locales/client.sq.yml +++ b/config/locales/client.sq.yml @@ -587,6 +587,8 @@ sq: title: "Ndrysho emrin e përdoruesit" taken: "Na vjen keq, por ky emër është i zënë." invalid: "Emri i përdoruesit nuk është i vlefshëm. Duhet të përmbaje vetëm shkronja ose numra" + add_email: + add: "shto" change_email: title: "Ndrysho email" taken: "Na vjen keq, por ky email nuk është i disponueshëm." @@ -605,6 +607,8 @@ sq: instructions: "Sfondi do të vendoset në qendër dhe do të ketë një gjerësi prej 590px." email: title: "Email" + primary_label: "parësor" + update_email: "Ndrysho email" instructions: "Mos e shfaq në publik." ok: "Do ju nisim emailin e konfirmimit" invalid: "Ju lutemi të vendosni një email të vlefshëm" @@ -1512,7 +1516,6 @@ sq: last: "Revizioni i fundit" hide: "Fshihe revizionin" show: "Trego revizionin" - revert: "Rikthe këtë version" displays: inline: title: "Show the rendered output with additions and removals inline" diff --git a/config/locales/client.sr.yml b/config/locales/client.sr.yml index 63116c89a8..15a7269c62 100644 --- a/config/locales/client.sr.yml +++ b/config/locales/client.sr.yml @@ -535,6 +535,8 @@ sr: title: "Promijeni Korisničko ime" taken: "Žao nam je, to je ime zauzeto." invalid: "Korisničko ime je nevažeće. Može sadržati samo slova i brojeve." + add_email: + add: "dodaj" change_email: title: "Promeni e-mail" taken: "Žao nam je, taj e-mail nije dostupan" @@ -551,6 +553,8 @@ sr: instructions: "Pozadinske slike će biti centrirane i imati standardu širinu od 590px." email: title: "E-mail" + primary_label: "primarna" + update_email: "Promeni e-mail" ok: "Poslaćemo vam e-mail za potvrdu" invalid: "Molimo unesite validnu e-mail adresu" authenticated: "E-mail vam je potvrđen od %{provider}" diff --git a/config/locales/client.sv.yml b/config/locales/client.sv.yml index e0a936164a..96b822cbe9 100644 --- a/config/locales/client.sv.yml +++ b/config/locales/client.sv.yml @@ -770,7 +770,7 @@ sv: all: "Alla" read: "Läst" unread: "Olästa" - ignore_duration_title: "Ignorera timer" + ignore_duration_title: "Ignorera användare" ignore_duration_username: "Användarnamn" ignore_duration_when: "Varaktighet:" ignore_duration_save: "Ignorera" @@ -875,7 +875,9 @@ sv: admin_delete: "Radera" users: "Användare" muted_users: "Tystat" + muted_users_instructions: "Undanta alla notiser och PM från dessa användare." ignored_users: "Ignorerade" + ignored_users_instructions: "Undanta alla inlägg, notiser och PM från dessa användare." tracked_topics_link: "Visa" automatically_unpin_topics: "Avklistra automatiskt ämnen när jag når botten" apps: "Appar" @@ -994,6 +996,9 @@ sv: confirm: "Är du absolut säker på att du vill ändra ditt användarnamn?" taken: "Tyvärr, det användarnamnet är taget." invalid: "Det användarnamnet är ogiltigt. Det får bara innehålla siffror och bokstäver" + add_email: + title: "Lägg till e-post" + add: "lägg till" change_email: title: "Byt e-post" taken: "Tyvärr den e-postadressen är inte tillgänglig." @@ -1024,8 +1029,17 @@ sv: title: "E-post" primary: "Primär e-post" secondary: "Sekundär e-post" - no_secondary: "Inga sekundära e-post" + primary_label: "primär" + unconfirmed_label: "obekräftad" + resend_label: "återsänd bekräftelse e-post" + resending_label: "skickar..." + resent_label: "e-post skickat" + update_email: "Byt e-post" + set_primary: "Ange primär e-post" + destroy: "Ta bort e-post" + add_email: "Lägg till alternativ e-post" sso_override_instructions: "E-post kan uppdateras från SSO leverantören." + no_secondary: "Inga sekundära e-post" instructions: "Visas aldrig publikt" ok: "Vi skickar e-post till dig för bekräftelse" required: "Vänligen ange en e-postadress" @@ -1178,6 +1192,7 @@ sv: expired: "Denna inbjudan har gått ut." rescind: "Ta bort" rescinded: "Inbjudan borttagen" + rescind_all: "Ta bort utgångna inbjudningar" rescinded_all: "Alla utgångna inbjudningar har tagits bort!" rescind_all_confirm: "Är du säker på att du vill ta bort alla utgångna inbjudningar?" reinvite: "Skicka inbjudan igen" @@ -1188,18 +1203,30 @@ sv: time_read: "Lästid" days_visited: "Dagar besökta" account_age_days: "Kontoålder i dagar" + source: "Inbjuden genom" links_tab: "Länkar" + links_tab_with_count: "Länkar (%{count})" + link_url: "Länk" link_created_at: "Skapad" + link_redemption_stats: "Återbeviljade" link_groups: Grupper + link_expires_at: Upphör create: "Skicka inbjudan" + copy_link: "Kopiera länk" generate_link: "Kopiera inbjudningslänken" 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}" single_user: "Enstaka användare" + multiple_user: "Flera användare" invite_link: + title: "Inbjudningslänk" success: "Länk för inbjudan framgångsrikt skapad!" + error: "Ett fel inträffade vid skapande av inbjudningslänk" + max_redemptions_allowed_label: "Hur många personer är tillåtna att registrera sig via denna länk?" + expires_at: "När ska denna inbjudningslänk upphöra?" bulk_invite: none: "Du har inte bjudit in någon ännu. Skicka individuella inbjudningar eller bjud in många personer på en gång genom att ladda upp en CSV-fil." + text: "Massinbjudan" success: "Filen laddades upp, du blir underrättad via meddelande när processen är klar" error: "Tyvärr, filen bör vara i CSV-format." confirmation_message: "Du är på väg att e-posta inbjudningar till alla personer i den uppladdade filen." @@ -2004,6 +2031,7 @@ sv: time_frame_required: Vänligen välj en tidsram auto_update_input: none: "Välj en tidsram" + now: "Nu" later_today: "Senare idag" tomorrow: "Imorgon" later_this_week: "Senare denna vecka" @@ -2265,11 +2293,14 @@ sv: publish: "Publicera" description: "När ett ämne publiceras som en sida kan deras URL delas och den kommer att visas med anpassad utformning." slug: "Slug" + public: "Offentligt" + public_description: "Folk kan se sidan även om det associerade ämnet är privat." publish_url: "Din sida har publicerats vid:" topic_published: "Ditt ämne har publicerats vid:" preview_url: "Din sida kommer publiceras vid:" invalid_slug: "Tyvärr, du kan inte publicera denna sida." unpublish: "Avpublicera" + update: "Uppdatera" unpublished: "Din sida har blivit avpublicerad och är inte längre tillgänglig." publishing_settings: "Inställningar för publicering" change_owner: @@ -2343,6 +2374,7 @@ sv: has_replies: one: "%{count} svar" other: "%{count} svar" + unknown_user: "(okänd/raderad användare)" has_likes_title: one: "%{count} person gillade detta inlägg" other: "%{count} personer gillade detta inlägg" @@ -2476,7 +2508,7 @@ sv: last: "Senaste revisionen" hide: "Göm version" show: "Visa version" - revert: "Återgå till den här revisionen" + revert: "Återgå till revision %{revision}" edit_wiki: "Uppdatera Wiki" edit_post: "Ändra meddelandet" comparing_previous_to_current_out_of_total: "%{previous}%{icon}%{current} / %{total}" @@ -2647,6 +2679,9 @@ sv: moderation: "Moderering" appearance: "Utseende" email: "E-post" + list_filters: + all: "alla ämnen" + none: "inga underkategorier" flagging: title: "Tack för att du hjälper till att hålla forumet civiliserat!" action: "Flagga inlägg" @@ -3165,13 +3200,13 @@ sv: more: 'Sökloggar' disabled: 'Den trendiga sökrapporten är inaktiverad. Aktivera sökfrågor för loggar för att samla data. ' filters: - file-extension: + file_extension: label: Filändelse group: label: Grupp category: label: Kategori - include-subcategories: + include_subcategories: label: "Inkludera underkategorier" commits: latest_changes: "Senaste ändringarna: snälla uppdatera ofta!" @@ -3869,6 +3904,9 @@ sv: override_upload_secure_status: "åsidosätt säkerhetsstatus för uppladdning" page_published: "sida publicerad" page_unpublished: "sida avpublicerad" + add_email: "lägg till e-post" + update_email: "Uppdatera e-post" + destroy_email: "förstör e-post" screened_emails: title: "Kontrollerad e-post" description: "När någon försöker skapa ett nytt konto, kommer följande e-postadresser att kontrolleras och registreringen blockeras, eller någon annan åtgärd vidtas." @@ -4414,8 +4452,9 @@ sv: category_id: "Kategori-ID" category_title: "Kategori" tag_name: "Namn på tagg" - external_url: "Extern URL" + external_url: "Extern eller relativ URL" destination: "Mål" + copy_to_clipboard: "Kopiera permalänk till urklipp" delete_confirm: "Är du säker på att du vill ta bort den här permalänken?" form: label: "Ny:" diff --git a/config/locales/client.sw.yml b/config/locales/client.sw.yml index e805f3aff2..6a90dd244d 100644 --- a/config/locales/client.sw.yml +++ b/config/locales/client.sw.yml @@ -717,6 +717,8 @@ sw: confirm: "Je, una uhakika unataka kuabadili jina la mtumiaji?" taken: "Samahani, hilo jina limechukuliwa." invalid: "Hilo jina ni batili. Jina lazima liwe na namba au herufi au vyote viwili" + add_email: + add: "ongeza" change_email: title: "Badilisha Barua Pepe" taken: "Samahani, hiyo barua pepe haipo hewani." @@ -737,6 +739,8 @@ sw: title: "Barua pepe" primary: "Barua pepe ya awali" secondary: "Barua pepe" + primary_label: "msingi" + update_email: "Badilisha Barua Pepe" ok: "Tutakutumia barua pepe kuthibitisha" invalid: "Andika barua pepe iliyo sahihi" authenticated: "Barua pepe yako imethibitishwa na %{mkimu}" @@ -1745,6 +1749,8 @@ sw: title: "Unganisha Machapisho Uliyochagua" action: "unganisha machapisho uliyochagua" error: "Hitilafu imetokea wakati wa kuunganisha machapisho yaliyochaguliwa." + publish_page: + public: "Umma" change_owner: action: "badilisha umiliki" error: "Hitilafu imetokea wakati wa kubadilisha mmiliki wa machapisho." @@ -1896,7 +1902,6 @@ sw: last: "Sahihisho iliopita" hide: "Ficha sahihisho" show: "Onyesha sahihisho" - revert: "Rudi kwenye sahihisho hili" edit_wiki: "Hariri Wiki" edit_post: "Hariri Chapisho" displays: @@ -2018,7 +2023,7 @@ sw: notify_action: "Ujumbe" official_warning: "Onyo Rasmi" delete_spammer: "Futa Muandishi wa Taka" - delete_confirm_MF: "Unakaribia kufuta {POSTS, plural, one {chapisho1} other {machapisho #}} na {TOPICS, plural, one {mada1} other {mada#}} kutoka kwa mtumiaji mwingine, ondoa akaunti yao, zuia usajili kutoka kwenye anwani zao za mtandao{anwani_ya mtandao}, na ongeza barua pepe zao {barua pepe}kwenye orodha ya waliozuliwa. Una uhakika mtumiaji huyu anatuma barua au ujumbe taka?" + delete_confirm_MF: "Unakaribia kufuta {POSTS, plural, one {chapisho1} other {machapisho #}} na {TOPICS, plural, one {mada1} other {mada#}} kutoka kwa mtumiaji mwingine, ondoa akaunti yao, zuia usajili kutoka kwenye anwani zao za mtandao{ip_address}, na ongeza barua pepe zao {email}kwenye orodha ya waliozuliwa. Una uhakika mtumiaji huyu anatuma barua au ujumbe taka?" yes_delete_spammer: "Ndiyo, futa mtuma barua taka" ip_address_missing: "(N/A)" hidden_email_address: "(imefichwa)" @@ -2996,7 +3001,7 @@ sw: penalty_post_delete: "Futa taarifa" penalty_post_edit: "Hariri Taarifa" penalty_post_none: "Usifanye chochote" - delete_all_posts_confirm_MF: "Unaenda kufuta {POSTS, plural, one {chapisho 1} other {machapisho #}} na {TOPICS, plural, one {mada 1} ziada {mada #}}. Una uhakika?" + delete_all_posts_confirm_MF: "Unaenda kufuta {POSTS, plural, one {chapisho 1} other {machapisho #}} na {TOPICS, plural, one {mada 1} other {mada #}}. Una uhakika?" silence: "Imenyamazishwa" unsilence: "Imeruhusiwa" silenced: "Nyamazishwa?" diff --git a/config/locales/client.te.yml b/config/locales/client.te.yml index c6f742e0a0..f432e5fef4 100644 --- a/config/locales/client.te.yml +++ b/config/locales/client.te.yml @@ -450,6 +450,8 @@ te: instructions: "వెనుతలం బొమ్మలు కేంద్రీకరించబడతాయి మరియు అప్రమేయ వెడల్పు 590 పిక్సెలు ఉంటాయి." email: title: "ఈమెయిల్" + primary_label: "ప్రాథమిక" + update_email: "ఈమెయిల్ మార్చు" ok: "ద్రువపరుచుటకు మీకు ఈమెయిల్ పంపాము" invalid: "దయచేసి చెల్లుబాటులోని ఈమెయిల్ చిరునామా రాయండి" authenticated: "మీ ఈమెయిల్ %{provider} చేత ద్రువీకరించబడింది" @@ -964,6 +966,8 @@ te: instructions: one: "ఈ టపాలు జరపాలనుకున్న విషయాన్ని ఎంచుకోండి." other: "ఈ %{count} టపాలను జరపాలనుకున్న విషయాన్ని ఎంచుకోండి." + publish_page: + public: "బహిరంగం" change_owner: action: "యజమానిని మార్చు" error: "ఆ టపాల యజమానిని మార్చేప్పుడు దోషం జరిగింది." @@ -1298,6 +1302,7 @@ te: tagging: tags: "ట్యాగులు" add_synonyms: "కలుపు" + sort_by_name: "పేరు" cancel_delete_unused: "రద్దుచేయి" notifications: watching: @@ -1514,6 +1519,7 @@ te: body: "శరీరం" theme: theme: "అలంకారం" + title: "అలంకారాలు" create_type: "రకం" create_name: "పేరు" edit: "సవరించు" diff --git a/config/locales/client.th.yml b/config/locales/client.th.yml index c1e43b699b..25c540ad3a 100644 --- a/config/locales/client.th.yml +++ b/config/locales/client.th.yml @@ -26,7 +26,10 @@ th: millions: "%{number}ล้าน" dates: time: "h:mm a" + time_with_zone: "HH:mm (z)" + time_short_day: "ddd, HH:mm" timeline_date: "MMM YYYY" + long_no_year: "D MMM, HH:mm" long_no_year_no_time: "MMM D" full_no_year_no_time: "MMMM Do" long_with_year: "MMM D, YYYY h:mm a" @@ -44,12 +47,16 @@ th: other: "< %{count} วินาที" x_seconds: other: "%{count} วินาที" + less_than_x_minutes: + other: "%{count}นาที" x_minutes: other: "%{count} นาที" about_x_hours: other: "%{count} ชั่วโมง" x_days: other: "%{count} วัน" + x_months: + other: "%{count}เดือน" about_x_years: other: "%{count} ปี" over_x_years: @@ -73,6 +80,10 @@ th: other: "%{count} ชั่วโมงที่แล้ว" x_days: other: "%{count} วันที่แล้ว" + x_months: + other: "%{count}เดือนที่แล้ว" + x_years: + other: "%{count}ปีที่แล้ว" later: x_days: other: "%{count} วันหลังจากนี้" @@ -84,6 +95,7 @@ th: next_month: "เดือนถัดไป" placeholder: วัน share: + topic_html: 'กระทู้: %{topicTitle}' post: "โพสต์ #%{postNumber}" close: "ปิด" twitter: "แชร์ลิ้งก์นี้ไปทวิตเตอร์" @@ -95,6 +107,7 @@ th: split_topic: "แบ่งกระทู้นี้เมื่อ %{when}" invited_user: "ได้เชิญ %{who} %{when}" invited_group: "ได้เชิญ %{who} %{when}" + user_left: "%{who}ลบตัวเองออกจากข้อความนี้%{when}" removed_user: "ลบ %{who} %{when}" removed_group: "ลบ %{who} %{when}" autoclosed: @@ -105,7 +118,7 @@ th: disabled: "เปิดเมื่อ %{when}" archived: enabled: "ถูกเก็บเข้าคลังเมื่อ %{when}" - disabled: "ถูกเอกออกจากคลังเมื่อ %{when}" + disabled: "ถูกเอาออกจากคลังเมื่อ %{when}" pinned: enabled: "ถูกปักหมุดเมื่อ %{when}" disabled: "ถูกปลดหมุดเมื่อ %{when}" @@ -118,6 +131,7 @@ th: banner: enabled: "ทำให้เป็นแบนเนอร์%{when} จะปรากฏที่ด้านบนสุดของทุกหน้าจนกว่าจะผู้ใช้งานจะกดลบ" disabled: "ลบแบนเนอร์นี้%{when} จะไม่ปรากฏที่ด้านบนของหน้าใดๆ" + forwarded: "ส่งต่ออีเมลข้างต้นแล้ว" emails_are_disabled: "อีเมลขาออกทั้งหมดถูกปิดโดยผู้ดูแลระบบ จะไม่มีอีเมลแจ้งเตือนใดๆถูกส่งออกไป" themes: default_description: "ค่าเริ่มต้น" @@ -128,11 +142,19 @@ th: ap_south_1: "เอเชียแปซิฟิก (มุมไบ)" ap_southeast_1: "เอเชียแปซิฟิก (สิงคโปร์)" ap_southeast_2: "เอเชียแปซิฟิก (ซิดนีย์)" + ca_central_1: "แคนาดา (กลาง)" cn_north_1: "จีน (ปักกิ่ง)" + cn_northwest_1: "จีน (หนิงเซี่ย)" eu_central_1: "อียู (แฟรงก์เฟิร์ต)" + eu_north_1: "อียู (สต็อกโฮล์ม)" eu_west_1: "อียู (ไอร์แลนด์)" + eu_west_2: "อียู (ลอนดอน)" + eu_west_3: "อียู (ปารีส)" + sa_east_1: "อเมริกาใต้ (เซาเปาโล)" us_east_1: "สหรัฐอเมริกาฝั่งตะวันออก (เวอร์จิเนียเหนือ)" us_east_2: "สหรัฐอเมริกาฝั่งตะวันออก (โอไฮโอ)" + us_gov_east_1: "AWS GovCloud (สหรัฐอเมริกาฝั่งตะวันออก)" + us_gov_west_1: "AWS GovCloud (สหรัฐอเมริกาฝั่งตะวันตก)" us_west_1: "สหรัฐอเมริกาฝั่งตะวันตก (แคลิฟอร์เนียเหนือ)" us_west_2: "สหรัฐอเมริกาฝั่งตะวันตก (ออริกอน)" edit: "แก้ไขหัวข้อและหมวดหมู่ของกระทู้นี้" @@ -143,6 +165,7 @@ th: submit: "ตกลง" generic_error: "ขออภัย เกิดข้อผิดพลาดขึ้น" generic_error_with_reason: "เกิดข้อผิดพลาดขึ้น: %{error}" + go_ahead: "ไปต่อ" sign_up: "สมัครสมาชิก" log_in: "เข้าสู่ระบบ" age: "อายุ" @@ -158,6 +181,7 @@ th: privacy_policy: "นโยบายความเป็นส่วนตัว" privacy: "ความเป็นส่วนตัว" tos: "เงื่อนไขการบริการ" + rules: "กฎ" mobile_view: "ดูแบบอุปกรณ์เคลื่อนที่" desktop_view: "ดูแบบเดสก์ท็อป" you: "คุณ" @@ -177,6 +201,9 @@ th: alternation: "หรือ" character_count: other: "%{count} ตัวอักษร" + related_messages: + title: "ข้อความที่เกี่ยวข้อง" + see_all: 'ดูข้อความทั้งหมดจาก @%{username}' suggested_topics: title: "กระทู้แนะนำ" pm_title: "ข้อความแนะนำ" @@ -186,8 +213,11 @@ th: stats: "สถิติเว็บไซต์" our_admins: "แอดมินของเรา" our_moderators: "ผู้ดูแลของเรา" + moderators: "ผู้ดูแล" stat: all_time: "ตลอดเวลา" + last_7_days: "7 วันที่ผ่านมา" + last_30_days: "30 วันที่ผ่านมา" like_count: "ถูกใจ" topic_count: "กระทู้" post_count: "โพสต์" @@ -202,17 +232,42 @@ th: bookmark: "คลิกเพื่อ บุ๊คมาร์ค ที่โพสแรกของกระทู้นี้" unbookmark: "คลิกเพื่อลบบุ๊กมาร์กทั้งหมดในกระทู้นี้" bookmarks: + created: "คุณได้บุ๊กมาร์กโพสต์นี้%{name}" + not_bookmarked: "บุ๊กมาร์กโพสต์นี้" remove: "ลบบุ๊กมาร์ก" + delete: "ลบบุ๊กมาร์ก" + confirm_clear: "คุณแน่ใจหรือว่าต้องการล้างบุ๊กมาร์กทั้งหมดจากกระทู้นี้" save: "บันทึก" + invalid_custom_datetime: "วันและเวลาที่คุณกรอกไม่ถูกต้อง กรุณาลองอีกครั้ง" + list_permission_denied: "คุณไม่ได้รับอนุญาตให้ดูบุ๊กมาร์กของผู้ใช้งานนี้" reminders: + later_today: "ภายหลังในวันนี้" + next_business_day: "ในวันทำการถัดไป" tomorrow: "พรุ่งนี้" + next_week: "สัปดาห์หน้า" + later_this_week: "ภายหลังในสัปดาห์นี้" + start_of_next_business_week: "วันจันทร์หน้า" + next_month: "เดือนหน้า" + last_custom: "ล่าสุด" + today_with_time: "วันนี้ตอน%{time}" + tomorrow_with_time: "พรุ่งนี้ตอน%{time}" + at_time: "เมื่อ%{date_time}" + copy_codeblock: + copied: "คัดลอกแล้ว!" drafts: remove: "ลบ" + new_topic: "แบบร่างกระทู้ใหม่" + new_private_message: "แบบร่างข้อความส่วนตัวใหม่" abandon: + confirm: "คุณได้เปิดแบบร่างอื่นในกระทู้นี้แล้ว แน่ใจหรือว่าต้องการละทิ้งมัน" yes_value: "ใช่ ละทิ้ง" no_value: "ไม่ เก็บไว้" topic_count_latest: other: "ดู %{count} กระทู้ใหม่หรือที่อัปเดต" + topic_count_unread: + other: "ดู%{count}กระทู้ที่ยังไม่ได้อ่าน" + topic_count_new: + other: "ดู%{count}กระทู้ใหม่" preview: "แสดงตัวอย่าง" cancel: "ยกเลิก" save: "บันทึกการเปลี่ยนแปลง" @@ -220,9 +275,11 @@ th: saved: "บันทึกแล้ว!" upload: "อัปโหลด" uploading: "กำลังอัปโหลด..." + uploading_filename: "กำลังอัปโหลด: %{filename} ..." uploaded: "อัปโหลดแล้ว!" enable: "เปิดใช้งาน" disable: "ปิดใช้งาน" + continue: "ดำเนินการต่อ" undo: "เลิกทำ" revert: "ย้อนกลับ" failed: "ล้มเหลว" @@ -231,41 +288,115 @@ th: banner: close: "ปิดแบนเนอร์นี้" edit: "แก้ไขแบนเนอร์นี้ >>" + pwa: + install_banner: "คุณต้องการติดตั้ง%{title}บนอุปกรณ์นี้ใช่ไหม" choose_topic: none_found: "ไม่พบกระทู้ใดๆ" + title: + search: "ค้นหากระทู้" + placeholder: "ระบุหัวข้อกระทู้ หมายเลข หรือ url ที่นี่ " + choose_message: + none_found: "ไม่พบข้อความ" + title: + search: "ค้นหาข้อความ" + placeholder: "ระบุหัวข้อข้อความ หมายเลข หรือ url ที่นี่ " review: + order_by: "สั่งโดย" + in_reply_to: "ตอบไปยัง" + explain: + total: "ทั้งหมด" + trust_level_bonus: + name: "ระดับความไว้ใจ" + awaiting_approval: "กำลังรอการยืนยัน" delete: "ลบ" settings: + saved: "บันทึกแล้ว" save_changes: "บันทึกการเปลี่ยนแปลง" title: "การตั้งค่า" + view_all: "ดูทั้งหมด" + grouped_by_topic: "จัดกลุ่มโดยหมวดหมู่" + topic_has_pending: + other: "กระทู้นี้มี%{count}โพสต์ที่กำลังรอการอนุมัติ" + title: "รีวิว" topic: "กระทู้:" filtered_user: "ผู้ใช้" + show_all_topics: "แสดงกระทู้ทั้งหมด" + deleted_post: "(โพสต์ถูกลบ)" + deleted_user: "(ผู้ใช้ถูกลบ)" user: + website: "เว็บไซต์" username: "ชื่อผู้ใช้" email: "อีเมล" name: "ชื่อ" + user_percentage: + summary: + other: "%{agreed},%{disagreed},%{ignored} (%{count}ธงทั้งหมด)" + agreed: + other: "%{count}% เห็นด้วย" + disagreed: + other: "%{count} % ไม่เห็นด้วย" + ignored: + other: "%{count} % ไม่สนใจ" topics: topic: "หัวข้อ" + deleted: "[กระทู้ถูกลบ]" + original: "(กระทู้ต้นฉบับ)" + details: "รายละเอียด" + unique_users: + other: "%{count} ผู้ใช้" + replies: + other: "%{count} ตอบ" edit: "แก้ไข" save: "บันทึก" cancel: "ยกเลิก" filters: + all_categories: "(หมวดหมู่ทั้งหมด)" type: title: "ชนิด" + all: "(ทุกประเภท)" + minimum_score: "คะแนนขั้นต่ำ:" refresh: "รีเฟรช" + status: "สถานะ" category: "หมวดหมู่" + orders: + score: "คะแนน" + created_at: "ถูกสร้างเมื่อ" + priority: + medium: "ปานกลาง" + high: "สูง" + conversation: + view_full: "ดูบทสนทนาทั้งหมด" scores: + score: "คะแนน" date: "วันที่" type: "ชนิด" + status: "สถานะ" + submitted_by: "ยืนยันโดย" + reviewed_by: "รีวิวโดย" statuses: pending: title: "อยู่ระหว่างการพิจารณา" + approved: + title: "อนุมัติ" + rejected: + title: "ปฏิเสธ" + deleted: + title: "ลบ" + reviewed: + title: "(ถูกรีวิวทั้งหมด)" + all: + title: "(ทุกสิ่ง)" types: + reviewable_flagged_post: + title: "โพสต์ที่ถูกปักธง" + flagged_by: "ถูกปักธงโดย" reviewable_user: title: "ผู้ใช้" approval: title: "โพสต์นี้ต้องได้รับการอนุมัติ" description: "เราได้รับโพสต์ใหม่ของคุณแล้ว แต่ต้องได้รับการอนุมัติจากผู้ดูแลก่อนถึงจะปรากฏขึ้น กรุณารอสักครู่" + pending_posts: + other: "คุณมี%{count}โพสต์ที่กำลังรอการยืนยัน" ok: "ตกลง" user_action: user_posted_topic: "%{user} โพสต์ กระทู้" @@ -298,6 +429,7 @@ th: days_visited_long: "วันที่เยี่ยมชม" posts_read: "อ่าน" posts_read_long: "โพสต์ถูกอ่าน" + last_updated: "อัปเดตล่าสุด:" total_rows: other: "%{count} ผู้ใช้" group_histories: @@ -305,12 +437,21 @@ th: change_group_setting: "แก้ไขการตั้งค่ากลุ่ม" add_user_to_group: "เพิ่มผู้ใช้" remove_user_from_group: "ลบผู้ใช้" + make_user_group_owner: "ตั้งเป็นเจ้าของ" groups: + member_added: "เพิ่ม" + member_requested: "ร้องขอเมื่อ" add_members: title: "เพิ่มสมาชิก" + description: "จัดการความเป็นสมาชิกของกลุ่มนี้" usernames: "ชื่อผู้ใช้" requests: + title: "คำร้องขอ" reason: "เหตุผล" + accept: "ยอมรับ" + accepted: "ยอมรับแล้ว" + deny: "ปฏิเสธ" + denied: "ปฏิเสธแล้ว" manage: title: "จัดการ" name: "ชื่อ" @@ -334,15 +475,26 @@ th: from: "จาก" to: "ถึง" public_exit: "อนุญาตให้ผู้ใช้ออกจากกลุ่มอย่างอิสระ" + empty: + posts: "ไม่มีโพสต์โดยสมาชิกของกลุ่มนี้" + members: "ไม่มีสมาชิกในกลุ่มนี้" + requests: "ไม่มีคำร้องขอเป็นสมาชิกของกลุ่มนี้" + mentions: "ไม่มีการกล่าวถึงของกลุ่มนี้" + messages: "ไม่มีข้อความสำหรับกลุ่มนี้" + topics: "ไม่มีกระทู้โดยสมาชิกของกลุ่มนี้" add: "เพิ่ม" join: "เข้าร่วม" leave: "ออก" request: "ร้องขอ" message: "ข้อความ


" + confirm_leave: "คุณแน่ใจหรือว่าต้องการออกจากกลุ่มนี้" membership_request: + submit: "ส่งคำร้องขอ" title: "ขอเข้าร่วม @%{group_name}" + reason: "บอกให้เจ้าของกลุ่มทราบว่าทำไมคุณถึงเหมาะสมกับกลุ่มนี้" membership: "การเป็นสมาชิก" name: "ชื่อ" + group_name: "ชื่อกลุ่ม" user_count: "ผู้ใช้" bio: "เกี่ยวกับกลุ่ม" selector_placeholder: "กรอกชื่อผู้ใช้" @@ -351,15 +503,35 @@ th: title: "กลุ่ม" all: "ทุกกลุ่ม" empty: "ไม่มีกลุ่มที่เห็นได้" + owner_groups: "กลุ่มที่ฉันเป็นเจ้าของ" + close_groups: "กลุ่มปิด" + automatic_groups: "กลุ่มอัตโนมัติ" + automatic: "อัตโนมัติ" closed: "ปิด" + public: "สาธารณะ" + private: "ส่วนตัว" + public_groups: "กลุ่มสาธารณะ" automatic_group: กลุ่มอัตโนมัติ close_group: กลุ่มปิด my_groups: "กลุ่มของฉัน" + group_type: "ประเภทกลุ่ม" + is_group_user: "สมาชิก" + is_group_owner: "เจ้าของ" + title: + other: "กลุ่ม" activity: "กิจกรรม" members: title: "สมาชิก" filter_placeholder_admin: "ชื่อผู้ใช้หรืออีเมล" filter_placeholder: "ชื่อผู้ใช้" + remove_member: "ลบสมาชิก" + remove_member_description: "ลบ%{username}ออกจากกลุ่มนี้" + make_owner: "แต่งตั้งเจ้าของ" + make_owner_description: "แต่งตั้ง%{username}เป็นเจ้าของกลุ่มนี้" + remove_owner: "ลบในสถานะเจ้าของ" + remove_owner_description: "ลบ%{username}ในสถานะเจ้าของกลุ่มนี้" + owner: "เจ้าของ" + forbidden: "คุณไม่ได้รับอนุญาตให้ดูสมาชิก" topics: "กระทู้" posts: "โพสต์" mentions: "กล่าวถึง" @@ -371,6 +543,7 @@ th: only_admins: "เฉพาะแอดมิน" mods_and_admins: "เฉพาะผู้ดูแลระบบและแอดมิน" members_mods_and_admins: "เฉพาะสมาชิกกลุ่ม ผู้ดูแลระบบและแอดมิน" + owners_mods_and_admins: "เฉพาะเจ้าของกลุ่ม ผู้ดูแลระบบ และแอดมินเท่านั้น" everyone: "ทุกคน" notifications: watching: @@ -378,6 +551,7 @@ th: description: "คุณจะถูกแจ้งเตือนทุกๆโพสต์ใหม่ในทุกๆข้อความ และจำนวนของคำตอบใหม่จะถูกแสดง" watching_first_post: title: "กำลังดูโพสต์แรก" + description: "คุณจะได้รับการแจ้งเตือนเมื่อมีข้อความใหม่ในกลุ่มนี้ ยกเว้นคำตอบของข้อความเหล่านั้น" tracking: title: "กำลังติดตาม" description: "คุณจะได้รับการแจ้งเตือนเมื่อมีคนกล่าวถึงชื่อของคุณ @name หรือตอบคุณ และจำนวนของคำตอบใหม่จะถูกแสดง" @@ -386,8 +560,13 @@ th: description: "คุณจะได้รับการแจ้งเตือนเมื่อมีคนกล่าวถึงชื่อของคุณ @name หรือตอบคุณ" muted: title: "ปิด" + description: "คุณจะไม่ได้รับการแจ้งเตือนใดๆเกี่ยวกับข้อความในกลุ่มนี้" + flair_upload_description: "ใช้รูปสี่เหลี่ยมไม่เล็กกว่า 20 พิกเซล x 20 พิกเซล" flair_preview_icon: "ไอคอนตัวอย่าง" flair_preview_image: "รูปภาพตัวอย่าง" + flair_type: + icon: "เลือกไอคอน" + image: "อัปโหลดรูปภาพ" user_action_groups: "1": "ถูกใจ" "2": "ถูกใจ" @@ -401,6 +580,7 @@ th: "12": "รายการที่ส่งแล้ว" "13": "กล่องข้อความ" "14": "อยู่ระหว่างการพิจารณา" + "15": "แบบร่าง" categories: all: "ทุกหมวดหมู่" all_subcategories: "ทั้งหมด" @@ -419,6 +599,13 @@ th: latest_by: "ล่าสุดโดย" toggle_ordering: "เปลี่ยนวิธีการจัดลำดับ" subcategories: "หมวดหมู่ย่อย" + topic_sentence: + other: "%{count}กระทู้" + topic_stat_sentence_week: + other: "%{count}กระทู้ใหม่ในสัปดาห์ที่ผ่านมา" + topic_stat_sentence_month: + other: "%{count}กระทู้ใหม่ในเดือนที่ผ่านมา" + n_more: "หมวดหมู่ (อีก%{count}) ..." ip_lookup: title: มองหาที่อยู่ไอพี hostname: ชื่อโฮสต์ @@ -434,6 +621,7 @@ th: topics_entered: "กระทู้ที่เข้า" post_count: "# โพสต์" confirm_delete_other_accounts: "คุณแน่ใจแล้วหรือว่าจะลบบัญชีเหล่านี้" + copied: "คัดลอกแล้ว" user_fields: none: "(เลือกตัวเลือก)" user: @@ -441,6 +629,10 @@ th: profile: "โปรไฟล์" mute: "ปิด" edit: "แก้ไขการตั้งค่า" + download_archive: + button_text: "ดาวน์โหลดทั้งหมด" + confirm: "คุณแน่ใจหรือว่าต้องการดาวน์โหลดโพสต์ของคุณ" + rate_limit_error: "สามารถดาวน์โหลดโพสต์ได้วันละหนึ่งครั้งเท่านั้น กรุณาลองใหม่พรุ่งนี้" new_private_message: "สร้างข้อความส่วนตัวใหม่" private_message: "ข้อความส่วนตัว" private_messages: "ข้อความ" @@ -450,17 +642,28 @@ th: read: "อ่าน" unread: "ยังไม่อ่าน" ignore_duration_username: "ชื่อผู้ใช้" + ignore_duration_when: "ช่วงเวลา:" + ignore_duration_save: "ไม่สนใจ" + add_ignored_user: "เพิ่ม..." mute_option: "ปิด" + mute_option_title: "คุณจะไม่ได้รับการแจ้งเตือนใดๆที่เกี่ยวกับผู้ใช้นี้" normal_option: "ปกติ" + normal_option_title: "คุณจะได้รับการแจ้งเตือนเมื่อผู้ใช้นี้ตอบคุณ อ้างอิงถึงคุณ หรือกล่าวถึงคุณ" activity_stream: "กิจกรรม" preferences: "การตั้งค่า" feature_topic_on_profile: + open_search: "เลือกกระทู้ใหม่" + title: "เลือกกระทู้" + search_label: "ค้นหากระทู้โดยหัวข้อ" save: "บันทึก" clear: title: "ล้าง" + use_current_timezone: "ใช้เขตเวลาปัจจุบัน" + profile_hidden: "โปรไฟล์สาธารณะของผู้ใช้นี้ถูกซ่อนอยู่" expand_profile: "ขยาย" bookmarks: "บุ๊กมาร์ก" bio: "เกี่ยวกับฉัน" + timezone: "เขตเวลา" invited_by: "เชิญชวนโดย" trust_level: "ระดับความถูกต้อง" notifications: "การแจ้งเตือน" @@ -476,6 +679,8 @@ th: dismiss: "ซ่อน" dismiss_notifications: "ซ่อนทั้งหมด" dismiss_notifications_tooltip: "ทำเครื่องหมายอ่านบนการแจ้งเตือนที่ยังไม่ได้อ่านทั้งหมด" + first_notification: "การแจ้งเตือนแรกของคุณ! กดเลือกเพื่อเริ่มต้น" + allow_private_messages: "อนุญาตให้ผู้ใช้อื่นส่งข้อความส่วนตัวหาฉัน" external_links_in_new_tab: "เปิดลิงก์ภายนอกทั้งหมดในแท็บใหม่" enable_quoting: "เปิดการตอบกลับการอ้างอิงโดยไฮไลท์ข้อความ" change: "เปลี่ยนแปลง" @@ -484,6 +689,7 @@ th: moderator_tooltip: "ผู้ใช้นี้เป็นผู้ดูแลระบบ" admin_tooltip: "ผู้ใช้นี้เป็นแอดมิน" suspended_notice: "ผู้ใช้นี้ถูกระงับจนถึง %{date}" + suspended_permanently: "ผู้ใช้นี้ถูกระงับชั่วคราว" suspended_reason: "เหตุผล:" github_profile: "Github" email_activity_summary: "สรุปกิจกรรม" @@ -494,6 +700,7 @@ th: การตั้งค่านี้จะเปลี่ยนแปลงการสรุปกิจกรรม
กระทู้และหมวดที่ปิดการแจ้งเตือนจะไม่ถูกรวมอยู่ในอีเมลเหล่านี้ individual: "ส่งอีเมลทุกครั้งที่มีโพสต์ใหม่" + individual_no_echo: "ส่งอีเมลทุกครั้งที่มีโพสต์ใหม่ ยกเว้นของตัวฉันเอง" many_per_day: "ส่งอีเมลหาฉันทุกๆโพสต์ใหม่ (ประมาณ %{dailyEmailEstimate} ต่อวัน)" few_per_day: "ส่งอีเมลหาฉันทุกๆโพสต์ใหม่ (ประมาณ 2 ต่อวัน)" tag_settings: "แท็ก" @@ -514,12 +721,18 @@ th: muted_users: "ปิดการแจ้งเตือน" tracked_topics_link: "แสดง" automatically_unpin_topics: "ยกเลิกปักหมุดกระทู้อัตโนมัติเมื่อถึงท้ายหน้า" + apps: "แอป" + api_approved: "อนุมัติแล้ว:" + api_last_used_at: "ใช้ครั้งสุดท้ายเมื่อ:" + theme: "ธีม" + save_to_change_theme: 'ธีมจะถูกอัปเดตเมื่อคุณคลิก "%{save_text}"' staff_counters: flags_given: "ธงที่เป็นประโยชน์" flagged_posts: "โพสต์ที่ปักธง" deleted_posts: "โพสต์ที่ลบ" suspensions: "ระงับการใช้งาน" warnings_received: "คำเตือน" + rejected_posts: "โพสต์ที่ถูกปฏิเสธ" messages: all: "ทั้งหมด" inbox: "กล่องจดหมายเข้า" @@ -528,17 +741,19 @@ th: groups: "กลุ่มของฉัน" bulk_select: "เลือกข้อความ" move_to_inbox: "ย้ายไปกล่องขาเข้า" - move_to_archive: "เก็บ" + move_to_archive: "เก็บเข้าคลัง" failed_to_move: "เกิดความผิดพลาดในการย้ายข้อความที่เลือก (เครือข่ายของคุณอาจล่ม)" select_all: "เลือกทั้งหมด" tags: "แท็ก" preferences_nav: + account: "บัญชี" profile: "โปรไฟล์" emails: "อีเมล" notifications: "การแจ้งเตือน" categories: "หมวดหมู่" users: "ผู้ใช้" tags: "แท็ก" + apps: "แอป" change_password: success: "(อีเมลถูกส่งแล้ว)" in_progress: "(กำลังส่งอีเมล)" @@ -551,26 +766,36 @@ th: disable: "ปิดใช้งาน" enable: "เปิดใช้งาน" second_factor: + forgot_password: "ลืมรหัสผ่านใช่ไหม" + confirm_password_description: "กรุณายืนยันรหัสผ่านเพื่อดำเนินการต่อ" name: "ชื่อ" disable: "ปิดใช้งาน" save: "บันทึก" edit: "แก้ไข" security_key: + register: "ลงทะเบียน" save: "บันทึก" change_about: title: "เปลี่ยนข้อมูลเกี่ยวกับฉัน" error: "เกิดความผิดพลาดในการแก้ไขค่านี้" change_username: title: "เปลี่ยนชื่อผู้ใช้" + confirm: "คุณแน่ใจจริงๆหรือว่าต้องการเปลี่ยนชื่อผู้ใช้ของคุณ" taken: "ขออภัย มีผู้ใช้ชื่อนี้แล้ว" invalid: "ชื่อผู้ใช้ไม่ถูกต้อง จะต้องมีเพียงแค่ตัวอักษรและตัวเลขเท่านั้น" + add_email: + title: "เพิ่มอีเมล" + add: "เพิ่ม" change_email: title: "เปลี่ยนอีเมล" taken: "ขออภัย อีเมลไม่ถูกต้อง" error: "มีข้อผิดพลาดในการเปลี่ยนอีเมล บางทีอีเมลนี้อาจถูกใช้งานแล้ว" success: "เราส่งอีเมลไปยังที่อยู่อีเมลดังกล่าวแล้ว กรุณาทำตามขั้นตอนยืนยัน" + success_staff: "เราส่งอีเมลไปยังที่อยู่อีเมลปัจจุบันแล้ว กรุณาทำตามขั้นตอนยืนยัน" change_avatar: title: "เปลี่ยนรูปโปรไฟล์ของคุณ" + gravatar_failed: "คุณไม่สามารถค้นหา%{gravatarName}ด้วยที่อยู่อีเมลนั้น" + refresh_gravatar_title: "รีเฟรช%{gravatarName}ของคุณ" letter_based: "รูปโพรไฟล์ที่ระบบทำให้อัตโนมัติ" uploaded_avatar: "รูปกำหนดเอง" uploaded_avatar_empty: "เพิ่มรูปกำหนดเอง" @@ -581,20 +806,35 @@ th: instructions: "รูปพื้นหลังจะถูกจัดให้อยู่ตรงกลางและมีความกว้างมาตรฐานที่ 590px" email: title: "อีเมล" + primary: "อีเมลหลัก" + secondary: "อีเมลสำรอง" + primary_label: "หลัก" + unconfirmed_label: "ไม่ได้ยืนยัน" + resend_label: "ส่งอีเมลยืนยันตัวตนอีกครั้ง" + resending_label: "กำลังส่ง..." + resent_label: "อีเมลถูกส่งแล้ว" + update_email: "เปลี่ยนอีเมล" + set_primary: "ตั้งอีเมลหลัก" + destroy: "ลบอีเมล" instructions: "ไม่แสดงเป็นสาธารณะ" ok: "เราจะส่งอีเมลไปหาคุณเพื่อยืนยัน" + required: "กรุณากรอกที่อยู่อีเมล" invalid: "กรุณาใส่อีเมลที่ถูกต้อง" authenticated: "อีเมลของคุณได้รับการยืนยันโดย %{provider}" frequency_immediately: "เราจะอีเมลถึงคุณทันทีหากคุณยังไม่ได้อ่านสิ่งที่เราอีเมลหาคุณ" frequency: other: "เราจะอีเมลหาคุณเฉพาะตอนที่ไม่ได้เห็นคุณเป็นเวลา %{count} นาที" associated_accounts: + connect: "เชื่อมต่อ" revoke: "เอาออก" cancel: "ยกเลิก" + not_connected: "(ไม่เชื่อมต่อ)" + confirm_modal_title: "เชื่อมต่อ%{provider}บัญชี" name: title: "ชื่อ" instructions: "ชื่อเต็มของคุณ (ไม่บังคับ)" instructions_required: "ชื่อเต็มของคุณ" + required: "กรุณากรอกชื่อ" too_short: "ชื่อของคุณสั้นไป" ok: "ชื่อของคุณเหมาะสม" username: @@ -603,19 +843,33 @@ th: short_instructions: "ผู้คนสามารถกล่าวถึงคุณโดย @%{username}" available: "ชื่อผู้ใช้ของคุณสามารถใช้ได้" not_available: "ใช้งานไม่ได้ กรุณาลอง%{suggestion}" + not_available_no_suggestion: "ถูกใช้แล้ว" too_short: "ชื่อผู้ใช้สั้นไป" too_long: "ชื่อผู้ใช้ยาวไป" checking: "กำลังตรวจสอบชื่อผู้ใช้" prefilled: "อีเมลตรงกับชื่อผู้ใช้ที่ลงทะเบียนนี้" + required: "กรุณากรอกชื่อผู้ใช้" locale: title: "ภาษา" instructions: "ภาษา จะเปลี่ยนเมื่อคุณรีเฟรชหน้า" default: "(ค่าเริ่มต้น)" + any: "ใดๆ" password_confirmation: title: "ยืนยันรหัสผ่าน" auth_tokens: + title: "อุปกรณ์ที่ถูกใช้เร็วๆนี้" ip: "ไอพี" details: "รายละเอียด" + log_out_all: "ออกจากระบบทั้งหมด" + active: "ใช้งานอยู่ตอนนี้" + not_you: "ไม่ใช่คุณใช่ไหม" + show_all: "แสดงทั้งหมด (%{count})" + show_few: "แสดงน้อยลง" + was_this_you: "ใช่คุณหรือไม่" + was_this_you_description: "ถ้าไม่ใช่คุณ เราแนะนำให้เปลี่ยนรหัสผ่านและออกจากระบบทุกเครื่อง" + browser_and_device: "%{browser}บน%{device}" + secure_account: "ตั้งค่าความปลอดภัยบัญชีของฉัน" + latest_post: "คุณโพสต์ครั้งล่าสุด..." last_posted: "โพสต์ล่าสุด" last_emailed: "อีเมลล่าสุด" last_seen: "ดูแล้ว" @@ -625,7 +879,13 @@ th: website: "เว็บไซต์" email_settings: "อีเมล" text_size: + title: "ขนาดข้อความ" + smaller: "เล็กลง" normal: "ปกติ" + larger: "ใหญ่ขึ้น" + largest: "ใหญ่ที่สุด" + title_count_mode: + notifications: "การแจ้งเตือนใหม่" like_notification_frequency: title: "แจ้งเตือนเมื่อมีคนกดถูกใจ" always: "เสมอ" @@ -638,6 +898,7 @@ th: always: "เสมอ" never: "ไม่เคย" email_digests: + title: "เมื่อฉันไม่ได้เยี่ยมชมเว็บไซต์ ให้ส่งอีเมลสรุปกระทู้ยอดนิยมและการตอบกลับ" every_30_minutes: "ทุก 30 นาที" every_hour: "ทุกชั่วโมง" daily: "ทุกวัน" @@ -649,7 +910,7 @@ th: always: "เสมอ" never: "ไม่เคย" email_messages_level: "ส่งอีเมลหาฉันเมื่อมีคนส่งข้อความส่วนตัวมาหาฉัน" - include_tl0_in_digests: "รวมถึงเนื้อหาจากผู้ใช้ใหม่ในอีเมลสรุป" + include_tl0_in_digests: "รวมเนื้อหาจากผู้ใช้ใหม่ในอีเมลสรุป" email_in_reply_to: "เพิ่มการตอบในโพสท์ที่คัดกรองแล้วในอีเมล" other_settings: "อื่นๆ" categories_settings: "หมวดหมู่" @@ -673,16 +934,18 @@ th: after_5_minutes: "หลังจาก 5 นาที" after_10_minutes: "หลังจาก 10 นาที" invited: - search: "พิมพ์เพื่อค้นหาการเชิญ..." + search: "พิมพ์เพื่อค้นหาคำเชิญ..." title: "เชิญชวน" user: "เชิญชวนผู้ใช้แล้ว" + sent: "ส่งล่าสุด" + none: "ไม่มีคำเชิญที่จะแสดง" truncated: other: "กำลังแสดงคำเชิญ %{count} รายการแรก" redeemed: "ยืนยันการเชิญชวน" redeemed_tab: "ยืนยัน" redeemed_tab_with_count: "ยืนยันแล้ว (%{count})" redeemed_at: "ยืนยัน" - pending: "รอการเชิญ" + pending: "คำเชิญที่กำลังรอการพิจารณา" pending_tab: "กำลังรอ" pending_tab_with_count: "กำลังรอ (%{count})" topics_entered: "กระทู้ที่ดูแล้ว" @@ -690,21 +953,34 @@ th: expired: "การเชิญชวนนี้หมดอายุแล้ว" rescind: "ลบ" rescinded: "การเชิญชวนถูกลบออก" + rescind_all: "ลบคำเชิญที่หมดอายุ" + rescinded_all: "คำเชิญที่หมดอายุทั้งหมดถูกลบแล้ว!" + rescind_all_confirm: "คุณแน่ใจหรือว่าต้องการลบคำเชิญที่หมดอายุทั้งหมด" reinvite: "ส่งการเชิญชวนอีกครั้ง" reinvite_all: "ส่งการเชิญชวนทั้งหมดอีกครั้ง" + reinvite_all_confirm: "คุณแน่ใจหรือว่าต้องการส่งคำเชิญทั้งหมดอีกครั้ง" reinvited: "การเชิญชวนถูกส่งอีกครั้งแล้ว" reinvited_all: "การเชิญชวนทั้งหมดถูกส่งอีกครั้งแล้ว" time_read: "เวลาอ่าน" days_visited: "วันที่เข้าชม" account_age_days: "อายุบัญชีผู้ใช้ในหน่วยวัน" + source: "ถูกเชิญโดย" links_tab: "ลิงก์" + links_tab_with_count: "ลิงก์ (%{count})" + link_url: "ลิงก์" link_created_at: "สร้างเมื่อ" link_groups: กลุ่ม + link_expires_at: หมดอายุ create: "ส่งคำเชิญ" + copy_link: "คัดลอกลิงก์" generate_link: "คัดลอกลิงก์การเชิญชวน" link_generated: "สร้างลิงก์การเชิญชวนสำเร็จแล้ว!" + valid_for: "ลิงก์คำเชิญใช้งานได้กับที่อยู่อีเมลนี้เท่านั้น: %{email}" invite_link: - success: "สร้างลิงก์การเชิญชวนสำเร็จแล้ว!" + title: "ลิงก์คำเชิญ" + success: "สร้างลิงก์คำเชิญสำเร็จแล้ว!" + max_redemptions_allowed_label: "มีกี่คนที่ได้รับอนุญาตให้ลงทะเบียนใช้ลิงก์นี้" + expires_at: "ลิงก์คำเชิญนี้จะหมดอายุเมื่อไร" bulk_invite: success: "ไฟล์ถูกอัปโหลดเรียบร้อยแล้ว คุณจะได้รับการแจ้งเตือนทางข้อความเมื่อขั้นตอนเสร็จสิ้น" password: @@ -714,14 +990,21 @@ th: same_as_username: "รหัสผ่านเหมือนกับชื่อผู้ใช้ของคุณ" same_as_email: "รหัสผ่านเหมือนกับอีเมลของคุณ" ok: "รหัสผ่านของคุณเหมาะสม" + instructions: "อย่างน้อย %{count} ตัวอักษร" + required: "กรุณากรอกรหัสผ่าน" summary: - title: "ภาพรวม" + title: "สรุปภาพรวม" stats: "สถิติ" time_read: "เวลาอ่าน" + recent_time_read: "เวลาอ่านเมื่อไม่นานมานี้" topic_count: other: "กระทู้ถูกสร้าง" post_count: other: "โพสต์ถูกสร้าง" + likes_given: + other: "ให้แล้ว" + likes_received: + other: "ได้รับแล้ว" days_visited: other: "วันที่เข้าชม" posts_read: @@ -738,11 +1021,12 @@ th: no_badges: "ยังไม่มีเหรียญ" more_badges: "เหรียญอื่น" top_links: "ลิงก์ยอดนิยม" - no_links: "ยังไม่มีลิงก์เลย" - most_liked_by: "ถูกชอบมากที่สุดโดย" - most_liked_users: "ถูกชอบมากที่สุด" + no_links: "ยังไม่มีลิงก์" + most_liked_by: "ถูกใจมากที่สุดโดย" + most_liked_users: "ไลค์มากที่สุด" most_replied_to_users: "ถูกตอบมากที่สุด" - no_likes: "ยังไม่มีใครชอบเลย" + no_likes: "ยังไม่มีใครถูกใจ" + top_categories: "หมวดหมู่ยอดนิยม" topics: "หัวข้อ" replies: "ตอบ" ip_address: @@ -750,8 +1034,8 @@ th: registration_ip_address: title: "ไอพีที่ลงทะเบียน" avatar: - title: "ภาพแทนตัว" - header_title: "ข้อมูลส่วนตัว,ข้อความ,บุ๊คมาร์คและการตั้งค่า" + title: "รูปโปรไฟล์" + header_title: "โปรไฟล์ ข้อความ บุ๊กมาร์ก และการตั้งค่า" title: title: "ชื่อเรื่อง" none: "(ไม่มี)" @@ -773,14 +1057,14 @@ th: server: "เซิร์ฟเวอร์มีปัญหา" forbidden: "การเข้าถึงถูกปฏิเสธ" unknown: "ผิดพลาด" - not_found: "ไม่หน้าดังกล่าว" + not_found: "ไม่พบหน้าดังกล่าว" desc: network: "โปรดตรวจสอบการเชื่อมต่อของคุณ" - network_fixed: "ดูเหมือนว่ามันจะกลับมา" - server: "รหัสข้อผิดพลาด: %{status}" - forbidden: "คุณไม่ได้รับอนุญาคิให้ดูมัน" - not_found: "อ๊ะ, ระบบพยายามโหลดหน้าที่ไม่มีอยู่" - unknown: "มีบางอย่างผิดปกติไป" + network_fixed: "ดูเหมือนว่ามันจะกลับมาแล้ว" + server: "รหัสที่ผิดพลาด: %{status}" + forbidden: "คุณไม่ได้รับอนุญาตให้ชม" + not_found: "อุ๊ปส์! ระบบพยายามโหลดหน้าที่ไม่มีอยู่" + unknown: "มีบางอย่างผิดปกติ" buttons: back: "ย้อนกลับ" again: "ลองอีกครั้ง" @@ -788,48 +1072,57 @@ th: modal: close: "ปิด" close: "ปิด" - assets_changed_confirm: "เว็บนี้พึ่งได้รับการอัปเดต รีเฟรชเพื่อเข้าหน้าเว็บล่าสุด?" + assets_changed_confirm: "เว็บไซต์นี้พึ่งอัปเดต รีเฟรชตอนนี้เพื่อใช้เวอร์ชันล่าสุด" logout: "คุณได้ออกจากระบบ" refresh: "รีเฟรช" + home: "หน้าแรก" read_only_mode: - enabled: "หน้าเว็บนี้อยู่ในสถานะอ่านเท่านั้น คุณสามารถดูได้แต่การตอบ ชอบ หรือการกระทำอื่นๆถูกปิดอยู่ในขณะนี้" - login_disabled: "การลงชื่อเข้าใช้จะไม่สามารถใช้งานได้เมื่อเว็บนี้ถูกตั้งเป็นรูปแบบอ่านอย่างเดียว" - logout_disabled: "การออกจากระบบนั้นไม่สามารถทำได้ในเวลาที่เว็บนั้นอยู่ในโหมด read only" + enabled: "เว็บไซต์นี้อยู่ในโหมดอ่านเท่านั้น คุณสามารถดูได้แต่การตอบ ถูกใจ และอื่นๆถูกปิดอยู่ในขณะนี้" + login_disabled: "การลงชื่อเข้าใช้จะไม่สามารถใช้งานได้เมื่อเว็บไซต์อยู่ในโหมดอ่านเท่านั้น" + logout_disabled: "การออกจากระบบจะไม่สามารถใช้งานได้เมื่อเว็บไซต์อยู่ในโหมดอ่านเท่านั้น" learn_more: "เรียนรู้เพิ่มเติม..." + all_time: "ทั้งหมด" + all_time_desc: "กระทู้ทั้งหมดถูกสร้าง" year: "ปี" - year_desc: "กระทู้ที่ถูกตั้งเมื่อ365 วันที่ผ่านมา" + year_desc: "กระทู้ที่ถูกสร้างใน 365 วันที่ผ่านมา" month: "เดือน" - month_desc: "กระทู้ที่ถูกตั้งเมื่อ 30 วันที่ผ่านมา" + month_desc: "กระทู้ที่ถูกสร้างใน 30 วันที่ผ่านมา" week: "สัปดาห์" - week_desc: "กระทู้ที่ถูกตั้งในรอบ 7 วันที่ผ่านมา" + week_desc: "กระทู้ที่ถูกสร้างใน 7 วันที่ผ่านมา" day: "วัน" - first_post: โพสแรก + first_post: โพสต์แรก mute: ปิดเสียง unmute: เลิกปิดเสียง + last_post: โพสต์แล้ว + local_time: "เวลาท้องถิ่น" time_read: อ่าน + time_read_recently: "%{time_read}ไม่นานมานี้" last_reply_lowercase: การตอบล่าสุด replies_lowercase: other: ตอบ signup_cta: - sign_up: "สมัคร" - hide_session: "แจ้งเตือนฉันอีกทีพรุ่งนี้" + sign_up: "สมัครสมาชิก" + hide_session: "เตือนฉันพรุ่งนี้" hide_forever: "ไม่เป็นไร" - hidden_for_session: "โอเค ฉันจะถามคุณอีกทีพรุ่งนี้ คุณสามารถใช้เมนู เข้าสู่ระบบ เพื่อสร้างบัญชีได้เหมือนกันนะ" + hidden_for_session: "ไม่เป็นไร ฉันจะถามคุณพรุ่งนี้อีกครั้ง คุณสามารถใช้เมนู เข้าสู่ระบบ เพื่อสร้างบัญชีได้เช่นกัน" summary: enabled_description: "คุณกำลังดูสรุปของกระทู้นี้ : นี่คือโพสที่น่าสนใจที่สุดที่หลายๆคนแนะนำ" - description: "ตอบทั้งหมด %{replyCount} ครั้ง" - description_time: "ตอบทั้งหมด %{replyCount} ครั้งโดยมีเวลาการอ่านประมาณ %{readingTime} นาที." + description: "มี %{replyCount} คำตอบ" + description_time: "มี %{replyCount} คำตอบ โดยมีเวลาการอ่านประมาณ %{readingTime} นาที." enable: "สรุปกระทู้นี้" disable: "แสดงโพสต์ทั้งหมด" deleted_filter: enabled_description: "กระทู้นี้ซ่อนโพสต์ที่ถูกลบไปแล้ว" - disabled_description: "ลบโพสต์ที่แสดงทั้งหมดในกระทู้" + disabled_description: "โพสต์ที่ถูกลบแสดงในกระทู้" enable: "ซ่อนโพสต์ที่ถูกลบ" disable: "แสดงโพสต์ที่ถูกลบ" private_message_info: title: "ข้อความ" - remove_allowed_user: "คุณต้องการจะลบ %{name} จากข้อความนี้ใช้หรือไม่" - remove_allowed_group: "คุณต้องการจะลบ %{name} จากข้อความนี้ใช้หรือไม่" + invite: "เชิญผู้อื่น ..." + edit: "เพิ่มหรือลบ ..." + leave_message: "คุณต้องการละทิ้งข้อความนี้จริงๆใช่หรือไม่" + remove_allowed_user: "คุณต้องการลบ %{name} จากข้อความนี้ใช่หรือไม่" + remove_allowed_group: "คุณต้องการลบ %{name} จากข้อความนี้ใช่หรือไม่" email: "อีเมล" username: "ชื่อผู้ใช้" last_seen: "เห็น" @@ -838,75 +1131,138 @@ th: trust_level: "ระดับความน่าไว้ใจ" search_hint: "ชื่อผู้ใช้ อีเมล หรือที่อยู่ไอพี" create_account: + disclaimer: "เมื่อลงทะเบียน คุณได้ยอมรับ นโยบายความเป็นส่วนตัว และ เงื่อนไขการบริการ" title: "สร้างบัญชีใหม่" - failed: "มีบางอย่างผิดพลาด อีเมลนี้อาจจะลงทะเบียนไว้แล้ว หากลืมรหัสให้กดลิงค์ลืมรหัสผ่าน" + failed: "มีบางอย่างผิดพลาด อีเมลนี้อาจถูกลงทะเบียนไว้แล้ว กดลิงก์หากลืมรหัสผ่าน" forgot_password: - title: "ขอรหัสใหม่" + title: "รีเซ็ตรหัสผ่าน" action: "ฉันลืมรหัสผ่าน" - invite: "กรอกชื่อผู้ใช้หรืออีเมลของท่าน, ทางเราจะส่งอีเมลสำหรับรีเซตรหัสผ่านให้" - reset: "รีเซ็ทรหัสผ่าน" - complete_username: "ถ้าบัญชีนี้ตรงกับชื่อผู้ใช้ %{username} คุณควรจะได้รับอีเมลเร็วๆนี้ ในอีเมลจะเป็นขั้นตอนการรีเซตรหัสผ่าน" - complete_email: "ถ้าบัญชีตรงกับ %{email} คุณจะได้รับอีเมลสำหรับขั้นตอนในการรีเซ็ตรหัสผ่านในเร็วๆนี้" - complete_username_not_found: "ไม่มีบัญชีตรงกับชื่อผู้ใช้ %{username}" - complete_email_not_found: "ไม่มีบัญชีตรงกับอีเมล %{email}" + invite: "กรอกชื่อผู้ใช้หรืออีเมลของท่าน เราจะส่งอีเมลสำหรับรีเซ็ตรหัสผ่านให้" + reset: "รีเซ็ตรหัสผ่าน" + complete_username: "ถ้าบัญชีตรงกับชื่อผู้ใช้ %{username} คุณจะได้รับอีเมลเกี่ยวกับขั้นตอนการรีเซ็ตรหัสผ่านในไม่ช้า" + complete_email: "ถ้าบัญชีตรงกับ %{email} คุณจะได้รับอีเมลเกี่ยวกับขั้นตอนการรีเซ็ตรหัสผ่านในไม่ช้า" + complete_username_not_found: "ไม่มีบัญชีที่ตรงกับชื่อผู้ใช้ %{username}" + complete_email_not_found: "ไม่มีบัญชีที่ตรงกับ %{email}" button_ok: "ตกลง" + button_help: "ช่วยเหลือ" email_login: - complete_username_not_found: "ไม่มีบัญชีตรงกับชื่อผู้ใช้ %{username}" - complete_email_not_found: "ไม่มีบัญชีตรงกับอีเมล %{email}" + button_label: "ด้วยอีเมล" + complete_username_not_found: "ไม่มีบัญชีที่ตรงกับชื่อผู้ใช้ %{username}" + complete_email_not_found: "ไม่มีบัญชีที่ตรงกับ %{email}" + confirm_title: "ดำเนินการต่อไปยัง %{site_name}" + logging_in_as: "กำลังเข้าสู่ระบบด้วย %{email}" + confirm_button: เสร็จสิ้นการเข้าสู่ระบบ login: title: "เข้าสู่ระบบ" username: "ชื่อผู้ใช้" password: "รหัสผ่าน" - email_placeholder: "อีเมล์หรือชื่อผู้ใช้" + security_key_alternative: "ลองวิธีอื่น" + email_placeholder: "อีเมลหรือชื่อผู้ใช้" caps_lock_warning: "เปิดแคปล็อคอยู่" error: "ข้อผิดพลาดไม่ทราบสาเหตุ" rate_limit: "กรุณารอสักครู่ก่อนเข้าสู่ระบบอีกครั้ง" + blank_username: "กรุณากรอกอีเมลหรือชื่อผู้ใช้" blank_username_or_password: "กรุณากรอกอีเมลหรือชื่อผู้ใช้ และรหัสผ่าน" - reset_password: "รีเซ็ทรหัสผ่าน" + reset_password: "รีเซ็ตรหัสผ่าน" logging_in: "กำลังลงชื่อเข้าใช้" or: "หรือ" - authenticating: "กำลังตรวจสอบ ..." - awaiting_activation: "บัญชีของคุณกำลังรอการเปิดใช้งาน ใช้ลิงค์ลืมรหัสผ่านถ้าค้องการส่งอีเมลยืนยันตัวตนอีกครั้ง" - awaiting_approval: "บัญชีของคุณยังไม่ได้รับการยืนยันโดยทีมงาน คุณจะได้รับอีเมลแจ้งเมื่อคุณได้รับการยืนยันแล้ว" + authenticating: "กำลังตรวจสอบ..." + awaiting_activation: "บัญชีของคุณกำลังรอการยืนยันตัวตน ใช้ลิงก์ลืมรหัสผ่านหากต้องการส่งอีเมลยืนยันตัวตนอีกครั้ง" + awaiting_approval: "บัญชีของคุณยังไม่ได้รับการยืนยันโดยทีมงาน คุณจะได้รับอีเมลแจ้งเมื่อได้รับการยืนยันแล้ว" requires_invite: "ขออภัย, สามารถเข้าถึงได้เฉพาะผู้ที่ได้รับเชิญเท่านั้น" not_activated: "คุณไม่สามารถเข้าสู่ระบบได้ เราได้ส่งอีเมลยืนยันตัวตนไปหาคุณที่ %{sentTo} กรุณาทำตามขั้นตอนในอีเมลเพื่อยืนยันตัวตนของคุณ" not_allowed_from_ip_address: "คุณไม่สามารถเข้าสู่ระบบด้วยไอพีนี้ได้" - admin_not_allowed_from_ip_address: "คุณไม่สามารถเข้าสู่ระบบด้วยผู้ดูแลระบบด้วยไอพีนี้" - resend_activation_email: "คลิกเพื่อส่งอีเมลยืนยันตัวตนอีกครั้ง" + admin_not_allowed_from_ip_address: "คุณไม่สามารถเข้าสู่ระบบในสถานะแอดมินด้วยไอพีนี้ได้" + resend_activation_email: "คลิกที่นี่เพื่อส่งอีเมลยืนยันตัวตนอีกครั้ง" + resend_title: "ส่งอีเมลยืนยันตัวตนอีกครั้ง" + change_email: "เปลี่ยนที่อยู่อีเมล" + provide_new_email: "กรอกที่อยู่อีเมลใหม่ แล้วเราจะส่งอีเมลยืนยันตัวตนอีกครั้ง" + submit_new_email: "อัปเดตที่อยู่อีเมล" sent_activation_email_again: "เราส่งอีเมลยืนยันตัวตนใหม่ไปให้คุณที่ %{currentEmail} กรุณารอสักครู่และตรวจสอบในถังขยะอีเมลของคุณ" - to_continue: "โปรดเข้าสู่ระบบ" - preferences: "คุณจำเป็นต้องเข้าสู่ระบบจึงจะสามารถเปลี่ยนการตั้งค่าส่วนตัวของคุณได้" + sent_activation_email_again_generic: "เราส่งอีเมลยืนยันตัวตนใหม่ไปแล้ว กรุณารอสักครู่และตรวจสอบในถังขยะอีเมลของคุณ" + to_continue: "กรุณาเข้าสู่ระบบ" + preferences: "คุณจำเป็นต้องเข้าสู่ระบบเพื่อเปลี่ยนการตั้งค่าผู้ใช้ของคุณได้" forgot: "ฉันจำรายละเอียดบัญชีของตัวเองไม่ได้" + not_approved: "บัญชีของคุณยังไม่ได้รับการยืนยัน คุณจะได้รับการแจ้งเตือนทางอีเมลเมื่อคุณสามารถเข้าสู่ระบบได้" google_oauth2: - name: "กูเกิ้ล" - title: "ด้วย Google" + name: "กูเกิล" + title: "ด้วยกูเกิล" twitter: name: "ทวิตเตอร์" - title: "ด้วย Twitter" + title: "ด้วยทวิตเตอร์" instagram: - title: "ด้วย Instragram" + name: "อินสตาแกรม" + title: "ด้วยอินสตาแกรม" facebook: - title: "ด้วย Facebook" + name: "เฟซบุ๊ก" + title: "ด้วยเฟซบุ๊ก" github: - title: "ด้วย GitHub" + name: "กิตฮับ" + title: "ด้วยกิตฮับ" invites: + accept_title: "คำเชิญ" + welcome_to: "ยินดีต้อนรับสู่ %{site_name}!" + invited_by: "คุณถูกเชิญโดย:" + your_email: "ที่อยู่อีเมลบัญชีของคุณคือ %{email}" + accept_invite: "ยอมรับคำเชิญ" + success: "บัญชีของคุณถูกสร้าง คุณได้เข้าสู่ระบบแล้ว" name_label: "ชื่อ" password_label: "ตั้งรหัสผ่าน" + optional_description: "(ทางเลือก)" + password_reset: + continue: "ดำเนินการต่อไปยัง %{site_name}" emoji_set: - apple_international: "แอปเปิ้ล/นานาชาติ" - google: "กูเกิ้ล" + apple_international: "แอปเปิล/นานาชาติ" + google: "กูเกิล" twitter: "ทวิตเตอร์" + win10: "Win10" + google_classic: "Google Classic" + facebook_messenger: "Facebook Messenger" + category_page_style: + categories_only: "หมวดหมู่เท่านั้น" + categories_and_latest_topics: "หมวดหมู่และกระทู้ล่าสุด" + categories_and_top_topics: "หมวดหมู่และกระทู้ยอดนิยม" shortcut_modifier_key: shift: "Shift" ctrl: "Ctrl" alt: "Alt" conditional_loading_section: loading: กำลังโหลด... + category_row: + topic_count: "%{count}กระทู้ในหมวดหมู่นี้" + select_kit: + default_header_text: เลือก... + filter_placeholder: ค้นหา... + filter_placeholder_with_any: ค้นหาหรือสร้าง... + create: "สร้าง: '%{content}'" + invalid_selection_length: "การเลือกต้องมีอย่างน้อย %{count} ตัวอักษร" date_time_picker: from: จาก to: ถึง emoji_picker: + filter_placeholder: ค้นหาอีโมจิ + smileys_&_emotion: ยิ้มและอารมณ์ + people_&_body: ผู้คนและร่างกาย + animals_&_nature: สัตว์และธรรมชาติ + food_&_drink: อาหารและเครื่องดื่ม + travel_&_places: ท่องเที่ยวและสถานที่ + activities: กิจกรรม + objects: วัตถุ + symbols: สัญลักษณ์ flags: ธง + recent: ใช่เมื่อไม่นานมานี้ + default_tone: ไม่มีโทนผิว + light_tone: โทนผิวอ่อน + medium_light_tone: โทนผิวอ่อนปานกลาง + medium_tone: โทนผิวปานกลาง + medium_dark_tone: โทนผิวเข้มปานกลาง + dark_tone: โทนผิวเข้ม + shared_drafts: + title: "แบบร่างที่ถูกแบ่งปัน" + notice: "กระทู้นี้แสดงให้ผู้ที่สามารถเห็นหมวดหมู่ %{category} เท่านั้น" + publish: "เผยแพร่แบบร่างที่ถูกแบ่งปัน" + confirm_publish: "คุณแน่ใจหรือว่าต้องการเผยแพร่แบบร่างนี้" + publishing: "กำลังเผยแพร่กระทู้..." composer: emoji: "อีโมจิ :)" more_emoji: "อื่นๆ..." @@ -915,16 +1271,20 @@ th: blockquote_text: "ส่วนอ้างถึง" add_warning: "นี่คือคำเตือนอย่างเป็นทางการ" toggle_whisper: "เปิดกระซิบ" - posting_not_on_topic: "กระทู้ไหนที่คุณต้องการตอบ?" + posting_not_on_topic: "กระทู้ไหนที่คุณต้องการตอบ" saved_local_draft_tip: "บันทึกบนอุปกรณ์" - similar_topics: "กระทู้ของคุณ ใกล้เคียงกับ ..." - drafts_offline: "ร่างออฟไลน์" + similar_topics: "กระทู้ของคุณใกล้เคียงกับ..." + drafts_offline: "แบบร่างออฟไลน์" + reference_topic_title: "ตอบกลับ: %{title}" error: title_missing: "ต้องมีชื่อเรื่อง" title_too_short: "ชื่อเรื่องต้องมีอย่างน้อย %{min} ตัวอักษร" title_too_long: "ชื่อเรื่องต้องไม่ยาวเกิน %{max} ตัวอักษร" - post_length: "โพสต้องมีอย่างน้อย %{min} ตัวอักษร" + post_missing: "โพสต์ไม่สามารถว่างได้" + post_length: "โพสต์ต้องมีอย่างน้อย %{min} ตัวอักษร" + try_like: "คุณได้ลองปุ่ม %{heart} แล้วหรือยัง" category_missing: "คุณต้องเลือกหมวดหมู่" + tags_missing: "คุณต้องเลือกอย่างน้อย %{count} แท็ก" save_edit: "บันทึกการแก้ไข" reply_original: "ตอบบนกระทู้ต้นฉบับ" reply_here: "ตอบที่นี่" @@ -935,27 +1295,35 @@ th: title: "หรือกด Ctrl+Enter" users_placeholder: "เพิ่มผู้ใช้" title_placeholder: "บทสนทนานี้เกี่ยวกับอะไร ขอสั้นๆ 1 ประโยค" - edit_reason_placeholder: "ทำไมคุณถึงแก้ไข?" + title_or_link_placeholder: "พิมพ์หัวข้อ หรือวางลิงก์ที่นี่" + edit_reason_placeholder: "ทำไมคุณถึงแก้ไข" + topic_featured_link_placeholder: "กรอกลิงก์ที่แสดงหัวข้อ" + remove_featured_link: "ลบลิงก์ออกจากกระทู้" reply_placeholder: "พิมพ์ที่นี่. ใช้ Markdown, BBCode หรือ HTML เพื่อจัดรูปแบบ สามารถลากหรือวางรูปภาพได้" + reply_placeholder_choose_category: "เลือกหมวดหมู่ก่อนพิมพ์ที่นี่" view_new_post: "ดูโพสต์ใหม่ของคุณ" saving: "กำลังบันทึก" saved: "บันทึกแล้ว!" uploading: "กำลังอัปโหลด..." show_preview: "แสดงตัวอย่าง »" hide_preview: "» ซ่อนตัวอย่าง" - quote_post_title: "อ้างถึงโพสทั้งหมด" + quote_post_title: "อ้างถึงโพสต์ทั้งหมด" + bold_label: "หนา" bold_title: "หนา" bold_text: "ตัวอักษรหนา" - italic_title: "ความสำคัญ" - italic_text: "ข้อความสำคัญ" + italic_label: "เอียง" + italic_title: "เอียง" + italic_text: "ตัวอักษรเอียง" link_title: "ลิงค์" - link_description: "กรอกรายละเอียดลิงค์ที่นี่" + link_description: "กรอกรายละเอียดลิงก์ที่นี่" link_dialog_title: "เพิ่มลิงค์" link_optional_text: "ชื่อเรื่องเพิ่มเติม" + link_url_placeholder: "วาง URL หรือพิมพ์เพื่อค้นหากระทู้" quote_title: "ส่วนอ้างถึง" quote_text: "ส่วนอ้างถึง" code_title: "ข้อความก่อนจัดรูปแบบ" code_text: "ข้อความก่อนจัดรูปแบบเยื้อง 4 เคาะ" + paste_code_text: "พิมพ์หรือวางโค้ดที่นี่" upload_title: "อัปโหลด" upload_description: "กรอกรายละเอียดการอัปโหลดที่นี่" olist_title: "รายการลำดับ" @@ -964,119 +1332,240 @@ th: help: "ช่วยเหลือการจัดรูปแบบ" modal_ok: "ตกลง" modal_cancel: "ยกเลิก" - cant_send_pm: "ขอโทษด้วย คุณไม่สามารถส่งข้อความหา %{username} ได้" + cant_send_pm: "ขออภัย คุณไม่สามารถส่งข้อความหา %{username} ได้" + yourself_confirm: + title: "คุณลืมเพิ่มผู้รับหรือไม่" + body: "ตอนนี้ข้อความนี้กำลังถูกส่งไปยังตัวคุณเท่านั้น" admin_options_title: "ตั้งค่าทางเลือกทีมงานสำหรับกระทู้นี้" composer_actions: reply: ตอบ + draft: แบบร่าง edit: แก้ไข + reply_to_post: + label: "ตอบกลับไปยังโพสต์ %{postNumber}โดย %{postUsername}" + reply_as_private_message: + label: ข้อความใหม่ + desc: สร้างข้อความส่วนตัวใหม่ + reply_to_topic: + label: ตอบกลับกระทู้ create_topic: label: "กระทู้ใหม่" + shared_draft: + label: "แบบร่างที่ถูกแบ่งปัน" + desc: "ร่างกระทู้ที่สามารถเห็นแค่ทีมงาน" + toggle_topic_bump: + desc: "ตอบกลับโดยไม่เปลี่ยนวันที่ตอบกลับล่าสุด" notifications: + tooltip: + regular: + other: "%{count} การแจ้งเตือนที่ยังไม่เห็น" + message: + other: "%{count} ข้อความที่ยังไม่ได้อ่าน" title: "การแจ้งเตือนการพูดถึง,การตอบกลับไปยังโพส กระทู้ หรือข้อความส่วนตัว และอื่นๆของ @name " - none: "ไม่สามารถโหลดการแจ้งเตือนในขณะนี้" + none: "ไม่สามารถโหลดการแจ้งเตือนได้ในขณะนี้" + empty: "ไม่พบการแจ้งเตือน" + post_approved: "โพสต์ของคุณได้รับการอนุมัติ" + mentioned: "%{username}%{description}" + group_mentioned: "%{username}%{description}" + quoted: "%{username}%{description}" + bookmark_reminder: "%{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}" + liked_consolidated_description: + other: "ถูกใจ %{count} ครั้งต่อโพสต์ของคุณ" + liked_consolidated: "%{username}%{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}" + topic_reminder: "%{username}%{description}" + watching_first_post: "กระทู้ใหม่%{description}" + membership_request_accepted: "ถูกรับเป็นสมาชิกในกลุ่ม '%{group_name}'" + group_message_summary: + other: "%{count}ข้อความในกล่องขาเข้าของกลุ่ม %{group_name}" popup: - mentioned: '%{username} พูดถึงคุณใน "%{topic}" - %{site_title}' - group_mentioned: '%{username} พูดถึงคุณใน "%{topic}" - %{site_title}' + 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}' + posted: '%{username} โพสต์ใน "%{topic}" - %{site_title}' + private_message: '%{username}ได้ส่งข้อความส่วนตัวไปหาคุณใน "%{topic}"-%{site_title}' linked: '%{username} ลิงค์โพสของคุณจาก "%{topic}" - %{site_title}' + watching_first_post: '%{username}ได้สร้างกระทู้ใหม่ "%{topic}"-%{site_title}' + confirm_title: "เปิดการแจ้งเตือนแล้ว - %{site_title}" + confirm_body: "สำเร็จแล้ว! การแจ้งเตือนถูกเปิดใช้งาน" + custom: "การแจ้งเตือนจาก %{username} บน %{site_title}" titles: - watching_first_post: "สร้างกระทู้" + mentioned: "ได้กล่าวถึง" + replied: "คำตอบใหม่" + quoted: "ถูกอ้างอิงถึง" + edited: "ถูกแก้ไข" + liked: "การถูกใจใหม่" + private_message: "ข้อความส่วนตัวใหม่" + invited_to_private_message: "ถูกเชิญไปยังข้อความส่วนตัว" + invitee_accepted: "คำเชิญถูกยอมรับ" + posted: "โพสต์ใหม่" + invited_to_topic: "ถูกเชิญไปยังกระทู้" + group_message_summary: "ข้อความกลุ่มใหม่" + watching_first_post: "กระทู้ใหม่" + liked_consolidated: "ไลค์ใหม่" + post_approved: "โพสต์ได้รับอนุมัติ" upload_selector: title: "เพิ่มรูปภาพ" title_with_attachments: "เพิ่มรูปภาพหรือไฟล์" - from_my_computer: "จากอุปกรณ์" + 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: "คุณยังสามารถลากหรือวางไฟล์ในช่องแก้ไขโดยตรงได้ด้วย" + remote_tip: "ลิงก์ไปยังรูปภาพ" + remote_tip_with_attachments: "ลิงก์ไปยังรูปภาพหรือไฟล์ %{authorized_extensions}" + local_tip: "เลือกรูปภาพจากอุปกรณ์ของคุณ" + local_tip_with_attachments: "เลือกรูปภาพหรือไฟล์จากอุปกรณ์ของคุณ %{authorized_extensions}" + hint: "(คุณสามารถลากไปวางในช่องแก้ไขเพื่ออัปโหลดได้ด้วย)" + hint_for_supported_browsers: "คุณสามารถลากหรือวางรูปภาพในช่องแก้ไขได้ด้วย" uploading: "กำลังอัปโหลด" select_file: "เลือกไฟล์" + default_image_alt_text: รูปภาพ search: sort_by: "เรียงโดย" relevance: "เกี่ยวข้อง" - latest_post: "โพสล่าสุด" - most_viewed: "ดูเยอะสุด" - most_liked: "ไลค์เยอะสุด" + latest_post: "โพสต์ล่าสุด" + latest_topic: "กระทู้ล่าสุด" + most_viewed: "ดูมากที่สุด" + most_liked: "ถูกใจมากที่สุด" select_all: "เลือกทั้งหมด" clear_all: "ล้างทั้งหมด" - title: "ค้นหากระทู้, โพสต์, ผู้ใช้ หรือ หมวดหมู่" + too_short: "คำค้นหาสั้นเกินไป" + title: "ค้นหากระทู้ โพสต์ ผู้ใช้ หรือหมวดหมู่" + full_page_title: "ค้นหากระทู้หรือโพสต์" no_results: "ไม่มีผลการค้นหา" - no_more_results: "ไม่พบการค้นหาเพิ่มเติมแล้ว" + no_more_results: "ไม่มีผลการค้นหาเพิ่มเติมแล้ว" searching: "กำลังค้นหา..." - post_format: "#%{post_number} ด้วย %{username}" - search_google_button: "กูเกิ้ล" + post_format: "#%{post_number} โดย %{username}" + cant_find: "ไม่พบสิ่งที่คุณค้นหาใช่หรือไม่" + start_new_topic: "ลองเริ่มกระทู้ใหม่ดีไหม" + or_search_google: "หรือลองค้นหาด้วยกูเกิล:" + search_google: "ลองค้นหาด้วยกูเกิล:" + search_google_button: "กูเกิล" + search_google_title: "ค้นหาเว็บไซต์นี้" context: - user: "ค้นหาโพสต์ด้วย @%{username}" + user: "ค้นหาโพสต์โดย @%{username}" category: "ค้นหาหมวด #%{category}" + tag: "ค้นหาแท็ก #%{tag}" topic: "ค้นหากระทู้นี้" private_messages: "ค้นหาข้อความ" advanced: + title: ค้นหาขั้นสูงสุด posted_by: label: โพสต์โดย - hamburger_menu: "ไปยังกระทู้อื่นหรือหมวดหมู่อื่น" + in_category: + label: จัดหมวดหมู่ + in_group: + label: ในกลุ่ม + with_tags: + label: แท็กแล้ว + filters: + likes: ฉันได้ถูกใจ + posted: ฉันได้โพสต์ใน + created: ฉันได้สร้าง + watching: ฉันกำลังดู + tracking: ฉันกำลังติดตาม + private: ในข้อความของฉัน + bookmarks: ฉันได้บุ๊กมาร์ก + first: เป็นโพสต์แรกๆ + pinned: ถูกปักหมุด + seen: ฉันได้อ่าน + unseen: ฉันยังไม่ได้อ่าน + images: พร้อมรูปภาพ + all_tags: แท็กด้านบนทั้งหมด + statuses: + open: เปิด + closed: ปิด + public: เป็นสาธารณะ + archived: ถูกเก็บเข้าคลัง + noreplies: ไม่มีการตอบกลับ + post: + time: + label: โพสต์แล้ว + before: ก่อน + after: หลังจาก + hamburger_menu: "ไปยังรายการกระทู้หรือหมวดหมู่อื่น" new_item: "ใหม่" go_back: "ย้อนกลับ" - not_logged_in_user: "หน้าผู้ใช้สำหรับสรุปกิจกรรมล่าสุดและการปรับแต่ง" - current_user: "ไปยังหน้าผู้ใช้" + not_logged_in_user: "หน้าผู้ใช้พร้อมสรุปกิจกรรมล่าสุดและการตั้งค่า" + current_user: "ไปยังหน้าผู้ใช้ของคุณ" + view_all: "ดูทั้งหมด" topics: + new_messages_marker: "เยี่ยมชมครั้งล่าสุด" bulk: select_all: "เลือกทั้งหมด" clear_all: "ล้างทั้งหมด" unlist_topics: "กระทู้ที่ไม่ได้แสดง" reset_read: "ล้างจำนวนการอ่าน" - delete: "ลบกระทู้นี้" + delete: "ลบกระทู้" dismiss: "ซ่อน" dismiss_read: "ซ่อนทั้งหมดที่ไม่ได้อ่าน" dismiss_button: "ซ่อน..." - dismiss_tooltip: "ซ่อนเฉพาะโพสใหม่หรือหยุดติดตามกระทู้" - also_dismiss_topics: "หยุดติดตามกระทู้เหล่านี้และอย่าแสดงพวกนั้นให้ฉันเห็นเป็นหัวข้อที่ยังไม่ได้อ่านอีก" + dismiss_tooltip: "ซ่อนเฉพาะโพสต์ใหม่หรือหยุดติดตามกระทู้" + also_dismiss_topics: "หยุดติดตามกระทู้เหล่านี้เพื่อไม่ให้แสดงว่าเป็นกระทู้ที่ยังไม่ได้อ่าน" dismiss_new: "ซ่อนใหม่" toggle: "สลับการเลือกกระทู้จำนวนมาก" actions: "การดำเนินการจำนวนมาก" - close_topics: "ลบกระทู้นี้" + change_category: "ตั้งค่าหมวดหมู่" + close_topics: "ปิดกระทู้" archive_topics: "คลังกระทู้" notification_level: "การแจ้งเตือน" - choose_new_category: "เลือกหมวดใหม่ให้กระทู้" + choose_new_category: "เลือกหมวดหมู่ใหม่ให้กระทู้" selected: other: "คุณได้เลือก %{count} กระทู้" + change_tags: "แทนที่แท็ก" + choose_new_tags: "เลือกแท็กใหม่เพื่อกระทู้เหล่านี้:" + changed_tags: "แท็กของกระทู้เหล่านี้ถูกเปลี่ยนแปลง" none: unread: "คุณไม่มีกระทู้ที่ยังไม่ได้อ่าน" new: "คุณไม่มีกระทู้ใหม่" - read: "คุณยังไม่ได้อ่านกระทู้เลย" - posted: "คุณยังไม่ได้โพสในกระทู้ใดๆ" - latest: "ไม่มีกระทู้ล่าสุด น่าเสียใจจริงๆ" - bookmarks: "คุณยังไม่ได้บุ๊คมาร์คกระทู้ใดๆเลย" - category: "ยังไม่ในกระทู้ในหมวด %{category}" - top: "ไม่มีหัวข้อสูงสุดแล้ว" + read: "คุณยังไม่ได้อ่านกระทู้ใดๆเลย" + posted: "คุณยังไม่ได้โพสต์ในกระทู้ใดๆเลย" + latest: "ยังไม่มีกระทู้ล่าสุด น่าเสียใจจริงๆ" + bookmarks: "คุณยังไม่ได้บุ๊กมาร์กกระทู้ใดๆเลย" + category: "ไม่มีกระทู้ในหมวด %{category}" + top: "ไม่มีกระทู้ยอดนิยม" bottom: - latest: "ไม่มีกระทู้ล่าสุด" - posted: "ไม่มีหัวข้อที่โพสแล้ว" - read: "ไม่มีหัวข้อที่อ่านแล้ว" - new: "ไม่มีกระทู้ใหม่" - unread: "ไม่มีหัวข้อที่ยังไม่อ่านแล้ว" - top: "ไม่มีหัวข้อสูงสุดแล้ว" - bookmarks: "ไม่มีบุ๊คมาร์คในหัวข้อใดอีกแล้ว" + latest: "ไม่มีกระทู้ล่าสุดอีกแล้ว" + posted: "ไม่มีกระทู้ที่โพสต์อีกแล้ว" + read: "ไม่มีกระทู้ที่อ่านแล้วอีก" + new: "ไม่มีกระทู้ใหม่อีกแล้ว" + unread: "ไม่มีกระทู้ที่ยังไม่อ่านอีกแล้ว" + category: "ไม่มีกระทู้อื่นอีกใน %{category}" + top: "ไม่มีกระทู้ยอดนิยมอีกแล้ว" + bookmarks: "ไม่มีกระทู้ที่บุ๊กมาร์กอีกแล้ว" topic: filter_to: - other: " %{count} โพสในกระทู้" + other: " %{count} โพสต์ในกระทู้" create: "กระทู้ใหม่" create_long: "สร้างกระทู้ใหม่" - private_message: "สร้างข้อความใหม่" + open_draft: "เปิดแบบร่าง" + private_message: "เริ่มข้อความ" archive_message: - help: "ย้ายข้อความไปกล่องเก็บข้อความ" + help: "ย้ายข้อความไปคลังของคุณ" title: "คลัง" move_to_inbox: title: "ย้ายไปกล่องขาเข้า" - help: "ย้ายข้อความกลับไปกล่องข้อความ" + help: "ย้ายข้อความกลับไปกล่องขาเข้า" edit_message: + help: "แก้ไขโพสต์แรกของข้อความ" title: "แก้ไข" + defer: + help: "ทำเครื่องหมายว่ายังไม่ได้อ่าน" + remove_from_profile: + title: "ลบออกจากโปรไฟล์" list: "กระทู้" - new: "สร้างกระทู้" + new: "กระทู้ใหม่" unread: "ยังไม่ได้อ่าน" new_topics: other: "%{count} กระทู้ใหม่" @@ -1085,62 +1574,138 @@ th: title: "กระทู้" invalid_access: title: "กระทู้นี้เป็นกระทู้ส่วนตัว" - description: "ขออภัยคุณไม่สามารถเข้าถึงกระทู้ที่ต้องการได้!" + description: "ขออภัย คุณไม่สามารถเข้าถึงกระทู้ที่ต้องการได้!" login_required: "คุณจำเป็นต้องเข้าสู่ระบบเพื่อดูกระทู้นี้" server_error: title: "ไม่สามารถโหลดกระทู้ได้" + description: "ขออภัย ไม่สามารถโหลดกระทู้ได้ อาจเป็นเพราะปัญหาการเชื่อมต่อ กรุณาลองใหม่อีกครั้ง หากยังไม่ได้รับการแก้ไข กรุณาติดต่อเรา" not_found: title: "ไม่พบกระทู้" + description: "ขออภัย ไม่สามารถค้นหากระทู้นั้นได้ อาจถูกลบโดยผู้ดูแลระบบ" total_unread_posts: - other: "คุณมี %{count} ความคิดเห็น ที่ยังไม่ได้อ่านในกระทู้นี้" + other: "คุณมี %{count} โพสต์ที่ยังไม่ได้อ่านในกระทู้นี้" unread_posts: - other: "คุณมี %{count} ความคิดเห็นเก่า ที่ยังไม่ได้อ่านในกระทู้นี้" + other: "คุณมี %{count} โพสต์เก่าที่ยังไม่ได้อ่านในกระทู้นี้" + new_posts: + other: "มี %{count}โพสต์ใหม่ในกระทู้นี้ตั้งแต่คุณอ่านครั้งล่าสุด" + likes: + other: "มี %{count}ถูกใจในกระทู้นี้" back_to_list: "กลับไปที่รายชื่อกระทู้" - show_links: "แสดงลิงค์ในกระทู้นี้" - read_more_in_category: "ต้องการจะอ่านเพิ่มเหรอ? ลองดูกระทู้อื่นใน %{catLink} หรือ %{latestLink}" - read_more: "ต้องการจะอ่านเพิ่ม? %{catLink} หรือ %{latestLink}." + options: "ตัวเลือกกระทู้" + show_links: "แสดงลิงก์ในกระทู้นี้" + read_more_in_category: "ต้องการอ่านเพิ่มใช่ไหม ลองดูกระทู้อื่นใน %{catLink} หรือ %{latestLink}" + read_more: "ต้องการอ่านเพิ่มใช่ไหม %{catLink} หรือ %{latestLink}" + group_request: "คุณต้องส่งคำขอเป็นสมาชิกในกลุ่ม `%{name}` เพื่อดูกระทู้นี้" + group_join: "คุณต้องเข้ากลุ่ม `%{name}` เพื่อดูกระทู้นี้" + group_request_sent: "คำขอเป็นสมาชิกกลุ่มของคุณได้ถูกส่งไปแล้ว คุณจะได้รับการแจ้งเตือนเมื่อถูกตอบรับ" + unread_indicator: "ยังไม่มีสมาชิกอ่านโพสต์ล่าสุดของกระทู้นี้" view_latest_topics: ดูกระทู้ล่าสุด - suggest_create_topic: ทำไมไม่สร้างกระทู้ละ - deleted: "หัวข้อถูกลบ" + suggest_create_topic: ทำไมไม่สร้างกระทู้ล่ะ + jump_reply_up: ข้ามไปยังคำตอบก่อนหน้านี้ + jump_reply_down: ข้ามไปยังคำตอบหลังจากนี้ + deleted: "กระทู้ถูกลบ" + topic_status_update: + num_of_hours: "จำนวนชั่วโมง:" + num_of_days: "จำนวนวัน:" + publish_to: "เผยแพร่ไปยัง:" + when: "เมื่อ:" auto_update_input: + now: "ตอนนี้" + later_today: "ภายหลังในวันนี้" tomorrow: "พรุ่งนี้" + later_this_week: "ภายหลังในสัปดาห์นี้" + this_weekend: "สัปดาห์นี้" + next_week: "สัปดาห์หน้า" + two_weeks: "สองสัปดาห์" + next_month: "เดือนหน้า" + two_months: "สองเดือน" + three_months: "สามเดือน" + four_months: "สี่เดือน" + six_months: "หกเดือน" + one_year: "หนึ่งปี" + forever: "ตลอดไป" + pick_date_and_time: "เลือกวันและเวลา" + temp_open: + title: "เปิดชั่วคราว" + auto_reopen: + title: "กระทู้ที่เปิดอัตโนมัติ" + temp_close: + title: "ปิดชั่วคราว" auto_close: + title: "กระทู้ที่ปิดอัตโนมัติ" error: "กรอกค่าที่ถูกต้อง" based_on_last_post: "ไม่ปิดจนกว่าโพสสุดท้ายในกระทู้นี่เก่า" + auto_delete: + title: "กระทู้ที่ลบอัตโนมัติ" + reminder: + title: "เตือนฉัน" + auto_delete_replies: + title: "คำตอบที่ลบอัตโนมัติ" status_update_notice: - auto_close: "กระทู้นี้จะถูกปิดใน %{timeLeft}" - auto_close_based_on_last_post: "กระทู้นี้จะถูกปิด %{duration} หลังจากการตอบสุดท้าย" + auto_open: "กระทู้นี้จะเปิดโดยอัตโนมัติ%{timeLeft}" + auto_close: "กระทู้นี้จะถูกปิดอัตโนมัติใน %{timeLeft}" + auto_close_based_on_last_post: "กระทู้นี้จะถูกปิด %{duration} หลังจากการตอบล่าสุด" + auto_delete: "กระทู้นี้จะลบโดยอัตโนมัติ%{timeLeft}" + auto_reminder: "คุณจะถูกเตือนเกี่ยวกับกระทู้นี้%{timeLeft}" + auto_delete_replies: "คำตอบในกระทู้นี้จะถูกลบโดยอัตโนมัติหลังจาก%{duration}" auto_close_title: "ปิดการตั้งค่าอัตโนมัติ" + auto_close_immediate: + other: "โพสต์ล่าสุดของกระทู้นี้มีอายุ %{count} ชั่วโมงแล้ว กระทู้จะถูกปิดเร็วๆนี้" timeline: back: "กลับ" + back_description: "กลับไปยังโพสต์ล่าสุดที่ยังไม่ได้อ่าน" + replies_short: "%{current} / %{total}" progress: - go_top: "บน" + go_top: "ด้านบน" + go_bottom: "ปุ่ม" + go: "ไป" + jump_bottom: "ข้ามไปยังโพสต์ล่าสุด" + jump_prompt: "ข้ามไปยัง..." + jump_prompt_of: "ของ %{count} โพสต์" + jump_prompt_long: "ข้ามไปยัง..." + jump_bottom_with_number: "ข้ามไปยังโพสต์ %{post_number}" + jump_prompt_to_date: "ไปวันที่" jump_prompt_or: "หรือ" + total: โพสต์ทั้งหมด + current: โพสต์ปัจจุบัน notifications: + title: เปลี่ยนความถี่ในการรับการแจ้งเตือนเกี่ยวกระทู้นี้ reasons: - "3_2": "คุณจะได้รับการแจ้งเตือนเพราะคุณดูกระทู้นี้" - "3_1": "คุณจะได้รับการแจ้งเตือนเพราะคุณสร้างกระทู้นี้" - "3": "คุณจะได้รับการแจ้งเตือนเพราะคุณดูกระทู้นี้" - "1_2": "คุณจะได้รับการแจ้งเตือนเมื่อใครก็ตามเอ่ยชื่อของคุณ @name หรือตอบคุณ" - "1": "คุณจะได้รับการแจ้งเตือนเมื่อใครก็ตามเอ่ยชื่อของคุณ @name หรือตอบคุณ" - "0_2": "คุณไม่ต้องการรับการแจ้งเตือนของกระทู้นี้" - "0": "คุณไม่ต้องการรับการแจ้งเตือนของกระทู้นี้" + "3_10": "คุณจะได้รับการแจ้งเตือนเพราะคุณกำลังดูแท็กในกระทู้นี้" + "3_6": "คุณจะได้รับการแจ้งเตือนเพราะคุณกำลังดูหมวดหมู่นี้" + "3_5": "คุณจะได้รับการแจ้งเตือนเพราะคุณได้เริ่มดูกระทู้นี้อย่างอัตโนมัติ" + "3_2": "คุณจะได้รับการแจ้งเตือนเพราะคุณกำลังดูกระทู้นี้" + "3_1": "คุณจะได้รับการแจ้งเตือนเพราะคุณได้สร้างกระทู้นี้" + "3": "คุณจะได้รับการแจ้งเตือนเพราะคุณกำลังดูกระทู้นี้" + "2_8": "คุณจะเห็นจำนวนคำตอบใหม่เพราะคุณกำลังติดตามหมวดหมู่นี้" + "2_4": "คุณจะเห็นจำนวนคำตอบใหม่เพราะคุณได้โพสต์คำตอบไปยังกระทู้นี้" + "2_2": "คุณจะเห็นจำนวนคำตอบใหม่เพราะคุณกำลังติดตามกระทู้นี้" + "2": 'คุณจะเห็นจำนวนคำตอบใหม่เพราะคุณอ่านกระทู้นี้' + "1_2": "คุณจะได้รับการแจ้งเตือนเมื่อมีคนกล่าวถึงชื่อของคุณ @name หรือตอบคุณ" + "1": "คุณจะได้รับการแจ้งเตือนเมื่อมีคนกล่าวถึงชื่อของคุณ @name หรือตอบคุณ" + "0_2": "คุณไม่ต้องการรับการแจ้งเตือนทั้งหมดจากกระทู้นี้" + "0": "คุณไม่ต้องการรับการแจ้งเตือนทั้งหมดจากกระทู้นี้" watching_pm: title: "กำลังดู" + description: "คุณจะได้รับการแจ้งเตือนของทุกคำตอบใหม่ในข้อความนี้ และจะเห็นจำนวนคำตอบใหม่" watching: title: "กำลังดู" + description: "คุณจะได้รับการแจ้งเตือนของทุกคำตอบใหม่ในกระทู้นี้ และจะเห็นจำนวนคำตอบใหม่" tracking_pm: title: "ติดตาม" + description: "จำนวนคำตอบใหม่จะถูกแสดงสำหรับข้อความนี้ คุณจะได้รับการแจ้งเตือนเมื่อมีคนกล่าวถึงชื่อของคุณ @name หรือตอบคุณ" tracking: title: "ติดตาม" + description: "จำนวนคำตอบใหม่จะถูกแสดงสำหรับกระทู้นี้ คุณจะได้รับการแจ้งเตือนเมื่อมีคนกล่าวถึงชื่อของคุณ @name หรือตอบคุณ" regular: title: "ปกติ" - description: "คุณจะได้รับการแจ้งเตือนเมื่อใครก็ตามเอ่ยชื่อของคุณ @name หรือตอบคุณ" + description: "คุณจะได้รับการแจ้งเตือนเมื่อมีคนกล่าวถึงชื่อของคุณ @name หรือตอบคุณ" regular_pm: title: "ปกติ" - description: "คุณจะได้รับการแจ้งเตือนเมื่อใครก็ตามเอ่ยชื่อของคุณ @name หรือตอบคุณ" + description: "คุณจะได้รับการแจ้งเตือนเมื่อมีคนกล่าวถึงชื่อของคุณ @name หรือตอบคุณ" muted_pm: title: "ปิด" + description: "คุณจะไม่ได้รับการแจ้งเตือนใดๆเกี่ยวกับข้อความนี้" muted: title: "ปิดการแจ้งเตือน" actions: @@ -1149,42 +1714,61 @@ th: delete: "ลบกระทู้" open: "เปิดกระทู้" close: "ปิดกระทู้" - multi_select: "เลือกโพส..." - pin: "ปักหมุดกระทู้" - unpin: "ยกเลิกปักหมุดกระทู้" + multi_select: "เลือกโพสต์..." + pin: "ปักหมุดกระทู้..." + unpin: "เลิกปักหมุดกระทู้" unarchive: "เลิกเก็บกระทู้เข้าคลัง" archive: "เก็บกระทู้เข้าคลัง" invisible: "ทำให้ไม่แสดงในรายชื่อ" visible: "ทำให้แสดงในรายชื่อ" - reset_read: "ล้างข้อมูลวันที่" + reset_read: "ล้างข้อมูลการอ่าน" make_public: "ทำให้กระทู้เป็นสาธารณะ" + make_private: "สร้างข้อความส่วนตัว" feature: pin: "ปักหมุดกระทู้" - unpin: "ยกเลิกปักหมุดกระทู้" + unpin: "เลิกปักหมุดกระทู้" pin_globally: "ปักหมุดกระทู้ทั้งหมด" make_banner: "ป้ายกระทู้" remove_banner: "ยกเลิกป้ายกระทู้" reply: title: "ตอบ" - help: "เริ่มการเขียนตอบกระทู้นี้" + help: "เริ่มเขียนตอบกระทู้นี้" + clear_pin: + title: "ล้างหมุด" share: title: "แบ่งปัน" - help: "แบ่งปันลิงค์ไปยังกระทู้นี้" + extended_title: "แบ่งปันลิงก์" + help: "แบ่งปันลิงก์ไปยังกระทู้นี้" + print: + title: "พิมพ์เอกสาร" flag_topic: title: "ธง" help: "ปังธงกระทู้นี้เพื่อติดตามหรือรับการแจ้งเตือนเกี่ยวกับกระทู้" success_message: "คุณปักธงกระทู้นี้แล้ว" + make_public: + choose_category: "กรุณาเลือกหมวดหมู่สำหรับกระทู้สาธารณะ:" feature_topic: title: "แนะนำกระทู้นี้" - confirm_pin: "ตอนนี้คุณมีกระทู้ที่ปักหมุดทั้งหมด %{count} กระทู้ การมีกระทู้ที่ปักหมุดมากๆจะทำให้ผู้ใช้ใหม่และผู้ใช้ที่ไม่ระบุชื่อรำคาญ คุณแน่ใจจริงๆหรือว่าจะปักหมุกกระทู้เพิ่มอีก?" - confirm_pin_globally: "ตอนนี้คุณมีหัวข้อที่ปักหมุดแบบรวม %{count} หัวข้อ การมีหัวข้อที่ปักหมุดมากๆจะทำให้ผู้ใช้ใหม่และผู้ใช้ที่ไม่ระบุชื่อรำคาญ คุณแน่ใจจริงๆหรือว่าจะปักหมุกหัวข้อเพิ่มอีก?" + pin: "ทำให้กระทู้นี้ปรากฏด้านบนสุดของหมวดหมู่ %{categoryLink} จนกระทั่ง" + confirm_pin: "คุณมีกระทู้ที่ปักหมุดทั้งหมด %{count} กระทู้ การมีกระทู้ที่ปักหมุดมากๆอาจสร้างปัญหาให้แก่ผู้ใช้ใหม่และผู้ใช้ที่ไม่ระบุชื่อได้ คุณแน่ใจหรือว่าจะปักหมุดกระทู้เพิ่มอีกในหมวดหมู่นี้" + unpin: "ลบกระทู้นี้ออกจากด้านบนสุดของหมวดหมู่ %{categoryLink}" + unpin_until: "ลบกระทู้นี้ออกจากด้านบนสุดของหมวดหมู่ %{categoryLink} หรือรอจนกระทั่ง %{until}" + pin_validation: "จำเป็นต้องมีวันที่เพื่อปักหมุดกระทู้นี้" + not_pinned: "ไม่มีกระทู้ที่ถูกปักหมุดใน %{categoryLink}" + already_pinned: + other: "ตอนนี้กระทู้ถูกปักหมุดใน %{categoryLink}: %{count}" + pin_globally: "ทำให้กระทู้นี้ปรากฏด้านบนสุดของรายการกระทู้ทั้งหมดจนกระทั่ง" + confirm_pin_globally: "คุณมีกระทู้ที่ปักหมุดทั้งหมด %{count} กระทู้ การมีกระทู้ที่ปักหมุดมากๆอาจสร้างปัญหาให้แก่ผู้ใช้ใหม่และผู้ใช้ที่ไม่ระบุชื่อได้ คุณแน่ใจหรือว่าจะปักหมุดกระทู้เพิ่มอีกในหมวดหมู่นี้" + unpin_globally: "ลบกระทู้นี้ออกจากด้านบนสุดของรายการกระทู้ทั้งหมด" + unpin_globally_until: "ลบกระทู้นี้ออกจากด้านบนสุดของรายการกระทู้ทั้งหมดหรือรอจนกระทั่ง %{until}" inviting: "กำลังเชิญ..." invite_private: - title: "ข้อความที่ใช้เชิญ" + title: "เชิญไปยังข้อความ" email_or_username: "อีเมลหรือชื่อผู้ใช้ที่ถูกเชิญ" email_or_username_placeholder: "อีเมลหรือชื่อผู้ใช้" action: "เชิญ" success: "เราได้เชิญผู้ใช้นั้นให้มีส่วนร่วมในข้อความนี้แล้ว" + success_group: "เราได้เชิญกลุ่มนั้นให้เข้าร่วมในข้อความนี้แล้ว" error: "ขออภัย เกิดความผิดพลาดในการเชิญผู้ใช้ท่านนี้" group_name: "ชื่อกลุ่ม" controls: "การควบคุมหัวข้อ" @@ -1192,25 +1776,70 @@ th: title: "เชิญ" username_placeholder: "ชื่อผู้ใช้" action: "ส่งคำเชิญ" + help: "เชิญคนอื่นมาที่กระทู้นี้โดยอีเมลหรือการแจ้งเตือน" + to_forum: "เราจะส่งอีเมลสั้นๆเพื่ออนุญาตให้เพื่อนของคุณเข้าร่วมได้โดยทันทีเพียงคลิกลิงก์ ไม่จำเป็นต้องเข้าสู่ระบบ" + sso_enabled: "กรอกชื่อผู้ใช้ของคนที่คุณต้องการเชิญมายังกระทู้นี้" + to_topic_blank: "กรอกชื่อผู้ใช้หรือที่อยู่อีเมลของคนที่คุณต้องการเชิญมายังกระทู้นี้" + to_topic_email: "คุณได้กรอกที่อยู่อีเมลแล้ว เราจะส่งอีเมลคำเชิญเพื่ออนุญาตเพื่อนของคุณให้ตอบกลับกระทู้นี้ได้โดยทันที" + to_topic_username: "คุณได้กรอกชื่อผู้ใช้แล้ว เราจะส่งการแจ้งเตือนพร้อมลิงก์เพื่อเชิญพวกเขามายังกระทู้นี้" + to_username: "กรอกชื่อผู้ใช้ของคนที่คุณต้องการเชิญ เราจะส่งการแจ้งเตือนพร้อมลิงก์เพื่อเชิญพวกเขามายังกระทู้นี้" email_placeholder: "name@example.com" + success_username: "เราได้เชิญผู้ใช้นั้นให้เข้าร่วมในกระทู้นี้แล้ว" + success_existing_email: "ผู้ใช้อีเมล %{emailOrUsername}มีอยู่ที่นี่แล้ว เราได้เชิญผู้ใช้นั้นให้เข้าร่วมในกระทู้นี้แล้ว" login_reply: "เข้าสู่ระบบเพื่อตอบ" filters: n_posts: - other: "%{count} โพส" - cancel: "เอาการกรองออก" + other: "%{count} โพสต์" + cancel: "เอาตัวกรองออก" + move_to: + title: "ย้ายไปยัง" + action: "ย้ายไปยัง" + error: "มีข้อผิดพลาดในการย้ายโพสต์" split_topic: - title: "ย้ายไปหัวข้อใหม่" - action: "ย้ายไปหัวข้อใหม่" + title: "ย้ายไปกระทู้ใหม่" + action: "ย้ายไปกระทู้ใหม่" + topic_name: "หัวข้อกระทู้ใหม่" radio_label: "กระทู้ใหม่" + error: "มีข้อผิดพลาดในการย้ายโพสต์ไปยังกระทู้ใหม่" merge_topic: - title: "ย้ายไปหัวข้อที่มีอยู่แล้ว" - action: "ย้ายไปหัวข้อที่มีอยู่แล้ว" + title: "ย้ายไปกระทู้ที่มีอยู่แล้ว" + action: "ย้ายไปกระทู้ที่มีอยู่แล้ว" + error: "มีข้อผิดพลาดในการย้ายโพสต์ไปยังกระทู้นั้น" + radio_label: "กระทู้ที่มีอยู่แล้ว" + instructions: + other: "กรุณาเลือกกระทู้ที่คุณต้องการย้าย %{count} โพสต์ไป" move_to_new_message: - radio_label: "สร้างข้อความส่วนตัวใหม่" + title: "ย้ายไปข้อความใหม่" + action: "ย้ายไปข้อความใหม่" + message_title: "หัวข้อข้อความใหม่" + radio_label: "สร้างข้อความใหม่" + move_to_existing_message: + title: "ย้ายไปข้อความที่มีอยู่แล้ว" + action: "ย้ายไปข้อความที่มีอยู่แล้ว" + radio_label: "ข้อความที่มีอยู่แล้ว" + instructions: + other: "กรุณาเลือกข้อความที่คุณต้องการย้าย%{count}โพสต์ไป" + publish_page: + title: "การเผยแพร่เพจ" + publish: "เผยแพร่" + public: "สาธารณะ" + publish_url: "เพจของคุณถูกเผยแพร่เมื่อ:" + topic_published: "กระทู้ของคุณถูกเผยแพร่เมื่อ:" + preview_url: "เพจของคุณจะถูกเผยแพร่เมื่อ:" + invalid_slug: "ขออภัย คุณไม่สามารถเผยแพร่เพจนี้" + unpublish: "ไม่เผยแพร่" + update: "อัปเดต" + unpublished: "เพจของคุณถูกหยุดการเผยแพร่และไม่สามารถเข้าถึงได้อีกต่อไป" + publishing_settings: "ตั้งค่าการเผยแพร่" change_owner: + title: "เปลี่ยนเจ้าของ" action: "เปลี่ยนความเป็นเจ้าของ" - error: "มีความผิดพลาดขณะเปลี่ยนความเป็นเจ้าของโพส" + error: "มีข้อผิดพลาดขณะกำลังเปลี่ยนความเป็นเจ้าของโพสต์" placeholder: "ชื่อผู้ใช้ของเจ้าของใหม่" + instructions: + other: "กรุณาเลือกเจ้าของใหม่สำหรับ %{count}โพสต์ โดย@%{old_user}" + instructions_without_old_user: + other: "กรุณาเลือกเจ้าของใหม่สำหรับ %{count}โพสต์" change_timestamp: action: "เปลี่ยนแปลงเวลา" multi_select: @@ -1218,134 +1847,306 @@ th: selected: "เลือกแล้ว (%{count})" select_post: label: "เลือก" + title: "เพิ่มโพสต์ไปยังการเลือก" + selected_post: + label: "เลือกแล้ว" + title: "คลิกเพื่อลบโพสต์จากการเลือก" select_replies: - label: "เลือก +ตอบ" + label: "เลือก + ตอบ" + title: "เพิ่มโพสต์และคำตอบทั้งหมดไปยังการเลือก" + select_below: + label: "เลือก+ด้านล่าง" + title: "เพิ่มโพสต์และทุกอย่างหลังจากนั้นไปยังการเลือก" delete: ลบที่เลือก cancel: ยกเลิกการเลือก select_all: เลือกทั้งหมด deselect_all: ไม่เลือกทั้งหมด description: - other: "คุณได้เลือก %{count} โพสต์." + other: "คุณได้เลือก %{count} โพสต์" + deleted_by_author: + other: "(กระทู้ถูกแจ้งลบโดยเจ้าของ และจะถูกลบโดยอัตโนมัติใน%{count}ชั่วโมง เว้นแต่จะถูกปักธง)" post: + quote_reply: "อ้างอิง" edit_reason: "เหตุผล:" post_number: "โพสต์ %{number}" - last_edited_on: "โพสแก้ไขล่าสุดเมื่อ" + last_edited_on: "โพสต์ถูกแก้ไขล่าสุดเมื่อ" reply_as_new_topic: "ตอบด้วยหัวข้อที่ลิงค์ไว้" - follow_quote: "ไปยังโพสที่ถูกอ้างถึง" - show_full: "แสดงโพสแบบเต็ม" + reply_as_new_private_message: "ตอบกลับด้วยข้อความใหม่ไปยังผู้รับคนเดียวกัน" + follow_quote: "ไปยังโพสต์ที่ถูกกล่าวถึง" + show_full: "แสดงโพสต์ทั้งหมด" deleted_by_author: other: "(โพสถูกแจ้งลบโดยเจ้าของ และจะถูกลบใน %{count} ชั่วโมงเว้นแต่จะถูกปักธง)" - expand_collapse: "ขยาย/หด" - unread: "โพสนี้ยังไม่ถูกอ่าน" + expand_collapse: "ขยาย/ย่อ" + locked: "ทีมงานได้ปิดโพสต์นี้จากการแก้ไข" + gap: + other: "ดู%{count}คำตอบที่ถูกซ่อน" + notice: + new_user: "นี่เป็นครั้งแรกที่ %{user} ได้โพสต์ มาร่วมต้อนรับเขาสู่ชุมชนของเรากันเถอะ!" + returning_user: "นานแล้วที่เราเห็น %{user} โพสต์ล่าสุดของเขาคือเมื่อ %{time}" + unread: "โพสต์นี้ยังไม่ถูกอ่าน" has_replies: other: "%{count} ตอบ" + unknown_user: "(ผู้ใช้ที่ลูกลบ/ไม่รู้จัก)" has_likes_title: - other: "%{count} ผู้คนที่ชอบโพสนี้" - has_likes_title_only_you: "คุณชอบโพสนี้" + other: "%{count} คนถูกใจโพสต์นี้" + has_likes_title_only_you: "คุณถูกใจโพสต์นี้" + has_likes_title_you: + other: "คุณและคนอื่นอีก %{count}คนถูกใจโพสต์นี้" errors: - create: "ขอโทษ, เกิดความผิดพลาดขณะกำลังสร้างโพสของคุณ โปรดลองใหม่อีกครั้ง" - edit: "ขอโทษ, เกิดความผิดพลาดขณะกำลังแก้ไขโพสต์ของคุณ โปรดลองใหม่อีกครั้ง" - upload: "ขอโทษ, เกิดความผิดพลาดขณะกำลังอัพโหลดไฟล์ โปรดลองใหม่อีกครั้ง" - too_many_uploads: "ขอโทษ, คุณสามารถอัพโหลดไฟล์ได้ครั้งล่ะหนึ่งไฟล์" - image_upload_not_allowed_for_new_user: "ขออภัย, ผู้ใช้ใหม่ไม่สามารถอัพโหลดรูปภาพได้" - attachment_upload_not_allowed_for_new_user: "ขออภัย, ผู้ใช้ใหม่ไม่สามารถอัพโหลดไฟล์แนบได้" - attachment_download_requires_login: "ขออภัย, คุณต้องเข้าสู่ระบบเพื่อดาวห์โหลดไฟล์แนบ" + create: "ขออภัย เกิดความผิดพลาดขณะกำลังสร้างโพสต์ของคุณ กรุณาลองใหม่อีกครั้ง" + edit: "ขออภัย เกิดความผิดพลาดขณะกำลังแก้ไขโพสต์ของคุณ กรุณาลองใหม่อีกครั้ง" + upload: "ขออภัย เกิดความผิดพลาดขณะกำลังอัปโหลดไฟล์ของคุณ กรุณาลองใหม่อีกครั้ง" + too_many_uploads: "ขออภัย คุณสามารถอัปโหลดได้ครั้งละหนึ่งไฟล์เท่านั้น" + too_many_dragged_and_dropped_files: "ขออภัย คุณสามารถอัปโหลดได้ครั้งละ %{max}ไฟล์เท่านั้น" + image_upload_not_allowed_for_new_user: "ขออภัย ผู้ใช้ใหม่ไม่สามารถอัปโหลดรูปภาพได้" + attachment_upload_not_allowed_for_new_user: "ขออภัย ผู้ใช้ใหม่ไม่สามารถอัปโหลดไฟล์แนบได้" + attachment_download_requires_login: "ขออภัย คุณต้องเข้าสู่ระบบเพื่อดาวน์โหลดไฟล์แนบ" abandon_edit: + confirm: "คุณแน่ใจหรือว่าต้องการละทิ้งการเปลี่ยนแปลง" no_value: "ไม่ เก็บไว้" + no_save_draft: "ไม่ บันทึกแบบร่าง" + yes_value: "ใช่ ละทิ้งการแก้ไข" abandon: - confirm: "คุณต้องการทิ้งโพสของคุณจริงๆเหรอ?" + confirm: "คุณแน่ใจหรือว่าต้องการละทิ้งโพสต์ของคุณ" no_value: "ไม่ เก็บไว้" - yes_value: "ใช่ ทิ้งไป" + no_save_draft: "ไม่ บันทึกแบบร่าง" + yes_value: "ใช่ ละทิ้ง" via_email: "โพสนี้ถูกเก็บโดยอีเมล" whisper: "โพสนี้คือการกระซิบจากผู้ดูแล" wiki: about: "โพสนี้เป็นวิกิ; ผู้ใช้ธรรมดาสามารถแก้ไขได้" archetypes: save: "บันทึกการตั้งค่า" + few_likes_left: "ขอบคุณสำหรับการแบ่งปันความรัก! คุณเหลือเพียงไม่กี่ไลค์สำหรับวันนี้" controls: - like: "ชอบโพสนี้" - has_liked: "คุณได้ชอบโพสนี้แล้ว" - undo_like: "ย้อนคืนการชอบ" - edit: "แก้ไขโพสนี้" + reply: "เริ่มเขียนคำตอบโพสต์นี้" + like: "ถูกใจโพสต์นี้" + has_liked: "คุณได้ถูกใจโพสต์นี้แล้ว" + read_indicator: "สมาชิกที่อ่านโพสต์นี้" + undo_like: "เลิกถูกใจ" + edit: "แก้ไขโพสต์นี้" edit_action: "แก้ไข" - edit_anonymous: "ขอโทษแต่คุณต้องเข้าสู่ระบบเพื่อแก้ไขโพสนี้" - delete: "ลบโพสนี้" - undelete: "เลือกลบโพสนี้" - more: "อื่น" + edit_anonymous: "ขออภัย คุณต้องเข้าสู่ระบบเพื่อแก้ไขโพสต์นี้" + delete: "ลบโพสต์นี้" + undelete: "เลิกลบโพสต์นี้" + share: "แบ่งปันลิงก์ไปยังโพสต์นี้" + more: "อื่นๆ" delete_replies: - just_the_post: "ไม่, แค่โพสนี้พอ" + confirm: "คุณต้องการลบคำตอบไปยังโพสต์นี้ด้วยหรือไม่" + direct_replies: + other: "ใช่ และ %{count}คำตอบโดยตรง" + all_replies: + other: "ใช่ และทั้งหมด %{count}คำตอบ" + just_the_post: "ไม่ แค่โพสต์นี้เท่านั้น" + publish_page: "การเผยแพร่เพจ" unhide: "เลิกซ่อน" - delete_topic: "ลบหัวข้อ" + lock_post: "ล็อกโพสต์" + lock_post_description: "ป้องกันผู้โพสต์จากการแก้ไขโพสต์นี้" + unlock_post: "เลิกล็อกโพสต์นี้" + unlock_post_description: "อนุญาตให้ผู้โพสต์แก้ไขโพสต์นี้" + delete_topic_disallowed: "คุณไม่ได้รับอนุญาตให้ลบกระทู้นี้" + delete_topic: "ลบกระทู้" actions: flag: "ธง" + defer_flags: + other: "ละทิ้งธง" undo: - bookmark: "ย้อนคืนการบุ๊คมาร์ค" + off_topic: "เลิกปักธง" + spam: "เลิกปักธง" + inappropriate: "เลิกปักธง" + bookmark: "เลิกบุ๊กมาร์ก" + like: "เลิกถูกใจ" + people: + spam: "ปักธงไว้ว่าเป็นสแปม" + inappropriate: "ปักธงไว้ว่าไม่เหมาะสม" + notify_user: "ส่งข้อความ" + bookmark: "บุ๊กมาร์กแล้ว" + like: + other: "ถูกใจแล้ว" + read: + other: "อ่านแล้ว" + like_capped: + other: "และอีก %{count}คนถูกใจสิ่งนี้" + read_capped: + other: "และอีก %{count}คนอ่านสิ่งนี้" by_you: - bookmark: "บุ๊คมาร์คโพสนี้" + spam: "คุณปักธงไว้ว่าเป็นสแปม" + inappropriate: "คุณปักธงไว้ว่าไม่เหมาะสม" + notify_user: "คุณได้ส่งข้อความไปหาผู้ใช้นี้แล้ว" + bookmark: "คุณได้บุ๊กมาร์กโพสต์นี้แล้ว" + like: "คุณถูกใจสิ่งนี้" + delete: + confirm: + other: "คุณแน่ใจหรือว่าต้องการลบ %{count}โพสต์นี้" + revisions: + controls: + edit_post: "แก้ไขโพสต์" + comparing_previous_to_current_out_of_total: "%{previous}%{icon}%{current} / %{total}" + displays: + inline: + button: "HTML" + side_by_side: + title: "HTML" + button: "HTML" + raw_email: + displays: + text_part: + button: "ข้อความ" + html_part: + button: "HTML" bookmarks: - created: "สร้างเมื่อ" + create: "สร้างบุ๊กมาร์ก" + edit: "แก้ไขบุ๊กมาร์ก" + created: "สร้าง" + updated: "อัปเดตแล้ว" name: "ชื่อ" + name_placeholder: "บุ๊กมาร์กนี้สำหรับสิ่งใด" + set_reminder: "เตือนฉัน" + actions: + delete_bookmark: + name: "ลบบุ๊กมาร์ก" + edit_bookmark: + name: "แก้ไขบุ๊กมาร์ก" category: + none: "(ไม่มีหมวดหมู่)" + all: "หมวดหมู่ทั้งหมด" edit: "แก้ไข" + edit_dialog_title: "แก้ไข: %{categoryName}" + view: "ดูกระทู้ในหมวดหมู่" + general: "ทั่วไป" settings: "การตั้งค่า" - tags: "ป้าย" + topic_template: "รูปแบบกระทู้" + tags: "แท็ก" + allow_global_tags_label: "อนุญาตแท็กอื่นด้วย" delete: "ลบหมวดหมู่" + create: "หมวดหมู่ใหม่" + create_long: "สร้างหมวดหมู่ใหม่" + save: "บันทึกหมวดหมู่" + creation_error: มีข้อผิดพลาดขณะสร้างหมวดหมู่ + save_error: มีข้อผิดพลาดในการบันทึกหมวดหมู่ + name: "ชื่อหมวดหมู่" description: "รายละเอียด" - delete_confirm: "คุณแน่ใจหรือว่าจะลบหมวดหมู่นี้ออก?" + topic: "กระทู้หมวดหมู่" + logo: "รูปโลโก้หมวดหมู่" + background_image: "รูปพื้นหลังหมวดหมู่" + background_color: "สีพื้นหลัง" + name_placeholder: "สูงสุดหนึ่งหรือสองคำ" + delete_confirm: "คุณแน่ใจหรือว่าจะลบหมวดหมู่นี้ออก" + delete_error: "มีข้อผิดพลาดในการลบหมวดหมู่" + no_description: "กรุณาเพิ่มรายละเอียดสำหรับหมวดหมู่นี้" + change_in_category_topic: "แก้ไขรายละเอียด" + already_used: "สีนี้ถูกใช้สำหรับหมวดหมู่อื่นแล้ว" security: "ความปลอดภัย" + pending_permission_change_alert: "คุณยังไม่ได้เพิ่ม %{group} ไปยังหมวดหมู่นี้ คลิกปุ่มนี้เพื่อเพิ่ม" + images: "รูปภาพ" email_in_allow_strangers: "ยอมรับอีเมลจากผู้ใช้ที่ไม่ระบุชื่อและไม่มีบัญชี" + edit_permissions: "แก้ไขการอนุญาต" + reviewable_by_group: "นอกจากทีมงานแล้ว โพสต์และธงในหมวดหมู่ยังสามารถถูกรีวิวโดย:" review_group_name: "ชื่อกลุ่ม" + require_topic_approval: "กระทู้ใหม่ทั้งหมดต้องผ่านการอนุมัติจากผู้ดูแลระบบ" + require_reply_approval: "คำตอบใหม่ทั้งหมดต้องผ่านการอนุมัติจากผู้ดูแลระบบ" + this_year: "ปีนี้" + minimum_required_tags: "จำนวนแท็กขั้นต่ำในกระทู้:" notifications: watching: title: "กำลังดู" watching_first_post: - title: "ดูโพสต์แรก" + title: "กำลังดูโพสต์แรก" tracking: - title: "ติดตาม" + title: "กำลังติดตาม" regular: title: "ปกติ" - description: "คุณจะได้รับการแจ้งเตือนเมื่อใครก็ตามเอ่ยชื่อของคุณ @name หรือตอบคุณ" + description: "คุณจะได้รับการแจ้งเตือนเมื่อมีคนกล่าวถึงชื่อของคุณ @name หรือตอบคุณ" muted: title: "ปิด" search_priority: options: normal: "ปกติ" + ignore: "ไม่สนใจ" + very_low: "ต่ำมาก" + low: "ต่ำ" + high: "สูง" + very_high: "สูงมาก" sort_options: likes: "ถูกใจ" views: "ดู" - posts: "โพส" + posts: "โพสต์" activity: "กิจกรรม" + posters: "ผู้โพสต์" category: "หมวดหมู่" - created: "สร้างเมื่อ" + created: "สร้าง" settings_sections: + general: "ทั่วไป" email: "อีเมล" + list_filters: + all: "กระทู้ทั้งหมด" + none: "ไม่มีหมวดหมู่ย่อย" flagging: notify_action: "ข้อความส่วนตัว" + official_warning: "คำเตือนอย่างเป็นทางการ" delete_spammer: "ลบสแปมเมอร์" - yes_delete_spammer: "ใช่ ลบสแปมเมอร์ออก" + yes_delete_spammer: "ใช่ ลบสแปมเมอร์" + hidden_email_address: "(ถูกซ่อน)" + cant: "ขออภัย คุณไม่สามารถปักธงโพสต์นี้ได้ในขณะนี้" + notify_staff: "แจ้งทีมงานโดยส่วนตัว" + formatted_name: + inappropriate: "มันไม่เหมาะสม" + spam: "มันคือสแปม" + custom_placeholder_notify_moderators: "บอกเราในเรื่องที่คุณไม่สบายใจ พร้อมส่งลิงก์และตัวอย่างที่เกี่ยวข้องหากเป็นไปได้" + custom_message: + at_least: + other: "กรอกอย่างน้อย %{count} ตัวอักษร" + more: + other: "อีก %{count}..." + left: + other: "เหลืออีก %{count}" flagging_topic: + action: "ปักธงกระทู้" notify_action: "ข้อความส่วนตัว" topic_map: - title: "ภาครวมหัวข้อ" + title: "สรุปกระทู้" + participants_title: "ผู้โพสต์บ่อย" + links_title: "ลิงก์ยอดนิยม" + links_shown: "แสดงลิงก์เพิ่มอีก..." + clicks: + other: "%{count} คลิก" + post_links: + title: + other: "อีก %{count}" topic_statuses: warning: help: "นี่คือคำเตือนอย่างเป็นทางการ" bookmarked: - help: "คุณได้บุ๊คมาร์คหัวข้อนี้แล้ว" + help: "คุณได้บุ๊กมาร์กกระทู้นี้แล้ว" + locked: + help: "กระทู้นี้ถูกปิด ไม่รับคำตอบใหม่อีกต่อไป" archived: help: "หัวข้อนี้ถูกจัดเก้บแล้ว; นั่นหมายความว่ามันถูกแช่แข็งและไม่สามารถเปลี่ยนแปลงได้" locked_and_archived: help: "หัวข้อนี้ถูกปิดและถูกจัดเก็บแล้ว; นั่นหมายความว่ามันไม่รับข้อความใหม่และไม่สามารถเปลี่ยนแปลงได้" - posts: "โพส" - original_post: "โพสต้นฉบับ" + unpinned: + title: "เลิกปักหมุดแล้ว" + help: "เลิกปักหมุดกระทู้นี้แล้ว มันจะถูกแสดงในลำดับปกติ" + pinned: + title: "ปักหมุดแล้ว" + help: "ปักหมุดกระทู้นี้แล้ว มันจะถูกแสดงด้านบนสุดของหมวดหมู่" + personal_message: + title: "กระทู้นี้เป็นข้อความส่วนตัว" + help: "กระทู้นี้เป็นข้อความส่วนตัว" + posts: "โพสต์" + posts_long: "มี %{number} โพสต์ในกระทู้นี้" + original_post: "โพสต์ต้นฉบับ" views: "ดู" views_lowercase: other: "ดู" replies: "ตอบ" + views_long: + other: "กระทู้นี้ถูกดู %{number}ครั้ง" activity: "กิจกรรม" - likes: "ชอบ" + likes: "ถูกใจ" likes_lowercase: - other: "ชอบ" + other: "ถูกใจ" + likes_long: "มี %{number}ไลค์ในกระทู้นี้" users: "ผู้ใช้" users_lowercase: other: "ผู้ใช้" @@ -1354,28 +2155,28 @@ th: changed_by: "โดย %{author}" raw_email: not_available: "ไม่พร้อม!" - categories_list: "รายการหมวดหมู่" + categories_list: "รายชื่อหมวดหมู่" filters: - with_topics: "%{filter} หัวข้อ" - with_category: "%{filter} %{category} หัวข้อ" + with_topics: "%{filter} กระทู้" + with_category: "%{filter} %{category} กระทู้" latest: title: "ล่าสุด" title_with_count: other: "ล่าสุด (%{count})" - help: "หัวข้อพร้อมโพสล่าสุด" + help: "กระทู้พร้อมโพสต์ล่าสุด" read: title: "อ่าน" categories: title: "หมวดหมู่" title_in: "หมวดหมู่ - %{categoryName}" - help: "ทุกหัวข้อจัดกลุ่มโดยหมวดหมู่" + help: "ทุกกระทู้ถูกจัดกลุ่มโดยหมวดหมู่" unread: title: "ยังไม่อ่าน" title_with_count: - other: "ยังไม่ได้อ่าน (%{count})" - help: "หัวข้อที่คุณกำลังจับตาหรือติดตามพร้อมโพสที่ยังไม่อ่าน" + other: "ยังไม่อ่าน (%{count})" + help: "กระทู้ที่คุณกำลังดูหรือติดตามพร้อมโพสต์ที่ยังไม่อ่าน" lower_title_with_count: - other: "%{count} ไม่ได้อ่าน" + other: "%{count} ยังไม่อ่าน" new: lower_title_with_count: other: "%{count} ใหม่" @@ -1383,47 +2184,54 @@ th: title: "ใหม่" title_with_count: other: "ใหม่ (%{count})" - help: "หัวข้อที่ถูกสร้างในช่วงไม่กี่วัน" + help: "กระทู้ที่ถูกสร้างในช่วงไม่กี่วันที่ผ่านมา" posted: - title: "โพสของฉัน" - help: "หัวข้อที่คุณโพส" + title: "โพสต์ของฉัน" + help: "กระทู้ที่คุณได้โพสต์" bookmarks: - title: "บุ๊คมาร์ค" - help: "หัวข้อของคุณได้รับการบุ๊คมาร์ค" + title: "บุ๊กมาร์ก" + help: "กระทู้ที่คุณได้บุ๊กมาร์ก" category: title: "%{categoryName}" title_with_count: other: "%{categoryName} (%{count})" - help: "หัวข้อล่าสุดในหมวดหมู่ %{categoryName}" + help: "กระทู้ล่าสุดในหมวดหมู่ %{categoryName}" top: title: "บน" - help: "หัวข้อที่มีการเลือกไหวมากที่สุดในปี เดือน อาทิตย์ หรือวันที่ผ่านมา" + help: "กระทู้ที่มีการเคลื่อนไหวมากที่สุดในปี เดือน สัปดาห์ หรือวันที่ผ่านมา" all: title: "ตลอดเวลา" yearly: - title: "ปี" + title: "รายปี" quarterly: - title: "สามเดือน" + title: "รายไตรมาส" monthly: - title: "เดือน" + title: "รายเดือน" weekly: - title: "อาทิตย์" + title: "รายสัปดาห์" daily: - title: "วัน" + title: "รายวัน" all_time: "ตลอดเวลา" this_year: "ปี" - this_quarter: "สามเดือน" + this_quarter: "ไตรมาส" this_month: "เดือน" - this_week: "อาทิตย์" + this_week: "สัปดาห์" today: "วันนี้" + other_periods: "ดูด้านบน:" permission_types: full: "สร้าง / ตอบ / ดู" create_post: "ตอบ / ดู" readonly: "ดู" lightbox: - download: "ดาวโหลด" + download: "ดาวน์โหลด" + close: "ปิด (Esc)" keyboard_shortcuts_help: - title: "ปุ่มลัดของคียบอร์ด" + shortcut_key_delimiter_comma: "," + shortcut_key_delimiter_plus: "+" + shortcut_delimiter_or: "%{shortcut1}หรือ%{shortcut2}" + shortcut_delimiter_slash: "%{shortcut1}/%{shortcut2}" + shortcut_delimiter_space: "%{shortcut1}%{shortcut2}" + title: "ปุ่มลัดของคีย์บอร์ด" jump_to: title: "ข้ามไปยัง" home: "%{shortcut} หน้าแรก" @@ -1431,52 +2239,76 @@ th: new: "%{shortcut} ใหม่" unread: "%{shortcut} ยังไม่อ่าน" categories: "%{shortcut} หมวดหมู่" - top: "%{shortcut} บน" - bookmarks: "%{shortcut} บุ๊คมาร์ค" - profile: "%{shortcut} ข้อมูลส่วนตัว" + top: "%{shortcut} ด้านบน" + bookmarks: "%{shortcut} บุ๊กมาร์ก" + profile: "%{shortcut} โปรไฟล์" messages: "%{shortcut} ข้อความ" + drafts: "%{shortcut}แบบร่าง" navigation: title: "การนำทาง" - jump: "%{shortcut} ไปยังโพส #" + jump: "%{shortcut} ไปยังโพสต์ #" back: "%{shortcut} กลับ" up_down: "%{shortcut} ย้ายส่วน ↑ ↓" - open: "%{shortcut} เปิดหัวข้อที่เลือก" - next_prev: "%{shortcut} หัวหมู่ ถัดไป/ก่อนหน้า" + open: "%{shortcut} เปิดกระทู้ที่เลือก" + next_prev: "%{shortcut} หมวดถัดไป/ก่อนหน้า" + go_to_unread_post: "%{shortcut}ไปยังโพสต์แรกที่ยังไม่ได้อ่าน" application: - title: "แอพพิเคชั่น" - create: "%{shortcut} สร้างหัวข้อใหม่" + title: "แอปพลิเคชัน" + create: "%{shortcut} สร้างกระทู้ใหม่" notifications: "%{shortcut} เปิดการแจ้งเตือน" user_profile_menu: "%{shortcut} เปิดเมนูผู้ใช้" - show_incoming_updated_topics: "%{shortcut} แสดงหัวข้ออัพเดตล่าสุด" + show_incoming_updated_topics: "%{shortcut} แสดงกระทู้ที่อัปเดต" + search: "%{shortcut}ค้นหา" help: "%{shortcut} เปิดความช่วยเหลือของแป้นพิมพ์" dismiss_new_posts: "%{shortcut} ยกเลิกการโพสใหม่" dismiss_topics: "%{shortcut} ยกเลิกหัวข้อ" log_out: "%{shortcut} ออกจากระบบ" + bookmarks: + title: "บุ๊กมาร์ก" + enter: "%{shortcut}บันทึกและปิด" + later_today: "%{shortcut}ภายหลังในวันนี้" + later_this_week: "%{shortcut}ภายหลังในสัปดาห์นี้" + tomorrow: "%{shortcut}พรุ่งนี้" + next_week: "%{shortcut}สัปดาห์หน้า" + next_month: "%{shortcut}เดือนหน้า" + next_business_week: "%{shortcut}เริ่มสัปดาห์หน้า" + next_business_day: "%{shortcut}วันทำการถัดไป" + delete: "%{shortcut}ลบบุ๊กมาร์ก" actions: title: "การกระทำ" bookmark_topic: "%{shortcut} บุ๊คมาร์คหัวข้อ" - pin_unpin_topic: "%{shortcut} ปักหรือเลิกปักหัวข้อ" - share_topic: "%{shortcut} แบ่งปันหัวข้อ" - share_post: "%{shortcut} แบ่งบันหัวข้อ" + pin_unpin_topic: "%{shortcut} ปักหมุด/เลิกปักหมุดกระทู้" + share_topic: "%{shortcut} แบ่งปันกระทู้" + share_post: "%{shortcut} แบ่งปันโพสต์" reply_as_new_topic: "%{shortcut} ตอบแบบหัวข้อที่ลิงค์ไว้" - reply_topic: "%{shortcut} ตอบไปยังหัวข้อ" - reply_post: "%{shortcut} ตอบไปยังโพส" - quote_post: "%{shortcut} อ้างถึงโพส" - like: "%{shortcut} ชอบโพส" - flag: "%{shortcut} ปักธงโพส" - bookmark: "%{shortcut} บุ๊คมาร์คโพส" - edit: "%{shortcut} แก้ไขโพส" - delete: "%{shortcut} ลบโพส" - mark_muted: "%{shortcut} ปิดการแจ้งเตือนโพส" + reply_topic: "%{shortcut} ตอบไปยังกระทู้" + reply_post: "%{shortcut} ตอบไปยังโพสต์" + quote_post: "%{shortcut} อ้างถึงโพสต์" + like: "%{shortcut} ถูกใจโพสต์" + flag: "%{shortcut} ปักธงโพสต์" + bookmark: "%{shortcut} บุ๊กมาร์กโพสต์" + edit: "%{shortcut} แก้ไขโพสต์" + delete: "%{shortcut} ลบโพสต์" + mark_muted: "%{shortcut} ปิดการแจ้งเตือนกระทู้" mark_regular: "%{shortcut} หัวข้อ ทั่วไป (มาตราฐาน)" - mark_tracking: "%{shortcut} ติดตามหัวข้อ" - mark_watching: "%{shortcut} เฝ้าดูหัวข้อ" + mark_tracking: "%{shortcut} ติดตามกระทู้" + mark_watching: "%{shortcut} ดูกระทู้" + print: "%{shortcut}พิมพ์กระทู้" + search_menu: + title: "เมนูค้นหา" badges: granted_on: "ได้รับเมื่อ %{date}" + title: เหรียญ + allow_title: "คุณสามารถใช้เหรียญนี้เป็นชื่อเรื่อง" + badge_count: + other: "%{count}เหรียญ" + more_badges: + other: "อีก+%{count}" + select_badge_for_title: เลือกเหรียญเพื่อใช้เป็นชื่อเรื่อง none: "(ไม่มี)" badge_grouping: getting_started: - name: เริ่มต้น + name: กำลังเริ่มต้น community: name: ชุมชน trust_level: @@ -1484,56 +2316,84 @@ th: other: name: อื่นๆ posting: - name: โพส + name: โพสต์ tagging: all_tags: "แท็กทั้งหมด" + other_tags: "แท็กอื่น" selector_all_tags: "แท็กทั้งหมด" + selector_no_tags: "ไม่มีแท็ก" changed: "เปลี่ยนแท็ก:" - tags: "ป้าย" + tags: "แท็ก" + choose_for_topic: "แท็กทางเลือก" + info: "ข้อมูล" + tag_groups_info: + other: "แท็กนี้เป็นของกลุ่มเหล่านี้: %{tag_groups}" + category_restrictions: + other: "สามารถใช้ได้แค่ในหมวดหมู่เหล่านี้เท่านั้น" add_synonyms: "เพิ่ม" delete_tag: "ลบแท็ก" + delete_confirm_no_topics: "คุณแน่ใจหรือว่าต้องการลบแท็กนี้" rename_tag: "เปลี่ยนชื่อแท็ก" rename_instructions: "เลือกชื่อใหม่สำหรับแท็ก:" sort_by: "เรียงโดย:" sort_by_count: "นับ" sort_by_name: "ชื่อ" + upload: "อัปโหลดแท็ก" + upload_successful: "แท็กถูกอัปโหลดสำเร็จแล้ว" + delete_unused_confirmation: + other: "%{count}แท็กจะถูกลบ: %{tags}" + delete_unused_confirmation_more_tags: + other: "%{tags}และอีก%{count}" + delete_unused: "ลบแท็กที่ไม่ได้ใช้" + delete_unused_description: "ลบแท็กทั้งหมดที่ไม่ได้ถูกติดในกระทู้หรือข้อความส่วนตัวใดๆ" cancel_delete_unused: "ยกเลิก" filters: - without_category: "%{filter} %{tag} หัวข้อ" - with_category: "%{filter} %{tag} หัวข้อใน %{category}" + without_category: "%{filter} %{tag} กระทู้" + with_category: "%{filter} %{tag} กระทู้ใน %{category}" notifications: watching: title: "กำลังดู" watching_first_post: - title: "ดูโพสต์แรก" + title: "กำลังดูโพสต์แรก" tracking: - title: "ติดตาม" + title: "กำลังติดตาม" regular: title: "ทั่วไป" muted: title: "ปิด" groups: + new: "กลุ่มใหม่" + tags_label: "แท็กในกลุ่มนี้:" + tags_placeholder: "แท็ก" + parent_tag_placeholder: "ทางเลือก" + one_per_topic_label: "จำกัดหนึ่งแท็กต่อหนึ่งกระทู้จากกลุ่มนี้" save: "บันทึก" delete: "ลบ" + everyone_can_use: "ทุกคนสามารถใช้แท็กได้" + usable_only_by_staff: "ทุกคนสามารถเห็นแท็กได้ แต่ทีมงานเท่านั้นที่สามารถใช้ได้" + visible_only_to_staff: "ทีมงานเท่านั้นที่สามารถมองเห็นแท็ก" topics: none: unread: "คุณไม่มีกระทู้ที่ยังไม่ได้อ่าน" new: "คุณไม่มีกระทู้ใหม่" - read: "คุณยังไม่ได้อ่านกระทู้เลย" - posted: "คุณยังไม่ได้โพสในกระทู้ใดๆ" - latest: "ไม่มีหัวข้อล่าสุดแล้ว" - bookmarks: "คุณยังไม่ได้บุ๊คมาร์คกระทู้ใดๆเลย" - top: "ไม่มีหัวข้อสูงสุดแล้ว" - bottom: + read: "คุณยังไม่ได้อ่านกระทู้ใดๆเลย" + posted: "คุณยังไม่ได้โพสต์ในกระทู้ใดๆเลย" latest: "ไม่มีกระทู้ล่าสุด" - posted: "ไม่มีหัวข้อที่โพสแล้ว" - read: "ไม่มีหัวข้อที่อ่านแล้ว" - new: "ไม่มีกระทู้ใหม่" - unread: "ไม่มีหัวข้อที่ยังไม่อ่านแล้ว" - top: "ไม่มีหัวข้อสูงสุดแล้ว" - bookmarks: "ไม่มีบุ๊คมาร์คในหัวข้อใดอีกแล้ว" + bookmarks: "คุณยังไม่ได้บุ๊กมาร์กกระทู้ใดๆเลย" + top: "ไม่มีกระทู้ยอดนิยม" + bottom: + latest: "ไม่มีกระทู้ล่าสุดอีกแล้ว" + posted: "ไม่มีกระทู้ที่โพสต์อีกแล้ว" + read: "ไม่มีกระทู้ที่อ่านแล้วอีก" + new: "ไม่มีกระทู้ใหม่อีกแล้ว" + unread: "ไม่มีกระทู้ที่ยังไม่อ่านอีกแล้ว" + top: "ไม่มีกระทู้ยอดนิยมอีกแล้ว" + bookmarks: "ไม่มีกระทู้ที่บุ๊กมาร์กอีกแล้ว" + invite: + custom_message_template_topic: "สวัสดี ฉันคิดว่าคุณอาจชอบกระทู้นี้!" footer_nav: back: "กลับ" + forward: "ส่งต่อ" share: "แบ่งปัน" dismiss: "ซ่อน" admin_js: @@ -1547,28 +2407,37 @@ th: never: "ไม่เลย" dashboard: title: "แดชบอร์ด" - version: "เวอร์ชั่น" + version: "เวอร์ชัน" up_to_date: "คุณเป็นเวอร์ชั่นล่าสุด!" critical_available: "การอัพเดตที่สำคัญมีให้อัพเดต" - updates_available: "มีการอัพเดต" - please_upgrade: "โปรดอัพเดต!" + updates_available: "มีการอัปเดต" + please_upgrade: "กรุณาอัปเกรด!" installed_version: "ติดตั้งแล้ว" latest_version: "ล่าสุด" last_checked: "ตรวจล่าสุด" refresh_problems: "รีเฟรช" no_problems: "ไม่พบปัญหา" moderators: "ผู้ดูแล:" - admins: "ผู้ดูแลระบบ:" - suspended: "ถูกปิด:" + admins: "แอดมิน:" + suspended: "ถูกระงับชั่วคราว:" private_messages_short: "ข้อความ" private_messages_title: "ข้อความ" mobile_title: "โทรศัพท์" + space_used_and_free: "%{usedSize}(%{freeSize}ฟรี)" + uploads: "อัปโหลด" backups: "สำรองข้อมูล" + lastest_backup: "ล่าสุด: %{date}" traffic_short: "การจราจร" + moderators_activity: กิจกรรมของผู้ดูแลระบบ + general_tab: "ทั่วไป" security_tab: "ความปลอดภัย" + report_filter_any: "ใดๆ" + disabled: ปิดใช้งานแล้ว reports: today: "วันนี้" yesterday: "เมื่อวาน" + last_7_days: "7 วันที่ผ่านมา" + last_30_days: "30 วันที่ผ่านมา" all_time: "ตลอดเวลา" 7_days_ago: "7 วันที่แล้ว" 30_days_ago: "30 วันที่แล้ว" @@ -1576,82 +2445,133 @@ th: view_table: "ตาราง" view_graph: "กราฟ" refresh_report: "โหลดรายงานใหม่" + dates: "วัน (UTC)" groups: "กลุ่มทั้งหมด" + no_data: "ไม่มีข้อมูลที่จะแสดง" filters: group: label: กลุ่ม category: label: หมวดหมู่ + include_subcategories: + label: "รวมหมวดหมู่ย่อย" commits: - latest_changes: "การเปลี่ยนแปลงล่าสุด: โปรดอัพเดตบ่อยๆ" + latest_changes: "การเปลี่ยนแปลงล่าสุด: กรุณาอัปเดตบ่อยๆ" by: "โดย" groups: + new: + title: "กลุ่มใหม่" + create: "สร้าง" + name: + too_short: "ชื่อกลุ่มสั้นเกินไป" + too_long: "ชื่อกลุ่มยาวเกินไป" + checking: "กำลังตรวจสอบชื่อกลุ่ม..." + available: "สามารถใช้ชื่อกลุ่มได้" + not_available: "ไม่สามารถใช้ชื่อกลุ่มได้" + blank: "ไม่สามารถเว้นว่างชื่อกลุ่มได้" manage: interaction: email: อีเมล incoming_email: "ตั้งที่อยู่สำหรับอีเมลขาเข้า" incoming_email_placeholder: "ใส่อีเมล" visibility_levels: - title: "ใครสามารถเห็นกลุ่มนี้?" + title: "ใครสามารถเห็นกลุ่มนี้" public: "ทุกคน" - staff: "เจ้าของกลุ่ม และผู้ดูแล" + members: "เจ้าของกลุ่ม สมาชิก" + staff: "เจ้าของกลุ่มและทีมงาน" + owners: "เจ้าของกลุ่ม" + description: "แอดมินสามารถกลุ่มทั้งหมดได้" + members_visibility_levels: + title: "ใครสามารถเห็นสมาชิกของกลุ่มนี้ได้" + description: "แอดมินสามารถเห็นสมาชิกของกลุ่มทั้งหมดได้" membership: + automatic: อัตโนมัติ trust_levels_title: "ระดับความไว้ใจจะถูกให้ไปยังผู้ใช้โดยอัตโนมัติเมื่อพวกเขาเพิ่ม:" trust_levels_none: "ไม่มี" - name_placeholder: "ชื่อกลุ่ม, ไม่มีเว้นวรรค, ใช้กฎเดียวกับชื่อผู้ใช้" + name_placeholder: "ชื่อกลุ่ม ไม่มีเว้นวรรค ใช้กฎเดียวกับชื่อผู้ใช้" primary: "กลุ่มหลัก" no_primary: "(ไม่มีกลุ่มหลัก)" title: "กลุ่ม" - edit: "แก้กลุ่ม" - refresh: "รีโหลด" + edit: "แก้ไขกลุ่ม" + refresh: "รีเฟรช" about: "แก้ไขสมาชิกและชื่อกลุ่มของคุณได้ที่นี่" - group_members: "ชื่อสมาชิก" + group_members: "สมาชิกกลุ่ม" delete: "ลบ" - delete_confirm: "ลบกลุ่มนี้?" - delete_failed: "ไม่สามารถลงกลุ่มได้ ถ้ากลุ่มนี้เป็นกลุ่มอัตโนมัติมันจะไม่สามารถถูกทำลายได้" + delete_confirm: "ลบกลุ่มนี้" + delete_failed: "ไม่สามารถลบกลุ่มได้ ถ้ากลุ่มนี้เป็นกลุ่มอัตโนมัติ จะไม่สามารถทำให้หายไปได้" delete_owner_confirm: "ลบสิทธิ์การเป็นเจ้าของ ของ '%{username}'?" add: "เพิ่ม" + automatic: "อัตโนมัติ" group_owners: เจ้าของ add_owners: เพิ่มเจ้าของ + none_selected: "เลือกกลุ่มเพื่อเริ่มต้น" api: user: "ผู้ใช้" title: "API" - created: สร้างเมื่อ + created: สร้างแล้ว + updated: อัปเดตแล้ว + last_used: ใช้ครั้งล่าสุด + never_used: (ไม่เคย) revoke: "เอาออก" + all_users: "ผู้ใช้ทั้งหมด" show_details: รายละเอียด description: รายละเอียด + user_placeholder: กรอกชื่อผู้ใช้ save: บันทึก + delete: ลบถาวร + continue: ดำเนินการต่อ web_hooks: + create: "สร้าง" save: "บันทึก" destroy: "ลบ" description: "รายละเอียด" + wildcard_event: "ส่งทุกอย่างหาฉัน" active: "ใช้งานอยู่" + user_badge_event: + details: "เมื่อผู้ใช้ได้รับเหรียญ" delivery_status: + title: "สถานะการส่ง" + inactive: "ไม่ใช้งาน" failed: "ล้มเหลว" + successful: "สำเร็จ" + disabled: "ปิดใช้งานแล้ว" events: + redeliver: "ส่งอีกครั้ง" + completed_in: + other: "เสร็จสิ้นใน %{count} วินาที" request: "ร้องขอ" - timestamp: "สร้างเมื่อ" + timestamp: "สร้าง" actions: "การกระทำ" plugins: title: "ปลั้กอิน" installed: "ปลั้กอินที่ติดตั้งแล้ว" name: "ชื่อ" none_installed: "คุณยังไม่มีปลั้กอินใดๆติดตั้ง" - version: "เวอร์ชั่น" - enabled: "เปิดใช้?" + version: "เวอร์ชัน" + enabled: "เปิดใช้" is_enabled: "Y" not_enabled: "N" + change_settings: "การตั้งค่าการเปลี่ยนแปลง" change_settings_short: "การตั้งค่า" backups: title: "สำรอง" menu: backups: "สำรอง" + columns: + filename: "ชื่อไฟล์" + size: "ขนาด" upload: label: "อัปโหลด" uploading: "กำลังอัปโหลด..." + uploading_progress: "กำลังอัปโหลด...%{progress}%" operations: cancel: label: "ยกเลิก" + download: + label: "ดาวน์โหลด" + title: "ส่งอีเมลพร้อมลิงก์ดาวน์โหลด" + location: + s3: "S3" export_csv: button_text: "ส่งออก" export_json: @@ -1664,24 +2584,50 @@ th: preview: "แสดงตัวอย่าง" save: "บันทึก" new: "ใหม่" + new_style: "รูปแบบใหม่" + install: "ติดตั้ง" delete: "ลบ" + delete_confirm: 'คุณแน่ใจหรือว่าต้องการลบ "%{theme_name}"' + color: "สี" + copy: "คัดลอก" + theme_owner: "ไม่สามารถแก้ไขได้ เป็นเจ้าของโดย:" email_templates: title: "อีเมล" subject: "หัวข้อ" revert: "ย้อนกลับการแก้ไข" revert_confirm: "คุณแน่ใจหรือว่าจะย้อนกลับการแก้ไข" theme: + theme: "ธีม" + theme_name: "ชื่อธีม" + title: "ธีม" + create: "สร้าง" create_type: "ชนิด" create_name: "ชื่อ" edit: "แก้ไข" mobile: "โทรศัพท์" settings: "การตั้งค่า" + preview: "แสดงตัวอย่าง" + add_all_themes: "เพิ่มธีมทั้งหมด" + inactive_themes: "ธีมที่ไม่ได้ใช้งาน:" + and_x_more: "และอีก%{count}" + uploads: "อัปโหลด" upload: "อัปโหลด" + add_all: "เพิ่มทั้งหมด" + install: "ติดตั้ง" installed: "ติดตั้งแล้ว" + install_popular: "ยอดนิยม" + install_upload: "จากอุปกรณ์ของคุณ" + install_create: "สร้างใหม่" about_theme: "เกี่ยวกับ" + version: "เวอร์ชัน:" + authors: "เขียนโดย:" + creator: "สร้างโดย:" enable: "เปิดใช้งาน" disable: "ปิดใช้งาน" + updating: "กำลังอัปเดต..." add: "เพิ่ม" + theme_settings: "การตั้งค่าธีม" + no_settings: "ธีมนี้ไม่มีการตั้งค่า" scss: text: "CSS" header: @@ -1692,19 +2638,44 @@ th: text: "Embedded CSS" head_tag: text: "" + body_tag: + text: "" + colors: + title: "สี" + undo: "เลิกทำ" + primary: + name: "หลัก" email_style: css: "CSS" + save_error_with_reason: "การเปลี่ยนแปลงไม่ได้ถูกบันทึก %{error}" email: title: "อีเมล" settings: "การตั้งค่า" + templates: "รูปแบบ" + advanced_test: + email: "ข้อความต้นฉบับ" + error: "ผิดพลาด - %{server_error}" sent: "ส่ง" + skipped: "ข้าม" received: "รับ" + rejected: "ถูกปฏิเสธ" + sent_at: "ถูกส่งเมื่อ" time: "เวลา" user: "ผู้ใช้" - refresh: "รีโหลด" + email_type: "ประเภทอีเมล" + to_address: "ไปยังที่อยู่" + sent_test: "ส่งแล้ว!" + refresh: "รีเฟรช" + send_digest_label: "ส่งผลลัพธ์นี้ไปยัง:" + send_digest: "ส่ง" + sending_email: "กำลังส่งอีเมล" + html: "html" + text: "ข้อความ" + last_seen_user: "ผู้ใช้ที่ดูล่าสุด:" incoming_emails: from_address: "จาก" to_addresses: "ถึง" + cc_addresses: "Cc" subject: "หัวข้อ" error: "ผิดพลาด" modal: @@ -1714,28 +2685,32 @@ th: from_placeholder: "from@example.com" to_placeholder: "to@example.com" cc_placeholder: "cc@example.com" - subject_placeholder: "เรื่อง" + subject_placeholder: "หัวข้อ..." error_placeholder: "ผิดพลาด" logs: filters: user_placeholder: "ผู้ใช้" address_placeholder: "name@example.com" logs: - created_at: "สร้างเมื่อ" + created_at: "สร้าง" ip_address: "ไอพี" - topic_id: "หมายเลขหัวข้อ" - post_id: "หมายเลยโพสต์" - category_id: "เลขที่หมวดหมู่" + topic_id: "หมายเลขกระทู้" + post_id: "หมายเลขโพสต์" + category_id: "หมายเลขหมวดหมู่" delete: "ลบ" edit: "แก้ไข" save: "บันทึก" + screened_actions: + block: "บล็อก" staff_actions: all: "ทั้งหมด" clear_filters: "แสดงทั้งหมด" staff_user: "ผู้ใช้" + target_user: "ผู้ใช้เป้าหมาย" subject: "หัวข้อ" when: "เมื่อ" details: "รายละเอียด" + previous_value: "ก่อนหน้า" new_value: "ใหม่" show: "แสดง" modal_title: "รายละเอียด" @@ -1743,29 +2718,90 @@ th: actions: delete_user: "ลบผู้ใช้" change_trust_level: "เปลี่ยนระดับความไว้ใจ" - delete_topic: "ลบหัวข้อ" - delete_post: "ลบโพส" + change_username: "เปลี่ยนชื่อผู้ใช้" + change_theme: "เปลี่ยนธีม" + delete_theme: "ลบธีม" + suspend_user: "ระงับผู้ใช้" + unsuspend_user: "เลิกระงับผู้ใช้" + removed_suspend_user: "ระงับผู้ใช้ (ถูกลบ)" + removed_unsuspend_user: "เลิกระงับผู้ใช้ (ถูกลบ)" + check_email: "ตรวจสอบอีเมล" + delete_topic: "ลบกระทู้" + delete_post: "ลบโพสต์" + change_category_settings: "เปลี่ยนการตั้งค่าหมวดหมู่" delete_category: "ลบหมวดหมู่" + create_category: "สร้างหมวดหมู่" + deleted_tag: "แท็กที่ถูกลบ" + renamed_tag: "แท็กที่ถูกเปลี่ยนชื่อ" + activate_user: "เปิดใช้งานผู้ใช้" + deactivate_user: "ระงับการเปิดใช้งานผู้ใช้" + reviewed_post: "โพสต์ที่ถูกรีวิว" + check_personal_message: "ตรวจสอบข้อความส่วนตัว" + topic_published: "กระทู้ถูกเผยแพร่" + post_approved: "โพสต์ได้รับอนุมัติ" + post_rejected: "โพสต์ถูกปฏิเสธ" + create_badge: "สร้างเหรียญ" + change_badge: "เปลี่ยนเหรียญ" + delete_badge: "ลบเหรียญ" + change_name: "เปลี่ยนชื่อ" + approve_user: "ผู้ใช้ที่ได้รับอนุมัติ" + change_theme_setting: "เปลี่ยนการตั้งค่าธีม" + change_title: "เปลี่ยนชื่อเรื่อง" + page_published: "เพจถูกเผยแพร่" + page_unpublished: "เพจไม่ถูกเผยแพร่" + add_email: "เพิ่มอีเมล" + update_email: "อัปเดตอีเมล" + destroy_email: "ทำลายอีเมล" + screened_emails: + email: "ที่อยู่อีเมล" + actions: + allow: "อนุญาต" screened_urls: url: "URL" + domain: "โดเมน" screened_ips: + actions: + block: "บล็อก" + do_nothing: "อนุญาต" + allow_admin: "อนุญาตแอดมิน" form: label: "ใหม่:" + ip_address: "ที่อยู่ไอพี" add: "เพิ่ม" filter: "ค้นหา" search_logs: + searches: "ค้นหา" types: + all_search_types: "การค้นหาทั้งหมด" header: "Header" + full_page: "ทั้งหน้า" watched_words: + search: "ค้นหา" clear_filter: "ล้าง" + download: ดาวน์โหลด clear_all: ล้างทั้งหมด + word_count: + other: "%{count}คำ" actions: + block: "บล็อก" + censor: "เซนเซอร์" + require_approval: "ต้องได้รับการอนุมัติ" flag: "ธง" form: + label: "คำใหม่:" add: "เพิ่ม" + success: "สำเร็จ" + exists: "มีอยู่แล้ว" + upload: "เพิ่มจากไฟล์" + upload_successful: "อัปโหลดสำเร็จแล้ว เพิ่มคำเรียบร้อย" + impersonate: + not_found: "ไม่พบผู้ใช้นั้น" users: title: "ผู้ใช้" last_emailed: "อีเมลล่าสุด" + active: "เปิดใช้งานแล้ว" + show_emails: "แสดงอีเมล" + hide_emails: "ซ่อนอีเมล" nav: new: "ใหม่" active: "ใช้งานอยู่" @@ -1782,31 +2818,44 @@ th: regular: "ผู้ใช้ที่ระดับความไว้ใจ 3 (ทั่วไป)" leader: "ผู้ใช้ที่ระดับความไว้ใจ 4 (ผู้นำ)" staff: "ทีมงาน" + moderators: "ผู้ดูแลระบบ" suspended: "ผู้ใช้งานที่ถูกระงับ" not_verified: "ยังไม่ได้รับการตรวจสอบ" check_email: - title: "แสดงอีเมลผู้ใช้งาน" + title: "แสดงอีเมลของผู้ใช้งานนี้" text: "แสดง" user: - suspend_failed: "มีข้อผิดพลาดในการระงับการใช้งาน %{error}" - unsuspend_failed: "มีข้อผิดพลาดในเปิดการใช้งาน %{error}" - suspend_duration: "ระงับการใช้งานถึงเมื่อไร" + suspend_failed: "มีข้อผิดพลาดในการระงับผู้ใช้งานนี้ %{error}" + unsuspend_failed: "มีข้อผิดพลาดในเปิดผู้ใช้งานนี้ %{error}" + suspend_duration: "ผู้ใช้งานนี้จะถูกระงับถึงเมื่อไร" suspend_reason: "เหตุผล" + suspend_message: "ข้อความอีเมล" suspended_by: "ระงับการใช้งานโดย" silence_reason: "เหตุผล" - delete_all_posts: "ลบโพสทั้งหมด" + silence_message: "ข้อความอีเมล" + suspended_until: "(จนกระทั่ง%{until})" + cant_suspend: "ไม่สามารถระงับผู้ใช้งานนี้ได้" + delete_all_posts: "ลบโพสต์ทั้งหมด" + delete_posts_progress: "กำลังลบโพสต์" + delete_posts_failed: "มีปัญหาขณะกำลังลบโพสต์" + penalty_post_delete: "ลบโพสต์" + penalty_post_delete_replies: "ลบโพสต์ + คำตอบ" + penalty_post_edit: "แก้ไขโพสต์" + moderator: "ผู้ดูแลระบบใช่ไหม" + admin: "แอดมินใช่ไหม" suspended: "ระงับการใช้งานหรือไม่" - show_admin_profile: "ผู้ดูแลระบบ" + show_admin_profile: "แอดมิน" + show_public_profile: "แสดงโปรไฟล์สาธารณะ" ip_lookup: "ค้นหา IP" log_out: "ออกจากระบบ" unsuspend: "เปิดการใช้งาน" suspend: "ระงับการใช้งาน" activity: กิจกรรม last_100_days: "ใน 100 วันที่ผ่านมา" - private_topics_count: หัวข้อส่วนตัว - posts_read_count: อ่านโพส - post_count: โพสถูกสร้างแล้ว - topics_entered: หัวข้อที่ได้ดูแล้ว + private_topics_count: กระทู้ส่วนตัว + posts_read_count: โพสต์ที่อ่าน + post_count: โพสต์ที่สร้าง + topics_entered: กระทู้ที่ดู approve: "อนุมัติ" approved_by: "อนุมัติโดย" time_read: "เวลาอ่าน" @@ -1814,14 +2863,25 @@ th: delete: "ลบผู้ใช้" merge: prompt: + title: "ย้ายและลบ @%{username}" + target_username_placeholder: "ชื่อผู้ใช้ของเจ้าของใหม่" + transfer_and_delete: "ถ่ายโอนและลบ @%{username}" cancel: "ยกเลิก" confirmation: + title: "ถ่ายโอนและลบ @%{username}" + text: "ถ่ายโอน @%{username} ไปยัง @%{targetUsername}" + transfer_and_delete: "ถ่ายโอนและลบ @%{username}" cancel: "ยกเลิก" - delete_forbidden_because_staff: "ผู้ดูแลระบบและผู้ดูแลไม่สามารถถูกลบได้" - delete_posts_forbidden_because_staff: "ไม่สามารถลบโพสทั้งหมดของผู้ดูแลระบบและผู้ดูแลได้" + delete_forbidden_because_staff: "ไม่สามารถลบแอดมินและผู้ดูแลระบบได้" + delete_posts_forbidden_because_staff: "ไม่สามารถลบโพสต์ทั้งหมดของแอดมินและผู้ดูแลระบบได้" delete_and_block: "ลบและ บล็อก อีเมลและไอพีนี้" delete_dont_block: "ลบเท่านั้น" + deleting_user: "กำลังลบผู้ใช้..." deleted: "ผู้ใช้ถูกลบแล้ว" + delete_failed: "มีข้อผิดพลาดขณะกำลังลบผู้ใช้นั้น กรุณาตรวจสอบอีกครั้งว่าโพสต์ทั้งหมดถูกลบก่อนลบผู้ใช้นั้น" + send_activation_email: "ส่งอีเมลยืนยันตัวตน" + activation_email_sent: "อีเมลยืนยันตัวตนถูกส่งแล้ว" + send_activation_email_failed: "เกิดปัญหาขณะกำลังส่งอีเมลยืนยันตัวตนอีกฉบับ %{error}" trust_level_change_failed: "มีความผิดพลาดขณะกำลังเปลี่ยนระดับความไว้ใจของผู้ใช้" trust_level_2_users: "ระดับความไว้ใจ 2 ผู้ใช้" trust_level_3_requirements: "ระดับความไว้ใจ 3 ความต้องการ" @@ -1831,14 +2891,19 @@ th: unlock_trust_level: "ปลดล็อกระดับความไว้ใจ" tl3_requirements: title: "ความต้องการเพิ่มปรับระดับความไว้ใจเป็น 3" + table_title: + other: "ในช่วง %{count}วันที่ผ่านมา:" value_heading: "ค่า" requirement_heading: "ความต้องการ" visits: "เยี่ยมชม" days: "วัน" topics_viewed: "กระทู้ที่ดู" - posts_read: "อ่านโพส" + posts_read: "โพสต์ที่อ่าน" + flagged_posts: "โพสต์ที่ถูกปักธง" + flagged_by_users: "ผู้ใช้ที่ปักธง" likes_given: "ได้ชอบ" likes_received: "ได้รับการชอบ" + suspended: "ถูกระงับการใช้งาน (6 เดือนที่ผ่านมา)" qualifies: "คุณสมบัติเพียงพอสำหรับระดับความไว้ใจที่ 3" does_not_qualify: "คุณสมบัติไม่เพียงพอสำหรับระดับความไว้ใจที่ 3" locked_will_not_be_promoted: "ระดับความไว้ใจถูกล็อก จะไม่ถูกปรับระดับความไว้ใจขึ้น" @@ -1848,7 +2913,7 @@ th: external_username: "ชื่อผู้ใช้" external_name: "ชื่อ" external_email: "อีเมล" - external_avatar_url: "ที่อยู่ภาพประจำตัว" + external_avatar_url: "URL ของรูปโปรไฟล์" user_fields: title: "ช่องข้อมูลผู้ใช้" help: "เพิ่มช่องที่คุณสามารถใส่ข้อมูลเพิ่มได้" @@ -1868,7 +2933,7 @@ th: enabled: "ต้องการ" disabled: "ไม่ต้องการ" editable: - title: "แก้ไขได้หลังลงทะเบียน?" + title: "แก้ไขหลังลงทะเบียนได้ใช่ไหม" enabled: "แก้ไขได้" disabled: "แก้ไขไม่ได้" show_on_profile: @@ -1886,6 +2951,7 @@ th: site_text: description: "คุณสามารถปรับแต่งข้อความบนฟอรั่มของคุณได้คุณอย่าง เริ่มได้โดยการค้นหาข้างล่างนี่" search: "ค้นหาข้อความที่คุณต้องการแก้ไข" + title: "ข้อความ" edit: "แก้ไข" revert: "ย้อนกลับการแก้ไข" revert_confirm: "คุณแน่ใจหรือว่าจะย้อนกลับการแก้ไข" @@ -1900,15 +2966,17 @@ th: clear_filter: "ล้าง" add_url: "เพิ่ม URL" add_host: "เพิ่มโฮส" + add_group: "เพิ่มกลุ่ม" uploaded_image_list: upload: label: "อัปโหลด" + title: "อัปโหลดรูปภาพ" categories: all_results: "ทั้งหมด" required: "ต้องการ" basic: "การตั้งค่าพื้นฐาน" users: "ผู้ใช้" - posting: "โพส" + posting: "กำลังโพสต์" email: "อีเมล" files: "ไฟล์" trust: "ระดับความไว้ใจ" @@ -1932,57 +3000,74 @@ th: default_categories: modal_yes: "ใช่" badges: + title: เหรียญ + new_badge: เหรียญใหม่ new: ใหม่ name: ชื่อ + badge: เหรียญ display_name: ชื่อที่ใช้แสดง description: รายละเอียด long_description: รายละเอียดแบบยาว + badge_type: ประเภทเหรียญ badge_grouping: กลุ่ม + badge_groupings: + modal_title: การจัดกลุ่มเหรียญ granted_by: อนุญาตโดย granted_at: อนุญาตเมื่อ reason_help: (ลิงก์ไปยังหัวข้อหรือโพส) save: บันทึก delete: ลบ + delete_confirm: คุณแน่ใจหรือว่าต้องการลบเหรียญนี้ revoke: เอาออก reason: เหตุผล - icon: ไอค่อน + edit_badges: แก้ไขเหรียญ + icon: ไอคอน image: ภาพ trigger_type: + none: "อัปเดตรายวัน" + post_revision: "เมื่อผู้ใช้แก้ไขหรือสร้างโพสต์" trust_level_change: "เมื่อผู้ใช้เปลี่ยนระดับความไว้ใจ" + user_change: "เมื่อผู้ใช้ถูกแก้ไขหรือถูกสร้าง" + post_processed: "หลังจากโพสต์ถูกดำเนินการ" preview: bad_count_warning: - header: "อันตราย!" + header: "ระวัง!" sample: "ตัวอย่าง:" grant: with: "%{username}" with_post: "%{username} สำหรับโพสต์ใน %{link}" with_post_time: "%{username} สำหรับโพสต์ใน %{link} เมื่อ %{time}" with_time: "%{username} เมื่อ %{time}" + badge_intro: + emoji: "อีโมจินักเรียนหญิง" + what_are_badges_title: "เหรียญคืออะไร" + mass_award: + replace_owners: ลบเหรียญจากผู้ใช้ก่อนหน้านี้ emoji: - title: "Emoji" - add: "เพิ่ม Emoji ใหม่" + title: "อีโมจิ" + add: "เพิ่มอีโมจิใหม่" uploading: "กำลังอัปโหลด..." name: "ชื่อ" group: "กลุ่ม" image: "ภาพ" - delete_confirm: "คุณแน่ใจหรือว่าจะลบ Emoji :%{name}: ออก?" + delete_confirm: "คุณแน่ใจหรือว่าจะลบอีโมจิ :%{name}: ออก" embedding: confirm_delete: "คุณแน่ใจหรือว่าจะลบโพสนั้น?" title: "ฝั่ง" host: "อนุญาตโฮส" edit: "แก้ไข" - category: "โพสไปยังหมวดหมู่" + category: "โพสต์ไปยังหมวดหมู่" add_host: "เพิ่มโฮส" settings: "การตั้งการการฝั่ง" save: "บันทึกการตั้งค่าการฝั่ง" permalink: title: "ลิงค์ถาวร" url: "URL" - topic_id: "เลขที่หัวข้อ" - topic_title: "หัวข้อ" - post_id: "เลขที่โพส" - post_title: "โพส" - category_id: "เลขที่หมวดหมู่" + topic_id: "หมายเลขกระทู้" + topic_title: "กระทู้" + post_id: "หมายเลขโพสต์" + post_title: "โพสต์" + category_id: "หมายเลขหมวดหมู่" category_title: "หมวดหมู่" external_url: "ลิงก์ภายนอก" delete_confirm: "คุณแน่ใจหรือว่าจะลบลิงค์ถาวรนี้?" @@ -1993,18 +3078,25 @@ th: reseed: modal: categories: "หมวดหมู่" - topics: "หัวข้อ" + topics: "กระทู้" wizard_js: wizard: done: "เสร็จ" + finish: "เสร็จสิ้น" back: "กลับ" + next: "ต่อไป" upload: "อัปโหลด" uploading: "กำลังอัปโหลด..." - upload_error: "ขอโทษ, เกิดความผิดพลาดขณะกำลังอัพโหลดไฟล์ โปรดลองใหม่อีกครั้ง" + upload_error: "ขออภัย เกิดความผิดพลาดขณะกำลังอัปโหลดไฟล์ กรุณาลองใหม่อีกครั้ง" + staff_count: + other: "ชุมชนของคุณมีทีมงาน %{count}คน รวมถึงคุณด้วย" invites: + add_user: "เพิ่ม" + none_added: "คุณยังไม่ได้เชิญทีมงาน คุณแน่ใจหรือว่าต้องการดำเนินการต่อ" roles: - admin: "ผู้ดูแลระบบ" + admin: "แอดมิน" moderator: "ผู้ดูแล" + regular: "ผู้ใช้ทั่วไป" previews: share_button: "แบ่งปัน" reply_button: "ตอบ" diff --git a/config/locales/client.tr_TR.yml b/config/locales/client.tr_TR.yml index 4b53d9f084..24402a0926 100644 --- a/config/locales/client.tr_TR.yml +++ b/config/locales/client.tr_TR.yml @@ -740,7 +740,6 @@ tr_TR: all: "Tümü" read: "Okunan" unread: "Okunmamış" - ignore_duration_title: "Zamanlayıcıyı Yoksay" ignore_duration_username: "Kullanıcı Adı" ignore_duration_when: "Süre:" ignore_duration_save: "Yoksay" @@ -951,6 +950,8 @@ tr_TR: confirm: "\"Kullanıcı Adı\"nı değiştirmek istediğine emin misin?" taken: "Üzgünüz, bu kullanıcı adı daha önce alınmış. " invalid: "Bu kullanıcı adı geçersiz. Kullanıcı adı, sadece sayı ve harf içerebilir. " + add_email: + add: "ekle" change_email: title: "\"E-posta Adresi\"ni Değiştir" taken: "Üzgünüz, bu e-posta kullanılabilir değil." @@ -977,8 +978,10 @@ tr_TR: title: "E-posta" primary: "Öncelikli E-posta" secondary: "İkincil E-postalar" - no_secondary: "İkincil e-posta adresi mevcut değil" + primary_label: "Ana" + update_email: "\"E-posta Adresi\"ni Değiştir" sso_override_instructions: "E-posta SSO sağlayıcısından güncellenebilir." + no_secondary: "İkincil e-posta adresi mevcut değil" instructions: "Hiç kimseye gösterilmedi." ok: "Onaylaman için sana e-posta göndereceğiz" invalid: "Lütfen geçerli bir e-posta adresi gir" @@ -1257,10 +1260,10 @@ tr_TR: login_disabled: "Site salt-okunur modda iken giriş işlemi devre dışı bırakılır ." logout_disabled: "Site salt-okunur modda iken çıkış işlemi yapılamaz." logs_error_rate_notice: - reached_hour_MF: "{relativeAge}{rate, plural, one {# hata/saat} diğeri {# hata/saat}} site limitlerine ulaştı {limit, plural, one {# hata/saat} other {# hata/saat}}." - reached_minute_MF: "{relativeAge}{rate, plural, one {# hata/saat} {# hata/dakika}} site limitlerine ulaştı {limit, plural, one {# hata/dakika} other {# hata/dakika}}." - exceeded_hour_MF: "{relativeAge}{rate, plural, one {# hata/saat} diğeri {# hata/saat}} site ayarlanmış limitini aştı {limit, plural, one {# hata/saat} diğer{# hata/saat}}." - exceeded_minute_MF: "{relativeAge}{rate, plural, one {# hata/saat} {# hata/dakika}} site ayarlanmış limitlerini aştı {limit, plural, one {# hata/dakika} diğer {# hata/dakika}}." + reached_hour_MF: "{relativeAge}{rate, plural, one {# hata/saat} other {# hata/saat}} site limitlerine ulaştı {limit, plural, one {# hata/saat} other {# hata/saat}}." + reached_minute_MF: "{relativeAge}{rate, plural, one {# hata/saat} other {# hata/dakika}} site limitlerine ulaştı {limit, plural, one {# hata/dakika} other {# hata/dakika}}." + exceeded_hour_MF: "{relativeAge}{rate, plural, one {# hata/saat} other {# hata/saat}} site ayarlanmış limitini aştı {limit, plural, one {# hata/saat} other {# hata/saat}}." + exceeded_minute_MF: "{relativeAge}{rate, plural, one {# hata/saat} other {# hata/dakika}} site ayarlanmış limitlerini aştı {limit, plural, one {# hata/dakika} other {# hata/dakika}}." learn_more: "daha fazlasını öğren..." all_time: "toplam" all_time_desc: "oluşturulan tüm konular " @@ -2180,6 +2183,8 @@ tr_TR: title: "Seçili Gönderileri Birleştir" action: "seçili gönderileri birleştir" error: "Seçili gönderileri birleştirirken bir hata oluştu." + publish_page: + public: "Herkese Açık" change_owner: title: "Sahibini Değiştir" action: "sahipliği değiştir" @@ -2380,7 +2385,6 @@ tr_TR: last: "Son revizyon" hide: "Düzenlemeyi gizle" show: "Düzenlemeyi göster" - revert: "Bu uyarlamaya geri dön" edit_wiki: "Wiki'yi düzenle" edit_post: "Gönderiyi düzenle" comparing_previous_to_current_out_of_total: "%{previous}%{icon}%{current}/%{total}" @@ -3036,7 +3040,7 @@ tr_TR: more: 'Arama Günlükleri' disabled: 'Trend arama raporu devredışı. Veri toplamak için log arama sorgusunu etkinleştirin.' filters: - file-extension: + file_extension: label: Dosya uzantısı group: label: Grup diff --git a/config/locales/client.uk.yml b/config/locales/client.uk.yml index e3674bd593..ad474f5214 100644 --- a/config/locales/client.uk.yml +++ b/config/locales/client.uk.yml @@ -821,7 +821,6 @@ uk: all: "Усі" read: "Прочитані" unread: "Непрочитані" - ignore_duration_title: "Ігнорувати таймер" ignore_duration_username: "Ім'я користувача" ignore_duration_when: "Тривалість:" ignore_duration_save: "Ігнорувати" @@ -1034,6 +1033,8 @@ uk: confirm: "Ви цілковито впевнені, що бажаєте змінити своє ім'я користувача?" taken: "Даруйте, це ім'я користувача вже зайняте." invalid: "Таке ім'я користувача не підійде. Воно має містити лише цифри та літери" + add_email: + add: "додати" change_email: title: "Змінити адресу електронної пошти" taken: "Даруйте, ця адреса не доступна." @@ -1060,8 +1061,10 @@ uk: title: "Електронна пошта" primary: "Основна електронна пошта" secondary: "Другорядна електронна пошта" - no_secondary: "Немає другорядних електронних скриньок" + primary_label: "основний" + update_email: "Змінити адресу електронної пошти" sso_override_instructions: "Електронну пошту можна оновити через SSO-провайдера." + no_secondary: "Немає другорядних електронних скриньок" instructions: "Ніколи не показується публічно." ok: "Ми надішлемо Вам листа для підтвердження" invalid: "Будь ласка, введіть вірний email" @@ -1359,11 +1362,6 @@ uk: enabled: "Сайт працює в режимі \"тільки для читання\". Зараз ви можете продовжувати переглядати сайт, але інші дії будуть недоступні. " login_disabled: "Вхід вимкнено, поки сайт перебуває в режимі лише для читання." logout_disabled: "Вихід відключений, поки сайт в режимі «тільки для читання»" - logs_error_rate_notice: - reached_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} або {# errors/hour}} досягнуто максимально дозволене значення {limit, plural, one {# error/hour} або {# errors/hour}}." - reached_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} або {# errors/minute}} досягнуто максимально дозволене значення {limit, plural, one {# error/minute} або {# errors/minute}}." - exceeded_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} або {# errors/hour}} досягнуто максимально дозволене значення {limit, plural, one {# error/hour} або {# errors/hour}}." - exceeded_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} або {# errors/minute}} перевищено максимально дозволене значення {limit, plural, one {# error/minute} або {# errors/minute}}." learn_more: "дізнатися більше..." all_time: "всього" all_time_desc: "всього створено тем" @@ -2337,6 +2335,8 @@ uk: title: "З’єднати виділені повідомлення" action: "З’єднати виділені повідомлення" error: "Сталася помилка під час з’єднання виділених повідомлень." + publish_page: + public: "Публічні" change_owner: title: "Змінити Власника" action: "змінити власність" @@ -2571,7 +2571,6 @@ uk: last: "Остання версія" hide: "Приховати версію" show: "Показати версію" - revert: "Відкат до цієї версії" edit_wiki: "редагувати Wiki" edit_post: "редагувати запис" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -3285,7 +3284,7 @@ uk: more: 'Пошукові логи' disabled: 'Звіт про пошукові запити відключено. Включити журнал пошукових запитів для збору даних.' filters: - file-extension: + file_extension: label: Розширення файлу group: label: Група diff --git a/config/locales/client.ur.yml b/config/locales/client.ur.yml index 55994f390e..66b740db6f 100644 --- a/config/locales/client.ur.yml +++ b/config/locales/client.ur.yml @@ -726,7 +726,6 @@ ur: all: "تمام" read: "پڑھ لیا گیا" unread: "بغیر پڑھے" - ignore_duration_title: "ٹائمر نظر انداز کریں" ignore_duration_username: "صارف کا نام" ignore_duration_when: "دورانیہ:" ignore_duration_save: "نظر انداز کریں" @@ -925,6 +924,8 @@ ur: confirm: "کیا آپ کو بالکل یقین ہے کہ آپ اپنا صارف نام تبدیل کرنا چاہتے ہیں؟" taken: "معذرت، یِہ صارف نام پہلے سے لیا جاچکا ہے۔" invalid: "یہ صارف نام غلط ہے۔ اِس میں صرف ہندسوں اور حروف کو شامل کیا جا سکتا ہے" + add_email: + add: "شامل کریں" change_email: title: "اِی میل تبدیل کریں" taken: "معذرت، یہ اِی میل دستیاب نہیں ہے۔" @@ -945,8 +946,10 @@ ur: title: "اِی میل" primary: "بنیادی ایمیل" secondary: "ثانوی ایمیلز" - no_secondary: "کوئی ثانوی ایمیلز نہیں" + primary_label: "بنیادی" + update_email: "اِی میل تبدیل کریں" sso_override_instructions: "SSO پرووَائیڈر سے ایمیل کو اَپ ڈیٹ کیا جا سکتا ہے۔" + no_secondary: "کوئی ثانوی ایمیلز نہیں" instructions: "کبھی بھی عوام کو دکھایا نہیں گیا۔" ok: "ہم تصدیق کے لئے آپ کو اِی میل کریں گے" invalid: "براہ کرم، ایک قابلِ قبول ایِ میل ایڈریس درج کریں" @@ -2116,6 +2119,8 @@ ur: title: "منتخب کردہ پوسٹس کو ضم کریں" action: "منتخب کردہ پوسٹس کو ضم کریں" error: "منتخب کردہ پوسٹس کو ضم کرنے میں ایک خرابی کا سامنا کرنا پڑا۔" + publish_page: + public: "عوامی" change_owner: title: "مالک تبدیل کریں" action: "پوسٹس کے مالک کو تبدیل کریں" @@ -2305,7 +2310,6 @@ ur: last: "آخری رَوِیژن" hide: "رَوِیژن چھپائیں" show: "رَوِیژن دکھائیں" - revert: "اِس رَوِیژن پر واپس جائیں" edit_wiki: "وِیکی میں ترمیم کریں" edit_post: "پوسٹ میں ترمیم کریں" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -2930,7 +2934,7 @@ ur: more: 'تلاشی کے لاگز' disabled: 'سرچ رجحان کی رپورٹ غیر فعال ہے۔ اعداد و شمار جمع کرنے کیلئے لاگ سرچ قُوَیریز کو فعال کریں۔' filters: - file-extension: + file_extension: label: فائل ایکسٹینشن group: label: گروپ diff --git a/config/locales/client.vi.yml b/config/locales/client.vi.yml index b63f5eed4d..e6b79954e0 100644 --- a/config/locales/client.vi.yml +++ b/config/locales/client.vi.yml @@ -701,7 +701,6 @@ vi: all: "Tất cả" read: "Đã đọc" unread: "Chưa đọc" - ignore_duration_title: "Bỏ qua bộ đếm giờ" ignore_duration_username: "Tên đăng nhập" ignore_duration_when: "Thời lượng:" ignore_duration_save: "Bỏ qua" @@ -881,6 +880,8 @@ vi: title: "Email" primary: "Email chính" secondary: "Email thứ hai" + primary_label: "chính" + update_email: "Thay đổi Email" no_secondary: "Không có email thứ hai" instructions: "Không hiển thị công cộng" ok: "Chúng tôi sẽ gửi thư điện tử xác nhận đến cho bạn" @@ -1737,6 +1738,8 @@ vi: other: "Hãy chọn chủ đề bạn muốn di chuyển %{count} bài viết này tới." move_to_new_message: radio_label: "Tin nhắn mới" + publish_page: + public: "Công khai" change_owner: action: "chuyển chủ sở hữu" error: "Có lỗi xảy ra khi thay đổi quyền sở hữu của các bài viết." @@ -1863,7 +1866,6 @@ vi: last: "Sửa đổi gần nhất" hide: "Ẩn sửa đổi" show: "Hiện sửa đổi" - revert: "Hoàn nguyên sửa đổi" edit_wiki: "Sửa wiki" edit_post: "Sửa bài đăng" displays: diff --git a/config/locales/client.zh_CN.yml b/config/locales/client.zh_CN.yml index adf1102e5f..3721637772 100644 --- a/config/locales/client.zh_CN.yml +++ b/config/locales/client.zh_CN.yml @@ -730,7 +730,7 @@ zh_CN: all: "全部" read: "阅读" unread: "未读" - ignore_duration_title: "忽略计时器" + ignore_duration_title: "忽略的用户" ignore_duration_username: "用户名" ignore_duration_when: "持续时间:" ignore_duration_save: "忽略" @@ -836,7 +836,9 @@ zh_CN: admin_delete: "删除" users: "用户" muted_users: "静音" + muted_users_instructions: "封禁来自这些用户的所有通知和私信。" ignored_users: "忽视" + ignored_users_instructions: "封禁来自这些用户的所有帖子、通知和私信。" tracked_topics_link: "显示" automatically_unpin_topics: "当我完整阅读了主题时自动解除置顶。" apps: "应用" @@ -954,6 +956,9 @@ zh_CN: confirm: "你确定要更改用户名吗?" taken: "抱歉,此用户名已经有人使用了。" invalid: "此用户名不合法,用户名只能包含字母和数字" + add_email: + title: "添加邮箱地址" + add: "添加" change_email: title: "更换邮箱" taken: "抱歉,此邮箱不可用。" @@ -984,8 +989,17 @@ zh_CN: title: "邮箱" primary: "主邮箱" secondary: "次邮箱" - no_secondary: "没有次邮箱" + primary_label: "主要" + unconfirmed_label: "未确认" + resend_label: "重新发送确认邮件" + resending_label: "发送中..." + resent_label: "邮件已发送" + update_email: "更换邮箱" + set_primary: "设置为主邮箱" + destroy: "删除邮箱" + add_email: "添加次要邮箱" sso_override_instructions: "电子邮件地址可以通过SSO登录来更新。" + no_secondary: "没有次邮箱" instructions: "绝不会被公开显示" ok: "将通过邮件验证确认" required: "请输入一个电子邮件地址" @@ -1136,6 +1150,7 @@ zh_CN: expired: "邀请已过期。" rescind: "移除" rescinded: "邀请已删除" + rescind_all: "删除过期的邀请" rescinded_all: "所有过期邀请已删除!" rescind_all_confirm: "你确定你想要移除所有过期邀请么?" reinvite: "重新发送邀请" @@ -1146,18 +1161,30 @@ zh_CN: time_read: "阅读时间" days_visited: "访问天数" account_age_days: "账户建立天数" + source: "被邀请通过" links_tab: "链接" + links_tab_with_count: "链接(%{count})" + link_url: "链接" link_created_at: "创建日期" + link_redemption_stats: "兑换量" link_groups: 群组 + link_expires_at: 过期 create: "发送邀请" + copy_link: "复制链接" generate_link: "复制邀请链接" link_generated: "邀请链接生成成功!" valid_for: "邀请链接只对这个邮件地址有效:%{email}" single_user: "单个用户" + multiple_user: "多个用户" invite_link: + title: "邀请链接" success: "邀请链接生成成功!" + error: "生成邀请链接时出错" + max_redemptions_allowed_label: "多少人被允许通过这个链接注册?" + expires_at: "邀请链接多久失效?" bulk_invite: none: "你还没有邀请任何人。你可以单独邀请用户,也可以通过上传CSV文件批量邀请。" + text: "批量邀请" success: "文件上传成功,当操作完成时将通过私信通知你。" error: "抱歉,文件必须是CSV格式。" confirmation_message: "你将通过电子邮件将邀请发送给在上传的文件中的每一个人。" @@ -1935,6 +1962,7 @@ zh_CN: time_frame_required: 请选择一个时间范围 auto_update_input: none: "选择时间范围" + now: "当前" later_today: "今天的某个时候" tomorrow: "明天" later_this_week: "这周的某个时候" @@ -2188,11 +2216,14 @@ zh_CN: publish: "出版" description: "当一个主题被出版为一个页面时,其链接是共享的,并且会以自定义的样式显示。" slug: "Slug" + public: "公开" + public_description: "尽管关联的主题是私有主题,但还是能被其他用户查看。" publish_url: "你的页面已出版于:" topic_published: "你的主题已出版于:" preview_url: "你的页面将出版于:" invalid_slug: "抱歉,您不能出版此页面。" unpublish: "取消出版" + update: "更新" unpublished: "你的页面已经取消出版并且不再可用。" publishing_settings: "出版设置" change_owner: @@ -2259,6 +2290,7 @@ zh_CN: unread: "未读帖子" has_replies: other: "%{count} 回复" + unknown_user: "(未知或已删除的用户)" has_likes_title: other: "%{count} 人赞了该贴" has_likes_title_only_you: "你喜欢了这个帖子" @@ -2381,7 +2413,7 @@ zh_CN: last: "最新版" hide: "隐藏版本历史" show: "显示版本历史" - revert: "还原至该版本" + revert: "还原到版本%{revision}" edit_wiki: "编辑维基" edit_post: "编辑帖子" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" @@ -2552,6 +2584,9 @@ zh_CN: moderation: "审核" appearance: "主题" email: "邮箱" + list_filters: + all: "所有主题" + none: "无子分类" flagging: title: "感谢你帮助我们建设文明社区!" action: "标记帖子" @@ -3043,13 +3078,13 @@ zh_CN: more: '搜索日志' disabled: '趋势搜索报告已停用。启用记录搜索查询以收集数据。' filters: - file-extension: + file_extension: label: 文件扩展名 group: label: 群组 category: label: 分类 - include-subcategories: + include_subcategories: label: "包括子分类" commits: latest_changes: "最近的更新:请经常升级!" @@ -3744,6 +3779,9 @@ zh_CN: override_upload_secure_status: "覆盖上传安全状态" page_published: "页面已出版" page_unpublished: "页面未出版" + add_email: "添加邮箱" + update_email: "更新邮箱" + destroy_email: "删除邮箱" screened_emails: title: "已屏蔽的邮件地址" description: "当有人试图用以下邮件地址注册时,将受到阻止或其它系统操作。" @@ -4283,8 +4321,9 @@ zh_CN: category_id: "分类 ID" category_title: "分类" tag_name: "标签名称" - external_url: "外部 URL" + external_url: "外部或相关 URL" destination: "目标" + copy_to_clipboard: "拷贝永久链接到剪贴板" delete_confirm: 你确定要删除该永久链接? form: label: "新:" diff --git a/config/locales/client.zh_TW.yml b/config/locales/client.zh_TW.yml index a93a1a3cc8..c4949bb986 100644 --- a/config/locales/client.zh_TW.yml +++ b/config/locales/client.zh_TW.yml @@ -649,7 +649,6 @@ zh_TW: all: "全部" read: "已讀" unread: "未讀" - ignore_duration_title: "忽略計時器" ignore_duration_username: "使用者名稱" ignore_duration_when: "持續時間:" ignore_duration_save: "忽略" @@ -836,6 +835,8 @@ zh_TW: confirm: "確定要修改你的使用者名稱嗎?" taken: "抱歉,此使用者名稱已經有人使用。" invalid: "此使用者名稱無效,只能使用數字與英文字母。" + add_email: + add: "添加" change_email: title: "修改電子郵件地址" taken: "抱歉,此電子郵件地址無效。" @@ -856,8 +857,10 @@ zh_TW: title: "電子郵件" primary: "主要電子郵件" secondary: "次要電子郵件" - no_secondary: "無次要電子郵件" + primary_label: "一級" + update_email: "修改電子郵件地址" sso_override_instructions: "單一登入服務提供者可更新電子郵件" + no_secondary: "無次要電子郵件" instructions: "不會公開顯示" ok: "我們將寄一封確認郵件給您。" invalid: "請輸入有效的電子郵件地址。" @@ -1949,6 +1952,8 @@ zh_TW: title: "合併選擇的貼文" action: "合併選擇的貼文" error: "合併選擇的貼文試出錯。" + publish_page: + public: "公開" change_owner: title: "變更擁有者" action: "變更擁有者" @@ -2120,7 +2125,6 @@ zh_TW: last: "最新版" hide: "隱藏修訂紀錄" show: "顯示修訂紀錄" - revert: "還原至該版本" edit_wiki: "編輯共筆" edit_post: "編輯貼文" comparing_previous_to_current_out_of_total: "%{previous}%{icon}%{current}/%{total}" @@ -2706,7 +2710,7 @@ zh_TW: more: ' 搜尋記錄檔 ' disabled: '搜尋趨勢已停用,啟用搜尋紀錄以收集資料。' filters: - file-extension: + file_extension: label: 檔案副檔名 group: label: 群組 diff --git a/config/locales/server.ar.yml b/config/locales/server.ar.yml index 8795267056..5c5fd2eff1 100644 --- a/config/locales/server.ar.yml +++ b/config/locales/server.ar.yml @@ -1013,7 +1013,6 @@ ar: maximum_backups: "أكبر قدر ممكن من النسخ الاحتياطي للحفاظ على القرص. يتم حذف النسخ الاحتياطية القديمة تلقائيا" automatic_backups_enabled: "فعل النسخ الإحتياطي التلقائي بشكل متكرر كما هو محدد." s3_backup_bucket: "الرفع عن بعد لإجراء نسخ إحتياطية. تحذير : تأكد من أنه رفع خاص." - s3_disable_cleanup: "عطل النسخ الاحتياطيه المحذوفه من S3 عندما يتم حذفها محلياً" backup_time_of_day: "الوقت الذي يجب ان تأخد النسخ الاحتياطية فيه." backup_with_uploads: "إضافة التحميلات ل النسخ الإحتياطية. إلغاء هذة الخاصية سوف تؤدي إلى أخذ نسخ إحتياطية من قاعدة البيانات فقط." active_user_rate_limit_secs: "كيف في كثير من الأحيان نقوم بتحديث حقل 'last_seen_at، في ثوان" @@ -1456,6 +1455,8 @@ ar: subject_template: "أكّد عنوان بريد الإلكتروني الجديد %{email_prefix}" confirm_old_email: subject_template: "أكّد عنوان بريد الإلكتروني الحالي %{email_prefix}" + confirm_old_email_add: + subject_template: "أكّد عنوان بريد الإلكتروني الحالي %{email_prefix}" notify_old_email: subject_template: "عنوان بريد الإلكتروني تم تغييرة %{email_prefix}" signup_after_approval: diff --git a/config/locales/server.be.yml b/config/locales/server.be.yml index 9973fdcc9c..5e6ee20aac 100644 --- a/config/locales/server.be.yml +++ b/config/locales/server.be.yml @@ -1042,7 +1042,6 @@ be: s3_backup_bucket: "Выдаленае вядро для захоўвання рэзервовых копій. УВАГА: Пераканайцеся, што гэта прыватнае вядро." s3_endpoint: "Канчатковая кропка можа быць мадыфікаваная для рэзервовага капіявання на сумяшчальную службу S3 як DigitalOcean прасторы або Minio. УВАГА: Пакіньце пустым, калі з дапамогай AWS S3." s3_configure_tombstone_policy: "Ўключыць аўтаматычную палітыку выдалення для загрузкі надмагільных. ВАЖНА: Калі адключана, няма месца будзе вызвалена пасля дадання будуць выдаленыя." - s3_disable_cleanup: "Адключыць выдаленне рэзервовых копій з S3, калі выдаляецца лакальна." enable_s3_inventory: "Стварэнне справаздач і праверкі загрузкі з дапамогай інвентарызацыі Amazon S3. ВАЖНА: патрабуе сапраўдныя ўліковыя дадзеныя S3 (як доступ да ключавой ідэнтыфікатар & сакрэтны ключ доступу)." backup_time_of_day: "Час дня UTC, калі павінна адбыцца рэзервовае капіраванне." backup_with_uploads: "Ўключыць загрузку ў запланаваныя аперацыі рэзервовага капіявання. Адключэнне гэтага будзе толькі рэзервовае капіраванне базы дадзеных." @@ -1351,7 +1350,6 @@ be: city_for_disputes: "Горад для спрэчак" shared_drafts_category: "Ўключыць функцыю агульных Шашкі шляхам прызначэння катэгорыі для тэматычных праектаў. Тэмы ў гэтай катэгорыі будуць душыцца са спісу тэмы для карыстальнікаў персаналу." push_notifications_prompt: "Дысплей згоды карыстальніка запрашэнне." - push_notifications_icon: "Значок значок, які з'яўляецца ў куце паведамлення. Неабходны памер 96 × 96." short_title: "Кароткае назва будзе выкарыстоўвацца на хатнім экране карыстальніка, пускавы, ці ў іншых месцах, дзе прастора можа быць абмежавана. Яно павінна быць абмежавана да 12 знакаў." dashboard_general_tab_activity_metrics: "Выберыце справаздачы, якія будуць адлюстроўвацца ў якасці паказчыкаў актыўнасці на ўкладцы Агульныя." errors: @@ -2020,6 +2018,8 @@ be: confirm_old_email: title: "Пацвердзіце стары адрас электроннай пошты" subject_template: "[%{email_prefix}] Пацвердзіце свой бягучы адрас электроннай пошты" + confirm_old_email_add: + subject_template: "[%{email_prefix}] Пацвердзіце свой бягучы адрас электроннай пошты" notify_old_email: title: "Апавяшчаць Стары e-mail" subject_template: "[%{email_prefix}] Ваш электронны адрас быў зменены" diff --git a/config/locales/server.ca.yml b/config/locales/server.ca.yml index 27c7c796a9..d06e89498c 100644 --- a/config/locales/server.ca.yml +++ b/config/locales/server.ca.yml @@ -717,7 +717,6 @@ ca: confirm: "Confirma" authorizing_new: title: "Confirmeu la vostra nova adreça electrònica" - description: "Confirmeu que voleu canviar la vostra nova adreça de correu electrònic a:" authorizing_old: title: "Canvieu la vostra adreça de correu electrònic" description: "Confirmeu el canvi d’adreça electrònica" @@ -1477,7 +1476,6 @@ ca: s3_backup_bucket: "Bucket remot que contindrà les còpies de seguretat. ATENCIÓ: Assegureu-vos que és un bucket privat." s3_endpoint: "El punt final es pot modificar per a fer còpies de seguretat en un servei compatible amb S3 com ara DigitalOcean Spaces o Minio. AVÍS: Deixeu-ho en blanc si feu servir AWS S3." s3_configure_tombstone_policy: "Activa la política de supressió automàtica per a càrregues 'tombstone'. IMPORTANT: si és desactivat, no es reclamarà cap espai després de suprimir les càrregues." - s3_disable_cleanup: "Inhabilita l'eliminació de còpies de seguretat de S3 quan s'eliminin localment." enable_s3_inventory: "Genera reports i verifica les càrregues de fitxers mitjançant l'inventari d'Amazon S3. IMPORTANT: Requereix credencials S3 vàlides (tant identificador de clau d'accés com clau d'accés secreta)." backup_time_of_day: "Hora del dia (UTC) en què s'hauria de fer la còpia de seguretat." backup_with_uploads: "Inclou els fitxers carregats en les còpies de seguretat planificades. Si s'inhabilita, només es farà còpia de seguretat de la base de dades." @@ -1860,7 +1858,6 @@ ca: city_for_disputes: "Ciutat per a les disputes" shared_drafts_category: "Activa la funció 'Esborranys compartits' designant una categoria per als esborranys de tema. Els temes d'aquesta categoria seran suprimits de les llistes de temes per als usuaris de l'equip responsable." push_notifications_prompt: "Mostra la sol·licitud de consentiment de l'usuari." - push_notifications_icon: "Icona d'insígnia que apareix a la zona de notificació. La mida requerida és de 96 × 96." short_title: "El títol curt s'utilitzarà en la pantalla d'inici de l'usuari, en el llançador o en altres llocs on l'espai sigui limitat. Hauria de limitar-se a 12 caràcters." dashboard_general_tab_activity_metrics: "Trieu reports que es mostraran com a mètriques d'activitat en la pestanya general." errors: @@ -2740,6 +2737,8 @@ ca: title: "Confirmeu l'adreça de correu antiga" subject_template: "[%{email_prefix}] Confirmeu la vostra adreça de correu actual" text_body_template: "Abans de canviar la vostra adreça electrònica, necessitem que confirmeu que controleu\nel compte de correu electrònic actual. Després de completar aquest pas, us haurem de confirmar \nla nova adreça electrònica. \n\nConfirmeu la vostra adreça electrònica actual per a %{site_name} fent clic en l'enllaç següent:\n\n%{base_url}/u/confirm-old-email/%{email_token}\n" + confirm_old_email_add: + subject_template: "[%{email_prefix}] Confirmeu la vostra adreça de correu actual" notify_old_email: title: "Notifica l'adreça de correu antiga" subject_template: "[%{email_prefix}] La vostra adreça de correu ha canviat" diff --git a/config/locales/server.da.yml b/config/locales/server.da.yml index 2f479f096f..dea86678e2 100644 --- a/config/locales/server.da.yml +++ b/config/locales/server.da.yml @@ -1514,6 +1514,8 @@ da: subject_template: "[%{email_prefix}] Bekræft din nye e-mail-adresse" confirm_old_email: subject_template: "[%{email_prefix}] Bekræft din nuværende e-mail-adresse" + confirm_old_email_add: + subject_template: "[%{email_prefix}] Bekræft din nuværende e-mail-adresse" notify_old_email: subject_template: "[%{email_prefix}] Din e-mail-adresse er ændret" signup_after_approval: diff --git a/config/locales/server.de.yml b/config/locales/server.de.yml index 4b02ef0eac..6177e95e85 100644 --- a/config/locales/server.de.yml +++ b/config/locales/server.de.yml @@ -712,7 +712,6 @@ de: confirm: "Bestätigen" authorizing_new: title: "Bestätige deine neue E-Mail" - description: "Bitte bestätige, dass deine E-Mail Adresse geändert wird auf:" authorizing_old: title: "Ändere deine E-Mail Adresse" description: "Bitte bestätige die Änderung deiner E-Mail Adresse" @@ -1486,7 +1485,6 @@ de: s3_backup_bucket: "Der entfernte Speicherort für Ihre Sicherungen. WARNUNG: Stellen Sie sicher, dass es sich um einen privaten Speicherort handelt." s3_endpoint: "Dieser Endpunkt kann so angepasst werden, dass er die Sicherung an einen S3-kompatiblen Service wie DigitalOcean Spaces oder Minio übertragt. WARNUNG: Verwende den Standard bei Verwendung von AWS S3." s3_configure_tombstone_policy: "Aktiviere die automatische Löschregel für Grabstein-Uploads. WICHTIG: Wenn deaktiviert, wird kein Speicherplatz freigegeben, wenn Uploads gelöscht werden." - s3_disable_cleanup: "Deaktiviere das Löschen von Backups aus S3 wenn sie lokal entfernt werden" enable_s3_inventory: "Erstelle Berichte und überprüfe Uploads mit Amazon S3-Bestand. WICHTIG: Benötigt gültige S3-Anmeldeinformationen (sowohl access_key_id als auch secret_access_key)." backup_time_of_day: "Uhrzeit in UTC, wenn Backups ausgeführt werden sollen." backup_with_uploads: "Hochgeladene Dateien bei geplanten Backups mit einbeziehen. Wenn diese Einstellung deaktiviert ist, wird nur die Datenbank gesichert." @@ -1874,7 +1872,6 @@ de: city_for_disputes: "Stadt für Rechtsstreitigkeiten" shared_drafts_category: "Aktiviere die Funktion „Gemeinsame Vorlagen“, indem du eine Kategorie für Themen-Vorlagen bestimmst. Themen in dieser Kategorie werden unterdrückt in der Themen Liste für Team Mitarbeiter." push_notifications_prompt: "Zeige eine Aufforderung zur Benutzerzustimmung an." - push_notifications_icon: "Das Abzeichen-Icon, das in der Benachrichtigungsecke erscheint. Erforderliche Größe ist 96 × 96." short_title: "Der Kurztitel wird beim Benutzer auf dem Startbildschirm, Startmenü oder an anderen Stellen mit begrenztem Platz verwendet. Er sollte auf 12 Zeichen begrenzt sein." dashboard_general_tab_activity_metrics: "Wähle Berichte, die als Aktivitätsmetrik auf dem Allgemein-Tab angezeigt werden." errors: @@ -3030,6 +3027,8 @@ de: Bestätige deine aktuelle E-Mail Adresse für %{site_name}, indem du auf den folgenden Link klickst: %{base_url}/u/confirm-old-email/%{email_token} + confirm_old_email_add: + subject_template: "[%{email_prefix}] Bestätige deine aktuelle E-Mail-Adresse" notify_old_email: title: "Benachrichtigung an alte E-Mail-Adresse" subject_template: "[%{email_prefix}] Deine E-Mail-Adresse wurde geändert" diff --git a/config/locales/server.el.yml b/config/locales/server.el.yml index 25b4562446..d4fa7e1db7 100644 --- a/config/locales/server.el.yml +++ b/config/locales/server.el.yml @@ -971,7 +971,6 @@ el: maximum_backups: "Το μέγιστο ποσό αντιγράφων ασφαλείας το οποία θα διατηρηθούν στο δίσκο. Παλαιότερα αντίγραφα ασφαλείας διαγράφονται αυτόματα" automatic_backups_enabled: "Πάρε αυτόματα αντίγραφα ασφαλείας όπως ορίζεται στη συχνότητα αντιγράφων ασφαλείας" s3_backup_bucket: "Απομακρυσμένος αποθηκευτικός χώρος για τα αντίγραφα ασφαλείας. ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Βεβαιωθείτε οτι ο χώρος είναι προσωπικός." - s3_disable_cleanup: "Απενεργοποιήστε την αφαίρεση των αντιγράφων ασφαλείας από το S3 όταν αφαιρεθούν τοπικά" backup_time_of_day: "Ώρα σε ζώνη UTC που το αντίγραφο ασφαλείας πρέπει να πραγματοποιηθεί." backup_with_uploads: "Συμπεριέλαβε τις μεταφορτώσεις στα αντίγραφα ασφαλείας. Απενεργοποιώντας το θα δημιουργηθούν αντίγραφα ασφαλείας μόνο για τη βάση δεδομένων." active_user_rate_limit_secs: "Πόσο συχνά ενημερώνουμε το 'last_seen_at' πεδίο, σε δευτερόλεπτα" @@ -2066,6 +2065,8 @@ el: confirm_old_email: title: "Επιβεβαίωση παλιάς διεύθυνσης email" subject_template: "[%{email_prefix}] Επικυρώστε την νέα σας διεύθυνση email" + confirm_old_email_add: + subject_template: "[%{email_prefix}] Επικυρώστε την νέα σας διεύθυνση email" notify_old_email: title: "Ειδοποίηση παλιάς διεύθυνσης email" subject_template: "[%{email_prefix}] Η διεύθυνση email σας έχει αλλαχθεί" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index d2e875d117..03d621d3de 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1449,6 +1449,7 @@ en: category_search_priority_very_high_weight: "Weight applied to ranking for very high category search priority." 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." + allow_duplicate_topic_titles_category: "Allow topics with identical, duplicate titles if the category is different. allow_duplicate_topic_titles must be false." 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." @@ -1682,7 +1683,7 @@ en: s3_backup_bucket: "The remote bucket to hold backups. WARNING: Make sure it is a private bucket." s3_endpoint: "The endpoint can be modified to backup to an S3 compatible service like DigitalOcean Spaces or Minio. WARNING: Leave blank if using AWS S3." s3_configure_tombstone_policy: "Enable automatic deletion policy for tombstone uploads. IMPORTANT: If disabled, no space will be reclaimed after uploads are deleted." - s3_disable_cleanup: "Disable the removal of backups from S3 when removed locally." + s3_disable_cleanup: "Prevent removal of old backups from S3 when there are more backups than the maximum allowed." enable_s3_inventory: "Generate reports and verify uploads using Amazon S3 inventory. IMPORTANT: requires valid S3 credentials (both access key id & secret access key)." 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." @@ -2131,6 +2132,7 @@ en: returning_user_notice_tl: "Minimum trust level required to see returning user post notices." returning_users_days: "How many days should pass before a user is considered to be returning." enable_page_publishing: "Allow staff members to publish topics to new URLs with their own styling." + show_published_pages_login_required: "Anonymous users can see published pages, even when login is required." 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." @@ -2205,7 +2207,7 @@ en: shared_drafts_category: "Enable the Shared Drafts feature by designating a category for topic drafts. Topics in this category will be suppressed from topic lists for staff users." push_notifications_prompt: "Display user consent prompt." - push_notifications_icon: "The badge icon that appears in the notification corner. Required size is 96 × 96." + push_notifications_icon: "The badge icon that appears in the notification corner. A 96×96 monochromatic PNG with transparency is recommended." short_title: "The short title will be used on the user's home screen, launcher, or other places where space may be limited. It should be limited to 12 characters." @@ -2253,6 +2255,7 @@ en: max_username_length_exists: "You cannot set the maximum username length below the longest username (%{username})." max_username_length_range: "You cannot set the maximum below the minimum." invalid_hex_value: "Color values have to be 6-digit hexadecimal codes." + empty_selectable_avatars: "You must first upload at least two selectable avatars before enabling this setting." category_search_priority: very_low_weight_invalid: "You cannot set the weight to be greater than 'category_search_priority_low_weight'." low_weight_invalid: "You cannot set the weight to be greater or equal to 1 or smaller than 'category_search_priority_very_low_weight'." @@ -4853,6 +4856,10 @@ en: email_style: html_missing_placeholder: "The html template must include %{placeholder}" + notification_level: + ignore_error: "Sorry, you can't ignore that user." + mute_error: "Sorry, you can't mute that user." + discord: not_in_allowed_guild: "Authentication failed. You are not a member of a permitted Discord guild." diff --git a/config/locales/server.es.yml b/config/locales/server.es.yml index 96d9d1fea8..fa1734d860 100644 --- a/config/locales/server.es.yml +++ b/config/locales/server.es.yml @@ -751,7 +751,6 @@ es: confirm: "Confirmar" authorizing_new: title: "Confirmar tu nuevo correo electrónico" - description: "Por favor, confirma que quisieras cambiar tu correo electrónico por el nuevo: " authorizing_old: title: "Cambiar tu dirección de correo electrónico" description: "Por favor, confirma el cambio de tu dirección de correo electrónico" @@ -1530,7 +1529,6 @@ es: s3_backup_bucket: "El bucket remoto para mantener copias de respaldo. AVISO: Asegúrate de que es un bucket privado." s3_endpoint: "El endpoint se puede modificar para realizar una copia de respaldo en un servicio compatible con S3 como DigitalOcean Spaces o Minio. ADVERTENCIA: dejar en blanco si usas AWS S3." s3_configure_tombstone_policy: "Habilitar la política de eliminación automática para cargas tombstone. IMPORTANTE: si está deshabilitado, no se reclamará ningún espacio después de eliminar las cargas." - s3_disable_cleanup: "Desactivar el eliminado de respaldos de S3 cuando se eliminen de forma local." enable_s3_inventory: "Generar informes y verificar las cargas utilizando el inventario de Amazon S3. IMPORTANTE: requiere credenciales S3 válidas (tanto la clave de acceso como la clave de acceso secreta)." backup_time_of_day: "Hora UTC del día cuando debería ejecutarse el respaldo." backup_with_uploads: "Incluir archivos subidos en los respaldos programados. Si esta opción está deshabilitada, tan solo se ejecutará una copia de respaldo de la base de datos." @@ -1929,7 +1927,6 @@ es: city_for_disputes: "Ciudad de disputas" shared_drafts_category: "Habilite la característica de borradores compartidos designando una categoría para borradores de temas. Los temas de esta categoría se eliminarán de las listas de temas para los miembros del staff." push_notifications_prompt: "Mostrar aviso del consentimiento del usuario." - push_notifications_icon: "El icono de la medalla que aparece en la esquina de notificación. El tamaño requerido es de 96 × 96." short_title: "El título corto se utilizará en la pantalla de inicio del usuario, el iniciador u otros lugares donde el espacio puede ser limitado. Debe limitarse a 12 caracteres." dashboard_general_tab_activity_metrics: "Selecciona los reportes que se muestran como medidas de actividad en la pestaña general." gravatar_name: "Nombre del proveedor de Gravatar" @@ -3231,6 +3228,8 @@ es: Confirma tu dirección de correo electrónico actual para %{site_name} haciendo clic en el siguiente enlace: %{base_url}/u/confirm-old-email/%{email_token} + confirm_old_email_add: + subject_template: "[%{email_prefix}] Confirma tu dirección actual de correo electrónico" notify_old_email: title: "Antiguo correo electrónico de notificaciones" subject_template: "[%{email_prefix}] Tu dirección de correo electrónico ha sido cambiada" diff --git a/config/locales/server.fa_IR.yml b/config/locales/server.fa_IR.yml index 636946370e..e83a16a5ec 100644 --- a/config/locales/server.fa_IR.yml +++ b/config/locales/server.fa_IR.yml @@ -958,7 +958,6 @@ fa_IR: maximum_backups: "حداکثر تعداد پشتیبان برای نگه داری بر روی دیسک. نسخه های پشتیبان قدیمی بطور خودکار پاک شده است" automatic_backups_enabled: "فعالسازی پشتیبان‌گیری خودکار در بازه زمانی مشخص" s3_backup_bucket: "میزبان راه‌دور برای نگهداری از نسخه‌های پشتیبان. اخطار: مطمئن شوید که میزبان خصوصی است. " - s3_disable_cleanup: "غیر‌فعال‌سازی حذف نسخه پشتیبان از S3 وقتی در هاست حذف می‌شود." backup_time_of_day: "زمان UTC روز برای رخ دادن نسخه پشتیبان." backup_with_uploads: "قراردادن فایل های بارگذاری شده در نسخه های پشتیبان. غیر فعال کردن این بخش باعث تهیه نسخه پشتیبان از دیتابیس می‌شود." active_user_rate_limit_secs: "چگونه فیلد 'last_seen_at' را به روز کنیم، واحد ثانیه " @@ -1889,6 +1888,8 @@ fa_IR: confirm_old_email: title: "تایید ایمیل قبلی" subject_template: "[%{email_prefix}] ایمیل فعلی خود را تایید کنید" + confirm_old_email_add: + subject_template: "[%{email_prefix}] ایمیل فعلی خود را تایید کنید" notify_old_email: title: "اعلام ایمیل قبلی" subject_template: "[%{email_prefix}] ایمیل شما تغییر کرده است" diff --git a/config/locales/server.fi.yml b/config/locales/server.fi.yml index 1a4326b984..c624456a0c 100644 --- a/config/locales/server.fi.yml +++ b/config/locales/server.fi.yml @@ -750,7 +750,6 @@ fi: confirm: "Vahvista" authorizing_new: title: "Vahvista uusi sähköpostiosoite" - description: "Vahvista, että haluat vaihtaa uudeksi sähköpostiosoitteeksesi:" authorizing_old: title: "Vaihda sähköpostiosoitettasi" description: "Vahvista sähköpostiosoitteesi vaihdos" @@ -1518,7 +1517,6 @@ fi: s3_backup_bucket: "Amazon S3 bucket johon varmuuskopiot ladataan. VAROITUS: Varmista, että se on yksityinen." s3_endpoint: "Kohdeasemaksi voidaan vaihtaa muu S3-yhteensopiva palvelu kuten DigitalOcean Spaces tai Minio. VAROITUS: Jätä tyhjäksi, jos käytät AWS S3:a." s3_configure_tombstone_policy: "Ota käyttöön tombstone-hakemiston automaattinen tyhjennys. TÄRKEÄÄ: Jos ei käytössä, tilaa ei vapaudu kun ladattuja tiedostoja poistetaan." - s3_disable_cleanup: "Älä poista varmuuskopiota S3:sta, kun se poistetaan paikallisesti." backup_time_of_day: "UTC-kellonaika, jolloin varmuuskopio tehdään." backup_with_uploads: "Sisällytä lataukset ajastettuihin varmuuskopioihin. Jos tämä on pois käytöstä, vain tietokanta varmuuskopioidaan." backup_location: "SIjainti, jonne varmuuskopiot säilötään. TÄRKEÄÄ: S3 vaatii toimiakseen, että käyvät S3-käyttöoikeustiedot on syötetty Tiedostot-asetuksiin." @@ -1895,7 +1893,6 @@ fi: city_for_disputes: "Kaupunki jonka oikeudessa riidat ratkotaan" shared_drafts_category: "Ota käyttöön jaetut luonnokset -toiminto määrittämällä alue, joka on ketjuluonnoksille varattu. Alueen ketjut eivät näy ketjulistauksissa henkilökunnankaan jäsenille." push_notifications_prompt: "Näytä käyttäjäsuostumuspyyntö." - push_notifications_icon: "Kuvakemerkki, joka näkyy ilmoituksen kulmassa. Vaadittu koko on 96×96." short_title: "Lyhyttä nimeä käytetään käyttäjän kotiruudussa (home screen), käynnistyssovelluksissa (launcher) ja muissa tilanteissa, joissa tilaa on rajallisesti. Sen tulisi olla enintään 12 merkin pituinen." dashboard_general_tab_activity_metrics: "Valitse raportit, jotka näytetään aktiivisuusmittareina Yleistä-välilehdellä." errors: @@ -3145,6 +3142,8 @@ fi: Vahvista nykyinen sähköpostiosoitteesi sivustolla %{site_name} klikkaamalla linkkiä: %{base_url}/u/confirm-old-email/%{email_token} + confirm_old_email_add: + subject_template: "[%{email_prefix}] Vahvista nykyinen sähköpostiosoitteesi" notify_old_email: title: "Ilmoita vanhaan sähköpostiosoitteeseen" subject_template: "[%{email_prefix}] Sähköpostiosoitteesi on vaihdettu" diff --git a/config/locales/server.fr.yml b/config/locales/server.fr.yml index 6484c1909b..138011d42e 100644 --- a/config/locales/server.fr.yml +++ b/config/locales/server.fr.yml @@ -757,15 +757,18 @@ fr: confirmed: "Votre adresse courriel a été mise à jour." please_continue: "Continuer vers %{site_name}" error: "Il y a eu une erreur lors de la modification de votre adresse courriel. Votre adresse courriel est peut-être déjà utilisée ?" + doesnt_exist: "Cette adresse courriel n'est pas associée à votre compte." error_staged: "Une erreur est survenue lors de la modification de votre adresse courriel. Cette adresse est déjà utilisée par un utilisateur distant." already_done: "Désolé, ce lien de confirmation n'est plus valide. Votre adresse courriel a peut-être déjà été changée ?" confirm: "Confirmer" authorizing_new: title: "Confirmer votre nouvelle adresse courriel" description: "Veuillez confirmer que vous souhaitez changer votre adresse courriel à :" + description_add: "Veuillez confirmer que vous souhaitez ajouter une adresse courriel alternative :" authorizing_old: title: "Changer votre adresse courriel" description: "Veuillez confirmer votre changement d'adresse courriel" + description_add: "Veuillez confirmer que vous souhaitez ajouter une adresse courriel alternative :" old_email: "Adresse courriel précédente : %{email}" new_email: "Nouvelle adresse courriel : %{email}" almost_done_title: "Confirmer une nouvelle adresse courriel" @@ -1172,12 +1175,12 @@ fr: topic: "Sujet" description: "Sujets qui ont reçu le plus de visites depuis des sources externes." page_view_anon_reqs: - title: "Anonyme" + title: "Anonymes" xaxis: "Jour" yaxis: "Nombre de vues par les utilisateurs non connectés" description: "Nombre de nouvelles vues de pages par des visiteurs sans compte." page_view_logged_in_reqs: - title: "Connecté" + title: "Connectés" xaxis: "Jour" yaxis: "Nombre de vues par les utilisateurs connectés" description: "Nombre de nouvelles vues d'utilisateurs connectés." @@ -1545,7 +1548,6 @@ fr: s3_backup_bucket: "Bucket distant qui contiendra les sauvegardes. ATTENTION : vérifiez que le bucket est privé." s3_endpoint: "La destination peut être modifiée pour envoyer les sauvegardes vers un service compatible avec S3, par exemple DigitalOcean Spaces ou Minio. ATTENTION : laisser vide si vous utilisez AWS S3." s3_configure_tombstone_policy: "Activer la suppression automatique des fichiers non utilisés. IMPORTANT : en cas de désactivation, aucun espace disque ne sera récupéré après la suppression des fichiers." - s3_disable_cleanup: "Désactiver la suppression des sauvegardes sur S3 lorsqu'elles sont supprimées localement." enable_s3_inventory: "Générer des rapports et vérifier les envois avec l'inventaire Amazon S3. IMPORTANT : nécessite un accès valide à S3 (l'identifiant et la clé secrète). " backup_time_of_day: "Heure (UTC) de planification de la sauvegarde." backup_with_uploads: "Inclure les fichiers envoyés dans les sauvegardes. Si désactivé, seule la base de données sera sauvegardée." @@ -1884,6 +1886,7 @@ fr: returning_user_notice_tl: "Niveau de confiance minimum requis pour voir les avis postés par les utilisateurs revenant." returning_users_days: "Combien de jours doivent s'écouler avant qu'un utilisateur soit considéré comme étant de retour." enable_page_publishing: "Autorisez les responsables de publier des sujets vers de nouvelles URL utilisant leur propre style." + show_published_pages_login_required: "Les utilisateurs anonymes peuvent voir les pages publiées même quand la connexion est nécessaire." default_email_digest_frequency: "Par défaut, à quelle fréquence les utilisateurs reçoivent les résumés par courriel." default_include_tl0_in_digests: "Par défaut, inclure les messages des nouveaux utilisateurs dans les résumés par courriel. Les utilisateurs peuvent changer cela dans leurs préférences." default_email_level: "Définissez le niveau de notification courriel par défaut pour les sujets standards." @@ -1943,7 +1946,7 @@ fr: city_for_disputes: "Ville pour les litiges" shared_drafts_category: "Activez la fonction Brouillons partagés en désignant une catégorie pour les brouillons de sujet. Les sujets dans cette catégorie ne figureront pas dans les listes de sujets pour les responsables." push_notifications_prompt: "Afficher la demande de consentement de l'utilisateur" - push_notifications_icon: "L'icône du badge qui apparaît dans les notifications. Taille requise : 96 x 96." + push_notifications_icon: "L'icône du badge qui apparaît dans les notifications. Une image monochrome de taille 96×96 et au format PNG avec transparence est recommandée." short_title: "Le titre court sera utilisé sur l'écran d'accueil de l'utilisateur, le lanceur d'applications ou d'autres endroits où la place disponible est limitée. Il devrait être limité à 12 caractères." dashboard_hidden_reports: "Permettre de masquer les rapports du tableau de bord." dashboard_visible_tabs: "Choisissez les onglets visibles sur le tableau de bord." @@ -3208,7 +3211,15 @@ fr: text_body_template: | Avant de pouvoir modifier votre adresse courriel, nous avons besoin de confirmer que vous contrôlez bien ce compte de messagerie. Une fois cette étape terminée, nous vous demanderons de confirmer la nouvelle adresse courriel. - Confirmez votre adresse courriel actuelle pour %{site_name} en cliquant sur le lien suivant: + Confirmez votre adresse courriel actuelle pour %{site_name} en cliquant sur le lien suivant : + + %{base_url}/u/confirm-old-email/%{email_token} + confirm_old_email_add: + subject_template: "[%{email_prefix}] Confirmez votre adresse courriel actuelle" + text_body_template: | + Avant de pouvoir ajouter une nouvelle adresse courriel, nous avons besoin de confirmer que vous contrôlez bien ce compte de messagerie. Une fois cette étape terminée, nous vous demanderons de confirmer la nouvelle adresse courriel. + + Confirmez votre adresse courriel actuelle pour %{site_name} en cliquant sur le lien suivant : %{base_url}/u/confirm-old-email/%{email_token} notify_old_email: @@ -3221,6 +3232,14 @@ fr: Votre adresse courriel a été modifiée à : + %{new_email} + notify_old_email_add: + subject_template: "[%{email_prefix}] Une nouvelle adresse courriel a été ajoutée" + text_body_template: | + Ceci est un message automatique pour vous informer qu'une adresse courriel pour %{site_name} a été ajoutée. Si c'est une erreur, merci de contacter ²un administrateur du site. + + Votre adresse courriel ajoutée : + %{new_email} signup_after_approval: title: "Inscription après approbation" diff --git a/config/locales/server.gl.yml b/config/locales/server.gl.yml index b5d1e339ac..cd31d01809 100644 --- a/config/locales/server.gl.yml +++ b/config/locales/server.gl.yml @@ -15,22 +15,94 @@ gl: short: "%d-%m-%Y" short_no_year: "%-d de %B" date_only: "%-d de %B, %Y" + long: "%-d %B %Y %H:%M" + no_day: "%B %Y" date: month_names: [~, Xaneiro, Febreiro, Marzo, Abril, Maio, Xuño, Xullo, Agosto, Setembro, Outubro, Novembro, Decembro] <<: *datetime_formats time: <<: *datetime_formats + am: "am" + pm: "pm" title: "Discourse" topics: "Temas" posts: "publicacións" - loading: "Cargndo" + loading: "Cargando" + powered_by_html: 'Con tecnoloxía de Discourse, vese mellor con Java habilitado' sign_up: "Crear unha conta" log_in: "Iniciar sesión" submit: "Enviar" + purge_reason: "Conta eliminada automaticamente por abandono; conta desactivada" + disable_remote_images_download_reason: "Habilitouse a descarga remota de imaxes por non haber espazo suficiente no disco." anonymous: "Anónimo" + remove_posts_deleted_by_author: "Eliminada polo autor" + redirect_warning: "Non puidemos verificar que a ligazón que seleccionaches está publicada agora mesmo no foro. Se queres continuar igualmente, selecciona a seguinte ligazón." + on_another_topic: "Noutro tema" + themes: + bad_color_scheme: "Non se pode actualizar o tema; paleta de cores non válida" + other_error: "Algo foi mal ao actualizar o tema" + compile_error: + unrecognized_extension: "Extensión de ficheiro non recoñecida: %{extension}" + import_error: + generic: Produciuse un erro mentres se importaba este tema + about_json: "Erro importante: about.json non existe ou non é válido. Tes a certeza que este é un tema de Discourse?" + about_json_values: "about.json contén valores non válidos: %{errors}" + modifier_values: "os modificadores about.json coteñen valores non válidos: %{errors}" + git: "Erro ao clonar o repositorio git; o acceso está denegado ou non se atopou o repositorio" + unpack_failed: "Erro ao descomprimir o ficheiro" + file_too_big: "O ficheiro sen comprimir é demasiado grande." + unknown_file_type: "O ficheiro que cargaches non semella ser un tema válido de Discourse." + errors: + component_no_user_selectable: "Os compoñentes do tema non poden ser seleccionados polo usuario" + component_no_default: "Os compoñentes do tema non poden ser o tema predefinido" + component_no_color_scheme: "Os compoñenetes do tema non poden ter paletas de cores" + no_multilevels_components: "Os temas con temas secundarios non poden ser temas secundarios en si mesmos." + optimized_link: As ligazóns de imaxe optimizadas son efémeras e non debería ser incluídas no código fonte do tema. + settings_errors: + invalid_yaml: "O YAML proporcionado non é válido." + data_type_not_a_number: "Tipo de axuste `%{name}` non compatible. Os tipos compatibles son `integer`, `bool`, `list`, `enum` e `upload`" + name_too_long: "Hai un axuste cun nome demasiado longo; a lonxitude máxima é de 255 caracteres" + default_value_missing: "O axuste '%{name}' non ten un valor predefinido" + default_not_match_type: "O tipo de valor predefinido para o axuste `%{name}` non coincide co tipo de axuste." + default_out_range: "O valor por defecto do axuste `%{name}` non está no rango especificado." + enum_value_not_valid: "O valor seleccionado non é unha das opcións enumeradas." + number_value_not_valid: "O novo valor no nestá dentro do rango permitido." + number_value_not_valid_min_max: "Debe ser entre %{min} e %{max}." + number_value_not_valid_min: "Debe ser maior ou igual que %{min}." + number_value_not_valid_max: "Debe ser menor ou igual que %{max}." + string_value_not_valid: "A lonxitude do novo valor non está no intervalo permitido." + string_value_not_valid_min_max: "Debe ter entre %{min} e %{max} caracteres de lonxitude." + string_value_not_valid_min: "Debe ter ao menos %{min} caracteres." + string_value_not_valid_max: "Debe ter un máximo de %{max} caracteres." + locale_errors: + top_level_locale: "A chave de nivel superior nun ficheiro local debe coincidir co nome local" + invalid_yaml: "YAML de tradución non válido" + emails: + incoming: + default_subject: "Este tema necesita un título" + show_trimmed_content: "Mostrar contido recortado" + maximum_staged_user_per_email_reached: "Alcanzouse o número máximo de usuarios creados por correo electrónico." + no_subject: "(sen asunto)" + no_body: "(sen mensaxe)" + missing_attachment: "(falta o ficheiro anexo %{filename})" + errors: + empty_email_error: "Sucede cando o texto en bruto do correo que recibimos está en branco." + no_message_id_error: "Sucede cando o correo electrónico non ten a cabeceira de 'Id da mensaxe'. " + inactive_user_error: "Sucede cando o remitente non está activo." + silenced_user_error: "Sucede cando o destinatario foi silenciado." + bad_destination_address: "Sucede cando ningún dos enderezos electrónicos nos campos Para/Cc coincide cun correo electrónico configurado como enderezo de correo entrante." + strangers_not_allowed_error: "Sucede cando un usuario tenta crear un novo tema nunha categoría da que non é membro." + insufficient_trust_level_error: "Sucede cando un usuario tenta crear un novo tema nunha categoría para a que non ten o nivel de confianza que se require." + reply_user_not_matching_error: "Sucede cando unha resposta vén desde un enderezo electrónico diferente ao que se lle enviou a notificación." + topic_not_found_error: "Sucede cando entra unha resposta pero o tema relacionado foi eliminado." + topic_closed_error: "Sucede cando entra unha resposta pero o tema relacionado foi pechado." + unrecognized_error: "Erro non recoñecido" errors: &errors format: "%{attribute} %{message}" + format_with_full_message: "%{attribute}: %{message}" messages: + too_long_validation: "Límite de %{max} caracteres; inseriches %{length}." + invalid_boolean: "Booleano non válido" taken: "xa está en uso" accepted: debe ser aceptado blank: non pode quedar baleiro @@ -38,66 +110,247 @@ gl: confirmation: "%{attribute} non coincide" empty: non pode quedar baleiro equal_to: "debe ser igual a %{count}" + even: debe ser par exclusion: está reservado greater_than: "debe ser maior de %{count}" greater_than_or_equal_to: "debe ser igual ou maior de %{count}" has_already_been_used: "xa está en uso" inclusion: no está incluído na lista invalid: é incorrecto + is_invalid: "parece pouco claro, é unha oración completa?" + invalid_timezone: "'%{tz}' non é un fuso horario válido" + contains_censored_words: "contén as seguintes palabras censuradas: %{censored_words}" less_than: "debe ser menor de %{count}" less_than_or_equal_to: "debe ser igual ou menor de %{count}" not_a_number: non é un número not_an_integer: debe ser un enteiro odd: debe ser impar record_invalid: "Fallou a validación: %{errors}" + max_emojis: "non pode ter máis de %{max_emojis_count} emojis" + emojis_disabled: "non pode ter emojis" + ip_address_already_screened: "xa está incluído nunha regra existente" restrict_dependent_destroy: - one: "Non é posíbel eliminalo porque existe outro %{record} dependente" - many: "Non é posíbel eliminalo porque existen outros %{record} dependentes" + one: "Non é posible eliminalo porque existe outro %{record} dependente" + many: "Non é posible eliminalo porque existen outros %{record} dependentes" too_long: one: demasiado longo (máximo un caracterer) other: demasiado longo (máximo %{count} caracteres) too_short: one: demasiado curto (mínimo un caracter) other: demasiado curto (mínimo %{count} caracteres) + wrong_length: + one: ten unha lonxitude incorrecta (debería ser de %{count} caracter) + other: ten unha lonxitude incorrecta (debería ser de %{count} caracteres) other_than: "debe ser distinto de %{count}" + sso_overrides_username: "O nome de usuario ten que actualizarse do lado do provedor SSO, dado que o axuste `sso_overrides_username` está activado." template: body: "Producíronse problemas cos seguintes campos:" + header: + one: "%{count} erro impediu gardar este %{model}" + other: "%{count} erros impediron gardar este %{model}" embed: load_from_remote: "Produciuse un erro cargando esta publicación." + site_settings: + invalid_category_id: "Especificaches unha categoría que non existe" + invalid_choice: + one: "Especificaches a opción non válida %{name}" + other: "Especificaches opcións non válidas %{name}" + default_categories_already_selected: "Non podes seleccionar unha categoría utilizada noutra listaxe." + default_tags_already_selected: "Non podes seleccionar unha etiqueta utilizada noutra listaxe." + s3_upload_bucket_is_required: "Non se poden activar as cargas a S3 a menos que proporciones un valor 's3_upload_bucket'." + enable_s3_uploads_is_required: "Non podes activar o inventario en S3 a menos que actives as cargas en S3." + s3_backup_requires_s3_settings: "Non podes utilizar S3 como localización da copia de seguranza a menos que proporcionaras '%{setting_name}'." + s3_bucket_reused: "Non podes utilizar o mesmo depósito (bucket) para 's3_upload_bucket' e 's3_backup_bucket'. Elixe un depósito diferente ou utiliza un camiño distinto para cada un deles." + secure_media_requirements: "Débese habilitar a carga de S3 antes de habilitar medios seguros." + second_factor_cannot_be_enforced_with_disabled_local_login: "Non podes aplicar 2FA se os inicios de sesión locais estás deshabilitados." + local_login_cannot_be_disabled_if_second_factor_enforced: "Non podes deshabilitar o inicio de sesión local se se aplica 2FA. Deshabilita 2FA antes de deshabilitar os inicios de sesión locais." + cannot_enable_s3_uploads_when_s3_enabled_globally: "Non podes habilitar as cargas S3 porque xa están habilitadas globalmente e habilitar este nivel de sitio podería provocar problemas críticos coas cargas." + conflicting_google_user_id: 'A ID de Google para esta conta cambiou; requírese a intervención do equipo por razóns de seguridade. Contacta con el e envíalle esta referencia
https://meta.discourse.org/t/76575' activemodel: errors: <<: *errors + invite: + not_found: "O teu código de invitación non é válido. Contacta co noso equipo." + not_found_json: "O teu código de invitación non é válido. Contacta co noso equipo." + not_found_template: | +

A túa invitación a %{site_name} xa foi aceptada.

+ +

Se lembras o teu contrasina, podes iniciar sesión.

+ +

Se non é así, restablece o contrasinal.

+ error_message: "Houbo un erro ao aceptar a invitación. Contacta co administrador do sitio." + user_exists: "Non necesitas invitar a %{email}, pois xa teñen unha conta!" + confirm_email: "

Xa case está! Enviámosche un correo de activación ao teu enderezo electrónico. Sigue as instrucións para activar a túa conta.

Se non che chega, comprobar o cartafol de correo lixo.

" + bulk_invite: + file_should_be_csv: "O ficheiro cargado debe ter o formato CSV." + max_rows: "As primeiras %{max_bulk_invites} invitacións xa foron enviadas. Tenta dividir o ficheiro en partes máis pequenas." + error: "Houbo un erro ao cargar o ficheiro. Téntao máis tarde." + invite_link: + email_taken: "Este correo electrónico xa está en uso. Se xa tes unha conta, inicia sesión ou restablece o contrasinal." + max_redemptions_limit: "debería estar entre 2 e %{max_limit}." + topic_invite: + failed_to_invite: "O usuario non pode ser invitado a este tema por non ser membro de ningún destes grupos: %{group_names}." + user_exists: "Este usuario xa foi invitado. Só se pode invitar a un usuario a un tema unha única vez." + backup: + operation_already_running: "Estase a executar unha operación. Nestes intres non se pode iniciar un novo traballo." + backup_file_should_be_tar_gz: "O ficheiro da copia de seguranza debe ter formato .tar.gz." + not_enough_space_on_disk: "Non hai suficiente espazo no disco para cargar a copia de seguranza." + invalid_filename: "O nome do ficheiro da copia de seguranza contén caracteres non válidos. Os caracteres que se admiten son a-z e 0-9." + file_exists: "O ficheiro que estás tentando subir xa existe." + location: + local: "Local" + s3: "Amazon S3" + invalid_params: "Proporcionaches parámetros non válidos para a solicitude: %{message}" not_logged_in: "Debes iniciar sesión para facer iso." not_found: "Non foi posíbel atopar o recurso ou URL solicitado." invalid_access: "Non se che permite ver o recurso solicitado." + authenticator_not_found: "O método de verificación non existe ou foi deshabilitado." + invalid_api_credentials: "Non tes permiso para ver o recurso solicitado. O nome de usuario API ou a chave non é válida." + provider_not_enabled: "Non tes permiso para ver o recurso solicitado. O provedor de autenticación non está habilitado." + provider_not_found: "Non tes permiso para ver o recurso solicitado. O provedor de autenticación non existe." read_only_mode_enabled: "O sitio está en modo só-lectura. As interaccións están desactivadas." + email_template_cant_be_modified: "Este modelo de correo electrónico non pode ser modificado." + not_in_group: + title_topic: "Debes estar no grupo para ver este tema." + title_category: "Debes estar no grupo para ver esta categoría." + request_membership: "Solicitar ser membro" + join_group: "Unirse ao grupo" + deleted_topic: "Vaites! Este tema foi eliminado e xa non está dispoñible." + delete_topic_failed: "Houbo un erro ao eliminar este tema. Contacta co administrador do sitio." reading_time: "Tempo de lectura" likes: "Gústames" + too_many_replies: + one: "Sentímolo, mais os novos usuarios teñen temporalmente o límite de %{count} respostas no mesmo tema." + other: "Sentímolo, mais os novos usuarios teñen temporalmente un límite de %{count} resposta no mesmo tema." + max_consecutive_replies: + one: "Non se permiten respostas consecutivas. Edita a túa resposta anterior ou agarda a que alguén che responda." + other: "Non se permiten máis de %{count} respostas consecutivas. Edita a túa resposta anterior ou agarda a que alguén che responda." embed: - start_discussion: "Comezar a discusión" - continue: "Continuar a discusión" + start_discussion: "Comezar discusión" + continue: "Continuar discusión" + error: "Erro ao inserir" + referer: "Referente:" + error_topics: "A configuración do sitio 'listaxe de temas inseridos' non está activada" + mismatch: "O referente non se enviou ou non coincide con ningún dos seguintes hosts:" + configure: "Configurar inserción" more_replies: one: "Unha resposta máis" other: "%{count} respostas máis" - loading: "Cargando a discusión..." + loading: "Cargando discusión..." permalink: "Ligazón permanente" + imported_from: "Este é un tema de discusión derivado da entrada %{link}" in_reply_to: "▶ %{username}" + replies: + one: "%{count} resposta" + other: "%{count} repostas" + likes: + one: "%{count} gústame" + other: "%{count} gústames" + last_reply: "Última resposta" created: "Creado" - no_mentions_allowed: "Sentímolo pero non podes mencionar outros usuarios" + new_topic: "Crear novo tema" + no_mentions_allowed: "Sentímolo, mais non podes mencionar outros usuarios." + too_many_mentions: + one: "Sentímolo, pero só podes mencionar un outro usuario nunha publicación." + other: "Sentímolo, mais non podes mencionar %{count} usuarios nunha publicación." + no_mentions_allowed_newuser: "Sentímolo, mais os novos usuarios non poden mencionar a outros." + too_many_mentions_newuser: + one: "Sentímolo, mais os novos usuarios só poden mencionar un usuario nunha publicación." + other: "Sentímolo, mais os novos usuarios só poden mencionar a %{count} usuarios nunha publicación." + no_images_allowed_trust: "Sentímolo, mais non podes poñer imaxes nunha publicación." + no_images_allowed: "Sentímolo, mais os novos usuarios non poden poñer imaxes nas publicacións." + too_many_images: + one: "Sentímolo, mais os novos usuarios só poden poñer unha imaxe nunha publicación." + other: "Sentímolo, mais os novos usuarios só poden poñer %{count} imaxes nunha publicación." + no_attachments_allowed: "Sentímolo, mais os novos usuarios non poden anexar ficheiros nas publicacións." + too_many_attachments: + one: "Sentímolo, mais os novos usuarios só poden anexar un ficheiro nunha publicación." + other: "Sentímolo, mais os novos usuarios só poden anexar %{count} ficheiros nunha publicación." + no_links_allowed: "Sentímolo, mais os novos usuarios non poden poñer ligazóns nas publicacións." + links_require_trust: "Sentímolo, non podes incluír ligazóns nas túas publicacións." + too_many_links: + one: "Sentímolo, mais os novos usuarios só poden poñer unha ligazón nunha publicación." + other: "Sentímolo, mais os novos usuarios só poden poñer %{count} ligazóns nunha publicación." + contains_blocked_word: "A túa publicación contén unha palabra que non está permitida: %{word}" + contains_blocked_words: "A túa publicación contén varias palabras que non están permitidas: %{words}" + spamming_host: "Sentímolo, non podes publicar unha ligazón a ese sitio." + user_is_suspended: "Aos usuarios suspendidos non se lles permite publicar." + topic_not_found: "Algo foi mal. Talvez este tema foi pechado ou eliminado mentres o estabas a mirar?" + not_accepting_pms: "Sentímolo, %{username} non acepta mensaxes neste momento." + max_pm_recipients: "Sentímolo, podes enviar mensaxes a un máximo de %{recipients_limit} destinatarios." + pm_reached_recipients_limit: "Sentímolo, non podes ter máis de %{recipients_limit} destinatarios nunha mensaxe." + removed_direct_reply_full_quotes: "Cita de toda a publicación anterior eliminada automaticamente" + secure_upload_not_allowed_in_public_topic: "Sentímolo, a(s) seguinte(s) carga(s) non pode(n) ser utilizada(s) nun tema público: %{upload_filenames}." + create_pm_on_existing_topic: "Sentímolo, non podes crear unha mensaxe privada nun tema existente." + just_posted_that: "é moi semellante ao que xa publicaches recentemente." invalid_characters: "contén caracteres incorrectos" + is_invalid: "parece pouco claro, é unha oración completa?" next_page: "páxina seguinte →" prev_page: "← páxina anterior" page_num: "Páxina %{num}" home_title: "Inicio" + topics_in_category: "Temas na categoría '%{category}'" rss_posts_in_topic: "Fonte RSS de '%{topic}»" + rss_topics_in_category: "Fonte RSS dos temas na categoría '%{category}'" + rss_num_posts: + one: "%{count} publicación" + other: "%{count} publicacións" + rss_num_participants: + one: "%{count} participante" + other: "%{count} participantes" read_full_topic: "Ler todo o tema" private_message_abbrev: "Msx." rss_description: latest: "Últimos temas" + top: "Temas destacados" + top_all: "Todos os temas destacados" + top_yearly: "Temas destacados do ano" + top_quarterly: "Temas destacados do trimestre" + top_monthly: "Temas destacados do mes" + top_weekly: "Temas destacados da semana" + top_daily: "Temas destacados do día" posts: "Últimas publicacións" - too_late_to_edit: "Esta publicación ten moito tempo. Xa non se pode modificar nin eliminar." + private_posts: "Últimas mensaxes privadas" + group_posts: "Últimas publicacións de %{group_name}" + group_mentions: "Últimas mencións de %{group_name}" + user_posts: "Últimas publicacións de @%{username}" + user_topics: "Últimos temas de @%{username}" + tag: "Temas etiquetados" + too_late_to_edit: "Esta publicación é de hai moito tempo. Xa non se pode modificar nin eliminar." + edit_conflict: "Esta publicación foi editada por outro usuario e os teus cambios non se poden gardar." + revert_version_same: "A versión actual é a mesma que a versión á que tentas volver." excerpt_image: "imaxe" + bookmarks: + errors: + already_bookmarked_post: "Non podes gardar a mesma publicación nos marcadores dúas veces." + cannot_set_past_reminder: "Non podes establecer un recordatorio de marcador no pasado." + cannot_set_reminder_in_distant_future: "Non podes establecer un recordatorio de marcador máis de 10 anos cara ao futuro." + time_must_be_provided: "o período debe ser facilitado para todos os recordatorios" + reminders: + at_desktop: "A vindeira vez que estea no meu ordenador" + later_today: "Hoxe, máis tarde" + next_business_day: "O vindeiro día laborable" + tomorrow: "Mañá" + next_week: "A vindeira semana" + next_month: "O vindeiro mes" + custom: "Personalizar data e hora" groups: + success: + bulk_add: + one: "%{count} usuario foi engadido ao grupo." + other: "%{count} usuarios foron engadidos ao grupo." + errors: + grant_trust_level_not_valid: "'%{trust_level}' non é un nivel de confianza válido." + can_not_modify_automatic: "Non podes modificar un grupo automático" + member_already_exist: + one: "'%{username}' xa é membro deste grupo." + other: "Os seguintes usuarios xa son membros deste grupo: %{username}" + invalid_domain: "'%{domain}' non é un dominio válido." + invalid_incoming_email: "'%{email}' non é un enderezo electrónico válido." + email_already_used_in_group: "'%{email}' xa está en uso polo grupo '%{group_name}'." + email_already_used_in_category: "'%{email}' xa está en uso pola categoría '%{category_name}'." + cant_allow_membership_requests: "Non podes permitir solicitudes para ser membros de grupos que carecen de propietario." + already_requested_membership: "Xa solicitaches ser membro deste grupo. " default_names: everyone: "todos" admins: "administradores" @@ -108,52 +361,203 @@ gl: trust_level_2: "nivel_de_confianza_2" trust_level_3: "nivel_de_confianza_3" trust_level_4: "nivel_de_confianza_4" + request_membership_pm: + title: "Solicitude de ser membro para @%{group_name}" + request_accepted_pm: + title: "Aceptouse a túa solicitude para @%{group_name}" + body: | + A túa solicitude para entrar no grupo @%{group_name} foi aceptada e agora xa es membro. + view_hidden_topic_request_reason: "Gustaríame unirme ao grupo '%{group_name}' para poder acceder a [este tema](%{topic_url})" education: until_posts: - one: "Unha publicación" + one: "%{count} publicación" other: "%{count} publicacións" + "new-topic": | + Benvido/a a %{site_name} — **grazas por iniciares unha nova conversa!** + + - Se o les en voz alta, soa ben o seu título? É un bo resumo do que trata? + + - Quen terá interese por ler isto? Por que é importante? A que tipo de respostas queres dar pé? + + - Inclúe palabras de uso frecuente no teu tema para facilitar que poida ser atopado. Para agrupalo con outros temas relacionados, selecciona unha categoría. + + Para máis información, [visita as nosas instrucións para a comunidade](%{base_path}/guidelines). Este panel só aparecerá nas túas %{education_posts_text} primeiras publicacións. + "new-reply": | + Benvido/a a %{site_name} — **grazas pola túa contribución!** + + - Dalgún xeito a túa resposta mellora a conversa? + + - Sé amable cos demais membros da comunidade. + + - A crítica construtiva é benvida, mais lembra criticar as ideas non as persoas. + + Para máis información, [visita as nosas instrucións para a comunidade](%{base_path}/guidelines). Este panel só aparecerá nas túas %{education_posts_text} primeiras publicacións. + avatar: | + ### Que tal se lle engades unha imaxe á túa conta? + + Xa publicaches uns cantos temas e respostas, mais a túa imaxe de perfil non é única coma ti; é simplemente unha letra. + + Pensaches na posibilidade de **[visitar o teu perfil de usuario](%{profile_path})** e subir unha imaxe que te represente? + + É máis fácil seguir debates e atopar xente interesante nas conversas cando cadaquén ten unha imaxe de perfil individualizada! + sequential_replies: | + ### Considera a posibilidade de responder varias publicación a un tempo + + No canto de publicares varias respostas seguidas nun mesmo tema, pensa na opción de dar unha única resposta que inclúa citas de respostas anteriores ou mencións a outros @usuarios. + + Podes editar a túa resposta e engadir unha cita seleccionando o texto e premendo no botón citar resposta que aparece. + + É máis sinxelo para a comunidade ler temas con menos respostas, pero con máis contido, que moitas respostas pequenas e individuais. + dominating_topic: | + ### Permite que máis xente se una á conversa + + Parece claro que este tema che importa – publicaches máis do %{percent}% das respostas. + + Aínda podería ser mellor se lles deses espazo a outras persoas para compartiren o seu punto de vista. Que tal se as convidas? + get_a_room: | + ### Anima a máis xente a participar na conversa + + Neste tema en concreto respondícheslle %{count} veces a @%{reply_username}! + + Unha discusión é boa cando involucra moitas voces e perspectivas. Que tal se involucras a alguén máis? + + E non esquezas que se queres continuar a conversa con este usuario en particular e en privado, [podes enviarlle unha mensaxe privada](%{base_path}/u/%{reply_username}). + too_many_replies: | + ### Alcanzaches o límite de respostas para este tema. + + Sentímolo, mais os novos usuarios teñen temporalmente un límite de %{newuser_max_replies_per_topic} respostas no mesmo tema. + + No canto de engadir unha outra resposta, pensa na posibilidade de editar algunhas das anteriores ou visitar outros temas. + reviving_old_topic: | + ### Queres revivir este tema? + + A última resposta que ten é de hai **%{time_ago}**. A túa resposta fará que se sitúe na parte superior da listaxe e suporá que os usuarios involucrados na conversa reciban unha notificación. + + Tes a certeza de querer continuar con esta antiga conversa? activerecord: attributes: category: name: "Nome da categoría" topic: title: "Título" + featured_link: "Ligazón destacada" category_id: "Categoría" post: - raw: "Corpo" + raw: "Mensaxe" user_profile: - bio_raw: "Verbo de min" + bio_raw: "Acerca de min" errors: <<: *errors models: topic: attributes: base: - no_user_selected: "Debes seleccionar un usuario correcto." + warning_requires_pm: "Só podes enviar advertencias en mensaxes privadas." + too_many_users: "Só podes enviar advertencias a un usuario de cada vez." + cant_send_pm: "Sentímolo, non podes enviarlle unha mensaxe privada a este usuario." + no_user_selected: "Debes seleccionar un usuario válido." + reply_by_email_disabled: "A resposta vía correo electrónico está deshabilitada." + target_user_not_found: "Non se atopou a un dos usuarios aos que lles envías esta mensaxe." + unable_to_update: "Produciuse un erro ao actualizar este tema." + featured_link: + invalid: "non é válido. Un URL debe incluír http:// or https://." + invalid_category: "non se pode editar nesta categoría." user: attributes: password: - common: "é un dos 10000 contrasinais máis habituais. Usa un máis seguro." - same_as_username: "é igual ao teu nome de usuario. Usa un contrasinal máis seguro." - same_as_email: "é igual ao teu correo electrónico. Usa un contrasinal máis seguro." + common: "é un dos 10000 contrasinais máis habituais. Utiliza un máis seguro." + same_as_username: "é igual ao teu nome de usuario. Utiliza un contrasinal máis seguro." + same_as_email: "é igual ao teu correo electrónico. Utiliza un contrasinal máis seguro." + same_as_current: "é igual ao teu contrasinal actual." + same_as_name: "é igual ao teu nome." + unique_characters: "ten demasiados caracteres repetidos. Utiliza un contrasinal máis seguro." + username: + same_as_password: "é igual ao teu contrasinal." + name: + same_as_password: "é igual ao teu contrasinal." ip_address: signup_not_allowed: "Non esta permitido rexistrarse desde esta conta." + user_profile: + attributes: + featured_topic_id: + invalid: "Este tema non pode ser destacado no teu perfil." + user_email: + attributes: + user_id: + reassigning_primary_email: "Non se permite reasignar un correo electrónico principal a outro usuario." color_scheme_color: attributes: hex: invalid: "non é unha cor válida" - vip_category_name: "Taberna" - vip_category_description: "Unha categoría exclusiva para membros cun nivel de confianza igual ou maior a 3." + post_reply: + base: + different_topic: "Publicación e resposta deben pertencer ao mesmo tema." + web_hook: + attributes: + payload_url: + invalid: "O URL non é válido; debería incluír http:// or https://. Non está permitido ningún espazo en branco." + custom_emoji: + attributes: + name: + taken: xa está en uso por outro emoji + topic_timer: + attributes: + execute_at: + in_the_past: "debe ser no futuro." + translation_overrides: + attributes: + value: + invalid_interpolation_keys: 'A(s) seguinte(s) chave(s) de interpolación non é/son válida(s): "%{keys}"' + watched_word: + attributes: + word: + too_many: "Demasiadas palabras para esa acción" + uncategorized_category_name: "Sen categoría" + vip_category_description: "Unha categoría exclusiva para membros cun nivel de confianza 3 ou superior." meta_category_name: "Opinións sobre o sitio" meta_category_description: "Discusións sobre este sitio, a súa organización, como funciona e como se pode mellorar." staff_category_name: "Equipo" - staff_category_description: "Categoría privada para discusións do equipo. Os temas son visíbeis unicamente para administradores e moderadores." - lounge_welcome: - title: "Benvido/a á Taberna" + staff_category_description: "Categoría privada para discusións do equipo. Os temas son visibles unicamente para administradores e moderadores." + discourse_welcome_topic: + title: "Benvido/a a Discourse" + body: |2 + + O primeiro parágrafo deste tema fixado será visible como mensaxe de benvida para todos os novos visitantes na túa páxina de inicio. É, pois, importante! + + **Edita isto** e describe brevemente a túa comunidade: + + - Para quen é? + - Que van poder atopar aquí? + - Por que deberían vir aquí? + - Onde poden ler máis sobre a comunidade (ligazóns, recursos etc)? + + + + Quizais queiras pechar este tema a través do administrador :wrench: (na parte superior dereita ou na parte inferior), co fin de que as respostas non se acumulen no anuncio. + admin_quick_start_title: "LER PRIMEIRO: Guía rápida de inicio para administradores" category: topic_prefix: "Sobre a categoría %{category}" + replace_paragraph: "(Substitúe este parágrafo cunha breve descrición da túa nova categoría. Este texto aparecerá na área de selección de categoría, así que procura que non supere os 200 caracteres.)" + post_template: "%{replace_paragraph}\n\nUtiliza os seguintes parágrafos para unha descrición máis detallada ou para establecer unha especie de guía ou as regras da categoría:\n\n- Para que debería utilizar esta categoría a xente?\n\n- Exactamente que é o que a distingue doutras categorías xa existentes?\n\n- Que temas se deberían tratar nesta categoría?\n\n- Necesitamos esta categoría? Podería fusionarse con outra categoría ou subcategoría?\n" errors: + not_found: "Categoría non atopada!" + uncategorized_parent: "Sen categoría non pode ter unha categoría principal" depth: "Non podes aniñar unha subcategoría dentro doutra" + invalid_email_in: "'%{email}' non é un enderezo electrónico válido." + email_already_used_in_group: "'%{email}' xa está en uso polo grupo '%{group_name}'." + email_already_used_in_category: "'%{email}' xa está en uso pola categoría '%{category_name}'." + description_incomplete: "A publicación que contén a descrición da categoría debe ter a ao menos un parágrafo." + permission_conflict: "Calquera grupo que teña acceso a unha subcategoría debe ter acceso tamén á categoría principal. Os seguintes grupos teñen acceso a unha das subcategorías, pero non así á principal: %{group_names}." + disallowed_topic_tags: "Este tema ten categorías non permitidas nesta categoría: '%{tags}'" + disallowed_tags_generic: "Este tema ten etiquetas non permitidas." + cannot_delete: + uncategorized: "Esta categoría é especial. Enténdese como unha área de espera para aqueles temas que non teñen categoría. Non se pode eliminar." + has_subcategories: "Non se pode eliminar esta categoría porque ten subcategorías." + topic_exists: + one: "Non se pode eliminar esta categoría porque ten %{count} tema. O máis antigo é %{topic_link}." + other: "Non se pode eliminar esta categoría porque ten %{count} temas. O máis antigo é %{topic_link}." + topic_exists_no_oldest: "Non se pode eliminar esta categoría porque o número de temas é %{count}." + uncategorized_description: "Temas que non teñen categoría ou non encaixan en ningunha das xa existentes." trust_levels: newuser: title: "novo usuario" @@ -162,13 +566,44 @@ gl: member: title: "membro" regular: - title: "normal" + title: "habitual" leader: title: "líder" + change_failed_explanation: "Trataches de rebaixar a %{user_name} a '%{new_trust_level}'. Porén, o seu nivel de confianza xa é '%{current_trust_level}'. %{user_name} vai permanecer en '%{current_trust_level}' - se queres rebaixarlle o nivel, primeiro bloque o seu nivel de confianza." + post: + image_placeholder: + broken: "Esta imaxe está rota" + has_likes: + one: "%{count} gústame" + other: "%{count} gústames" rate_limiter: + slow_down: "Executaches esta acción demasiadas veces, téntao máis tarde." + too_many_requests: "Executaches esta acción demasiadas veces. Agarda %{time_left} antes de volvelo tentar." + by_type: + first_day_replies_per_day: "Alcanzaches o número máximo de respostas que un novo usuario pode dar no seu primeiro día. Agarda %{time_left} antes de volvelo tentar." + first_day_topics_per_day: "Alcanzaches o número máximo de temas que un usuario novo pode crear no seu primeiro día. Agarda %{time_left} antes de volvelo tentar." + create_topic: "Estás a crear temas dun xeito moi rápido. Agarda %{time_left} antes de volvelo tentar." + create_post: "Estás a responder dun xeito moi rápido. Agarda %{time_left} antes de volvelo tentar." + delete_post: "Estás a eliminar publicacións dun xeito moi rápido. Agarda %{time_left} antes de volvelo tentar." + public_group_membership: "Estás a unirte e a deixar grupos con demasiada frecuencia. Agarda %{time_left} antes de volvelo tentar." + topics_per_day: "Alcanzaches o número máximo de novos temas. Agarda %{time_left} antes de volvelo tentar." + pms_per_day: "Alcanzaches o número máximo de mensaxes. Agarda %{time_left} antes de volvelo tentar." + create_like: "Alcanzaches o número máximo de gústames. Agarda %{time_left} antes de volvelo tentar." + create_bookmark: "Alcanzaches o número máximo de marcadores. Agarda %{time_left} antes de volvelo tentar." + edit_post: "Alcanzaches o número máximo de edicións. Agarda %{time_left} antes de volvelo tentar." + live_post_counts: "Estás a pedir que se conten as publicacións dun xeito moi rápido. Agarda %{time_left} antes de volvelo tentar." + unsubscribe_via_email: "Alcanzaches o número máximo de baixas en subscricións por correo electrónico. Agarda %{time_left} antes de volvelo tentar." + topic_invitations_per_day: "Alcanzaches o número máximo de invitacións ao tema. Agarda %{time_left} antes de volvelo tentar." hours: one: "Unha hora" other: "%{count} horas" + minutes: + one: "%{count} minuto" + other: "%{count} minutos" + seconds: + one: "%{count} segundo" + other: "%{count} segundos" + short_time: "uns poucos segundos" datetime: distance_in_words: half_a_minute: "< 1m" @@ -181,6 +616,9 @@ gl: less_than_x_minutes: one: "< %{count}m" other: "< %{count}m" + x_minutes: + one: "%{count}m" + other: "%{count}m" about_x_hours: one: "%{count}h" other: "%{count}h" @@ -189,140 +627,399 @@ gl: other: "%{count}d" about_x_months: one: "%{count}mes" - other: "%{count}mes" + other: "%{count}meses" x_months: one: "%{count}mes" - other: "%{count}mes" + other: "%{count}meses" about_x_years: one: "%{count}ano" - other: "%{count}ano" + other: "%{count}anos" over_x_years: one: "> %{count}ano" - other: "> %{count}ano" + other: "> %{count}anos" almost_x_years: one: "%{count}ano" - other: "%{count}ano" + other: "%{count}anos" distance_in_words_verbose: half_a_minute: "agora mesmiño" less_than_x_seconds: "agora mesmiño" + x_seconds: + one: "hai %{count} segundo" + other: "hai %{count} segundos" + less_than_x_minutes: + one: "hai menos de %{count} minuto" + other: "hai menos de %{count} minutos" + x_minutes: + one: "hai %{count} minuto" + other: "hai %{count} minutos" + about_x_hours: + one: "hai %{count} hora" + other: "hai %{count} horas" + x_days: + one: "hai %{count} día" + other: "hai %{count} días" + about_x_months: + one: "hai como %{count} mes" + other: "hai como uns %{count} meses" + x_months: + one: "hai %{count} mes" + other: "hai %{count} meses" + about_x_years: + one: "hai como %{count} ano" + other: "hai como uns %{count} anos" + over_x_years: + one: "hai máis de %{count} ano" + other: "hai máis de %{count} anos" + almost_x_years: + one: "hai case %{count} ano" + other: "hai case %{count} anos" password_reset: + no_token: "Sentímolo, esa ligazón para trocar o contrasinal é demasiado antiga. Preme no botón Iniciar sesión e dálle a 'Esquecín o meu contrasinal' para obter unha nova ligazón." + choose_new: "Elixir un novo contrasinal" + choose: "Elixir un contrasinal" update: "Actualizar contrasinal" save: "Estabelecer o contrasinal" title: "Contrasinal restabelecido" + success: "Cambiaches satisfactoriamente o teu contrasinal e agora iniciaches sesión." + success_unapproved: "Cambiaches satisfactoriamente o teu contrasinal." + email_login: + invalid_token: "Sentímolo, o correo coa ligazón para iniciar sesión é demasiado antigo. Preme no botón Iniciar sesión e dálle a 'Esquecín o meu contrasinal' para obter unha nova ligazón." + title: "Iniciar sesión vía correo electrónico" + user_auth_tokens: + browser: + chrome: "Google Chrome" + discoursehub: "App DiscourseHub" + edge: "Microsoft Edge" + firefox: "Firefox" + ie: "Internet Explorer" + opera: "Opera" + safari: "Safari" + unknown: "navegador descoñecido" + device: + android: "Dispositivo Android" + chromebook: "Chromebook" + ipad: "iPad" + iphone: "iPhone" + ipod: "iPod" + linux: "Sistema operativo GNU/Linux" + mac: "Mac" + mobile: "Dispositivo móbil" + windows: "Sistema operativo Windows" + unknown: "dispositivo descoñecido" + os: + android: "Android" + chromeos: "ChromeOS" + ios: "iOS" + linux: "Linux" + macos: "macOS" + windows: "Microsoft Windows" + unknown: "sistema operativo descoñecido" change_email: + wrong_account_error: "Iniciaches sesión cunha conta incorrecta; sae e vólveo tentar." confirmed: "O teu correo electrónico foi actualizado." please_continue: "Continuar a %{site_name}" - error: "Produciuse un erro cambiando o enderezo de correo electrónico. Quizais xa está en uso?" + error: "Produciuse un erro ao cambiar o enderezo electrónico. Quizais xa está en uso?" + doesnt_exist: "Este enderezo electrónico non está asociado coa túa conta." + error_staged: "Produciuse un erro ao cambiar o enderezo electrónico. O enderezo xa está en uso por un usuario temporal." + already_done: "Sentímolo, a ligazón de confirmación xa non está dispoñible. Talvez o teu correo electrónico xa se modificou?" + confirm: "Confirmar" + authorizing_new: + title: "Confirma o teu novo correo electrónico" + description: "Confirma que queres cambiar o teu enderezo electrónico a:" + description_add: "Confirma que queres engadir un enderezo electrónico alternativo:" + authorizing_old: + title: "Cambiar o teu enderezo electrónico" + description: "Confirma o cambio do teu enderezo electrónico" + description_add: "Confirma que queres engadir un enderezo electrónico alternativo:" + old_email: "Corre electrónico antigo: %{email}" + new_email: "Novo correo electrónico: %{email}" + almost_done_title: "Confirmando o novo enderezo electrónico" + almost_done_description: "Enviámosche un correo ao teu novo enderezo para confirmar o cambio!" + associated_accounts: + revoke_failed: "Erro ao revogar a túa conta con %{provider_name}." + connected: "(conectadas)" activation: - action: "Preme aquí para activar a conta" + action: "Preme aquí para activar a túa conta" + already_done: "Sentímolo, esta ligazón de confirmación da conta xa non está dispoñible. Talvez a túa conta xa estea activada?" + please_continue: "A túa nova conta está confirmada; redireccionarésmote á páxina de inicio." continue_button: "Continuar a %{site_name}" welcome_to: "Benvido/a a %{site_name}!" + approval_required: "Un moderador debe aprobar manualmente a túa nova conta antes de que poidas acceder a este foro. Recibirás un correo electrónico cando a túa conta sexa aprobada!" + missing_session: "Non podemos detectar se se creou a túa conta; asegúrate de teres as cookies activadas." + activated: "Sentímolo, esta conta xa foi activada." + admin_confirm: + title: "Confirmar conta de administrador" + description: "Tes a certeza de querer converter a %{target_username} (%{target_email}) en administrador?" + grant: "Conceder permiso de administrador" + complete: "%{target_username} é agora administrador." + back_to: "Volver a %{title}" reviewable_score_types: needs_approval: title: "Cómpre aprobación" post_action_types: off_topic: - title: "Sen-relación" - long_form: "marcou isto como non relacionado" + title: "Sen relación co tema" + description: "Esta publicación non é relevante para a discusión actual tal e como se define no título e na súa primeira entrada; probablemente debería moverse a outro lugar." + short_description: "Non é relevante para a discusión" + long_form: "denunciado como sen relación co tema" spam: - title: "Spam" - long_form: "denunciou isto como spam" + title: "Correo lixo" + description: "Esta publicación é publicidade ou vandalismo. Non é útil nin relevante para o tema." + short_description: "Isto é publicidade ou vandalismo" + long_form: "denunciado como correo lixo" + email_title: '"%{title}" foi denunciado como correo lixo' + email_body: "%{link}\n\n%{message}" inappropriate: title: "Inapropiado" - long_form: "denunciou isto como inapropiado" + description: 'Esta publicación ten contido que unha persoa razoable podería considerar ofensivo, abusivo ou supor unha violación das nosas instrucións para a comunidade.' + short_description: 'Unha violación dasnosas instrucións para a comunidade ' + long_form: "denunciado como inapropiado" + notify_user: + title: "Enviar unha mensaxe a @%{username}" + description: "Quero falar con esta persoa directa e persoalmente acerca da súa publicación." + short_description: "Quero falar con esta persoa directa e persoalmente acerca da súa publicación." + long_form: "usuario notificado vía mensaxe" + email_title: 'A túa publicación en "%{title}"' + email_body: "%{link}\n\n%{message}" notify_moderators: title: "Algo máis" - description: "Esta publicación require a atención dos responsábeis do sitio por unha razón non listada arriba." - long_form: "denunciou isto para revisión polo equipo" - email_title: 'Unha publicación en «%{title}» require a atención dos responsábeis do sitio' + description: "Esta publicación require a atención dos responsables do sitio por unha razón non listada arriba." + short_description: "Require a atención do equipo por outro motivo" + long_form: "denunciado para ser revisado polo equipo" + email_title: 'Unha publicación en «%{title}» require a atención dos responsables do sitio' + email_body: "%{link}\n\n%{message}" bookmark: title: "Marcador" - description: "Marcar esta publicación" - short_description: "Marcar esta publicación" - long_form: "Marcar este tema" + description: "Engadir esta publicación aos marcadores" + short_description: "Engadir esta publicación a marcadores" + long_form: "publicación engadida a marcadores" like: title: "Gústame" description: "Gústame esta publicación" short_description: "Gústame esta publicación" long_form: "gustoume isto" + draft: + sequence_conflict_error: + title: "erro no borrador" + description: "O borrador está a ser editado noutra xanela. Volve cargar esta páxina." + draft_backup: + pm_title: "Borradores de apoio de temas en curso" + user_activity: + no_default: + self: "Aínda non tes actividade." + others: "Sen actividade." + no_bookmarks: + self: "Non tes publicacións engadidas aos marcadores; os marcadores permítenche volver rapidamente sobre publicacións específicas." + others: "Sen marcadores" + no_likes_given: + self: "Non lle deches Gústame a ningunha publicación." + others: "Ningún gústame en publicacións." + no_replies: + self: "Non respondiches a ningunha publicación." + others: "Sen respostas." + no_drafts: + self: "Non tes borradores; comeza responder en calquera tema e gardarase automaticamente como un novo borrador." + webauthn: + validation: + invalid_type_error: "O provedor tipo webauthn facilitado non é válido. Os tipos válidos son webauthn.get e webauthn.create." + invalid_origin_error: "A orixe da solicitude de autenticación non coincide coa orixe do servidor." + malformed_attestation_error: "Produciuse un erro ao descodificar os datos de certificación." + user_verification_error: "Requírese a verificación do usuario." + unsupported_public_key_algorithm_error: "O servidor non é compatible co algoritmo de chave pública facilitado." + unsupported_attestation_format_error: "O formato de certificación non é compatible co servidor." + credential_id_in_use_error: "A ID da credencial facilitada xa está en uso." + public_key_error: "Houbo un erro na verificación da chave pública da credencial." + ownership_error: "A chave de seguridade non pertence ao usuario." + not_found_error: "Non se atopou ningunha chave de seguridade coa ID da credencial facilitada." + unknown_cose_algorithm_error: "Non se recoñece o algoritmo utilizado para a chave de seguridade." topic_flag_types: spam: - title: "Spam" - long_form: "denunciou isto como spam" + title: "Correo lixo" + description: "Este tema é publicidade. Non é util nin relevante para este sitio; a súa natureza é de carácter promocional." + long_form: "denunciado como correo lixo" + short_description: "Isto é publicidade" inappropriate: title: "Inapropiado" + description: 'Esta publicación ten contido que unha persoa razoable podería considerar ofensivo, abusivo ou supor unha violación das nosas instrucións para a comunidade.' long_form: "denunciou isto como inapropiado" + short_description: 'Unha violación dasnosas instrucións para a comunidade ' notify_moderators: title: "Algo máis" + description: 'Este tema require da atención do equipo con base nas instrucións, os termos de servizo ou por calquera outro motivo non listado enriba.' long_form: "denunciou isto para revisión por un moderador" + short_description: "Require a atención do equipo por outro motivo" + email_title: 'O tema "%{title}" require a atención do moderador' + email_body: "%{link}\n\n%{message}" + flagging: + you_must_edit: '

A túa publicación foi denunciada pola comunidade. Por favor, revista as túas mensaxes.

' + user_must_edit: "

Esta publicación foi denunciada pola comunidade e temporalmente permanecerá oculta.

" + ignored: + hidden_content: "

Contido ignorado

" archetypes: regular: title: "Tema normal" banner: title: "Tema do báner" + unsubscribed: + title: "Preferencias de correo electrónico actualizadas!" + description: "as preferencias para %{email} foron actualizadas. Para cambiar a configuración do teu correo electrónico visita as túas preferencias de usuario." + topic_description: "Para volver subscribirte a%{link}, utiliza o control de notificacións na parte inferior ou dereita do tema." + private_topic_description: "Para volver subscribirte, utiliza o control de notificacións na parte inferior ou dereita do tema." unsubscribe: + title: "Cancelar subscrición" + stop_watching_topic: "Deixar de seguir este tema, %{link}" + mute_topic: "Silenciar todas as notificacións para este tema, %{link}" + unwatch_category: "Deixar de seguir todos os temas en %{category}" + mailing_list_mode: "Desactivar o modo de lista de correo" + all: "Non enviarme ningún correo electrónico de %{sitename}" + different_user_description: "Actualmente tes a sesión iniciada cun usuario diferente ao que lle enviamos un correo electrónico. Sae, ou entra en modo anónimo, e vólveo tentar." + not_found_description: "Non puidemos atopar a cancelación da subscrición. É posible que caducase a ligazón do teu correo electrónico xa caducase?" log_out: "Saír da sesión" + submit: "Gardar preferencias" digest_frequency: + title: "Estás a recibir correos electrónicos de resumo %{frequency}" + select_title: "Establecer a frecuencia dos correos electrónicos resumo:" never: "nunca" every_30_minutes: "cada 30 minutos" every_hour: "cada hora" daily: "diariamente" weekly: "semanalmente" + every_month: "cada mes" + every_six_months: "cada seis meses" user_api_key: + title: "Autorizar acceso á aplicación" + authorize: "Autorizar" + read: "lectura" + read_write: "lectura/escritura" + description: '"%{application_name}" está a solicitar o seguinte acceso á túa conta:' + instructions: 'Acabamos de xerar unha nova chave API de usuario para que utilices con "%{application_name}"; pega a seguinte chave na túa aplicación.' + otp_description: 'Gustaríache permitirlle a "%{application_name}" acceder a este sitio?' otp_confirmation: confirm_title: "Continuar a %{site_name}" + logging_in_as: "Iniciando sesión como %{username}" + confirm_button: Finalizar inicio de sesión + no_trust_level: "Sentímolo, non tes o nivel de confianza que se necesita para acceder á API de usuario." + generic_error: "Sentimolo, non nos é posible emitir chaves API de usuario, pois esta funcionalidade debeu ser desactivada polo administrador do sitio" + scopes: + message_bus: "Actualizacións ao vivo" + notifications: "Ler e borrar as notificacións" + push: "Notificacións emerxentes para servizos externos" + session_info: "Ler información da sesión de usuario" + read: "Ler todo" + write: "Escribir todo" + one_time_password: "Crear un código de inicio de sesión dun só uso" + invalid_public_key: "Sentímolo, a chave pública non é válida" + invalid_auth_redirect: "Sentímolo, este host auth_redirect host non está permitido." + invalid_token: "Código non válido, caducado ou ausente." reports: default: labels: + count: Número + percent: Porcentaxe day: Día post_edits: + title: "Edicións publicadas" labels: edited_at: Data post: Publicación editor: Editor + author: Autor edit_reason: Razón + description: "Número de edicións de novas publicacións" user_flagging_ratio: labels: user: Usuario + score: Puntuación + description: "Listaxe de usuarios ordenada segundo a porcentaxe de respostas ás súas por parte do equipo (en desacordo ou en acordo)." moderators_activity: + title: "Actividade do moderador" labels: moderator: Moderador + flag_count: Marcas revisadas + time_read: Tempo de lectura + topic_count: Temas creados + post_count: Publicacións creadas + pm_count: Mensaxes privadas creadas + revision_count: Revisións + description: "Listaxe da actividade de moderación que inclúe as marcas revisadas, o tempo de lectura, os temas creados, as mensaxes privadas e as revisións." + flags_status: + values: + agreed: De acordo + disagreed: En desacordo + deferred: Adiado + no_action: Sen acción + labels: + flag: Tipo + assigned: Asignado + poster: Autor + time_to_resolution: Tempo de resolución visits: title: "Visitas de usuarios" xaxis: "Día" yaxis: "Número de visitas" + description: "Número de todas as visitas do usuario" signups: + title: "Rexistros" xaxis: "Día" + yaxis: "Número de rexistros" + description: "Novos rexistros de conta para este período." new_contributors: + title: "Novos colaboradores" xaxis: "Día" + yaxis: "Número de novos colaboradores" + description: "Número de usuarios que publicaron por primeira vez durante este período." trust_level_growth: + title: "Crecemento do nivel de confianza" + xaxis: + tl1_reached: "NC1 alcanzado" + tl2_reached: "NC2 alcanzado" + tl3_reached: "NC3 alcanzado" + tl4_reached: "NC4 alcanzado" yaxis: "Día" + description: "Número de usuarios que incrementaron o seu nivel de confianza durante este período" consolidated_page_views: + title: "Visualizacións de páxinas consolidadas" + xaxis: + page_view_crawler: "Rastrexadores" + page_view_anon: "Usuarios anónimos" + page_view_logged_in: "Usuarios conectados" yaxis: "Día" + description: "Visualizacións de páxinas para usuarios conectados, anónimos e rastrexadores." labels: post: Publicación editor: Editor + author: Autor edit_reason: Razón dau_by_mau: + title: "UAD/UAM" xaxis: "Día" + yaxis: "UAD/UAM" + description: "Número de membros que iniciaron sesión no último día entre o número de membros que iniciaron sesión no último mes - devolve a porcentaxe que indica o grao de permanencia da comunidade. Obxectivo: >30%." daily_engaged_users: + title: "Usuarios comprometidos a diario" xaxis: "Día" + yaxis: "Usuarios comprometidos" + description: "Número de usuarios que lle deron a Gústame ou publicaron no último día." profile_views: - title: "Vistas dos perfís de usuario" + title: "Visualizacións dos perfís de usuario" xaxis: "Día" yaxis: "Número de perfís de usuario vistos" + description: "Número total de visualizacións de perfís de usuario." topics: title: "Temas" xaxis: "Día" - yaxis: "Número de temas vistos" + yaxis: "Número de novos temas" + description: "Novos temas creados durante este período." posts: title: "Publicacións" xaxis: "Día" yaxis: "Número de novas publicacións" + description: "Novas publicacións creadas durante este período" likes: title: "Gústames" xaxis: "Día" yaxis: "Número de novos gústames" + description: "Número de novos gústames." flags: title: "Denuncias" xaxis: "Día" @@ -331,43 +1028,70 @@ gl: title: "Marcadores" xaxis: "Día" yaxis: "Número de novos marcadores" + description: "Número de novos temas e publicacións engadidos aos marcadores." users_by_trust_level: title: "Usuarios por nivel de confianza" xaxis: "Nivel de confianza" yaxis: "Número de usuarios" + labels: + level: Nivel + description: "Número de usuarios agrupados polo nivel de confianza." + description_link: "https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/" users_by_type: + title: "Usuarios por tipo" + xaxis: "Tipo" yaxis: "Número de usuarios" + labels: + type: Tipo xaxis_labels: - admin: Administración + admin: Administrador moderator: Moderador suspended: Suspendido + silenced: Silenciado + description: "Número de usuarios agrupados por administradores, moderadores, suspendidos e silenciados." + trending_search: + title: Termos de busca populares + labels: + term: Termo + searches: Buscas + click_through: CTR emails: - title: "Correos-e enviados" + title: "Correos electrónicos enviados" xaxis: "Día" - yaxis: "Número de correos-e enviados" + yaxis: "Número de correos electrónicos enviados" + description: "Número de novos correos electrónicos enviados" user_to_user_private_messages: + title: "Usuario a usuario (respostas excluídas)" xaxis: "Día" yaxis: "Número de mensaxes" + description: "Número de mensaxes persoais iniciadas recentemente" user_to_user_private_messages_with_replies: + title: "Usuario a usuario (con respostas)" xaxis: "Día" yaxis: "Número de mensaxes" + description: "Número de todas as novas mensaxes persoais e respostas." system_private_messages: title: "Sistema" xaxis: "Día" yaxis: "Número de mensaxes" + description: "Número de mensaxes persoais enviadas automaticamente polo sistema." moderator_warning_private_messages: title: "Avisos dun moderador" xaxis: "Día" yaxis: "Número de mensaxes" + description: "Número de avisos enviados a través de mensaxes persoais polos moderadores." notify_moderators_private_messages: - title: "Notificacións os moderadores" + title: "Notificar aos moderadores" xaxis: "Día" yaxis: "Número de mensaxes" + description: "Número de veces que os moderadores foron notificados por privado dunha denuncia." notify_user_private_messages: title: "Notificacións os usuarios" xaxis: "Día" yaxis: "Número de mensaxes" + description: "Número de veces que os usuarios foron notificados por privado dunha denuncia." top_referrers: + title: "Referenciadores populares" xaxis: "Usuario" num_clicks: "Clics" num_topics: "Temas" @@ -375,8 +1099,9 @@ gl: user: "Usuario" num_clicks: "Clics" num_topics: "Temas" + description: "Usuarios listados polo número de clics nas ligazóns que compartiron." top_traffic_sources: - title: "As maiores fontes de tráfico" + title: "Maiores fontes de tráfico" xaxis: "Dominio" num_clicks: "Clics" num_topics: "Temas" @@ -385,36 +1110,55 @@ gl: domain: Dominio num_clicks: Clics num_topics: Temas + description: "Fontes externas que mais ligaron con este sitio." top_referred_topics: + title: "Temas con máis referencias" labels: num_clicks: "Clics" topic: "Tema" + description: "Temas que máis clics recibiron desde fontes externas." page_view_anon_reqs: title: "Anónimo" xaxis: "Día" + yaxis: "Visualicacións de páxinas anónimas" + description: "Número de novas visualizacións de páxinas feitas por visitantes sen a sesión iniciada na súa conta." page_view_logged_in_reqs: - title: "Sesión iniciada" + title: "Coa sesión iniciada" xaxis: "Día" + yaxis: "Visualizacións de páxina coa sesión iniciada" + description: "Número de novas visualizacións de páxinas feitas por usuarios coa sesión iniciada." page_view_crawler_reqs: + title: "Visualizacións de páxina por rastrexadores web" xaxis: "Día" + yaxis: "Visualizacións de páxina por rastrexadores web" + description: "Total de visualizacións desde rastrexadores web ao longo do tempo." page_view_total_reqs: + title: "Visualizacións de páxinas" xaxis: "Día" + yaxis: "Total de visualizacións de páxina" + description: "Número de novas visualizacións de páxina de todos os visitantes." page_view_logged_in_mobile_reqs: + title: "Visualizacións de páxina coa sesión iniciada" xaxis: "Día" + yaxis: "Visualizacións de páxina desde coa sesión iniciada desde un móbil" + description: "Número de novas visualizacións de páxina de usuarios coa sesión iniciada desde un dispositivo móbil." page_view_anon_mobile_reqs: + title: "Visualizacións de páxinas anónimas" xaxis: "Día" + yaxis: "Visualizacións de páxinas anónimas desde un dispositivo móbil" + description: "Número de novas visualizacións de páxina de visitantes desde un dispositivo móbil sen a sesión iniciada." http_background_reqs: title: "Fondo" xaxis: "Día" - yaxis: "Peticións usadas para actualizacións e seguimentos" + yaxis: "Solicitudes utilizadas para actualizacións e seguimentos ao vivo" http_2xx_reqs: title: "Estado 2xx (OK)" xaxis: "Día" - yaxis: "Peticións con éxito (estado 2xx)" + yaxis: "Solicitudes con éxito (estado 2xx)" http_3xx_reqs: title: "HTTP 3xx (redireccionar)" xaxis: "Día" - yaxis: "Redireccionar peticións (estado 3xx)" + yaxis: "Redireccionar solicitudes (estado 3xx)" http_4xx_reqs: title: "HTTP 4xx (erro do cliente)" xaxis: "Día" @@ -422,28 +1166,73 @@ gl: http_5xx_reqs: title: "HTTP 5xx (erro do servidor)" xaxis: "Día" + yaxis: "Erros do servidor (estado 5xx)" http_total_reqs: title: "Total" xaxis: "Día" + yaxis: "Solicitudes totais" time_to_first_response: + title: "Tempo transcorrido ata a primeira resposta" xaxis: "Día" + yaxis: "Tempo medio (horas)" + description: "Tempo medio (horas) ata a primeira resposta a novos temas." topics_with_no_response: + title: "Temas sen resposta" xaxis: "Día" yaxis: "Total" + description: "Número de temas novos que non recibiron resposta." mobile_visits: + title: "Visitas de usuarios (móbil)" xaxis: "Día" yaxis: "Número de visitas" + description: "Número de usuarios únicos que utilizaron un dispositivo móbil." + web_crawlers: + labels: + user_agent: "Axentes de usuario" + page_views: "Visualizacións de páxinas" suspicious_logins: + title: "Inicios de sesión sospeitosos" labels: user: Usuario + client_ip: IP do cliente location: Localización + browser: Navegador + device: Dispositivo + os: Sistema operativo + login_time: Data e hora do inicio de sesión + description: "Detalles de novos inicios de sesión que difiren sospeitosamente doutros anteriores." staff_logins: labels: user: Usuario location: Localización + login_at: Inicio de sesión ás top_uploads: labels: filename: Nome do ficheiro + extension: Extensión + author: Autor + filesize: Tamaño do ficheiro + description: "Listaxe de todas as cargas por extensión, tamaño e autor." + top_ignored_users: + labels: + ignored_user: Usuario ignorado + ignores_count: Número de ignorados + mutes_count: Número de silenciados + description: "Usuarios que foron silenciados e/ou ignorados por moitos outros usuarios." + dashboard: + rails_env_warning: "O teu servidor está a executarse en modo %{env}." + host_names_warning: "O teu ficheiro config/database.yml file está a usar o nome do servidor localhost predefinido. Actualízao para utilizar o nome do servidor do teu sitio." + sidekiq_warning: 'Sidekiq non está a funcionar. Moitas tarefas, caso do envío de correos electrónicos, están a ser realizadas de forma asíncrona por sidekiq. Asegúrate de que, ao menos un proceso de sidekiq está funcionando. Aprende máis sobre Sidekiq aquí.' + queue_size_warning: "O número de tarefas na cola é %{queue_size}, que é unha cifra alta. Isto pode indicar un problema co(s) proceso(s) de Sidekiq ou tes que engadir máis traballadores de Sidekiq." + memory_warning: "O teu servidor estase a executar con menos de 1 GB da memoria total. Recoméndase ao menos unha memoria de 1 GB." + google_oauth2_config_warning: 'O servidor está configurado para permitir o rexistro de inicio sesión mediante Google OAuth2 (enable_google_oauth2_logins), pero os valores ID do cliente e do cliente secreto non foron establecidos. Vai a Axustes do sitio e actualiza a configuración. Revisa esta guía para saber máis.' + image_magick_warning: 'O servidor está configurado para crear miniaturas de imaxes grandes, pero ImageMagick non está instalado. Instálao utilizando o teu administrador de paquetes favorito ou descarga a última versión.' + failing_emails_warning: 'Hai %{num_failed_jobs} tarefas de correo electrónico que fallaron. Comproba o teu app.yml e asegúrate de que os axustes do servidor de correo son correctos. Mira as tarefas que fallaron en Sidekiq.' + subfolder_ends_in_slash: "A configuración do subcartafol non é correcta; o campo DISCOURSE_RELATIVE_URL_ROOT remata cunha barra." + missing_mailgun_api_key: "O servidor está configurado para enviar correos electrónicos a través de Mailgun, pero non proporcionaches unha chave API que se utiliza para verificar as mensaxes de webhook." + bad_favicon_url: "Erro ao cargar a favicona. Comproba a súa configuración en Axustes do sitio." + out_of_date_themes: "Hai actualizacións dispoñibles para os seguintes temas:" + unreachable_themes: "Non puidemos comprobar se hai actualizacións para os seguintes temas:" site_settings: delete_old_hidden_posts: "Eliminar automaticamente as publicacións ocultas durante máis de 30 días." allow_user_locale: "Permitir os usuarios escoller o idioma da interface" @@ -451,8 +1240,103 @@ gl: min_first_post_length: "Número mínimo de caracteres (corpo do tema) permitido para unha primeira publicación" min_personal_message_post_length: "Número mínimo de caracteres permitido para unha mensaxe" max_post_length: "Número máximo de caracteres permitido para unha publicación" - post_undo_action_window_mins: "Número de minutos que os usuarios teñen para desfacer accións recentes nunha publicación (gústames, denuncias, etc)." + topic_featured_link_enabled: "Activar a publicación dunha ligazón con temas." + show_topic_featured_link_in_digest: "Mostrar a ligazón destacada do tema no correo electrónico de resumo." + min_topic_title_length: "Extensión mínima do título dos temas en número de caracteres" + max_topic_title_length: "Extensión máxima do título dos temas en número de caracteres" + min_personal_message_title_length: "Extensión mínima do título dunha mensaxe en número de caracteres" + max_emojis_in_title: "Número máximo de emojis permitido no título dun tema" + min_search_term_length: "Extensión mínima dunha busca válida en número de caracteres" + search_recent_posts_size: "Número de publicacións recentes que se manteñen no índice" + log_search_queries: "Rexistro de buscas realizadas polos usuarios" + search_query_log_max_size: "Número máximo de consultas que se conservan" + search_query_log_max_retention_days: "Tempo máximo que se conservan as consultas de buscas, en días." + search_ignore_accents: "Ignorar os acentos nas buscas de texto." + allow_duplicate_topic_titles: "Permitir temas con títulos idénticos, duplicados" + allow_duplicate_topic_titles_category: "Permitir temas con títulos idénticos, duplicados, se a categoría é diferente. allow_duplicate_topic_titles debe ser falso." + unique_posts_mins: "Minutos que deben transcorrer antes de que usuario poida volver publicar o mesmo contido" + educate_until_posts: "Cando o usuario comeza a escribir as súas primeiras (n) publicacións, mostrarlle o panel emerxente cos consellos para usuarios novos no editor." + title: "O nome deste sitio, utilizado na etiqueta título." + site_description: "Describe o sitio nunha única frase, utilizada na etiqueta metadescrición." + short_site_description: "Breve descrición, utilizada como o título da etiqueta na páxina principal." + contact_email: "Enderezo electrónico do/a responsable deste sitio. Utilízase para notificacións críticas e mais na páxina de información de contacto para asuntos urxentes." + contact_url: "URL de contacto para este sitio. Utilízase na información do formulario de contacto para asuntos urxentes." + crawl_images: "Recuperar imaxes desde URL remotos para inserilas coas dimensións correctas de largura e altura." + download_remote_images_to_local: "Converter imaxes remotas en locais ao descargalas; isto prevé ter imaxes rotas." + download_remote_images_threshold: "Espazo mínimo no disco necesario para descargar imaxes remotas de forma local (en porcentaxe)" + disabled_image_download_domains: "As imaxes remotas procedentes destes dominios non serán descargadas. Listaxe delimitada por barras." + editing_grace_period: "Durante (n) segundos logo de publicar, pódese editar sen chegar a crear unha nova versión no historial." + max_image_width: "Largura máxima das miniaturas de imaxes nunha publicación" + max_image_height: "Altura máxima das miniaturas de imaxes nunha publicación" + post_excerpt_maxlength: "Lonxitude máxima do resumo/extracto dunha publicación." + topic_excerpt_maxlength: "Lonxitude máxima dun extracto/resumo dun tema xerado a partir da primeira publicación dun tema." + show_pinned_excerpt_mobile: "Mostrar o extracto de temas destacados na vista móbil." + show_pinned_excerpt_desktop: "Mostrar o extracto de temas destacados na vista de escritorio." + post_onebox_maxlength: "Lonxitude máxima en caracteres dunha publicación de Discourse en formato onebox." + onebox_domains_blacklist: "Unha listaxe de dominios que nunca se mostrarán en formato onebox." + inline_onebox_domains_whitelist: "Unha listaxe de dominios que se transformarán en formato onebox en miniatura se son ligados sen un título." + enable_system_message_replies: "Permitirlles aos usuarios responder mensaxes do sistema, mesmo aínda que as mensaxes persoais estean desactivadas." + cooldown_minutes_after_hiding_posts: "Número de minutos que un usuario debe esperar para poder editar unha publicación oculta por mor das denuncias da comunidade." + max_topics_in_first_day: "Número máximo de temas que un usuario ten permitido crear nas 24 horas posteriores logo de crear a súa primeira publicación" + max_replies_in_first_day: "Número máximo de respostas que un usuario ten permitido deixar nas 24 horas posteriores logo de crear a súa primeira publicación" + tl2_additional_likes_per_day_multiplier: "Incrementar o número de gústames por día para usuarios con nivel de confianza 2 (membros) multiplicándoo por este número" + tl4_additional_likes_per_day_multiplier: "Incrementar o número de gústames por día para usuarios con nivel de confianza 3 (líderes) multiplicándoo por este número" + num_users_to_silence_new_user: "Se as publicacións dun usuario novo non se denuncian como lixo ou non desexadas por num_spam_flags_to_silence_new_user, agochar todas as súas publicacións e evitar que publique no futuro. Valor en 0 para deshabilitar." + num_tl3_flags_to_silence_new_user: "Se as publicacións dun novo usuario reciben este número de denuncias num_tl3_users_to_silence_new_user different de diferentes usuarios con nivel 3 de confianza, agochar todas as súas publicacións e evitar que publique no futuro. Valor en 0 para deshabilitar." + num_tl3_users_to_silence_new_user: "Se as publicacións dun novo usuario reciben num_tl3_users_to_silence_new_user different denuncias deste número de usuarios con nivel 3 de confianza, agochar todas as súas publicacións e evitar que publique no futuro. Valor en 0 para deshabilitar." + notify_mods_when_user_silenced: "Se un usuario é silenciado automaticamente, enviarlles unha mensaxe a todos os moderadores." + flag_sockpuppets: "Se un novo usuario responde a un tema desde o mesmo enderezo IP que o usuario que iniciou o tema, denunciar as publicacións de ambos como lixo en potencia." + traditional_markdown_linebreaks: "Utilizar saltos de liña tradicionais en Markdown, que requiren dous espazos ao fina para un salto de liña." + enable_markdown_typographer: "Utilizar regras tipográficas para mellorar a lexibilidade do texto: substituír comas rectas «con comiñas ou aspas», (c) (tm) con símbolos, -- con guión longo –, etc" + enable_markdown_linkify: "Tratar automaticamente o texto que pareza unha ligazón como unha ligazón: www.exemplo.com e https://exemplo.com vincúlanse automaticamente" + markdown_linkify_tlds: "Listaxe de dominios de nivel superior que se tratan automaticamente como ligazóns" + markdown_typographer_quotation_marks: "Listaxe de pares de substitución de comiñas dobres e simples" + post_undo_action_window_mins: "Número de minutos que os usuarios teñen para desfacer accións recentes nunha publicación (gústames, denuncias etc)." + must_approve_users: "O equipo debe aprobar todas as novas contas antes de que teñan permiso para acceder ao sitio." + invite_code: "O usuario debe inserir este código para que se lle permita o rexistro da conta, ignorado cando está baleiro (non distingue entre maiúsculas e minúsculas)" + approve_suspect_users: "Engadir usuarios sospeitosos á cola de revisión. Usuarios sospeitosos que inseriron unha biografía ou sitio web, pero non teñen actividade de lectura." + pending_users_reminder_delay: "Notificarlles aos moderadores se hai novos usuarios que estiveran á espera da súa aprobación por máis tempo desta cantidade de horas. Valor -1 para deshabilitar notificacións. " + maximum_session_age: "O usuario permanecerá coa sesión iniciada durante n horas desde a última visita." + ga_universal_tracking_code: "Código de seguimento de Google Universal Analytics (analytics.js) , ex: UA-12345678-9; visita https://google.com/analytics" + ga_universal_domain_name: "Nome do dominio establecido en Google Universal Analytics (analytics.js), ex: mysite.com; visita https://google.com/analytics" + ga_universal_auto_link_domains: "Habilitar o seguimento multidominio de Google Universal Analytics (analytics.js). As ligazóns saíntes destes dominios terán a ID do cliente agregadas. Revisa A guía de Google para o seguimento multidominio." + gtm_container_id: "ID do contedor de Google Tag Manager. ex: GTM-ABCDEF.
Nota: pode ser necesario que os scripts de terceiros cargados a través de GTM se engadan á lista branca en 'content security policy script src'." + moderators_create_categories: "Permitir que os moderadores cren novas categorías" + blacklist_ip_blocks: "Unha listaxe privada de enderezos IP bloqueados que nunca deberían ser rastrexadas por Discourse" + whitelist_internal_hosts: "Unha listaxe con hosts internos que Discourse pode rastrexar de forma segura para utilizar con Onebox e outros propósitos." + site_contact_group_name: "Un nome de grupo válido para ser convidado a todas as mensaxes automatizadas." + send_welcome_message: "Enviar aos novos usuarios unha mensaxe de benvida cunha guía de acceso rápido." + send_tl1_welcome_message: "Enviar aos novos usuarios con nivel 1 de confianza unha mensaxe de benvida." + suppress_reply_directly_below: "Non mostrar o contador de respostas despregable cando hai unha única resposta xusto embaixo desta publicación." + suppress_reply_directly_above: "Non mostrar o despregable en-resposta-a nunha publicación se unicamente hai unha resposta xusto enriba dela." + remove_full_quote: "Eliminar automaticamente citas completas nas respostas directas." + suppress_reply_when_quoting: "Non mostrar o despregable en-resposta-a nunha publicación cando esta cite a resposta." + max_reply_history: "Número máximo de respostas que se mostran ao expandir en-resposta-a" + topics_per_period_in_top_summary: "Número de temas destacados que se mostran no resumo de temas destacados." + topics_per_period_in_top_page: "Número de temas destacados que se mostran na vista expandida ao premer en 'Mostrar máis'." + redirect_users_to_top_page: "Redirixir automaticamente á páxina de destacados a aqueles usuarios novos e aos que se ausentan por un longo período." + top_page_default_timeframe: "Período predefinido para a páxina de temas destacados." + moderators_view_emails: "Permitir que os moderadores vexas os correos electrónicos dos usuarios" + prioritize_username_in_ux: "Mostrar o nome de usuario primeiro na páxina de usuario, a tarxeta de usuario e as publicacións (cando está desactivado, o nome móstrase primeiro)" + enable_rich_text_paste: "Habilitar conversión automática de HTML a Markdown ao pegar texto no compositor. (Experimental)" + send_old_credential_reminder_days: "Lembrar as credencias antigas despois de días" + email_token_valid_hours: "Os códigos para restablecer o contrasinal ou activar a conta son válidos durante (n) horas." enable_badges: "Activar o sistema de insignias" + enable_whispers: "Permitir que os membros do equipo se comuniquen entre eles por privado dentro dos temas." + allow_index_in_robots_txt: "Especificar en robots.txt que se permite que este sitio sexa indexado polos motores de busca en internet. En casos excepcionais, podes
sobrescribir robots.txtpermanentemente." + invite_expiry_days: "Tempo de duración que as claves para convidar usuarios son válidas, en días" + login_required: "Requírese autenticación para ler contido neste sitio; deshabilitar o acceso anónimo." + min_username_length: "Lonxitude mínima do nome de usuario en caracteres. Advertencia: se hai usuarios ou grupos cunha extensión menor, o teu sitio quebrará!" + max_username_length: "Lonxitude máxima do nome de usuario en caracteres. Advertencia: se hai usuarios ou grupos cunha extensión maior, o teu sitio quebrará!" + unicode_usernames: " Permitir que os nomes de usuario conteñan algunhas letras e números Unicode." + unicode_username_character_whitelist: "Expresión regular para permitir unicamente algúns caracteres Unicode dentro dos nomes de usuario. As letras ASCII e os números sempre se permitirán e non é necesario que os inclúas nunha listaxe branca. " + reserved_usernames: "Nomes de usuario que non están permitidos. O asterisco * pódese utilizar para coincidir con calquera carácter cero ou máis veces." + min_password_length: "Lonxitude mínima do contrasinal" + min_admin_password_length: "Lonxitude mínima do contrasinal para un administrador" + password_unique_characters: "Número mínimo de caracteres únicos que un contrasinal debe conter" + block_common_passwords: "Non permitir contrasinais que estean entre os 10.000 contrasinais máis comúns." + enable_sso: "Habilitar o inicio de sesión único a través dun sitio externo (AVISO: OS ENDEREZOS DE CORREO ELECTRÓNICO DOS USUARIOS *TEÑEN* QUE SER VALIDADOS NO SITIO EXTERNO!)" + verbose_sso_logging: " Rexistrar diagnósticos detallados relacionados con SSO en /logs" max_flags_per_day: "Número máximo de denuncias por usuario e día." category_style: "Estilo visual para as insignias de categoría." enable_user_directory: "Proporcionar un directorio de usuarios para navegación" @@ -468,6 +1352,7 @@ gl: types: category: "Categorías" user: "Usuarios" + results_page: "Buscar resultados para '%{term}'" original_poster: "Publicador orixinal" most_recent_poster: "Publicador máis recente" frequent_poster: "Publicador frecuente" @@ -478,12 +1363,42 @@ gl: blank: "non pode quedar baleiro" invalid: "contén caracteres incorrectos" login: + security_key_alternative: "Tentalo doutro xeito" + not_approved: "A túa conta non foi aínda aprobada. Notificaráseche por correo electrónico cando poidas iniciar a sesión." admin_not_allowed_from_ip_address: "Non podes acceder como administrador desde este enderezo IP." not_available: "Non dispoñíbel. Tentar %{suggestion}?" + omniauth_confirm_button: "Continuar" new_registrations_disabled: "Neste momento non se permite o rexistro de novas contas." + second_factor_title: "Autenticación de dobre factor" + second_factor_backup_description: "Escribe un dos códigos de copia de seguranza" + second_factor_toggle: + backup_code: "Usar no seu lugar un código de copia de seguranza" admin: email: sent_test: "enviado!" + user: + username: + too_long: "é demasiado longo" + characters: "só debe incluír números, letras, guións, puntos e guións baixos" + unique: "debe ser único" + must_begin_with_alphanumeric_or_underscore: "debe comezar cunha letra, número ou un guión baixo" + must_end_with_alphanumeric: "debe rematar cunha letra ou número" + must_not_contain_two_special_chars_in_seq: "non debe conter unha secuencia de 2 ou máis caracteres especiais (.-_)" + must_not_end_with_confusing_suffix: "non debe remtar cun sufixo confuso do tipo .json ou .png etc." + email: + invalid: "non é válido." + blocked: "non está permtido." + ip_address: + blocked: "Non están permitidos novos rexistros desde o teu enderezo IP." + max_new_accounts_per_registration_ip: "Non están permitidos novos rexistros desde o teu enderezo IP (alcanzouse o límite). Contacta cun membro do equipo." + website: + domain_not_allowed: "O sitio web non é válido. Os dominios permitidos son: %{domains}" + destroy_reasons: + inactive_user: "Usuario inactivo" + invite_mailer: + subject_template: "%{inviter_name} invitoute a '%{topic_title}' en%{site_domain_name}" + custom_invite_mailer: + subject_template: "%{inviter_name} invitoute a '%{topic_title}' en%{site_domain_name}" flags_dispositions: agreed: "Grazas por comunicárnolo. Estamos de acordo en que hai un problema e estamos botándolle un ollo." agreed_and_deleted: "Grazas por comunicárnolo. Estamos de acordo en que hai un problema e xa eliminamos a publicación." @@ -492,7 +1407,18 @@ gl: ignored_and_deleted: "Grazas por comunicárnolo. Xa eliminamos a publicación." system_messages: welcome_user: + title: "Benvida ao usuario" subject_template: "Benvido/a a %{site_name}!" + text_body_template: | + Grazas por te unires a %{site_name} e benvido/a! + + %{new_user_tips} + + Cremos nunha [comunidade cun comportamento civilizado](%{base_url}/instrucions) en todo momento. + + Desfruta da túa estancia! + welcome_tl1_user: + subject_template: "Grazas por pasares o tempo connosco" welcome_invite: subject_template: "Benvido/a a %{site_name}!" backup_succeeded: @@ -500,27 +1426,420 @@ gl: bulk_invite_succeeded: subject_template: "O convite en bloque procesouse correctamente" user_notifications: + unsubscribe: + title: "Cancelar subscrición" + user_invited_to_private_message_pm_group: + text_body_template: | + %{header_instructions} + + %{message} + + %{respond_instructions} + user_invited_to_private_message_pm: + text_body_template: | + %{header_instructions} + + %{message} + + %{respond_instructions} + user_invited_to_private_message_pm_staged: + text_body_template: | + %{header_instructions} + + %{message} + + %{respond_instructions} + user_invited_to_topic: + text_body_template: | + %{header_instructions} + + %{message} + + %{respond_instructions} + user_replied: + subject_template: "[%{email_prefix}] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_replied_pm: + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_quoted: + subject_template: "[%{email_prefix}] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_linked: + subject_template: "[%{email_prefix}] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_mentioned: + subject_template: "[%{email_prefix}] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_mentioned_pm: + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_group_mentioned: + subject_template: "[%{email_prefix}] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_posted: + subject_template: "[%{email_prefix}] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_watching_first_post: + subject_template: "[%{email_prefix}] %{topic_title}" + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_posted_pm: + text_body_template: | + %{header_instructions} + + %{message} + + %{context} + + %{respond_instructions} + user_posted_pm_staged: + subject_template: "%{optional_re}%{topic_title}" + text_body_template: |2 + + %{message} + account_suspended: + title: "Conta suspendida" + subject_template: "[%{email_prefix}] A túa conta foi suspendida" + account_silenced: + title: "Conta silenciada" + subject_template: "[%{email_prefix}] A túa conta foi silenciada" + account_exists: + title: "A conta xa existe" + subject_template: "[%{email_prefix}] A conta xa existe" digest: + since_last_visit: "Desde a túa última visita" + new_topics: "Novos temas" + unread_notifications: "Notificacións sen ler" + unread_high_priority: "Notificacións de prioridade alta sen ler" liked_received: "Gústames recibidos" new_users: "Novos usuarios" + popular_topics: "Temas populares" + follow_topic: "Seguir este tema" + join_the_discussion: "Ler máis" + more_new: "Novo para ti" + subject_template: "[%{email_prefix}] Resumo" + unsubscribe: "Este resumo envíaseche desde %{site_link} cando non te vemos durante certo tempo. Cambia %{email_preferences_link} ou %{unsubscribe_link} para cancelar a subscrición." + your_email_settings: "a configuración do teu correo electrónico" + click_here: "preme aquí" + from: "%{site_name}" + preheader: "Un breve resumo desde a túa última visita en %{last_seen_at}" + forgot_password: + title: "Esquecín o contrasinal" + subject_template: "[%{email_prefix}] Restablecer contrasinal" + text_body_template: | + Alguén solicitou restablecer o teu contrasinal en [%{site_name}](%{base_url}). + + Se non fuches ti, podes tranquilamente ignorar este correo electrónico. + + Preme na seguinte ligazón para elixir un novo contrasinal: + %{base_url}/u/password-reset/%{email_token} + email_login: + title: "Iniciar sesión vía ligazón" + subject_template: "[%{email_prefix}] Iniciar sesión vía ligazón" + text_body_template: | + Velaquí a túa ligazón para iniciares sesión en [%{site_name}](%{base_url}). + + Se non solicitaches esta ligazón, podes tranquilamente ignorar este correo electrónico. + + Preme na seguinte ligazón para iniciar sesión en: + %{base_url}/session/email-login/%{email_token} set_password: - title: "Estabelecer o contrasinal" + title: "Establecer o contrasinal" + subject_template: "[%{email_prefix}] Establecer o contrasinal" + text_body_template: | + Alguén solicitou engadir un contrasinal á túa conta en [%{site_name}](%{base_url}). Alternativamente, podes iniciar sesión utilizando calquera dos servizos en liña compatible (Google, Facebook etc.) que estea asociado con este enderezo de correo electrónico xa validado. + + Se ti non fixeches esta solicitude, podes tranquilamente ignorar este correo electrónico. + + Click the following link to choose a password: + %{base_url}/u/password-reset/%{email_token} + admin_login: + title: "Inicio de sesión de administrador" + subject_template: "[%{email_prefix}] Inicio de sesión" + text_body_template: | + Alguén solicitou iniciar sesión na túa conta en [%{site_name}](%{base_url}). + + Se non fuches ti, podes tranquilamente ignorar este correo electrónico. + + Preme na seguinte ligazón para iniciar sesión: + %{base_url}/session/email-login/%{email_token} + account_created: + title: "Conta creada" + subject_template: "[%{email_prefix}] A túa nova conta" + text_body_template: | + Creouse unha nova conta para ti en %{site_name} + + Preme na seguinte ligazón para elixir un contrasinal para a túa nova conta: + %{base_url}/u/password-reset/%{email_token} + confirm_new_email: + title: "Confirmar novo correo electrónico" + subject_template: "[%{email_prefix}] Confirma o teu novo enderezo de correo electrónico" + text_body_template: | + Confirma o teu novo enderezo de correo electrónico para %{site_name} premendo na seguinte ligazón: + + %{base_url}/u/confirm-new-email/%{email_token} + confirm_old_email: + title: "Confirmar o correo electrónico antigo" + subject_template: "[%{email_prefix}] Confirma o teu enderezo de correo electrónico actual" + text_body_template: | + Antes de cambiar o teu enderezo electrónico, necesitamos que confirmes que o correo + electrónico actual está baixo o teu control. Logo de completar este paso, teremos que confirmar + o novo enderezo de correo electrónico. + + Confirma o teu correo electrónico actual para %{site_name} premendo na seguinte ligazón: + + %{base_url}/u/confirm-old-email/%{email_token} + confirm_old_email_add: + title: "Confirmar o correo electrónico antigo (engadir)" + subject_template: "[%{email_prefix}] Confirma o teu enderezo de correo electrónico actual" + text_body_template: | + Antes de que poidamos engadir un novo enderezo electrónico, necesitamos que confirmes que o actual + está baixo o teu control. Logo de completar este paso, teremos que confirmar + o novo enderezo electrónico. + + Confirma o teu correo electrónico actual para %{site_name} premendo na seguinte ligazón: + + %{base_url}/u/confirm-old-email/%{email_token} + notify_old_email: + subject_template: "[%{email_prefix}] O teu enderezo de correo electrónico foi cambiado" + text_body_template: | + Esta é unha mensaxe automática para comunicarche que o teu enderezo electrónico para + %{site_name} foi cambiado. Se isto é un erro, contacta co administrador + do sitio. + + O teu enderezo de correo electrónico cambiouse a: + + %{new_email} + notify_old_email_add: + subject_template: "[%{email_prefix}] Engadiuse un novo enderezo de correo electrónico" + text_body_template: | + Esta é unha mensaxe automática para comunicarche que se engadiu un enderezo electrónico + para %{site_name}. Se isto é un erro, contacta contacta + co administrador do sitio. + + O teu enderezo de correo electrónico engadido é: + + %{new_email} + signup_after_approval: + title: "Rexistro despois da aprobación" + subject_template: "A túa solicitude foi aprobada en %{site_name}!" + text_body_template: | + Benvido/a a %{site_name}! + + Un membro do equipo aprobou a túa conta en %{site_name}. + + Agora podes acceder á túa nova conta iniciando sesión en: + %{base_url} + + Se non podes premer na ligazón, proba a copiala e pegala na barra de enderezos do teu navegador. + + %{new_user_tips} + + Cremos nunha comunidade cun [comportamento civilizado](%{base_url}/guidelines) en todo momento. + + Desfruta a túa estancia! + signup: + title: "Rexistrarse" + subject_template: "[%{email_prefix}] Confirma a túa nova conta" + text_body_template: | + Benvido/a a %{site_name}! + + Preme na seguinte ligazón para confirmar e activar a túa nova conta: + %{base_url}/u/activate-account/%{email_token} + + Se non podes premer na ligazón, proba a copiala e pegal na barra de enderezos do teu navegador. + activation_reminder: + title: "Recordatorio de activación" + subject_template: "[%{email_prefix}] Recordatorio para confirmar a túa conta" + text_body_template: | + Benvido/a a %{site_name}! + + Este é un recordatorio para activar a túa conta. + + Preme na seguinte ligazón para confirmar e activar a túa nova conta: + %{base_url}/u/activate-account/%{email_token} + + Se non podes premer na ligazón, proba a copiala e pegala na barra de enderezos do teu navegador. + suspicious_login: + title: "Alerta de novo inicio de sesión" + subject_template: "[%{site_name}] Novo inicio de sesión desde %{location}" + text_body_template: | + Ola, + + Detectamos dun inicio de sesión desde un dispositivo ou localización que non adoitas utilizar. Fuches ti? + + - Localización: %{location} (%{client_ip}) + - Navegador: %{browser} + - Dispositivo: %{device} – %{os} + + Se fuches ti, perfecto! Non tes que facer máis nada. + + If this was not you, please [review your existing sessions](%{base_url}/my/preferences/account) and consider changing your password. + page_forbidden: + title: "Vaites! Esta páxina é privada." page_not_found: + title: "Vaites! A páxina non existe ou é privada." + popular_topics: "Destacados" + recent_topics: "Recentes" see_more: "Máis" + search_title: "Buscar neste sitio" search_button: "Buscar" + offline: + title: "Non se pode cargar a aplicación" + offline_page_message: "Semella que non estás conectado/a! Comproba a túa conexión á rede e vólveo tentar." + login_required: + welcome_message: | + ## [Benvido/a a %{title}](#welcome) + Requírese unha conta. Crea unha ou inicia sesión para continuar. + welcome_message_invite_only: | + ## [Benvido/a a %{title}](#welcome) + Requírese unha conta. Pídelle a un membro que te convide ou inicia sesión para continuar. image: "imaxe" + upload: + edit_reason: "copias locais de imaxes descargadas" + unauthorized: "Sentímolo, o ficheiro que tentas subir non está autorizado (extensións permitidas: %{authorized_extensions})." + pasted_image_filename: "Imaxe pegada" + store_failure: "Erro ao almacenar a carga #%{upload_id} para o usuario #%{user_id}." + file_missing: "Sentímolo, debes facilitar un ficheiro para subir." + empty: "Sentímolo, mais o ficheiro que facilitaches está baleiro." + png_to_jpg_conversion_failure_message: "Produciuse un erro ao converter de PNG a JPG." + optimize_failure_message: "Produciuse un erro ao optimizar a imaxe subida." + attachments: + too_large: "Sentímolo, o ficheiro que tentas subir é demasiado grande (o tamaño máximo é de %{max_size_kb} KB)." + images: + too_large: "Sentímolo, a imaxe que tentas subir é demasiado grande (o tamaño máximo é de %{max_size_kb} KB); redimensiónaa e vólveo tentar." + larger_than_x_megapixels: "Sentímolo, a imaxe que tentas subir é demasiado grande (o tamaño máximo é de %{max_image_megapixels} megapíxeles); redimensiónaa e vólveo tentar." + size_not_found: "Sentímolo, mais non puidemos determinar o tamaño da imaxe. Talvez está danada?" + placeholders: + too_large: "(imaxe máis grande que %{max_size_kb} KB)" + avatar: + missing: "Sentímolo, non puidemos atopar ningún avatar asociado con ese correo electrónico. Podes tentar volvelo subir?" + flag_reason: + sockpuppet: "Un novo usuario creou un tema e outro novo usuario respondeu desde a mesma IP (%{ip_address}). Revisa a opción `flag_sockpuppets` na configuración do sitio." + spam_hosts: "Este novo usuario tentou crear múltiples publicacións con ligazóns ao mesmo dominio. Todas as publicacións deste usuario que inclúan estas ligazóns deberían ser revisadas. Revisa a configuración do sitio `newuser_spam_host_threshold`." + skipped_email_log: + exceeded_emails_limit: "Exceeded max_emails_per_day_per_user" + exceeded_bounces_limit: "Exceeded bounce_score_threshold" + mailing_list_no_echo_mode: "Notificacións da lista de correo deshabilitadas para as publicacións do propio usuario." + user_email_no_user: "Non se atopa o usuario coa ID %{user_id}" + user_email_post_not_found: "Non se atopa ningunha publicación coa ID %{post_id}" + user_email_anonymous_user: "O usuario é anónimo" + user_email_user_suspended_not_pm: "O usuario está suspendido, non é unha mensaxe" + user_email_seen_recently: "O usuario foi visto recentemente" + user_email_notification_already_read: "A notificación sobre a que trata o correo xa foi lida." + user_email_notification_topic_nil: "post.topic é nulo" + user_email_post_user_deleted: "O usuario da publicación foi eliminado." + user_email_post_deleted: "a publicación foi eliminada polo autor" + user_email_user_suspended: "o usuario foi suspendido" + user_email_already_read: "o usuario xa leu esta publicación" + user_email_access_denied: "o usuario non ten permitido ler esta publicación" + user_email_no_email: "Non hai un correo electrónico asociado coa ID de usuario %{user_id}" + sender_message_blank: "a mensaxe está en branco" + sender_message_to_blank: "message.to está en branco" + sender_text_part_body_blank: "text_part.body está en branco" + sender_body_blank: "o corpo está en branco" + sender_post_deleted: "a publicación foi eliminada" + sender_message_to_invalid: "o destinatario ten un enderezo electrónico non válido" + sender_topic_deleted: "o tema foi eliminado" + color_schemes: + base_theme_name: "Base" + light: "Claro" + dark: "Escuro" + neutral: "Neutro" + grey_amber: "Gris ámbar" + shades_of_blue: "Azulado" + summer: "Verán" + dark_rose: "Rosa escuro" + default_theme_name: "Claro" + light_theme_name: "Claro" + dark_theme_name: "Escuro" + neutral_theme_name: "Neutro" + grey_amber_theme_name: "Gris ámbar" + shades_of_blue_theme_name: "Azulado" + summer_theme_name: "Verán" + dark_rose_theme_name: "Rosa escuro" + edit_this_page: "Editar esta páxina" csv_export: boolean_yes: "Si" boolean_no: "Non" rate_limit_error: "Só se poden descargar as publicacións unha vez por día. Téntao de novo mañá." + static_topic_first_reply: | + Editar a primeira publicación deste tema para cambiar o contido da páxina %{page_name}. tos_topic: title: "Termos do servizo" privacy_topic: - title: "Política de intimidade" + title: "Política de privacidade" badges: + mass_award: + errors: + invalid_csv: "Atopamos un erro na liña %{line_number}. Confirma que o CSV ten un único correo electrónico por liña." editor: name: Editor description: Edición da publicación inicial + wiki_editor: + name: Editor wiki + description: Primeira edición wiki basic_user: name: Básico member: @@ -537,12 +1856,24 @@ gl: anniversary: name: Aniversario description: "Membro activo durante un ano, publicou cando menos unha vez" + nice_post: + name: Boa resposta + description: Recibiu 10 gústames + good_post: + name: Moi boa resposta + description: Recibiu 25 gústames + great_post: + name: Excelente resposta + description: Recibiu 50 gústames nice_topic: name: Tema riquiño + description: Recibiu 10 gústames good_topic: name: Tema bo + description: Recibiu 25 gústames great_topic: name: Gran tema + description: Recibiu 50 gústames nice_share: name: Compartición riquiña description: Compartiu unha publicación con 25 visistantes únicos @@ -553,7 +1884,7 @@ gl: name: Gran compartición description: Compartiu unha publicación con 1000 visistantes únicos first_like: - name: Primeiro Gústame + name: Primeiro gústame description: Gustou unha publicación long_description: | Esta insignia concédese a primeira vez que che gusta unha publicación e usas o botón :heart:. Darlle Gústame a unha publicción e unha gran forma de dicirlles aos membros da comunidade que publicaron algo interesante, útil, riquiño ou divertido. Comparte o amor! @@ -565,6 +1896,7 @@ gl: description: Convidou un usuario campaigner: name: Padriño + description: Convidou a 3 usuarios básicos champion: name: Campión first_share: @@ -574,6 +1906,7 @@ gl: name: Primeira ligazón first_quote: name: Primeira cita + description: Citou unha publicación read_guidelines: name: Ler as Directrices reader: @@ -584,21 +1917,123 @@ gl: name: Ligazón quente famous_link: name: Ligazón popular + first_emoji: + name: Primeiro emoji + first_mention: + name: Primeira mención + first_reply_by_email: + name: Primeira resposta vía correo electrónico + enthusiast: + name: Entusiasta admin_login: - submit_button: "Enviar correo-e" + success: "Correo electrónico enviado" + errors: + unknown_email_address: "Enderezo de correo electrónico descoñecido" + invalid_token: "Código non válido." + submit_button: "Enviar correo electrónico" + performance_report: + initial_post_raw: Este tema inclúe informes diarios sobre o rendemento do teu sitio. + initial_topic_title: Informes sobre o rendemento do sitio web + tags: + title: "Etiquetas" + staff_tag_disallowed: 'A etiqueta "%{tag}" só pode ser aplicada polo equipo.' + staff_tag_remove_disallowed: 'A etiqueta "%{tag}" só pode ser eliminada polo equipo.' + minimum_required_tags: + one: "Debes seleccionar ao menos %{count} etiqueta." + other: "Debes seleccionar ao menos %{count} etiquetas." + upload_row_too_long: "O ficheiro CSV debe ter unha etiqueta por liña. Opcionalmente, a etiqueta pode ir seguida dunha coma; despois o nome do grupo de etiquetas." + forbidden: + invalid: + one: "A etiqueta que seleccionaches non pode ser utilizada" + other: "Ningunha das etiquetas que seleccionaches pode ser utilizada" + in_this_category: '"%{tag_name}" non se pode utilizar nesta categoría' + restricted_to: + one: '"%{tag_name}" está restrinxida á categoría "%{category_names}"' + other: '"%{tag_name}" está restrinxida ás seguintes categorías: %{category_names}' + synonym: 'Non están permitidos os sinónimos. Utiliza "%{tag_name}" no seu lugar.' + has_synonyms: '"%{tag_name}" non se pode utilizar porque ten sinónimos.' + required_tags_from_group: + one: "Debes incluír ao menos %{count} etiqueta en %{tag_group_name}." + other: "Debes incluír ao menos %{count} etiquetas en %{tag_group_name}." + invalid_target_tag: "non pode ser o sinónimo dun sinónimo" + synonyms_exist: "non está permitido mentres existan sinónimos" + rss_by_tag: "Temas etiquetados %{tag}" + finish_installation: + congratulations: "Parabéns! Instalaches Discourse!" + register: + button: "Rexistrarse" + title: "Rexistrar conta de administrador" + help: "rexistrar unha nova conta para comezar" + confirm_email: + title: "Confirma o teu correo electrónico" + message: "

Enviámosche un correo de activación a %{email}. Sigue as instrucións para activar a túa conta.

Se non che chega, comproba o cartafol de correo lixo e asegúrate de configurar correctamente o teu correo.

" + resend_email: + title: "Reenviar correo electrónico de activación" + message: "

Volvímosche enviar o correo de activación a %{email}" + safe_mode: + title: "Entrar en modo seguro" + description: "O modo seguro permíteche probar o teu sitio sen cargar complementos nin outras personalizacións." + no_customizations: "Desactivar tema actual" + only_official: "Desactivar complementos non oficiais" + no_plugins: "Desactivar todos os complementos" + enter: "Entrar en modo seguro" + must_select: "Debes seleccionar ao menos unha opción para entrar no modo seguro." wizard: step: forum_title: title: "Nome" + privacy: + title: "Acceso" + fields: + privacy: + choices: + open: + label: "Público" + restricted: + label: "Privado" contact: fields: contact_email: placeholder: "name@example.com" corporate: title: "Organización" + colors: + title: "Tema" + themes_further_reading: + title: "Temas" + homepage: + title: "Páxina de inicio" + fields: + homepage_style: + choices: + latest: + label: "Últimos temas" + categories_only: + label: "Só categorías" + categories_with_featured_topics: + label: "Categorías con temas destacados" + categories_and_latest_topics: + label: "Categorías e últimos temas" + categories_and_top_topics: + label: "Categorías e temas destacados" + categories_boxes: + label: "Caixas de categorías" + categories_boxes_with_topics: + label: "Caixas de categorías con temas" emoji: title: "Emoji" - joined: "Inscrito" + description: "Que estilo de emojis prefires para a túa comunidade? Podes engadir máis e personalizalos vía Administración, Personalizar, Emoji." + invites: + description: "Xa está case! Imos convidar outras persoas para axudar ainiciar discusións con temas e respostas de interese para que comece a túa comunidade." + disabled: "Como os inicios de sesión locais están desactivados, non é posible enviar invitacións a ninguén. Vai ao seguinte paso." + finished: + title: "O teu Discourse está pronto!" + description: | +

Se nalgún momento queres cambiar algún axuste, volve lanzar este asistente en calquera momento, ou visita o teu panel de administración; atoparalo ao lado da icona coa chave inglesa no menú.

+

Pásao ben e boa sorte construíndo a túa nova comunidade!

+ search_logs: + graph_title: "Análise das buscas" + joined: "Uniuse" discourse_push_notifications: popup: mentioned: '%{username} mencionoute en "%{topic}" - %{site_title}' @@ -606,25 +2041,68 @@ gl: quoted: '%{username} citoute en "%{topic}" - %{site_title}' replied: '%{username} respondeute en "%{topic}" - %{site_title}' posted: '%{username} publicou en "%{topic}" - %{site_title}' + private_message: '%{username} enviouche unha mensaxe privada en "%{topic}" - %{site_title}' linked: '%{username} ligou a túa publicación desde "%{topic}" - %{site_title}' + watching_first_post: '%{username} creou un tema novo "%{topic}" - %{site_title}' + confirm_title: "Notificacións habilitadas - %{site_title}" + confirm_body: "Perfecto! As notificacións están habilitadas." + custom: "Notificación de %{username} en %{site_title}" + staff_action_logs: + not_found: "non atopado" + unknown: "decoñecido" + user_merged: "%{username} combinouse con esta conta" + user_delete_self: "Eliminouse a si mesmo/a de %{url}" reviewables: + already_handled: "Grazas, mais xa revisamos esta publicación e determinamos que non necesita volver ser denunciada." + priorities: + low: "Baixa" + medium: "Media" + high: "Alta" + sensitivity: + low: "Baixa" + medium: "Media" + high: "Alta" + must_claim: "Debes reclamar os elementos antes de actuar sobre eles." + user_claimed: "Este elemento foi reclamado por outro usuario." actions: agree_and_suspend: title: "Suspender usuario" + agree_and_silence: + title: "Silenciar usuario" + agree_and_restore: + description: "Restaurar a publicación para que todos os usuarios a poidan ver." delete_spammer: title: "Eliminar spammer" delete_single: title: "Eliminar" + disagree_and_restore: + description: "Restaurar a publicación para que todos os usuarios a poidan ver." disagree: title: "Non aceptar" ignore: title: "Ignorar" approve: title: "Aprobar" + approve_post: + title: "Aprobar publicación" + confirm_closed: "Este tema está pechado. Gustaríache igualmente crear a publicación?" + reject_post: + title: "Rexeitar a publicación" + approve_user: + title: "Aprobar usuario" reject_user: + title: "Eliminar usuario..." delete: title: "Eliminar usuario" + block: + title: "Eliminar e bloquear usuario" + description: "O usuario será eliminado e bloquearase a súa IP e enderezo electrónico." reject: title: "Rexeitar" delete_user: title: "Eliminar usuario" + email_style: + html_missing_placeholder: "O modelo HTML debe incluír %{placeholder}" + notification_level: + ignore_error: "Sentímolo, non podes ignorar este usuario." + mute_error: "Sentímolo, non podes ignorar este usuario." diff --git a/config/locales/server.he.yml b/config/locales/server.he.yml index abd3465d12..b589257484 100644 --- a/config/locales/server.he.yml +++ b/config/locales/server.he.yml @@ -829,15 +829,18 @@ he: confirmed: "כתובת הדוא״ל שלך עודכנה." please_continue: "להמשיך אל %{site_name}" error: "הייתה שגיאה בעדכון כתובת הדוא״ל. אולי היא כבר בשימוש?" + doesnt_exist: "כתובת דוא\"ל זו אינה משויכת לחשבונך." error_staged: "אירעה שגיאה בהחלפת כתובת הדוא״ל שלך. הכתובת כבר נמצאת בשימוש על ידי משתמשים מבוימים במערכת." already_done: "קישור אימות זה אינו תקף עוד, עמך הסליחה. אולי כתובת הדוא״ל שלך כבר הוחלפה?" confirm: "אישור" authorizing_new: title: "אישור כתובת הדוא״ל החדשה שלך" - description: "נא לאשר את החלפת כתובת הדוא״ל שלך לכתובת:" + description: "אנא אשר שברצונך שכתובת הדוא\"ל שלך תשתנה ל:" + description_add: "אנא אשר שברצונך להוסיף כתובת דוא\"ל חלופית:" authorizing_old: title: "החלפת כתובת הדוא״ל שלך" description: "נא לאשר את החלפת כתובת הדוא״ל שלך" + description_add: "אנא אשר שברצונך להוסיף כתובת דוא\"ל חלופית:" old_email: "כתובת דוא״ל ישנה: %{email}" new_email: "כתובת דוא״ל חדשה: %{email}" almost_done_title: "אישור כתובת הדוא״ל החדשה" @@ -1414,6 +1417,7 @@ he: category_search_priority_very_high_weight: "משקל שהוחל על הדירוג בעדיפות חיפוש גבוהה מאוד בקטגוריות." allow_uncategorized_topics: "לאפשר לפתוח נושאים ללא קטגוריה. אזהרה: אם יש נושאים ללא קטגוריה, יש לסדר אותם לפני שמבטלים את ההגדרה הזאת. " allow_duplicate_topic_titles: "לאפשר נושאים עם כותרות זהות או כפולות." + allow_duplicate_topic_titles_category: "לאפשר נושאים עם כותרות זהות, כפולות אם הם לא באותה הקטגוריה. ההגדרה allow_duplicate_topic_titles (לאפשר כותרות נושאים כפולות) חייבת להיות שקר." unique_posts_mins: "כמה דקות לפני שמשתמש יכול לפרסם את אותו תוכן שוב" educate_until_posts: "כאשר המשתמש/ת מתחילים להקיש את (n) הפוסטים הראשונים שלהם, הציגו פאנל הנחיה למשתמש באזור חיבור הפוסטים." title: "שם האתר הזה, כפי שהוא משמש בתגית הכותרת." @@ -1620,7 +1624,7 @@ he: s3_backup_bucket: "הדלי המרוחק שבו לשמור גיבויים. אזהרה: שימו לב שהוא דלי פרטי." s3_endpoint: "ניתן לערוך את נקודת הגישה לגיבוי כדי שתפנה לשירות תואם S3 כגון DigitalOcean Spaces או Minio. אזהרה: יש להשאיר ריק בעת שימוש ב־S3 מבית AWS." s3_configure_tombstone_policy: "הפעלת מדיניות מחיקה אוטומטית להעלאות מצבה. חשוב: אם אפשרות זו מנוטרלת, לא יפונה מקום לאחר מחיקת העלאות." - s3_disable_cleanup: "בטלו את ההסרה של גיבויים מ S3 כאשר הם מוסרים מקומית." + s3_disable_cleanup: "למנוע הסרה של גיבויים ישנים מ־S3 שיש יותר גיבויים מהמותר." enable_s3_inventory: "יצירת דוחות ואימות העלאות באמצעות מאגר של Amazon S3. חשוב: נדרשים פרטי גישה תקפים ל־S3 (מזהה מפתח הגישה ומפתח הגישה הסודי)." backup_time_of_day: "הגדרת זמן לגיבוי לפי UTC." backup_with_uploads: "כללו העלאות בגיבויים התקופתיים. ביטול של אפשרות זו תגבה רק את בסיס הנתונים." @@ -1651,6 +1655,7 @@ he: max_logins_per_ip_per_minute: "מספר מקסימלי של התחברויות מורשות לכתובת IP לדקה" max_post_deletions_per_minute: "מספר הפוסטים המרבי שמשתמש יכול למחוק בדקה." max_post_deletions_per_day: "מספר הפוסטים המרבי שמשתמש יכול למחוק ביום." + invite_link_max_redemptions_limit: "כמות הניצולים המרבית שמורשית לקישורים הזמנה לא יכולה לעבור את הערך הזה." alert_admins_if_errors_per_minute: "מספר השגיאות בדקה לפני ששולחים התראה למנהל. ערך של 0 מנטרל אפשרות זו. שימו לב: מצריך הרצה מחדש." alert_admins_if_errors_per_hour: "מספר השגיאות בשעה לפני ששולחים התראה למנהל. ערך של 0 מנטרל אפשרות זו. שימו לב: מצריך הרצה מחדש." categories_topics: "מספר הנושאים להציג בעמוד ה־‎/categories (קטגוריות). אם הוגדר ל־0, יתבצע ניסיון למצוא ערך שישאיר את שתי העמודות סימטריות (קטגוריות ונושאים)." @@ -1960,6 +1965,7 @@ he: returning_user_notice_tl: "דרגת האמון המזערית הדרושה לצפייה בהתראות משתמש חוזר." returning_users_days: "כמה ימים אמורים לעבור לפני שמשתמש נחשב למשתמש חוזר." enable_page_publishing: "לאפשר לחברי סגל לפרסם נושאים לכתובות חדשות עם סגנון עצמאי." + show_published_pages_login_required: "משתמשים אלמוניים יכולים לראות דפים שפורסמו, אפילו כשנדרשת כניסה למערכת." default_email_digest_frequency: "באיזו תדירות משתמשים יקבלו סיכומי מיילים כברירת מחדל." default_include_tl0_in_digests: "כללו פוסטים ממשתמשים חדשים בדוא\"ל מסכם כברירת מחדל. משתמשים יוכלו לשנות זאת בהעדפות האישיות." default_email_level: "הגדרת רמת ההתראה בדוא״ל כבררת מחדל לנושאים רגילים." @@ -2019,7 +2025,7 @@ he: city_for_disputes: "עיר המחלוקת" shared_drafts_category: "הפעלת תכונת הטיוטות המשותפות על ידי הקצאת קטגוריה שתשמש לטובת טיוטות לנושאים. נושאים בקטגוריה זו יוסתרו מרשימות הנושאים לחברי הסגל." push_notifications_prompt: "הצגת בקשה להסכמת המשתמש." - push_notifications_icon: "סמל העיטור שמופיע בפינת ההתרעה. הגודל הנדרש הוא 96 × 96." + push_notifications_icon: "סמל העיטור שמופיע בפינת ההתרעה. מומלץ PNG בצבעים אחידים עם שקיפות בגודל 96 × 96." short_title: "בכותרת הקצרה ייעשה שימוש במסך הבית של המשתמש, במשגר או במקומות אחרים שבהם המקום מוגבל. אורכה לא יעלה על 12 תווים." dashboard_hidden_reports: "לאפשר להסתיר את הדוחות המסוימים בלוח הבקרה." dashboard_visible_tabs: "נא לבחור אילו לשוניות תופענה בלוח הבקרה." @@ -2063,6 +2069,7 @@ he: max_username_length_exists: "לא ניתן להגדיר את האורך המרבי לשם המשתמש ליותר תווים מאשר שם המשתמש הארוך ביותר במערכת (%{username})." max_username_length_range: "לא ניתן לקבוע את המקסימום מתחת למינימום." invalid_hex_value: "ערכי הצבעים חייבים להיות קודים הקסדצימליים באורך 6 תווים." + empty_selectable_avatars: "עליך להעלות שתי תמונות ייצוגיות לפחות כדי לבחור ביניהן לפני הפעלת האפשרות הזאת." category_search_priority: very_low_weight_invalid: "לא ניתן להגדיר משקל מעבר ל־‚category_search_priority_low_weight’ (משקל נמוך לעדיפות חיפוש בקטגוריות)." low_weight_invalid: "לא ניתן להגדיר משקל שווה או גדול מ־1 או קטן מ־‚category_search_priority_very_low_weight’." @@ -3384,6 +3391,16 @@ he: ניתן לאשר את כתובת הדוא״ל הנוכחית שלך לגישה לאתר %{site_name} בלחיצה על הקישור הבא: + %{base_url}/u/confirm-old-email/%{email_token} + confirm_old_email_add: + title: "אישור דוא\"ל ישן (הוסף)" + subject_template: "[%{email_prefix}] אשרו את כתובת המייל הנוכחית שלכם" + text_body_template: | + לפני שיתאפשר לנו להוסיף כתובת דוא״ל חדשה, עלינו לאמת את שליטתך על כתובת הדוא״ל + הנוכחית. לאחר השלמת השלב הזה, נבקש ממך לאשר את כתובת הדוא״ל החדשה. + + ניתן לאשר את כתובת הדוא״ל הנוכחית עבור %{site_name} בלחיצה על הקישור הבא: + %{base_url}/u/confirm-old-email/%{email_token} notify_old_email: title: "התראת דוא״ל ישן" @@ -3393,6 +3410,16 @@ he: כתובת המייל שלכם שונתה ל: + %{new_email} + notify_old_email_add: + title: "הודעה לכתובת הדוא״ל הקודמת (הוספה)" + subject_template: "[%{email_prefix}] נוספה כתובת דוא״ל חדשה" + text_body_template: | + זו הודעה אוטומטית שנועדה ליידע אותך שנוספה כתובת דוא״ל עבור %{site_name}. + אם זה נעשה בטעות, נא ליצור קשר עם הנהלת האתר. + + כתובת הדוא״ל שנוספה לחשבונך היא: + %{new_email} signup_after_approval: title: "הרשמה אחרי אישור" @@ -4312,6 +4339,9 @@ he: reason: "למחוק דרך תור סקירה" email_style: html_missing_placeholder: "תבנית ה־html חייבת לכלול %{placeholder}" + notification_level: + ignore_error: "אין אפשרות להתעלם מהמשתמש הזה, עמך הסליחה." + mute_error: "אין אפשרות להשתיק את המשתמש הזה, עמך הסליחה." discord: not_in_allowed_guild: "האימות נכשל. הגילדה ב־Discord אליה הצטרפת אינה מורשית לגשת." old_keys_reminder: diff --git a/config/locales/server.hy.yml b/config/locales/server.hy.yml index a4299bbde1..3f7ece83c2 100644 --- a/config/locales/server.hy.yml +++ b/config/locales/server.hy.yml @@ -1308,7 +1308,6 @@ hy: s3_backup_bucket: "Պահուստների պահպանման համար հեռակա արկղ: ԶԳՈՒՇԱՑՈՒՄ՝ Համոզվեք, որ այն գաղտնի արկղ է:" s3_endpoint: "Վերջնակետը կարող է փոփոխվել S3 -ի հետ համատեղելի ծառայության պահուստի, նիչպես օրինակ՝ DigitalOcean Spaces կամ Minio: ՈՒՇԱԴՐՈՒԹՅՈՒՆ՝ թաղեք դատարկ, եթե օգտագործում եք AWS S3:" s3_configure_tombstone_policy: "Միացնել ավտոմատ ջնջման քաղաքականությունը tombstone վերբեռնումների համար: ԿԱՐԵՎՈՐ՝ անջատված լինելու դեպքում վերբեռնումները ջնջելուց հետո տարածք չի վերադարձվի: " - s3_disable_cleanup: "Անջատել պահուստների հեռացումը S3 -ից՝ տեղական կերպով հեռացնելու դեպքում:" enable_s3_inventory: "Գեներացնել հաշվետվություններ և հաստատել վերբեռնումներ՝ օգտագործելով Amazon S3 գույքագրումը: ԿԱՐԵՎՈՐ՝ պահանջում է վավեր S3 տվյալներ (access key id և secret access key):" backup_time_of_day: "Պահուստի ստեղծման ժամը UTC ժամային գոտու համաձայն:" backup_with_uploads: "Ներառել վերբեռնումները պլանավորված պահուստներում: Սա անջատելը կպահուստավորի միայն տվյալների բազան:" @@ -1652,7 +1651,6 @@ hy: city_for_disputes: "Վեճերի Քաղաք" shared_drafts_category: "Միացնել Կիսված Սևագրեր հատկանիշը՝ կանխորոշելով կատեգորիա թեմաների սևագրերի համար: Այս կատեգորիայի թեմաները կթաքցվեն թեմաների ցանկերից անձնակազմի օգտատերերի համար:" push_notifications_prompt: "Ցուցադրել օգտատիրոջ համաձայնության հարցումը:" - push_notifications_icon: "Կրծքանշանի պատկերակ, որ հայտնվում է ծանուցումների անկյուններում: Պահանջվող չափը՝ 96 × 96:" short_title: "Կարճ վերնագիրը օգտագործվի օգտատիրոջ անձնական էջում, մեկնարկում կամ այլ տեղերում, որտեղ տարածքը կարող է սահմանափակված լինել: Այն պետք է սահմանափակ լինի մինչև 12 սիմվոլ:" dashboard_general_tab_activity_metrics: "Ընտրել հաշվետվությունները, որոնք կցուցադրվեն որպես ակտիվության չափանիշ ընդհանուր ներդիրում:" errors: @@ -2660,6 +2658,8 @@ hy: confirm_old_email: title: "Հաստատել Հին Էլ. Հասցեն" subject_template: "[%{email_prefix}] Հաստատել Ձեր ընթացիկ էլ. հասցեն" + confirm_old_email_add: + subject_template: "[%{email_prefix}] Հաստատել Ձեր ընթացիկ էլ. հասցեն" notify_old_email: title: "Ծանուցել Հին Էլ. Նամակը" subject_template: "[%{email_prefix}] Ձեր էլ. հասցեն փոփոխվել է " diff --git a/config/locales/server.it.yml b/config/locales/server.it.yml index 9e087e425a..19397f7699 100644 --- a/config/locales/server.it.yml +++ b/config/locales/server.it.yml @@ -45,6 +45,7 @@ it: unrecognized_extension: "Estensione del file non riconosciuta: %{extension}" import_error: generic: Errore durante l'importazione del tema + about_json: "Errore di importazione: about.json non esiste o non è valido. Sei sicuro che questo sia un tema di Discourse?" about_json_values: "about.json contiene valori non validi: %{errors}" modifier_values: "I modificatori about.json contengono valori non validi: %{errors}" git: "Errore nella clonazione del repository git, accesso negato o repository non trovato" @@ -193,6 +194,9 @@ it: file_should_be_csv: "Il file caricato deve essere in formato csv." max_rows: "I primi %{max_bulk_invites} inviti sono stati spediti. Prova a dividere il file in parti più piccole." error: "Si è verificato un errore durante il caricamento del file. Per favore riprova più tardi." + invite_link: + email_taken: "Questa e-mail è già in uso. Se hai già un account, effettua il login o reimposta la password." + max_redemptions_limit: "dovrebbe essere compreso tra 2 e %{max_limit}." topic_invite: failed_to_invite: "L'utente non può essere invitato in questo argomento senza essere membro di uno dei seguenti gruppi: %{group_names}." user_exists: "Spiacenti, l'utente è stato già invitato. Puoi invitare un utente ad uno stesso argomento solo una volta ." @@ -289,6 +293,7 @@ it: pm_reached_recipients_limit: "Spiacente, non sono consentiti più di %{recipients_limit} destinatari in un messaggio." removed_direct_reply_full_quotes: "La citazione dell'intero messaggio precedente è stata rimossa automaticamente." secure_upload_not_allowed_in_public_topic: "Siamo spiacenti, i seguenti caricamenti sicuri non possono essere utilizzati in un argomento pubblico: %{upload_filenames}." + create_pm_on_existing_topic: "Spiacenti, non puoi creare un PM su un argomento esistente." just_posted_that: "è troppo simile a ciò che hai appena pubblicato" invalid_characters: "contiene caratteri non validi" is_invalid: "sembra poco chiaro, è una frase completa?" @@ -370,6 +375,10 @@ it: trust_level_4: "trust_level_4" request_membership_pm: title: "Richesta di Adesione per @%{group_name}" + request_accepted_pm: + title: "Sei stato accettato in @ %{group_name}" + body: | + La tua richiesta di far parte di @ %{group_name} è stata accettata e ora sei un membro. view_hidden_topic_request_reason: "Vorrei far parte del gruppo '%{group_name}', per accedere [all'argomento](%{topic_url})" education: until_posts: @@ -734,15 +743,18 @@ it: confirmed: "La tua email è stata aggiornata." please_continue: "Procedi su %{site_name}." error: "Si è verificato un errore durante la modifica del tuo indirizzo email. Forse l'indirizzo è già in uso?" + doesnt_exist: "Questo indirizzo email non è associato al tuo account." error_staged: "Si è verificato un errore durante il cambio di indirizzo email. L'indirizzo è già stato usato da un utente temporaneo." already_done: "Spiacenti, il collegamento di conferma non è più valido. Hai forse già cambiato email?" confirm: "Conferma" authorizing_new: title: "Conferma il tuo nuovo indirizzo email" - description: "Conferma che vuoi cambiare il tuo nuovo indirizzo email in:" + description: "Conferma di voler cambiare il tuo indirizzo email in:" + description_add: "Conferma di voler aggiungere un indirizzo email alternativo:" authorizing_old: title: "Cambia il tuo indirizzo email" description: "Conferma la modifica del tuo indirizzo email" + description_add: "Conferma di voler aggiungere un indirizzo email alternativo:" old_email: "Vecchia email: %{email}" new_email: "Nuova email: %{email}" almost_done_title: "Conferma nuovo indirizzo email" @@ -1285,6 +1297,7 @@ it: unreachable_themes: "È fallita la verifica della presenza di aggiornamenti per i seguenti temi:" watched_word_regexp_error: "L'espressione regolare per %{action} per le parole osservate è invalida. Per favore controlla le impostazioni Parola Osservata, o disabilita le impostazioni del sito 'espressioni regolari delle parole osservate'." site_settings: + display_local_time_in_user_card: "Visualizza l'ora locale in base al fuso orario di un utente quando viene aperta la sua scheda utente." censored_words: "Parole che saranno automaticamente sostituite con ■■■■" delete_old_hidden_posts: "Cancella automaticamente tutti i messaggi nascosti che restano nascosti per più di 30 giorni." default_locale: "La lingua di default di questa istanza di Discourse. Puoi rimpiazzare il testo delle categorie e argomenti generati dal sistema in Personalizza / Testo ." @@ -1330,6 +1343,8 @@ it: editing_grace_period_max_diff: "Numero massimo di modifiche ai caratteri consentite durante la modifica del periodo di tolleranza, se più modifiche memorizzano un'altra revisione post (Livello Esperienza 0 e 1)" editing_grace_period_max_diff_high_trust: "Numero massimo di modifiche ai caratteri consentite durante la modifica del periodo di tolleranza, se più modifiche memorizzano un'altra revisione post (Livello Esperienza 2 e successivi)" staff_edit_locks_post: "I post saranno bloccati dalla modifica se sono modificati dai membri dello staff" + post_edit_time_limit: "Un autore LE0 o LE1 può modificare il proprio messaggio per (n) minuti dopo la pubblicazione. Impostare su 0 per sempre." + tl2_post_edit_time_limit: "Un autore LE2+ può modificare il proprio messaggio per (n) minuti dopo la pubblicazione. Impostare su 0 per sempre." edit_history_visible_to_public: "Permetti a tutti di vedere le precedenti versioni di un messaggio modificato. Se disabilitato solo i membri dello staff possono vederle." delete_removed_posts_after: "I messaggi rimossi dall'autore saranno automaticamente cancellati dopo (n) ore. Se impostato a 0, i messaggi saranno cancellati subito." max_image_width: "Larghezza massima delle miniature delle immagini in un messaggio" @@ -1340,6 +1355,7 @@ it: add_rel_nofollow_to_user_content: 'Aggiungi l''attributo rel nofollow a tutti i contenuti degli utenti, tranne per i link interni (compresi i domini di livello superiore). Se modifichi questa opzione devi aggiornare tutti i messaggi con il comando "rake posts:rebake"' exclude_rel_nofollow_domains: "Un elenco di domini dove l'attributo nofollow non dovrebbe essere aggiunto ai collegamenti. \"esempio.com\" consentirà automaticamente anche \"sub.esempio.com\". Come minimo si dovrebbe aggiungere il dominio di questo sito per aiutare i web crawler a trovare tutti i contenuti. Se altre parti del tuo sito web sono in altri domini, aggiungi anche quelle." post_excerpt_maxlength: "Lunghezza massima dell'estratto / riassunto di un messaggio." + topic_excerpt_maxlength: "Lunghezza massima di un estratto / riepilogo di un argomento, generata dal primo post di un argomento." show_pinned_excerpt_mobile: "Mostra estratti sugli argomenti appuntati nella vista mobile." show_pinned_excerpt_desktop: "Mostra estratti sugli argomenti appuntati nella vista desktop." post_onebox_maxlength: "Lunghezza massima in caratteri di un messaggio Discourse in Onebox." @@ -1360,10 +1376,13 @@ it: notification_email: "L'indirizzo presente nel campo from: usato per inviare tutte le email essenziali di sistema. Il dominio indicato deve avere i record SPF, DKIM e reverse PTR impostati correttamente perché l'email arrivi." email_custom_headers: "Una lista di intestazioni email personalizzate delimitata da una barra verticale (pipe |)" email_subject: "Formato oggetto personalizzabile per e-mail standard. Vedi https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801" + detailed_404: "Fornisce maggiori dettagli agli utenti sul perché non possono accedere a un argomento specifico. Nota: questo è meno sicuro perché gli utenti sapranno se un URL si collega a un argomento valido." enforce_second_factor: "Forza l'abilitazione dell'autenticazione a due fattori per gli utenti. Seleziona 'tutti' per applicarlo a tutti gli utenti. Seleziona 'staff' per applicarlo solo agli utenti staff." force_https: "Forza il tuo sito ad usare solo HTTPS. ATTENZIONE: NON abilitare questa opzione finché non hai verificato che HTTPS è pienamente configurato e sta funzionando ovunque! Hai verificato il tuo CDN, tutti i social login, ed ogni logo esterno / dipendenze per essere sicuro che sono anch'essi tutti compatibili con HTTPS?" same_site_cookies: "Utilizza gli stessi cookie del sito, si eliminano tutti i vettori Cross Site Request Forgery nei browser supportati (Lax o Strict). Avviso: Strict lavorerà solo su siti che forzano l'accesso e utilizzano SSO." summary_score_threshold: "Il punteggio minimo richiesto affinché un messaggio sia incluso in 'Riassumi Questo Argomento'" + summary_posts_required: "Numero minimo di messaggi in un argomento prima che "Riassumi questo argomento" sia abilitato. Le modifiche a questa impostazione verranno applicate retroattivamente entro una settimana." + summary_likes_required: "Minimo numero di \"Mi piace\" in un argomento prima che "Riepiloga questo argomento" sia abilitato. Le modifiche a questa impostazione verranno applicate retroattivamente entro una settimana." summary_percent_filter: "Quando un utente clicca su 'Riassumi Questo Argomento', mostra i primi % messaggi" summary_max_results: "Messaggi massimi restituiti da 'Riepiloga questo argomento'." enable_personal_messages: "Autorizza gli utenti con livello di esperienza 1 (configurabile attraverso \"min livello di esperienza per l'invio di messaggi\") a creare e rispondere ai messaggi. Nota che lo staff può inviare messaggi in ogni caso." @@ -1395,6 +1414,7 @@ it: markdown_typographer_quotation_marks: "Lista delle coppie di citazioni di rimpiazzo doppie e singole" post_undo_action_window_mins: "Numero di minuti durante i quali gli utenti possono annullare le loro azioni recenti su un messaggio (segnalazioni, Mi piace, ecc.)." must_approve_users: "Lo staff deve approvare tutti i nuovi account utente prima che essi possano accedere al sito." + invite_code: "L'utente deve digitare questo codice per consentire la registrazione dell'account, ignorato quando vuoto (senza distinzione tra maiuscole e minuscole)" pending_users_reminder_delay: "Notifica i moderatori se nuovi utenti sono in attesa di approvazione per più di queste ore. Imposta a -1 per disabilitare le notifiche." maximum_session_age: "L'utente resterà connesso per n ore dall'ultima visita" ga_universal_tracking_code: "ID del codice di tracciamento di Google Universal Analytics (analytics.js), ad esempio: UA-12345678-9; vedi https://google.com/analytics" @@ -1495,6 +1515,9 @@ it: enable_github_logins: "Abilita l'autenticazione Github, richiede github_client_id e github_client_secret. Vedi Configurare l'accesso a GitHub per Discourse ." github_client_id: "Client id per l'autenticazione Github, registrato su https://github.com/settings/developers" github_client_secret: "Client secret per l'autenticazione Github, registrato su https://github.com/settings/developers" + enable_discord_logins: "Consentire agli utenti di autenticarsi utilizzando Discord?" + discord_client_id: 'ID client Discord (Te ne serve uno? Visita il portale per sviluppatori Discord )' + discord_secret: "Secret Key di Discord" enable_backups: "Consenti agli amministratori di creare backup del forum" allow_restore: "Abilita il ripristino, che sostituisce TUTTI i dati del sito! Lascia a falso a meno che non hai intenzione di ripristinare un backup." maximum_backups: "Il numero massimo di backup da mantenere sul disco. I backup più vecchi vengono automaticamente cancellati." @@ -1503,7 +1526,6 @@ it: s3_backup_bucket: "Il bucket remoto che contiene i backup. ATTENZIONE: assicurati che sia un bucket privato." s3_endpoint: "L'endpoint può essere modificato per eseguire il backup su un servizio compatibile S3 come DigitalOcean Spaces o Minio. ATTENZIONE: lasciare vuoto se si utilizza AWS S3." s3_configure_tombstone_policy: "Abilita la cancellazione automatica per i caricamenti in \"tombstone\". IMPORTANTE: se disabilitato, nessuno spazio verrà recuperato dopo aver eliminato i caricamenti." - s3_disable_cleanup: "Disabilita la rimozione dei backup da S3 quando rimossi localmente." enable_s3_inventory: "Genera rapporti e verifica i caricamenti utilizzando l'inventario Amazon S3. IMPORTANTE: richiede credenziali S3 valide (sia l'access key id che la secret access key)." backup_time_of_day: "Ora del giorno in UTC in cui eseguire il backup." backup_with_uploads: "Includi i caricamenti nei backup programmati. Se disabilitata verrà eseguito il backup del solo database." @@ -1536,6 +1558,7 @@ it: max_post_deletions_per_day: "Numero massimo di post che un utente può eliminare al giorno." alert_admins_if_errors_per_minute: "Soglia di errori al minuto che scatena un allarme agli amministratori. Un valore pari a 0 disabilita questa caratteristica. NOTA: richiede un riavvio." alert_admins_if_errors_per_hour: "Soglia di errori all'ora che scatena un allarme agli amministratori. Un valore pari a 0 disabilita questa caratteristica. NOTA: richiede un riavvio." + categories_topics: "Numero di argomenti da mostrare nella pagina /categories. Se impostato su 0, proverà automaticamente a trovare un valore per mantenere simmetriche le due colonne (categorie e argomenti)." suggested_topics: "Numero di argomenti suggeriti mostrati in fondo ad un argomento." limit_suggested_to_category: "Negli argomenti suggeriti, mostra soltanto argomenti della categoria corrente. " suggested_topics_max_days_old: "Gli argomenti suggeriti non dovrebbero essere più vecchi di n giorni." @@ -1624,11 +1647,13 @@ it: desktop_category_page_style: "Stile visuale per la pagina /categorie." category_colors: "Un elenco di valori esadecimali di colori permessi per le categorie." category_style: "Stile grafico dei distintivi relativi alle categorie." + max_image_size_kb: "La dimensione massima di un'allegato immagine in KB. Deve essere configurato anche in nginx (client_max_body_size) / apache o proxy. Le immagini più grandi di questa e più piccole di client_max_body_size verranno ridimensionate per adattarsi al caricamento." max_attachment_size_kb: "Dimensione massima dei file che gli utenti possono caricare, in kB. Configura il limite anche in nginx (client_max_body_size) / apache o nel proxy." authorized_extensions: "Una lista di estensioni dei file che è permesso caricare (usa '*' per permettere tutti i tipi di file) " authorized_extensions_for_staff: "Un elenco di estensioni di file consentite per il caricamento da parte dello staff in aggiunta all'elenco definito nell'impostazione del sito `authorized_extensions`. (usa '*'; per abilitare tutti i tipi di file)" theme_authorized_extensions: "Una lista di estensioni dei file permessi per i caricamenti dei temi (usa '*' per abilitare tutti i tipi di file)" max_similar_results: "Quanti argomenti simili mostrare sopra l'editor quando si scrive un nuovo argomento. Il paragone viene fatto sul titolo e sul corpo." + max_image_megapixels: "Numero massimo di megapixel consentiti per un'immagine. Le immagini con un numero maggiore di megapixel verranno rifiutate." title_prettify: "Evita refusi ed errori comuni nei titoli, incluso il testo tutto maiuscolo, il primo carattere minuscolo, troppi caratteri ! e ?, puntini aggiuntivi alla fine della parola ecc." title_remove_extraneous_space: "Rimuovi gli spazi bianchi davanti alla punteggiatura." automatic_topic_heat_values: 'Aggiorna automaticamente le impostazioni "topic views heat" e "topic post like heat" in base all''attività del sito.' @@ -1668,6 +1693,7 @@ it: reviewable_claiming: "È necessario rivendicare il contenuto revisionabile prima che possa essere manipolato?" reviewable_default_topics: "Mostra contenuto revisionabile raggruppato per argomento per impostazione predefinita" reviewable_default_visibility: "Non mostrare elementi revisionabili a meno che non soddisfino questa priorità" + high_trust_flaggers_auto_hide_posts: "I messaggi di nuovi utenti vengono automaticamente nascosti dopo essere stati contrassegnati come spam da un utente TL3 +" reply_by_email_enabled: "Abilita la possibilità di rispondere ai messaggi tramite email." reply_by_email_address: "Modello per rispondere via email, per esempio: %%{reply_key}@risposta.esempio.com o risposte+%%{reply_key}@esempio.com" alternative_reply_by_email_addresses: "Elenco dei template alternativi per la risposta via email in arrivo da indirizzi email. Esempio: %%{reply_key}@reply.example.com|replies+%%{reply_key}@example.com" @@ -1871,7 +1897,6 @@ it: city_for_disputes: "Sede per eventuali controversie" shared_drafts_category: "Abilita la funzione Bozze Condivise designando una categoria per le bozze di argomento. Gli argomenti in questa categoria verranno eliminati dagli elenchi di argomenti per gli utenti dello staff." push_notifications_prompt: "Visualizza richiesta di consenso dell'utente." - push_notifications_icon: "L'icona del Distintivo che appare nell'angolo della notifica. La dimensione richiesta è 96 × 96." short_title: "Il titolo breve verrà utilizzato nella schermata iniziale dell'tente, nel programma di avvio o in altri contesti in cui lo spazio potrebbe essere limitato. Dovrebbe essere limitato a 12 caratteri." dashboard_general_tab_activity_metrics: "Scegli i report da visualizzare come metriche di attività nella scheda generale." errors: @@ -2966,6 +2991,8 @@ it: Conferma il tuo attuale indirizzo email su %{site_name} cliccando il seguente collegamento: %{base_url}/u/confirm-old-email/%{email_token}%{email_token} + confirm_old_email_add: + subject_template: "[%{email_prefix}] Conferma il tuo attuale indirizzo email" notify_old_email: title: "Notifica Vecchia Email" subject_template: "[%{email_prefix}] Il tuo indirizzo email è stato cambiato" diff --git a/config/locales/server.ja.yml b/config/locales/server.ja.yml index 1fd072c688..f5b812fb6e 100644 --- a/config/locales/server.ja.yml +++ b/config/locales/server.ja.yml @@ -1299,6 +1299,8 @@ ja: confirm_old_email: title: "古いメールの確認" subject_template: "[%{email_prefix}]現在のメールアドレスの確認" + confirm_old_email_add: + subject_template: "[%{email_prefix}]現在のメールアドレスの確認" signup_after_approval: subject_template: "%{site_name} への参加承認完了!" signup: diff --git a/config/locales/server.ko.yml b/config/locales/server.ko.yml index 2764eaa628..31fe36a105 100644 --- a/config/locales/server.ko.yml +++ b/config/locales/server.ko.yml @@ -649,7 +649,6 @@ ko: confirm: "확인" authorizing_new: title: "새 이메일 확인" - description: "새 이메일 주소가 다음으로 변경되었는지 확인하십시오." authorizing_old: title: "이메일 주소 변경" description: "이메일 주소 변경을 확인하십시오" @@ -1427,7 +1426,6 @@ ko: s3_backup_bucket: "백업본을 유지할 s3 버켓 이름. 주의 : 프라이빗 버켓인지 반드시 확인해야하세요." s3_endpoint: "엔드 포인트는 DigitalOcean Spaces 또는 Minio와 같은 S3 호환 서비스에 백업하도록 수정할 수 있습니다. 경고 : AWS S3를 사용하는 경우 비워 두십시오." s3_configure_tombstone_policy: "삭제 표시 업로드에 대한 자동 삭제 정책을 사용하십시오. 중요 : 비활성화하면 업로드가 삭제 된 후 공간이 회수되지 않습니다." - s3_disable_cleanup: "로컬에서 백업 삭제 시 S3에서 백업 제거하는 기능 해제" enable_s3_inventory: "Amazon S3 인벤토리를 사용하여 보고서를 생성하고 업로드를 확인하십시오. 중요 : 유효한 S3 자격 증명 (액세스 키 ID 및 비밀 액세스 키 모두)이 필요합니다." backup_time_of_day: "백업이 실행되어야 할 UTC 시간" backup_with_uploads: "스케쥴링된 백업을 실행할 때 업로드된 자료도 포함. 해제하면 데이터베이스만 백업합니다." @@ -1825,7 +1823,6 @@ ko: city_for_disputes: "분쟁의 도시" shared_drafts_category: "주제 초안의 범주를 지정하여 공유 초안 기능을 사용하십시오. 이 범주의 주제는 직원 사용자의 주제 목록에서 표시되지 않습니다." push_notifications_prompt: "사용자 동의 프롬프트를 표시합니다." - push_notifications_icon: "알림 코너에 나타나는 배지 아이콘. 필요한 크기는 96 × 96입니다." short_title: "짧은 제목은 사용자의 홈 화면, 실행기 또는 공간이 제한 될 수있는 다른 장소에서 사용됩니다. 12 자로 제한되어야합니다." dashboard_general_tab_activity_metrics: "일반 탭에서 활동 메트릭으로 표시 할 보고서를 선택하십시오." gravatar_name: "Gravatar 제공 업체 이름" diff --git a/config/locales/server.nl.yml b/config/locales/server.nl.yml index 96f2334196..e6d80bf5f8 100644 --- a/config/locales/server.nl.yml +++ b/config/locales/server.nl.yml @@ -762,7 +762,6 @@ nl: confirm: "Bevestigen" authorizing_new: title: "Bevestig uw nieuwe e-mailadres" - description: "Bevestig dat u uw nieuwe e-mailadres gewijzigd wilt zien naar:" authorizing_old: title: "Uw e-mailadres wijzigen" description: "Bevestig de wijziging van uw e-mailadres" @@ -1340,6 +1339,7 @@ nl: category_search_priority_very_high_weight: "Op rangschikking toegepast gewicht voor zeer hoge prioriteit bij doorzoeken van categorie." allow_uncategorized_topics: "Topics maken zonder categorie toestaan. WAARSCHUWING: als er topics zonder categorie zijn, moet u deze opnieuw aan een categorie toewijzen voordat dit wordt uitgezet." allow_duplicate_topic_titles: "Topics met dezelfde identieke titels toestaan" + allow_duplicate_topic_titles_category: "Topics met identieke, dubbele titels toestaan als de categorie anders is. allow_duplicate_topic_titles moet moet false zijn." unique_posts_mins: "Hoeveel minuten iemand moet wachten voordat deze een bericht met dezelfde inhoud mag plaatsen" educate_until_posts: "De pop-up voor nieuwe gebruikers tonen als een gebruiker begint met het typen van de eerste (n) nieuwe berichten in de berichteditor." title: "De naam van deze website, zoals gebruikt in de titeltag" @@ -1546,7 +1546,7 @@ nl: s3_backup_bucket: "De externe bucket voor back-ups. WAARSCHUWING: zorg ervoor dat dit een privébucket is." s3_endpoint: "Het eindpunt kan worden gewijzigd voor back-ups van een met S3 compatibele dienst, zoals DigitalOcean Spaces of Minio. WAARSCHUWING: laat dit leeg als u AWS S3 gebruikt." s3_configure_tombstone_policy: "Automatisch verwijderingsbeleid voor tombstone-uploads inschakelen. BELANGRIJK: wanneer uitgeschakeld, wordt geen ruimte vrijgemaakt na het verwijderen van uploads." - s3_disable_cleanup: "Verwijderen van back-ups van S3 uitschakelen bij lokaal verwijderen." + s3_disable_cleanup: "Verwijderen van oude back-ups van S3 voorkomen als er meer back-ups zijn dan maximaal toegestaan." enable_s3_inventory: "Rapporten genereren en uploads verifiëren via Amazon S3-inventory. BELANGRIJK: vereist geldige S3-referenties (zowel toegangssleutel-ID als geheime toegangssleutel)." backup_time_of_day: "Tijdstip (UTC) waarop de back-up moet plaatsvinden." backup_with_uploads: "Uploads opnemen in geplande back-ups. Wanneer uitgeschakeld, wordt alleen een back-up van de database gemaakt." @@ -1887,6 +1887,7 @@ nl: returning_user_notice_tl: "Het minimale vertrouwensniveau dat nodig is om berichtmeldingen van terugkerende gebruikers te zien." returning_users_days: "Het aantal dagen dat voorbij moet gaan voordat een gebruiker als terugkerend wordt beschouwd." enable_page_publishing: "Stafleden mogen topics naar nieuwe URL's publiceren met hun eigen stijlen." + show_published_pages_login_required: "Anonieme gebruikers kunnen gepubliceerde pagina's zien, zelfs wanneer aanmelding is vereist." default_email_digest_frequency: "Hoe vaak gebruikers standaard e-mailsamenvattingen ontvangen." default_include_tl0_in_digests: "Standaard berichten van nieuwe gebruikers in e-mailsamenvattingen opnemen. Gebruikers kunnen dit in hun voorkeuren wijzigen." default_email_level: "Standaard e-mailmeldingsniveau voor normale topics." @@ -1946,7 +1947,7 @@ nl: city_for_disputes: "Stad voor geschillen" shared_drafts_category: "Schakel de functie Gedeelde concepten in door een categorie voor topicconcepten aan te geven. Topics in deze categorie worden onderdrukt in topiclijsten voor stafgebruikers." push_notifications_prompt: "Prompt voor gebruikerstoestemming weergeven." - push_notifications_icon: "Het badgepictogram dat in de meldingenhoek verschijnt. Vereiste grootte is 96 × 96." + push_notifications_icon: "Het badgepictogram dat in de meldingshoek verschijnt. Een eenkleurige PNG van 96×96 met transparantie wordt aanbevolen." short_title: "De korte titel wordt gebruikt op het startscherm van de gebruiker, de starter, of andere plaatsen waar ruimte beperkt kan zijn. Beperk de naam tot 12 tekens." dashboard_hidden_reports: "Toestaan dat de opgegeven rapporten worden verborgen op het dashboard." dashboard_visible_tabs: "Kiezen welke dashboardtabbladen zichtbaar zijn." @@ -1990,6 +1991,7 @@ nl: max_username_length_exists: "U kunt de maximale gebruikersnaamlengte niet lager instellen dan de langste gebruikersnaam (%{username})." max_username_length_range: "U kunt het maximum niet lager instellen dan het minimum." invalid_hex_value: "Kleurwaarden moeten 6-cijferige hexadecimale codes zijn." + empty_selectable_avatars: "U moet eerst minstens twee selecteerbare avatars uploaden voordat u deze instelling inschakelt." category_search_priority: very_low_weight_invalid: "U kunt het gewicht niet groter instellen dan 'category_search_priority_low_weight'." low_weight_invalid: "U kunt het gewicht niet groter of gelijk aan 1 of kleiner instellen dan 'category_search_priority_very_low_weight'." @@ -2171,8 +2173,8 @@ nl: new_user_typed_too_fast: "Nieuwe gebruiker typte te snel" content_matches_auto_block_regex: "Inhoud komt overeen met regex voor auto-blokkeren" username: - short: "moet ten minste %{min} tekens zijn" - long: "moet niet meer dan %{max} tekens zijn" + short: "moet uit minstens %{min} tekens bestaan" + long: "mag niet meer dan %{max} tekens zijn" too_long: "is te lang" characters: "mag alleen cijfers, letters, streepjes, punten en onderstrepingstekens bevatten" unique: "moet uniek zijn" @@ -2535,6 +2537,8 @@ nl: Bevestig uw huidige e-mailadres voor %{site_name} door op de volgende koppeling te klikken: %{base_url}/u/confirm-old-email/%{email_token} + confirm_old_email_add: + subject_template: "[%{email_prefix}] Bevestig uw huidige e-mailadres" notify_old_email: subject_template: "[%{email_prefix}] Uw e-mailadres is gewijzigd" signup_after_approval: @@ -2987,3 +2991,6 @@ nl: title: "Gebruiker verwijderen" confirm: "Weet u zeker dat u die gebruiker wilt verwijderen? Dit verwijdert alle berichten en blokkeert het e-mail- en IP-adres van de gebruiker." reason: "Verwijderd via wachtrij voor beoordeling" + notification_level: + ignore_error: "Sorry, u kunt die gebruiker niet negeren." + mute_error: "Sorry, u kunt die gebruiker niet dempen." diff --git a/config/locales/server.pl_PL.yml b/config/locales/server.pl_PL.yml index d16570fb7f..459de21cb3 100644 --- a/config/locales/server.pl_PL.yml +++ b/config/locales/server.pl_PL.yml @@ -794,7 +794,6 @@ pl_PL: confirm: "Potwierdź" authorizing_new: title: "Potwierdź swój nowy adres e-mail" - description: "Potwierdź zmianę adresu e-mail na:" authorizing_old: title: "Zmień swój adres e-mail" description: "Potwierdź zmianę adresu e-mail" @@ -1575,7 +1574,6 @@ pl_PL: s3_backup_bucket: "Zdalne wiadro do przechowywania kopii zapasowych. UWAGA: Upewnij się, że jest to wiadro prywatne." s3_endpoint: "Punkt końcowy można zmodyfikować, aby utworzyć kopię zapasową w usłudze zgodnej z S3, takiej jak DigitalOcean Spaces lub Minio. OSTRZEŻENIE: Pozostaw puste, jeśli używasz AWS S3." s3_configure_tombstone_policy: "Włącz zasady automatycznego usuwania przy przesyłaniu nagrobków. WAŻNE: Jeśli ta opcja jest wyłączona, nie zostanie odzyskane żadne miejsce po usunięciu przesłanych plików." - s3_disable_cleanup: "Dezaktywuj usuwanie kopii zapasowych z S3 kiedy usunięte lokalnie." enable_s3_inventory: "Generuj raporty i weryfikuj przesyłane materiały za pomocą zasobów Amazon S3. WAŻNE: wymaga prawidłowych poświadczeń S3 (zarówno identyfikator klucza dostępu, jak i tajny klucz dostępu)." backup_time_of_day: "Godzina (UTC) wykonania kopii zapasowej." backup_with_uploads: "Uwzględniaj przesyły w zaplanowanych backupach. Wyłączenie tej opcji spowoduje backup jedynie bazy danych." @@ -2637,6 +2635,8 @@ pl_PL: confirm_old_email: title: "Potwierdź stary email" subject_template: "[%{site_name}] Potwierdź aktualny adres email" + confirm_old_email_add: + subject_template: "[%{site_name}] Potwierdź aktualny adres email" notify_old_email: title: "Powiadom Stary Email" subject_template: "[%{site_name}] Twój adres email został zmieniony" diff --git a/config/locales/server.pt.yml b/config/locales/server.pt.yml index dea79c962c..280184f709 100644 --- a/config/locales/server.pt.yml +++ b/config/locales/server.pt.yml @@ -946,7 +946,6 @@ pt: maximum_backups: "Valor máximo de cópias de segurança a serem guardadas em disco. Cópias de Segurança antigas são automaticamente eliminadas." automatic_backups_enabled: "Executar cópias de segurança automáticas de acordo com as definições de frequência de cópia de segurança" s3_backup_bucket: "Balde remoto para guardar cópias de segurança. AVISO: Certifique-se que este é um balde privado." - s3_disable_cleanup: "Desactive a remoção das cópias de segurança do S3 quando removidas localmente." backup_time_of_day: "Altura do dia UTC em que a cópia de segurança deve ocorrer." backup_with_uploads: "Incluir carregamentos em cópias de segurança agendadas. Desativar isto irá salvaguardar apenas a base de dados." active_user_rate_limit_secs: "Qual a frequência de atualização do campo 'última vez visto em', em segundos." diff --git a/config/locales/server.pt_BR.yml b/config/locales/server.pt_BR.yml index 3d2f607751..26297dfc04 100644 --- a/config/locales/server.pt_BR.yml +++ b/config/locales/server.pt_BR.yml @@ -730,7 +730,6 @@ pt_BR: confirm: "Confirmar" authorizing_new: title: "Confirme seu novo e-mail" - description: "Por favor confirme que você deseja que seu novo endereço de e-mail seja alterado para:" authorizing_old: title: "Troque seu endereço de e-mail" description: "Por favor confirme a alteração do seu endereço de e-mail" @@ -1469,7 +1468,6 @@ pt_BR: s3_backup_bucket: "O repositório remoto para realizar backups. AVISO: Certifique-se de que é um repositório privado." s3_endpoint: "O endpoint pode ser modificado para fazer backup em um serviço compatível com S3, como DigitalOcean Spaces ou Minio. AVISO: Deixe em branco se estiver usando o AWS S3." s3_configure_tombstone_policy: "Habilitar a política de exclusão automática para uploads de tombstone. IMPORTANTE: Se desabilitado, nenhum espaço será recuperado depois que os uploads forem excluídos." - s3_disable_cleanup: "Desabilitar a remoção de backups na S3 quando removidos localmente." enable_s3_inventory: "Gerar relatórios e verificar os uploads usando o inventário do Amazon S3. IMPORTANTE: requer credenciais S3 válidas (tanto a ID da chave de acesso quanto a chave de acesso secreta)." backup_time_of_day: "Hora do dia, em UTC, quando o backup deve ocorrer." backup_with_uploads: "Incluir uploads nos backups programados. Desabilite para copiar apenas a base de dados. " @@ -1831,7 +1829,6 @@ pt_BR: city_for_disputes: "Cidade para Disputas" shared_drafts_category: "Habilitar o recurso Rascunhos Compartilhados, designando uma categoria para rascunhos de tópicos. Os tópicos nesta categoria serão suprimidos das listas de tópicos para usuários da staff." push_notifications_prompt: "Exibir o prompt de consentimento do usuário." - push_notifications_icon: "O ícone do emblema que aparece no canto de notificação. O tamanho requerido é 96 × 96." short_title: "O título abreviado será usado na tela inicial do usuário, no iniciador ou em outros locais onde o espaço possa ser limitado. Deveria ser limitado a 12 caracteres." dashboard_general_tab_activity_metrics: "Escolher relatórios para serem exibidos como métricas de atividade na guia geral." errors: @@ -1983,12 +1980,12 @@ pt_BR: invalid_second_factor_method: "O método de autenticação de dois fatores selecionado é inválido." not_enabled_second_factor_method: "O método de autenticação de dois fatores selecionado não está ativado para sua conta." security_key_description: "Quando você tiver uma chave física de segurança preparada, pressione o Anti\n\nQuando sua chave de segurança física estiver pronta, pressione o botão \"Autenticar com Chave de Segurança\" abaixo." - security_key_alternative: "T" + security_key_alternative: "Tente de uma outra forma" security_key_authenticate: "Autenticar com Chave de Segurança" security_key_not_allowed_error: "O processo de autenticação de chave de segurança atingiu o limite de tempo ou foi cancelado." security_key_no_matching_credential_error: "Nenhuma credencial correspondente pôde ser encontrada na chave de segurança fornecida." security_key_support_missing_error: "Seu dispositivo atual ou navegador não suportam o uso de chaves de segurança. Por favor, use um método diferente." - not_approved: "A sua conta ainda não foi aprovada. Vais ser notificado por email assim que estiver pronto para fazeres log in." + not_approved: "A sua conta ainda não foi aprovada. Você será notificado por e-mail assim que estiver pronto para fazer login." incorrect_username_email_or_password: "Usuário, email ou senha incorretos" incorrect_password: "senha incorreta" wait_approval: "Obrigado por se registar. Você será notificado por email quando a sua conta for aprovada." @@ -3010,6 +3007,8 @@ pt_BR: title: "Confirmar Antigo e-mail" subject_template: "[%{email_prefix}] Confirme seu endereço de e-mail atual" text_body_template: "Antes de podermos alterar seu endereço de e-mail, precisamos confirmar que você \ncontrola a conta de e-mail atual. Depois de concluir esta etapa, solicitaremos que você \nconfirme o novo endereço de e-mail.\n\nConfirme seu endereço de email atual para %{site_name} clicando no seguinte link: \n\n%{base_url}/u/confirm-old-email/%{email_token}\n" + confirm_old_email_add: + subject_template: "[%{email_prefix}] Confirme seu endereço de e-mail atual" notify_old_email: title: "Notificar e-mail antigo" subject_template: "[%{email_prefix}] Seu endereço de e-mail foi alterado" diff --git a/config/locales/server.ro.yml b/config/locales/server.ro.yml index 4a22f56119..3515f217f1 100644 --- a/config/locales/server.ro.yml +++ b/config/locales/server.ro.yml @@ -906,7 +906,6 @@ ro: maximum_backups: "Maximul de fișiere backup păstrate. Fișierele backup vechi sunt șterse automat" automatic_backups_enabled: "Rulează automat operațiuni de backup după cum este definit la frecvența de backup" s3_backup_bucket: "Containerul (bucket) de la distanță care ține backupurile. ATENȚIE: Asgură-te că e un container privat." - s3_disable_cleanup: "Dezactivează eliminarea backup-urilor de pe S3 când sunt șterse local." backup_time_of_day: "Ora în format UTC la care să înceapă operațiunea de backup." backup_with_uploads: "Include încărcări în backup-urile programate. Dezactivarea acestei opțiuni va face backup doar la baza de date." active_user_rate_limit_secs: "Cât de des se actualizează câmpul 'last_seen_at', în secunde" diff --git a/config/locales/server.ru.yml b/config/locales/server.ru.yml index 0a48738185..bd3f364304 100644 --- a/config/locales/server.ru.yml +++ b/config/locales/server.ru.yml @@ -203,6 +203,9 @@ ru: file_should_be_csv: "Загружаемый файл должен быть в csv-формате." max_rows: "Первые %{max_bulk_invites} приглашения были отправлены. Попробуйте разделить файл на более мелкие части." error: "Произошла ошибка при загрузке файла. Пожалуйста, повторите попытку позже." + invite_link: + email_taken: "Этот email уже используется. Если у вас есть учётная запись - войдите в систему или запустите процедуру сброса пароля." + max_redemptions_limit: "Значение должно быть в интервале от 2 до %{max_limit}." topic_invite: failed_to_invite: "Пользователь не может быть приглашен в эту тему без членства в одной из следующих групп: %{group_names}." user_exists: "К сожалению, этот пользователь уже был приглашён. Вы можете пригласить пользователя в тему только один раз." @@ -792,15 +795,18 @@ ru: confirmed: "Ваш адрес электронной почты обновлен." please_continue: "Перейти на %{site_name}" error: "При смене электронного адреса произошла ошибка. Возможно, этот адрес уже используется?" + doesnt_exist: "Этот email не связан с Вашей учётной записью." error_staged: "При смене электронного адреса произошла ошибка. Этот адрес уже используется другим пользователем." already_done: "Извините, ссылка для подтверждения устарела. Возможно, ваш email уже изменен?" confirm: "Подтверждение" authorizing_new: title: "Подтвердите свой новый e-mail" - description: "Пожалуйста, подтвердите, что вы хотите изменить свой новый e-mail на:" + description: "Подтвердите, что Вы хотите поменять свой email на новый:" + description_add: "Подтвердите, что Вы хотите добавить дополнительный email:" authorizing_old: title: "Измените свой адрес e-mail почты" description: "Пожалуйста, подтвердите изменение вашего e-mail" + description_add: "Подтвердите, что Вы хотите добавить дополнительный email:" old_email: "Старый e-mail: %{email}" new_email: "Новый e-mail: %{email}" almost_done_title: "Подтверждение нового e-mail" @@ -844,7 +850,7 @@ ru: short_description: 'Нарушение правил сообщества' long_form: "отметить как неуместное" notify_user: - title: "Отправить @%{username} личное сообщение" + title: "Отправить пользователю @%{username} личное сообщение" description: "Я хочу поговорить с этим человеком напрямую и лично об этом посте." short_description: "Я хочу поговорить с этим человеком напрямую и лично об этом посте." long_form: "оповещаемый пользователь" @@ -1279,9 +1285,11 @@ ru: filesize: Размер файла description: "Список всех загрузок по расширению, размеру файла и автору." top_ignored_users: - title: "Топ Игнорируемых / Приглушенных Пользователей" + title: "Топ игнорируемых / приглушенных пользователей" labels: - ignored_user: Игнорируемый Пользователь + ignored_user: Игнорируемый пользователь + ignores_count: Количество игнорируемых + mutes_count: Количество приглушённых description: "Пользователи, которые были отключены и / или проигнорированы другими пользователями." dashboard: rails_env_warning: "Ваш сервер работает в режиме %{env}." @@ -1324,6 +1332,7 @@ ru: category_search_priority_very_high_weight: "Вес применяется к ранжированию для очень высокого приоритета поиска раздела." allow_uncategorized_topics: "Разрешить создание тем без раздела. ВНИМАНИЕ: Если есть какие-либо темы без раздела, вы должны переклассифицировать их, прежде чем отключить." allow_duplicate_topic_titles: "Разрешить создание тем с одинаковыми названиями." + allow_duplicate_topic_titles_category: "Разрешить создание тем с одинаковыми названиями, если они создаются в разных разделах (предыдущий параметр allow_duplicate_topic_titles должен быть отключён)." unique_posts_mins: "Количество минут до того, как пользователь сможет разместить сообщение с тем же содержанием." educate_until_posts: "Количество первых сообщений новых пользователей, для которых необходимо показывать всплывающую подсказку с советами для новичков." title: "Название этого сайта. Будет использоваться в HTML-тэге title." @@ -1460,9 +1469,15 @@ ru: google_oauth2_client_secret: "Client secret для Google приложения" twitter_consumer_key: "Ключ пользователя для аутентификации в Twitter, зарегистрированный по адресу https://developer.twitter.com/apps" twitter_consumer_secret: "Секретный номер для проверки подлинности Twitter, зарегистрированный в https://developer.twitter.com/apps" - allow_restore: "Позволить импорт, который может заменить ВСЕ данные сайта. Оставьте выключенным, если не планируете восстанавливать резервную копию" - maximum_backups: "Максимальное количество резервных копий к сохранению. Более старые резервные копии будут автоматически удалены." + enable_backups: "Разрешать администраторам создавать резервные копии форума" + allow_restore: "Позволить импорт, который может заменить ВСЕ данные сайта. Оставьте опцию выключенной, если не планируете восстанавливать резервную копию" + maximum_backups: "Максимальное количество сохраняемых резервных копий. Более старые резервные копии будут автоматически удалены." + automatic_backups_enabled: "Запускать автоматическое создание резервных копий с указанной в настройках периодичностью" + backup_frequency: "Периодичность создания резервных копий (в днях)." s3_backup_bucket: "Адрес папки удаленного сервера для резервных копий. ВНИМАНИЕ: Убедитесь, что место назначения защищено от посторонних." + backup_time_of_day: "Время создания резервной копии (UTC)." + backup_with_uploads: "Сохранять в резервной копии все загружаемые файлы. В противном случае будет сохраняться только база данных." + backup_gzip_compression_level_for_uploads: "Уровень gzip-сжатия для загружаемых файлов." active_user_rate_limit_secs: "Как часто мы обновляем поле 'last_seen_at', в секундах" verbose_localization: "Показывать ключи используемых строк в интерфейсе для перевода на другой язык" previous_visit_timeout_hours: "Как долго должно длиться посещение сайта, чтобы мы посчитали его «предыдущим посещением», в часах" @@ -1484,6 +1499,7 @@ ru: max_logins_per_ip_per_minute: "Максимальное количество входов в систему на IP-адрес в минуту" max_post_deletions_per_minute: "Максимальное количество записей, которые пользователь может удалить за минуту." max_post_deletions_per_day: "Максимальное количество записей, которые пользователь может удалить за день." + invite_link_max_redemptions_limit: "Количество пользователей, получающих приглашение по ссылке, не может превышать указанное здесь значение." alert_admins_if_errors_per_minute: "Количество ошибок в минуту для предупреждения администратора. Значение 0 отключает эту опцию. ВНИМАНИЕ: требуется перезагрузка." alert_admins_if_errors_per_hour: "Количество ошибок в час для предупреждения администратора. Значение 0 отключает эту опцию. ВНИМАНИЕ: требуется перезагрузка." suggested_topics: "Количество рекомендованных тем, отображаемых внизу текущей темы." @@ -1687,6 +1703,7 @@ ru: auto_close_topics_post_count: "Максимальное количество постов, разрешенных в теме до ее автоматического закрытия (0 для отключения)" max_allowed_message_recipients: "Максимальное число получателей сообщения." enable_page_publishing: "Разрешить сотрудникам публиковать темы на новых URL-адресах с их собственным стилем." + show_published_pages_login_required: "Опубликованные страницы доступны анонимным пользователям, для этого не требуется регистрация на форуме." default_email_mailing_list_mode: "По умолчанию присылать почтовое уведомление, когда появляется новое сообщение." default_other_auto_track_topics_after_msecs: "Глобальное время по умолчанию перед автоматическим отслеживанием темы." default_other_external_links_in_new_tab: "По умолчанию открывать внешние ссылки в новой вкладке." @@ -1714,7 +1731,7 @@ ru: governing_law: "Регулирующий Закон" city_for_disputes: "Город для решения споров" push_notifications_prompt: "Отображение запроса согласия пользователя." - push_notifications_icon: "Иконка значка, который появляется в углу уведомлений. Необходимый размер 96 × 96." + push_notifications_icon: "Иконка значка, который появляется в углу уведомлений. Рекомендуется монохроматическое изображение в формате PNG размером 96 × 96 пикселей с поддержкой прозрачности." dashboard_hidden_reports: "Разрешить скрытие отдельных отчётов из админки." dashboard_visible_tabs: "Выберите закладки, которые будут отображаться в админке." dashboard_general_tab_activity_metrics: "Выберите отчеты для отображения в качестве метрики активности на вкладке Общие." @@ -1749,6 +1766,7 @@ ru: max_username_length_exists: "Вы не можете установить максимальную длину имени пользователя короче самого длинного псевдонима (%{username})." max_username_length_range: "Нельзя установить максимум ниже минимума." invalid_hex_value: "Значения цвета должны быть шестнадцатеричными кодами из 6 цифр." + empty_selectable_avatars: "Для включения этого параметра необходимо загрузить не менее двух аватаров, из которых можно будет сделать выбор." category_search_priority: very_low_weight_invalid: "Вы не можете установить вес больше, чем 'category_search_priority_low_weight'." low_weight_invalid: "Вы не можете установить вес больше или равно 1 или меньше, чем указано в 'category_search_priority_very_low_weight'." @@ -2073,6 +2091,9 @@ ru: %{post_error} Если вы не можете исправить ошибку, попробуйте снова. + email_reject_bad_destination_address: + text_body_template: | + Сожалеем, но Ваше письмо адресату %{destination} (озаглавленное как %{former_title}не может быть отправлено. Вы используете более одного электронного адреса? Или Вы отвечаете с различных электронных адресов? При ответе необходимо использовать тот же самый электронный адрес. В противном случае ID заголовка сообщения может быть изменён. email_reject_unrecognized_error: subject_template: "[%{email_prefix}] Проблема с e-mail почтой -- Нераспознанная ошибка" email_reject_reply_not_allowed: @@ -2346,8 +2367,19 @@ ru: subject_template: "[%{email_prefix}] Ваш новый аккаунт" confirm_new_email: title: "Подтвердить Новый E-mail" + confirm_old_email: + subject_template: "%{email_prefix}Подтверждение текущего электронного адеса" + confirm_old_email_add: + subject_template: "%{email_prefix}Подтверждение текущего электронного адреса" + text_body_template: | + Перед добавлением нового электронного адреса необходимо убедиться в том, что Вы имеете доступ к текущему электронному адресу, после чего можно будет подтвердить новый адрес. + + Подтвердите текущий электронный адрес для сайта %{site_name} нажатием на следующую ссылку: %{base_url}/u/confirm-old-email/%{email_token} notify_old_email: subject_template: "[%{email_prefix}] Ваш адрес электронной почты был изменён" + notify_old_email_add: + subject_template: "%{email_prefix} Новый электронный адрес успешно добавлен." + text_body_template: "Это автоматическое сообщение, уведомляющее, что для сайта %{site_name} был добавлен электронный адрес. Если Вы считаете, что это было сделано по ошибке, свяжитесь с администратором сайта.\n\nДобавленный адрес: \n\n%{new_email}\n" signup_after_approval: title: "Регистрация После Утверждения" subject_template: "Ваша учетная запись на сайте %{site_name} одобрена!" @@ -2995,3 +3027,6 @@ ru: reason: "Удалено через очередь просмотра" email_style: html_missing_placeholder: "HTML-шаблон должен содержать %{placeholder}" + notification_level: + ignore_error: "Извините, но вы не можете игнорировать этого пользователя." + mute_error: "Извините, но вы не можете приглушить этого пользователя." diff --git a/config/locales/server.sl.yml b/config/locales/server.sl.yml index c94af00741..6caeb0afc4 100644 --- a/config/locales/server.sl.yml +++ b/config/locales/server.sl.yml @@ -1648,6 +1648,8 @@ sl: confirm_old_email: title: "Potrdite star e-naslov" subject_template: "[%{email_prefix}] Potrdite vaš trenutni e-naslov" + confirm_old_email_add: + subject_template: "[%{email_prefix}] Potrdite vaš trenutni e-naslov" notify_old_email: title: "Obvesti stari e-naslov" subject_template: "[%{email_prefix}] Vaš e-naslov je bil spremenjen" diff --git a/config/locales/server.sq.yml b/config/locales/server.sq.yml index 588f03e98b..caef7a150f 100644 --- a/config/locales/server.sq.yml +++ b/config/locales/server.sq.yml @@ -1158,6 +1158,8 @@ sq: subject_template: "[%{email_prefix}] Konfirmoni adresën tuaj të re të emailit" confirm_old_email: subject_template: "[%{email_prefix}] Konfirmoni adresën e tanishme të emailit " + confirm_old_email_add: + subject_template: "[%{email_prefix}] Konfirmoni adresën e tanishme të emailit " notify_old_email: text_body_template: | Ky është një mesazh automatik që ju njofton se adresa juaj email për diff --git a/config/locales/server.sv.yml b/config/locales/server.sv.yml index 14211b141c..93339f52b4 100644 --- a/config/locales/server.sv.yml +++ b/config/locales/server.sv.yml @@ -196,6 +196,7 @@ sv: error: "Det uppstod ett problem när filerna skulle laddas upp. Vad snäll och försök senare igen." invite_link: email_taken: "Den här e-postadressen används redan. Om du redan har ett konto ber vi dig logga in eller återställa lösenordet." + max_redemptions_limit: "bör vara mellan 2 och %{max_limit}." topic_invite: failed_to_invite: "Användaren kan inte bjudas in till detta ämne utan gruppmedlemskap i någon av de följande grupperna: %{group_names}." user_exists: "Tyvärr, den användaren har redan bjudits in. Du kan endast bjuda in en användare till ett ämne en gång." @@ -736,15 +737,18 @@ sv: confirmed: "Din e-post har uppdaterats." please_continue: "Fortsätt till %{site_name}" error: "Det uppstod ett fel med ändringen av din e-postadress. Adressen kanske redan används?" + doesnt_exist: "Den e-postadressen är inte associerad till ditt konto." error_staged: "Ett problem uppstod vid ändring av din e-postadress. Adressen används redan av en annan användare. " already_done: "Tyvärr har den här aktiveringslänken löpt ut. Kanske är din e-postadress redan ändrad? " confirm: "Bekräfta" authorizing_new: title: "Bekräfta din nya e-post" - description: "Vänligen bekräfta att du önskar ändra din nya e-postadress till:" + description: "Vänligen bekräfta att du önskar ändra din e-postadress till:" + description_add: "Vänligen bekräfta att du önskar lägga till en alternativ e-postadress:" authorizing_old: title: "Ändra din e-postadress" description: "Vänligen konfirmera din e-postadressändring" + description_add: "Vänligen bekräfta att du önskar lägga till en alternativ e-postadress:" old_email: "Gammal e-post: %{email}" new_email: "Ny e-post: %{email}" almost_done_title: "Bekräftar ny e-postadress" @@ -1319,6 +1323,7 @@ sv: category_search_priority_very_high_weight: "Vikt applicerad på rankning vid mycket hög sökprioritet för kategori" allow_uncategorized_topics: "Tillåt att ämnen skapas utan en kategori. VARNING: Om det finns några okategoriserade ämnen så måste dessa omkategoriseras innan den här inställningen stängs av. " allow_duplicate_topic_titles: "Tillåt ämnen med identiska rubriker." + allow_duplicate_topic_titles_category: "Tillåt ämnen med identisk, duplicerad titel om kategorierna är olika. allow_duplicate_topic_titles måste vara avbockad." unique_posts_mins: "Hur många minuter innan en användare kan göra ett inlägg med precis samma innehåll igen" educate_until_posts: "Visa hjälppanelen för komponering tills dess att användaren har gjort (n) nya inlägg. " title: "Namnet på denna webbplats som används i titel-taggen." @@ -1525,7 +1530,7 @@ sv: s3_backup_bucket: "Den externa behållaren för säkerhetskopieringar. VARNING: Se till att det är en privat behållare." s3_endpoint: "Ändpunkten kan ändras för att säkerhetskopiera till en S3-kompatibel tjänst som DigitalOcean Spaces eller Minio. VARNING: Lämna tomt om du använder AWS S3." s3_configure_tombstone_policy: "Aktivera automatisk raderingspolicy för Tombstone uppladdningar. VIKTIGT: Om det är inaktiverat kommer inget utrymme att återtas efter att överföringar har tagits bort." - s3_disable_cleanup: "Inaktivera borttagande av säkerhetskopior från S3 när de tagits bort lokalt." + s3_disable_cleanup: "Förhindra borttagning av äldre säkerhetskopior från S3 när det finns fler säkerhetskopior än högsta tillåtna." enable_s3_inventory: "Generera rapporter och verifiera uppladdningar med Amazon S3 inventering. VIKTIGT: kräver giltiga S3-referenser (både åtkomstnyckel-ID och hemlig åtkomstnyckel)." backup_time_of_day: "Tid på dygnet UTC då säkerhetskopieringen sker." backup_with_uploads: "Inkludera uppladdning i schemalagda säkerhetskopieringar. Inaktivering av det här kommer endast att säkerhetskopiera databasen." @@ -1556,6 +1561,7 @@ sv: max_logins_per_ip_per_minute: "Maximalt antal inloggningar tillåtna per IP-adress per minut" max_post_deletions_per_minute: "Maximalt antal inlägg som en användare kan radera per minut." max_post_deletions_per_day: "Maximalt antal inlägg som en användare kan radera per dag." + invite_link_max_redemptions_limit: "Maximalt antal återinbjudningar tillåtna för inbjudningslänkar kan inte vara större än detta värde." alert_admins_if_errors_per_minute: "Antal felindikeringar per minut för att utlösa ett administratörslarm. Ange 0 för att inaktivera den här funktionen. OBS: kräver omstart." alert_admins_if_errors_per_hour: "Antal felindikeringar per timme för att utlösa ett administratörslarm. Ange 0 för att inaktivera den här funktione. OBS: kräver omstart." categories_topics: "Antal ämnen som ska visas i /kategorisida. Om satt till 0 kommer systemet automatiskt att försöka hitta ett värde så att de två kolumnerna hålls symmetriskt (kategorier och ämnen.) " @@ -1865,6 +1871,7 @@ sv: returning_user_notice_tl: "Lägsta förtroendenivå som krävs för se återkommande användares inläggsnoteringar." returning_users_days: "Hur många dagar bör gå innan en användare anses återkomma." enable_page_publishing: "Tillåt personal att publicera ämnen för nya URL:er med deras egna utformning." + show_published_pages_login_required: "Anonyma användare kan se publicerade sidor, även när inloggning krävs." default_email_digest_frequency: "Standardinställning för hur ofta användare mottar e-postsammanfattningar." default_include_tl0_in_digests: "Standardinställning för hur ofta nya användare får e-postsammanfattningar. Användare kan ändra det i sina inställningar." default_email_level: "Ställ in standardnivå för e-postmeddelanden för vanliga ämnen." @@ -1924,7 +1931,7 @@ sv: city_for_disputes: "Stad för tvister" shared_drafts_category: "Aktivera funktionen delade utkast genom att ange en kategori för ämnesutkast. Ämnen i den här kategorin exkluderas från ämneslistor för personalanvändare." push_notifications_prompt: "Visa användarens samtycke genast." - push_notifications_icon: "Utmärkelseikonen som visas i notifieringshörnet. Obligatorisk storlek är 96 x 96." + push_notifications_icon: "Utmärkelseikonen som visas i notifieringshörnet. En 96x96 enfärgad PNG med genomskinlighet rekommenderas." short_title: "Den korta titeln kommer att användas på användarens startskärm, startapparat eller andra platser där utrymmet kan vara begränsat. Det bör begränsas till 12 tecken." dashboard_hidden_reports: "Tillåt att de specificerade rapporterna döljs från översiktspanelen." dashboard_visible_tabs: "Välj vilka flikar på översiktspanelen som ska vara synliga." @@ -1968,6 +1975,7 @@ sv: max_username_length_exists: "Du kan inte sätta högsta tillåtna längd på användarnamn lägre än det längsta användarnamnet (%{username})." max_username_length_range: "Du kan inte sätta maximum högre än minimum." invalid_hex_value: "Färgvärden måste vara sexsiffriga hexadecimala koder." + empty_selectable_avatars: "Du måste först ladda upp åtminstone två valbara avatarer innan du aktiverar denna inställning." category_search_priority: very_low_weight_invalid: "Du kan inte ställa in vikten att vara större än 'category_search_priority_low_weight'." low_weight_invalid: "Du kan inte ställa in vikten att vara större än eller lika med 1 eller mindre än 'category_search_priority_very_low_weight'." @@ -3075,6 +3083,17 @@ sv: Du kan bekräfta e-postadressen för %{site_name} genom att följa länken nedan: + %{base_url}/u/confirm-old-email/%{email_token} + confirm_old_email_add: + title: "Bekräfta tidigare e-postadress (Lägg till)" + subject_template: "[%{email_prefix}] Bekräfta din nuvarande e-postadress" + text_body_template: | + Innan vi kan lägga till en e-postadress, behöver du bekräfta att du kontrollerar + den nuvarande e-postadressen. Efter att du har genomfört detta steg, behöver du bekräfta + den nya e-postadressen. + + Du kan bekräfta e-postadressen för %{site_name} genom att klicka på följande länk: + %{base_url}/u/confirm-old-email/%{email_token} notify_old_email: title: "Meddela gamla epostmeddelanden" @@ -3084,6 +3103,17 @@ sv: Din e-postadress har ändrats till: + %{new_email} + notify_old_email_add: + title: "Notifiera tidigare e-postadress (Lägg till)" + subject_template: "[%{email_prefix}] En ny e-postadress har lagts till" + text_body_template: | + Det här är ett automatiserat meddelande för att informera dig om att en e-postadress för + %{site_name} har lagts till. Om detta har gjorts felaktigt, vänligen kontakta + en administratör. + + Din tillagda e-postadress är: + %{new_email} signup_after_approval: title: "Ny medlem efter godkännande" @@ -3861,6 +3891,9 @@ sv: reason: "Raderad via granskningskön" email_style: html_missing_placeholder: "Html-mallen måste inkludera %{placeholder}" + notification_level: + ignore_error: "Tyvärr, du kan inte ignorera den användaren." + mute_error: "Tyvärr, du kan inte tysta den användaren." discord: not_in_allowed_guild: "Autentisering misslyckades. Du är inte medlem i ett tillåtet Discord sällskap. " old_keys_reminder: diff --git a/config/locales/server.sw.yml b/config/locales/server.sw.yml index 493f78ca9a..7b91fd4802 100644 --- a/config/locales/server.sw.yml +++ b/config/locales/server.sw.yml @@ -1713,6 +1713,8 @@ sw: confirm_old_email: title: "Thibitisha Barua pepe ya Zamani" subject_template: "[%{email_prefix}] Thibitisha barua pepe ya sasa" + confirm_old_email_add: + subject_template: "[%{email_prefix}] Thibitisha barua pepe ya sasa" notify_old_email: title: "Ijulishe Barua Pepe ya Zamani" subject_template: "[%{email_prefix}] Barua pepe yako imebadilishwa" diff --git a/config/locales/server.te.yml b/config/locales/server.te.yml index 08dfc30c4e..08494d40b0 100644 --- a/config/locales/server.te.yml +++ b/config/locales/server.te.yml @@ -743,6 +743,8 @@ te: title: "సంస్థ" colors: title: "అలంకారం" + themes_further_reading: + title: "అలంకారాలు" homepage: fields: homepage_style: diff --git a/config/locales/server.th.yml b/config/locales/server.th.yml index a9ce6f2d1a..b9ea397350 100644 --- a/config/locales/server.th.yml +++ b/config/locales/server.th.yml @@ -60,9 +60,15 @@ th: next_page: "หน้าถัดไป →" prev_page: "← หน้าก่อนหน้า" page_num: "หน้า %{num}" + home_title: "หน้าแรก" + excerpt_image: "รูปภาพ" bookmarks: reminders: + later_today: "ภายหลังในวันนี้" + next_business_day: "ในวันทำการถัดไป" tomorrow: "พรุ่งนี้" + next_week: "สัปดาห์หน้า" + next_month: "เดือนหน้า" groups: default_names: everyone: "ทุกคน" @@ -74,6 +80,8 @@ th: other: "%{count} โพส" activerecord: attributes: + category: + name: "ชื่อหมวดหมู่" topic: title: "ชื่อเรื่อง" category_id: "หมวดหมู่" @@ -93,17 +101,28 @@ th: choose: "เลือกรหัสผู้ใช้" save: "ตั้งรหัสผ่าน" title: "รีเซ็ทรหัสผ่าน" + change_email: + please_continue: "ดำเนินการต่อไปยัง %{site_name}" + activation: + continue_button: "ดำเนินการต่อไปยัง %{site_name}" + welcome_to: "ยินดีต้อนรับสู่ %{site_name}!" reviewable_score_types: needs_approval: title: "ต้องการอนุมัติ" post_action_types: spam: title: "ขยะ" + long_form: "ปักธงไว้ว่าเป็นสแปม" + inappropriate: + long_form: "ปักธงไว้ว่าไม่เหมาะสม" bookmark: title: "บุ๊คมาร์ค" topic_flag_types: spam: title: "ขยะ" + long_form: "ปักธงไว้ว่าเป็นสแปม" + inappropriate: + long_form: "ปักธงไว้ว่าไม่เหมาะสม" archetypes: banner: title: "ป้ายหัวข้อ" @@ -117,6 +136,10 @@ th: weekly: "รายสัปดาห์" every_month: "ทุกเดือน" every_six_months: "ทุกหกเดือน" + user_api_key: + otp_confirmation: + confirm_title: "ดำเนินการต่อไปยัง %{site_name}" + confirm_button: เสร็จสิ้นการเข้าสู่ระบบ reports: post_edits: labels: @@ -126,6 +149,7 @@ th: user_flagging_ratio: labels: user: ผู้ใช้ + score: คะแนน moderators_activity: labels: moderator: ผู้ดูแล @@ -156,6 +180,9 @@ th: admin: ผู้ดูแลระบบ moderator: ผู้ดูแล suspended: ระงับการใช้งาน + trending_search: + labels: + searches: ค้นหา system_private_messages: title: "ระบบ" top_referrers: @@ -165,15 +192,21 @@ th: user: "ผู้ใช้" num_topics: "หัวข้อ" top_traffic_sources: + xaxis: "โดเมน" num_topics: "หัวข้อ" num_users: "ผู้ใช้" labels: + domain: โดเมน num_topics: หัวข้อ top_referred_topics: labels: topic: "หัวข้อ" page_view_anon_reqs: title: "ไม่ระบุชื่อ" + http_total_reqs: + title: "ทั้งหมด" + topics_with_no_response: + yaxis: "ทั้งหมด" suspicious_logins: labels: user: ผู้ใช้ @@ -182,6 +215,9 @@ th: labels: user: ผู้ใช้ location: ที่อยู่ + top_uploads: + labels: + filename: ชื่อไฟล์ search: within_post: "#%{post_number} ด้วย %{username}" types: @@ -191,8 +227,19 @@ th: slug_errors: invalid: "มีตัวอักษรที่ไม่สามารถใช้งานได้" login: + security_key_alternative: "ลองวิธีอื่น" + not_approved: "บัญชีของคุณยังไม่ได้รับการยืนยัน คุณจะได้รับการแจ้งเตือนทางอีเมลเมื่อคุณสามารถเข้าสู่ระบบได้" admin_not_allowed_from_ip_address: "คุณไม่สามารถเข้าสู่ระบบด้วยผู้ดูแลระบบด้วยไอพีนี้" not_available: "ใช้การไม่ได้ ลอง%{suggestion}?" + omniauth_confirm_button: "ดำเนินการต่อ" + admin: + email: + sent_test: "ส่งแล้ว!" + system_messages: + welcome_user: + subject_template: "ยินดีต้อนรับสู่ %{site_name}!" + welcome_invite: + subject_template: "ยินดีต้อนรับสู่ %{site_name}!" subject_re: "ตอบ: " subject_pm: "[PM] " user_notifications: @@ -298,16 +345,22 @@ th: set_password: title: "ตั้งรหัสผ่าน" page_not_found: + popular_topics: "ยอดนิยม" see_more: "อื่น" + search_title: "ค้นหาเว็บไซต์นี้" search_button: "ค้นหา" + image: "รูปภาพ" csv_export: boolean_yes: "ใช่" boolean_no: "ไม่ใช่" + rate_limit_error: "สามารถดาวน์โหลดโพสต์ได้วันละหนึ่งครั้งเท่านั้น กรุณาลองใหม่พรุ่งนี้" tos_topic: title: "เงื่อนไขการบริการ" privacy_topic: title: "นโยบายความเป็นส่วนตัว" badges: + member: + name: สมาชิก regular: name: ทั่วไป first_link: @@ -318,18 +371,44 @@ th: name: ลิงค์ที่ได้รับความนิยม tags: title: "ป้าย" + finish_installation: + register: + button: "ลงทะเบียน" + resend_email: + title: "ส่งอีเมลยืนยันตัวตนอีกครั้ง" wizard: step: forum_title: title: "ชื่อ" privacy: title: "การเข้าถึง" + fields: + privacy: + choices: + open: + label: "สาธารณะ" + restricted: + label: "ส่วนตัว" contact: fields: contact_email: placeholder: "name@example.com" corporate: title: "องค์กร" + colors: + title: "ธีม" + themes_further_reading: + title: "ธีม" + homepage: + fields: + homepage_style: + choices: + categories_only: + label: "หมวดหมู่เท่านั้น" + categories_and_latest_topics: + label: "หมวดหมู่และกระทู้ล่าสุด" + categories_and_top_topics: + label: "หมวดหมู่และกระทู้ยอดนิยม" emoji: title: "Emoji" joined: "สมัครสมาชิกเมื่อ" @@ -341,7 +420,20 @@ th: replied: '%{username} ตอบคุณใน "%{topic}" - %{site_title}' posted: '%{username} โพสท์ใน "%{topic}" - %{site_title}' linked: '%{username} ลิงค์โพสของคุณจาก "%{topic}" - %{site_title}' + watching_first_post: '%{username}ได้สร้างกระทู้ใหม่ "%{topic}"-%{site_title}' + confirm_title: "เปิดการแจ้งเตือนแล้ว - %{site_title}" + confirm_body: "สำเร็จแล้ว! การแจ้งเตือนถูกเปิดใช้งาน" + custom: "การแจ้งเตือนจาก %{username} บน %{site_title}" reviewables: + priorities: + low: "ต่ำ" + medium: "ปานกลาง" + high: "สูง" + sensitivity: + disabled: "ปิดใช้งานแล้ว" + low: "ต่ำ" + medium: "ปานกลาง" + high: "สูง" actions: delete_spammer: title: "ลบสแปมเมอร์" @@ -349,6 +441,8 @@ th: title: "ลบ" disagree: title: "ไม่เห็นด้วย" + ignore: + title: "ไม่สนใจ" approve: title: "อนุมัติ" reject_user: diff --git a/config/locales/server.tr_TR.yml b/config/locales/server.tr_TR.yml index 576d551f86..56ae382a51 100644 --- a/config/locales/server.tr_TR.yml +++ b/config/locales/server.tr_TR.yml @@ -723,7 +723,6 @@ tr_TR: confirm: "Onayla" authorizing_new: title: "Yeni e-postanı onayla" - description: "Lütfen yeni e-posta adresinizin değiştirilmesini istediğinizi onaylayın:" authorizing_old: title: "E posta adresini değiştir" description: "Lütfen e-posta adresİ değişikliğini onayla" @@ -1496,7 +1495,6 @@ tr_TR: s3_backup_bucket: "Yedeklemelerin yüklenmesi için uzak biriktirme yeri. UYARI: Özel bir biriktirme yeri olduğundan emin olun" s3_endpoint: "Bitiş noktası, DigitalOcean Spaces veya Minio gibi S3 uyumlu bir hizmete yedekleme yapmak için değiştirilebilir. UYARI: AWS S3 kullanıyorsanız boş bırakın." s3_configure_tombstone_policy: "Kaldırıldı olarak işaretleme yüklemeleri için otomatik silme politikasını etkinleştirin. ÖNEMLİ: Devre dışı bırakılırsa, yüklemeler silindikten sonra yer kazanılamaz." - s3_disable_cleanup: "Yerel olarak silinen yedeklerin S3 sunucularından silinmesini kapat" enable_s3_inventory: "Amazon S3 envanterini kullanarak raporlar oluşturun ve yüklemeleri doğrulayın. ÖNEMLİ: geçerli S3 kimlik bilgileri gerektirir (hem erişim anahtarı kimliği hem de gizli erişim anahtarı)." backup_time_of_day: "Yedeklemenin yapılacağı vaktin gün içindeki UTC zamanı." backup_with_uploads: "Planlanmış yedeklere yüklemeleri de dahil et. Etkisizleştirilirse sadece veritabanı yedeklenecek." @@ -1883,7 +1881,6 @@ tr_TR: city_for_disputes: "Anlaşmazlıklar Şehri" shared_drafts_category: "Konu taslakları için bir kategori belirleyerek Paylaşılan Taslaklar özelliğini etkinleştirin. Bu kategorideki konular, yetkili kullanıcılar için konu listelerinden kaldırılacaktır." push_notifications_prompt: "Kullanıcı izni komut istemini görüntüle." - push_notifications_icon: "Bildirim köşesinde görünen rozet simgesi. Gerekli boyut 96 × 96 'dır." short_title: "Kısa başlık kullanıcının ana ekranında, başlatıcısında veya alanın sınırlı olabileceği diğer yerlerde kullanılır. En fazla 12 karakter olmalıdır." dashboard_general_tab_activity_metrics: "Genel sekmesinde etkinlik ölçümleri olarak görüntülenecek raporları seçin." errors: @@ -3078,6 +3075,8 @@ tr_TR: title: "Eski E-postayı Onayla" subject_template: "[%{email_prefix}] Mevcut e-posta adresinizi onaylayın" text_body_template: "E-posta adresinizi değiştirebilmemiz için \nmevcut e-posta hesabını kontrol ettiğinizi onaylamanız gerekiyor. \nBu adımı tamamladıktan sonra yeni e-posta adresini onaylamanızı isteyeceğiz. \n\nAşağıdaki bağlantıya tıklayarak %{site_name} için mevcut e-posta adresinizi onaylayın: \n\n%{base_url} / u / confirm-old-email / %{email_token}\n" + confirm_old_email_add: + subject_template: "[%{email_prefix}] Mevcut e-posta adresinizi onaylayın" notify_old_email: title: "Eski E-postayı Bildir" subject_template: "[%{email_prefix}] E-posta adresiniz değiştirildi" diff --git a/config/locales/server.uk.yml b/config/locales/server.uk.yml index dabc8e2e60..0fef6d3b40 100644 --- a/config/locales/server.uk.yml +++ b/config/locales/server.uk.yml @@ -778,7 +778,6 @@ uk: confirm: "Підтвердіть" authorizing_new: title: "Підтвердьте свій новий електронний лист" - description: "Підтвердьте, що хочете, щоб ваша нова електронна пошта була змінена на:" authorizing_old: title: "Змінити свою електронну пошту" description: "Підтвердьте зміну своєї електронної пошти" @@ -1503,7 +1502,6 @@ uk: backup_frequency: "Кількість днів між резервними копіями." s3_backup_bucket: "Адреса папки віддаленого сервера для резервних копій. УВАГА: Переконайтеся, що місце призначення захищено від сторонніх." s3_endpoint: "Кінцеву точку можна змінити для резервного копіювання на службу, сумісну з S3, наприклад DigitalOcean Spaces або Minio. УВАГА: Не використовуйте AWS S3." - s3_disable_cleanup: "Вимкнути видалення резервних копій з S3, коли їх видалити локально." backup_time_of_day: "Час доби UTC, коли має відбуватися резервне копіювання" backup_with_uploads: "Додайте завантаження до запланованих резервних копій. Якщо вимкнути це, ви можете створити резервну копію бази даних." backup_gzip_compression_level_for_uploads: "Рівень стиснення Gzip, який використовується для стискання завантажень." @@ -1861,7 +1859,6 @@ uk: city_for_disputes: "Місто для суперечок" shared_drafts_category: "Увімкніть функцію Спільні чернетки, призначивши категорію для чернеток теми. Теми в цій категорії будуть витіснені зі списку тем для персоналу." push_notifications_prompt: "Відобразити запит на згоду користувача" - push_notifications_icon: "Іконка значка, який з’являється в куті сповіщення. Необхідний розмір - 96 × 96." short_title: "Короткий заголовок буде використовуватися на домашньому екрані користувача, стартовому вікні чи інших місцях, де можливо обмежене місце. Він повинен бути обмежений 12 символами." dashboard_general_tab_activity_metrics: "Виберіть звіти для відображення як активні показники діяльності на загальній вкладці." errors: @@ -2518,6 +2515,8 @@ uk: confirm_old_email: title: "Підтвердіть стару електронну пошту" subject_template: "[%{email_prefix}] Підтвердіть свою поточну адресу електроної пошти" + confirm_old_email_add: + subject_template: "[%{email_prefix}] Підтвердіть свою поточну адресу електроної пошти" notify_old_email: title: "Повідомлення на стару електронну пошту" subject_template: "[%{email_prefix}] Вашу електронну адресу змінено" diff --git a/config/locales/server.ur.yml b/config/locales/server.ur.yml index f8e1a75334..61c927eff4 100644 --- a/config/locales/server.ur.yml +++ b/config/locales/server.ur.yml @@ -1432,7 +1432,6 @@ ur: s3_backup_bucket: "بیک اَپس رکھنے کیلئے ریمَوٹ بَکِّٹ۔ انتباہ: یقینی بنائیں کہ یہ ایک زاتی بَکِّٹ ہے۔" s3_endpoint: "اَینڈ پوائنٹ کو S3 سے مطابقت رکھنے والی سروس جیسے کہ ڈیجیٹل اَوشن سپَیسز یا مینیو پر بیک اَپ کرنے کیلئے ترمیم کیا جا سکتا ہے۔ انتباہ: اگر AWS S3 کا استعمال کر رہے ہوں تو خالی چھوڑ دیں۔" s3_configure_tombstone_policy: "سنگ مزار اپ لوڈوں کیلئے خود کار طریقے سے حذف کر دینے کی پالیسی فعال کریں۔ اہم: اگر غیر فعال ہو، تو اپلوڈ حذف ہونے پر کوئی جگہ دوبارہ حاصل نہیں کی جائے گی۔" - s3_disable_cleanup: "جب مقامی طور پر بیک اَپ ہٹا دیا جائے اُس کے ساتھ S3 پر سے بھی ہٹا دینا غیر فعال کریں۔" enable_s3_inventory: "رپورٹیں بنائیں اور اَیمَیزَون S3 انوینٹری کا استعمال کرتے ہوئے اپلوڈ کی توثیق کریں۔ اہم: درست S3 اسناد ضروری ہیں (ایکسَیس قی آئی ڈی اور سیکرٹ ایکسَیس قی، دونوں)۔" backup_time_of_day: "دن کا وقت UTC جب بیک اَپ ہونا چاہئے۔" backup_with_uploads: "شیڈول کردہ بیک اَپس میں اپلوڈز شامل کریں۔ اِس کو غیر فعال کرنے پر صرف ڈَیٹا بَیس بیک اَپ کیا جائے گا۔" @@ -1803,7 +1802,6 @@ ur: city_for_disputes: "تنازعات کیلئے شہر" shared_drafts_category: "ٹاپک ڈرافٹس کیلئے ایک زُمرَہ کو مقرر کر کہ مشترکہ ڈرافٹس کی صلاحیت کو فعال کریں۔ اِس زُمرہ کے ٹاپکس کو سٹاف صارفین کیلئے ٹاپک فہرستوں سے دبا دیا جائے گا۔" push_notifications_prompt: "صارف رضامندی پرامپٹ دکھائیں۔" - push_notifications_icon: "نوٹیفکیشن کونے میں ظاہر ہونے والا بَیج آئکن۔ درکار سائز 96 × 96 ہے۔" short_title: "مختصر عنوان صارف کے ہوم اسکرین، لانچر، یا دیگر جگہیں جہاں خلا محدود ہوسکتی ہے، پر استعمال کیا جائے گا۔ یہ 12 حروف تک محدود ہونا چاہئیے۔" dashboard_general_tab_activity_metrics: "جنرل ٹیب پر سرگرمی میٹریکس کے طور پر ظاہر ہونے والی رپورٹیں منتخب کریں۔" errors: @@ -2936,6 +2934,8 @@ ur: confirm_old_email: title: "پرانی ای میل تصدیق" subject_template: "[%{email_prefix}] اپنا موجودہ ای میل ایڈریس تصدیق کریں" + confirm_old_email_add: + subject_template: "[%{email_prefix}] اپنا موجودہ ای میل ایڈریس تصدیق کریں" notify_old_email: title: "پرانا ای میل مطلع" subject_template: "[%{email_prefix}] آپ کا ای میل ایڈریس تبدیل ہوگیا ہے" diff --git a/config/locales/server.vi.yml b/config/locales/server.vi.yml index 3ab4ab3d6f..286deab470 100644 --- a/config/locales/server.vi.yml +++ b/config/locales/server.vi.yml @@ -766,7 +766,6 @@ vi: maximum_backups: "Số bản sao lưu tối đa lưu trong đĩa cứng. Những bản sao lưu cũ sẽ được xóa tự động" automatic_backups_enabled: "Chạy sao lưu tự động như cấu hình trong tần số sao lưu" s3_backup_bucket: "Địa chỉ tách biệt lưu trữ backup. LƯU Ý: đây phải là địa chỉ được giành riêng." - s3_disable_cleanup: "Vô hiệu hóa việc loại bỏ các bản sao lưu từ S3 khi lấy ra tại địa phương." backup_time_of_day: "Thời gian theo ngày UTC khi backup." backup_with_uploads: "Kèm theo cả thư mục uploads theo lịch trình backup. Tắt tính năng này sẽ chỉ backup csdl." active_user_rate_limit_secs: "Tần số cập nhật trường 'last_seen_at, tính theo giây" diff --git a/config/locales/server.zh_CN.yml b/config/locales/server.zh_CN.yml index ebf8927920..c2edf55c57 100644 --- a/config/locales/server.zh_CN.yml +++ b/config/locales/server.zh_CN.yml @@ -189,6 +189,9 @@ zh_CN: file_should_be_csv: "上传的文件应为 csv 格式。" max_rows: "前%{max_bulk_invites}个邀请已经被发出。尝试将文件分割成更小的部分。" error: "上传文件的时候出错了。请稍后重试。" + invite_link: + email_taken: "这个电子邮件地址已被注册。如果你已经有一个账户,请登录或重置密码。" + max_redemptions_limit: "应该在 2 和 %{max_limit} 之间。" topic_invite: failed_to_invite: "如果用户不是以下任一群组的成员,则无法被邀请加入到此主题:%{group_names}。" user_exists: "抱歉,用户已经被邀请过了。你只可以邀请一个用户到一个主题中一次。" @@ -708,15 +711,18 @@ zh_CN: confirmed: "你的电子邮箱已被更新。" please_continue: "转入到%{site_name}" error: "在修改你的电子邮箱地址时出现了错误,可能此邮箱已经在论坛中使用了?" + doesnt_exist: "这个电子邮件地址与你的账户没有关联。" error_staged: "在修改你的电子邮箱地址时出现了错误。这个邮箱已经被一个暂存用户占用了。" already_done: "抱歉,此激活链接已经失效。可能你已经修改了邮箱?" confirm: "确认" authorizing_new: title: "确认您的新邮箱" - description: "请你确认要将新的电子邮件地址更改为:" + description: "请确认你想要修改的电子邮件地址:" + description_add: "请确认你要添加的次要电子邮件地址:" authorizing_old: title: "修改你的电子邮件地址" description: "请确认你的电子邮件地址更改" + description_add: "请确认你要添加的次要电子邮件地址:" old_email: "旧邮件:%{email}" new_email: "新邮件:%{email}" almost_done_title: "确认新的电子邮件地址" @@ -1421,6 +1427,7 @@ zh_CN: moderators_view_emails: "允许版主查看用户电子邮件" prioritize_username_in_ux: "在用户页、用户卡片和帖子上优先显示用户名(未选时,昵称将先显示)" enable_rich_text_paste: "将文本粘贴到编辑器中时自动启用HTML到Markdown转换。(实验性)" + send_old_credential_reminder_days: "几天后提醒有关旧凭证" email_token_valid_hours: "“忘记密码”/“激活账户”令牌有效的小时数。" enable_badges: "启用徽章系统" enable_whispers: "允许管理人员在主题中私密交流。" @@ -1495,7 +1502,6 @@ zh_CN: s3_backup_bucket: "远端备份 bucket。警告:确认它使私有的 bucket。" s3_endpoint: "可以修改端点以备份到S3兼容服务,如DigitalOcean Spaces或Minio。警告:留空以使用AWS S3。" s3_configure_tombstone_policy: "为逻辑删除上载启用自动删除策略。注意:如果禁用,在删除上载后不会回收空间。" - s3_disable_cleanup: "当在本地删除备份时不删除 S3 上的备份。" enable_s3_inventory: "使用Amazon S3存储验证上传并生成报告。重要:需要有效的S3证书(包括 access key id & secret access key)。" backup_time_of_day: "备份的 UTC 时间" backup_with_uploads: "在备份日程中包括上传。关闭此项仅备份数据库。" @@ -1526,6 +1532,7 @@ zh_CN: max_logins_per_ip_per_minute: "一分钟内同一个IP(网络)地址能允许最大的登录次数。" max_post_deletions_per_minute: "用户每分钟可以删除的最大帖子数。" max_post_deletions_per_day: "用户每天可以删除的最大帖子数。" + invite_link_max_redemptions_limit: "邀请链接所允许的最大兑换量不能超过这个数值。" alert_admins_if_errors_per_minute: "激活管理员警告的每分钟错误的数量。0 会禁用这个特性。注意:需要重启。" alert_admins_if_errors_per_hour: "激活管理员警告的每小时错误的数量。0 会禁用这个特性。注意:需要重启。" categories_topics: "要在 /categories 页面中显示的主题数量。如果设置为0,它将自动尝试寻找一个值来保持两列对称(分类和主题)。" @@ -1894,7 +1901,6 @@ zh_CN: city_for_disputes: "争议之城" shared_drafts_category: "为主题草稿指定分类以启用共享草稿功能。此分类中的主题将从管理人员的主题列表中删除。" push_notifications_prompt: "显示用户同意提示。" - push_notifications_icon: "通知角中显示的徽章图标。尺寸必须为96px × 96px。" short_title: "短标题将用于用户主页、启动器或其他可能空间有限的地方。应该控制在12个字符内。" dashboard_hidden_reports: "允许从仪表盘中隐藏指定的报告。" dashboard_visible_tabs: "选择可见的仪表盘标签页" @@ -2641,6 +2647,10 @@ zh_CN: email_reject_bad_destination_address: title: "Email被拒绝:收件人地址不正确" subject_template: "[%{email_prefix}] 邮件问题 -- 未知的发至:地址" + text_body_template: | + 很抱歉,你通过邮件发往%{destination}(标题%{former_title})的私信/消息没有成功。 + + 你是否使用一个以上的电子邮件地址?你是否使用了不同的电子邮件地址回复?电子邮件回复要求你在回复时使用相同的电子邮件地址。或者,邮件中的私信/消息-ID 头可能被修改。 email_reject_old_destination: title: "邮件拒绝老地址" subject_template: "[%{email_prefix}] 邮件问题 - 你正尝试回复旧通知" @@ -3183,6 +3193,17 @@ zh_CN: 点击下面链接以确认你当前在%{site_name}的邮件地址: %{base_url}/u/confirm-old-email/%{email_token} + confirm_old_email_add: + title: "确认旧邮箱(添加)" + subject_template: "[%{email_prefix}] 确认你现在的电子邮箱地址" + text_body_template: | + 在我们添加新的电子邮件地址之前,我们需要确认你控制了 + 当前的电子邮件账户。在你完成这一步后,我们会让你确认 + 新的电子邮件地址。 + + 点击以下链接,确认你当前的%{site_name}电子邮件地址: + + %{base_url}/u/confirm old-email/%{email_token} notify_old_email: title: "通知旧邮箱" subject_template: "[%{email_prefix}] 你的邮箱已经修改成功" @@ -3191,6 +3212,17 @@ zh_CN: 你的邮箱地址被修改为: + %{new_email} + notify_old_email_add: + title: "通知旧邮件(添加)" + subject_template: "[%{email_prefix}]一个新的电子邮件已被添加。" + text_body_template: | + 请了解,这是一条自动的私信/消息,这个电子邮件地址 + 已添加至%{site_name}。如果有误,请联系 + 网站管理员。 + + 你添加的电子邮件地址是: + %{new_email} signup_after_approval: title: "在审批之后注册" @@ -4258,3 +4290,13 @@ zh_CN: html_missing_placeholder: "HTML模板必须包含%{placeholder}" discord: not_in_allowed_guild: "验证失败。您不是允许的Discord公会的成员。" + old_keys_reminder: + title: "关于旧凭证的提醒" + body: | + Hello!这是你的 Discourse 实例每年例行安全提醒。 + + 出于礼貌,我们想让你知道,你的 Discourse 实例上使用的以下凭证已经两年多没有更新了。 + + %{keys} + + 目前不需要采取任何行动,但是,每隔几年对所有重要凭证进行周期性更新是一种良好的安全做法。 diff --git a/config/locales/server.zh_TW.yml b/config/locales/server.zh_TW.yml index 4527cff87d..e13de862c0 100644 --- a/config/locales/server.zh_TW.yml +++ b/config/locales/server.zh_TW.yml @@ -1348,7 +1348,6 @@ zh_TW: s3_backup_bucket: "遠端備份 bucket ,注意:請確定是私有的 bucket" s3_endpoint: "Discourse 備份空間有支援其他第三方服務,可修改備份空間存向 DigitalOcean Spaces、Minio或是Amazon S3。警告:如果使用Amazon S3,請留白。" s3_configure_tombstone_policy: "啟用上傳的自動刪除功能。重要提醒:如果禁用此功能,在檔案刪除後,不會回收空間。" - s3_disable_cleanup: "當在本地刪除備份時不刪除 S3 上的備份。" enable_s3_inventory: "使用Amazon S3 清單生成報告並驗證上傳。注意:需要設定Amazon S3 驗證資料(包括Access Key ID、Secret Access Key)。" backup_time_of_day: "備份的 UTC 時間" backup_with_uploads: "在備份日程中包括上傳。關閉此項僅備份資料庫。" @@ -1705,7 +1704,6 @@ zh_TW: city_for_disputes: "爭議" shared_drafts_category: "通過為討論話題的草稿以指定一個類別,來啟用「共用草稿」功能。此類別中的話題將從工作人員使用者的主題清單中取消。" push_notifications_prompt: "顯示使用者同意提示" - push_notifications_icon: "通知角中顯示的徽章 icon,所需圖片尺寸為96×96" short_title: "短標題將用於使用者的主螢幕、啟動器或其他可能空白鍵有限的地方,它應限制為12個字。" dashboard_general_tab_activity_metrics: "選擇在一般頁面中要顯示為活躍指標的報告" errors: @@ -2727,6 +2725,8 @@ zh_TW: confirm_old_email: title: "確認原郵件地址" subject_template: "[%{email_prefix}] 確認你的現行郵件地址" + confirm_old_email_add: + subject_template: "[%{email_prefix}] 確認你的現行郵件地址" notify_old_email: title: "通知原郵件地址" subject_template: "[%{email_prefix}] 已變更你的郵件地址" diff --git a/config/nginx.sample.conf b/config/nginx.sample.conf index 52e5660954..310e8c84e2 100644 --- a/config/nginx.sample.conf +++ b/config/nginx.sample.conf @@ -4,10 +4,8 @@ types { } upstream discourse { - server unix:/var/www/discourse/tmp/sockets/thin.0.sock; - server unix:/var/www/discourse/tmp/sockets/thin.1.sock; - server unix:/var/www/discourse/tmp/sockets/thin.2.sock; - server unix:/var/www/discourse/tmp/sockets/thin.3.sock; + server unix:/var/www/discourse/tmp/sockets/nginx.http.sock; + server unix:/var/www/discourse/tmp/sockets/nginx.https.sock; } # inactive means we keep stuff around for 1440m minutes regardless of last access (1 week) diff --git a/config/routes.rb b/config/routes.rb index 0de10003e5..f34b9123d4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -736,7 +736,7 @@ Discourse::Application.routes.draw do get "private-messages-sent/:username" => "list#private_messages_sent", as: "topics_private_messages_sent", defaults: { format: :json } get "private-messages-archive/:username" => "list#private_messages_archive", as: "topics_private_messages_archive", defaults: { format: :json } get "private-messages-unread/:username" => "list#private_messages_unread", as: "topics_private_messages_unread", defaults: { format: :json } - get "private-messages-tags/:username/:tag_id.json" => "list#private_messages_tag", as: "topics_private_messages_tag", constraints: StaffConstraint.new + get "private-messages-tags/:username/:tag_id.json" => "list#private_messages_tag", as: "topics_private_messages_tag", defaults: { format: :json } get "groups/:group_name" => "list#group_topics", as: "group_topics", group_name: RouteFormat.username scope "/private-messages-group/:username", group_name: RouteFormat.username do diff --git a/config/site_settings.yml b/config/site_settings.yml index 08e16c94f1..e8cd6f7d7a 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -62,30 +62,18 @@ branding: default: -5 client: true type: upload - logo_url: - hidden: true - default: "/images/d-logo-sketch.png" logo_small: default: -6 client: true type: upload - logo_small_url: - hidden: true - default: "/images/d-logo-sketch-small.png" digest_logo: default: "" client: true type: upload - digest_logo_url: - hidden: true - default: "" mobile_logo: default: "" client: true type: upload - mobile_logo_url: - hidden: true - default: "" large_icon: default: "" client: true @@ -93,35 +81,20 @@ branding: manifest_icon: default: "" type: upload - large_icon_url: - hidden: true - default: "" favicon: default: "" client: true type: upload - favicon_url: - hidden: true - default: "/images/default-favicon.ico" apple_touch_icon: default: "" client: true type: upload - apple_touch_icon_url: - hidden: true - default: "/images/default-apple-touch-icon.png" opengraph_image: default: "" type: upload - default_opengraph_image_url: - hidden: true - default: "" twitter_summary_large_image: default: "" type: upload - twitter_summary_large_image_url: - hidden: true - default: "" basic: display_local_time_in_user_card: @@ -300,9 +273,6 @@ basic: push_notifications_icon: default: "" type: upload - push_notifications_icon_url: - hidden: true - default: "" short_title: default: "" max: 12 @@ -716,6 +686,7 @@ posting: default: true refresh: true allow_duplicate_topic_titles: false + allow_duplicate_topic_titles_category: false min_title_similar_length: client: true default: 10 @@ -947,6 +918,8 @@ posting: max: 36500 enable_page_publishing: default: false + show_published_pages_login_required: + default: false email: email_time_window_mins: @@ -1268,6 +1241,7 @@ files: selectable_avatars_enabled: default: false client: true + validator: "SelectableAvatarsEnabledValidator" selectable_avatars: default: "" type: uploaded_image_list diff --git a/config/unicorn.conf.rb b/config/unicorn.conf.rb index 71831433dd..1d1d0135ab 100644 --- a/config/unicorn.conf.rb +++ b/config/unicorn.conf.rb @@ -2,7 +2,7 @@ # See http://unicorn.bogomips.org/Unicorn/Configurator.html -if ENV["LOGSTASH_UNICORN_URI"] +if (ENV["LOGSTASH_UNICORN_URI"] || "").length > 0 require_relative '../lib/discourse_logstash_logger' logger DiscourseLogstashLogger.logger(uri: ENV['LOGSTASH_UNICORN_URI'], type: :unicorn) end diff --git a/db/fixtures/001_refresh.rb b/db/fixtures/001_refresh.rb index 5188adc6cb..514789616d 100644 --- a/db/fixtures/001_refresh.rb +++ b/db/fixtures/001_refresh.rb @@ -1,5 +1,24 @@ # frozen_string_literal: true -# fix any bust caches post initial migration -ActiveRecord::Base.public_send(:subclasses).each { |m| m.reset_column_information } +class SeedData::Refresher + @mutex = Mutex.new + + def self.refresh! + return if @refreshed + + @mutex.synchronize do + return if @refreshed + # Fix any bust caches post initial migration + # Not that reset_column_information is not thread safe so we have to becareful + # not to run it concurrently within the same process. + ActiveRecord::Base.connection.tables.each do |table| + table.classify.constantize.reset_column_information rescue nil + end + + @refreshed = true + end + end +end + +SeedData::Refresher.refresh! SiteSetting.refresh! diff --git a/db/fixtures/990_topics.rb b/db/fixtures/990_topics.rb index 13c8b53c8e..fd29715bee 100644 --- a/db/fixtures/990_topics.rb +++ b/db/fixtures/990_topics.rb @@ -1,12 +1,8 @@ # frozen_string_literal: true -require 'seed_data/topics' - -User.reset_column_information -Topic.reset_column_information -Post.reset_column_information - if !Rails.env.test? + require 'seed_data/topics' + topics_exist = Topic.where(<<~SQL).exists? id NOT IN ( SELECT topic_id diff --git a/db/migrate/20190315025804_migrate_blank_override_for_upload_site_settings.rb b/db/migrate/20190315025804_migrate_blank_override_for_upload_site_settings.rb deleted file mode 100644 index 1e5a3c5e33..0000000000 --- a/db/migrate/20190315025804_migrate_blank_override_for_upload_site_settings.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -class MigrateBlankOverrideForUploadSiteSettings < ActiveRecord::Migration[5.2] - def up - { - 'logo_url' => 'logo', - 'logo_small_url' => 'logo_small', - 'digest_logo_url' => 'digest_logo', - 'mobile_logo_url' => 'mobile_logo', - 'large_icon_url' => 'large_icon', - 'favicon_url' => 'favicon', - 'apple_touch_icon_url' => 'apple_touch_icon', - 'default_opengraph_image_url' => 'opengraph_image', - 'twitter_summary_large_image_url' => 'twitter_summary_large_image', - 'push_notifications_icon_url' => 'push_notifications_icon' - }.each do |old_name, new_name| - if DB.query_single("SELECT 1 FROM site_settings WHERE name = '#{old_name}' AND value = ''").present? && - DB.query_single("SELECT 1 FROM site_settings WHERE name = '#{new_name}'").empty? - - ActiveRecord::Base.connection.execute <<~SQL - INSERT INTO site_settings ( - name, - data_type, - value, - created_at, - updated_at - ) VALUES ( - '#{new_name}', - 18, - '', - CURRENT_TIMESTAMP, - CURRENT_TIMESTAMP - ) - SQL - end - end - end - - def down - raise ActiveRecord::IrreversibleMigration - end -end diff --git a/db/migrate/20190315055432_migrate_null_override_for_upload_site_settings.rb b/db/migrate/20190315055432_migrate_null_override_for_upload_site_settings.rb deleted file mode 100644 index f47b35276f..0000000000 --- a/db/migrate/20190315055432_migrate_null_override_for_upload_site_settings.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -class MigrateNullOverrideForUploadSiteSettings < ActiveRecord::Migration[5.2] - def up - { - 'logo_url' => 'logo', - 'logo_small_url' => 'logo_small', - 'digest_logo_url' => 'digest_logo', - 'mobile_logo_url' => 'mobile_logo', - 'large_icon_url' => 'large_icon', - 'favicon_url' => 'favicon', - 'apple_touch_icon_url' => 'apple_touch_icon', - 'default_opengraph_image_url' => 'opengraph_image', - 'twitter_summary_large_image_url' => 'twitter_summary_large_image', - 'push_notifications_icon_url' => 'push_notifications_icon' - }.each do |old_name, new_name| - if DB.query_single("SELECT 1 FROM site_settings WHERE name = '#{old_name}' AND value IS NULL").present? && - DB.query_single("SELECT 1 FROM site_settings WHERE name = '#{new_name}'").empty? - - ActiveRecord::Base.connection.execute <<~SQL - INSERT INTO site_settings ( - name, - data_type, - value, - created_at, - updated_at - ) VALUES ( - '#{new_name}', - 18, - '', - CURRENT_TIMESTAMP, - CURRENT_TIMESTAMP - ) - SQL - end - end - end - - def down - raise ActiveRecord::IrreversibleMigration - end -end diff --git a/db/migrate/20200611104600_create_missing_badge_indexes.rb b/db/migrate/20200611104600_create_missing_badge_indexes.rb new file mode 100644 index 0000000000..7750d8118b --- /dev/null +++ b/db/migrate/20200611104600_create_missing_badge_indexes.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# Badge and user_badge tables were created using add_column index: true +# When the migration was written, `index: true` was a no-op for non-reference columns +# Since then, rails made it work https://github.com/rails/rails/commit/9a0d35e820464f872b0340366dded639f00e19b9 +# This migration adds the index to very old sites, so that we have a consistent state + +# frozen_string_literal: true + +class CreateMissingBadgeIndexes < ActiveRecord::Migration[6.0] + def up + execute "CREATE INDEX IF NOT EXISTS index_user_badges_on_user_id ON public.user_badges USING btree (user_id)" + execute "CREATE INDEX IF NOT EXISTS index_badges_on_badge_type_id ON public.badges USING btree (badge_type_id)" + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/migrate/20200617144300_add_public_field_to_published_pages.rb b/db/migrate/20200617144300_add_public_field_to_published_pages.rb new file mode 100644 index 0000000000..2bdfbfc50e --- /dev/null +++ b/db/migrate/20200617144300_add_public_field_to_published_pages.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class AddPublicFieldToPublishedPages < ActiveRecord::Migration[6.0] + def up + # Delete the record of https://github.com/discourse/discourse/commit/b9762afc106ee9b18d1ac33ca3cac281083e428e + execute <<~SQL + DELETE FROM schema_migrations WHERE version='20201006172700' + SQL + + # Delete the reference to the incorrectly versioned version of this migration + execute <<~SQL + DELETE FROM schema_migrations WHERE version='20201006172701' + SQL + + # Using IF NOT EXISTS because the version number of this migration was changed + # Therefore some sites may have already added the column + execute <<~SQL + ALTER TABLE "published_pages" ADD COLUMN IF NOT EXISTS "public" boolean DEFAULT FALSE NOT NULL + SQL + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/migrate/20200618175923_delete_tracking_state_for_staged_users.rb b/db/migrate/20200618175923_delete_tracking_state_for_staged_users.rb new file mode 100644 index 0000000000..9885b561fb --- /dev/null +++ b/db/migrate/20200618175923_delete_tracking_state_for_staged_users.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class DeleteTrackingStateForStagedUsers < ActiveRecord::Migration[6.0] + def up + execute <<~SQL + DELETE FROM category_users + WHERE user_id IN (SELECT id FROM users WHERE staged = true) + SQL + + execute <<~SQL + DELETE FROM tag_users + WHERE user_id IN (SELECT id FROM users WHERE staged = true) + SQL + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/post_migrate/20200610150900_correct_posts_schema.rb b/db/post_migrate/20200610150900_correct_posts_schema.rb new file mode 100644 index 0000000000..c2fc2ba5d6 --- /dev/null +++ b/db/post_migrate/20200610150900_correct_posts_schema.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +class CorrectPostsSchema < ActiveRecord::Migration[6.0] + # In the past, rails changed the default behavior for varchar columns + # This only affects older discourse installations + # This migration removes the character limits from posts columns, so that they match modern behavior + # + # To modify the posts table schema we need to recreate the badge_posts view + # This should be done in a transaction + def up + result = DB.query <<~SQL + SELECT character_maximum_length + FROM information_schema.columns + WHERE table_schema='public' + AND table_name = 'posts' + AND column_name IN ('action_code', 'edit_reason') + SQL + + # No need to continue if the schema is already correct + return if result.all? { |r| r.character_maximum_length.nil? } + + execute "DROP VIEW badge_posts" + + execute "ALTER TABLE posts ALTER COLUMN action_code TYPE varchar" + execute "ALTER TABLE posts ALTER COLUMN edit_reason TYPE varchar" + + # we must recreate this view every time we amend posts + # p.* is auto expanded and persisted into the view definition + # at create time + execute <<~SQL + CREATE VIEW badge_posts AS + SELECT p.* + FROM posts p + JOIN topics t ON t.id = p.topic_id + JOIN categories c ON c.id = t.category_id + WHERE c.allow_badges AND + p.deleted_at IS NULL AND + t.deleted_at IS NULL AND + NOT c.read_restricted AND + t.visible AND + p.post_type IN (1,2,3) + SQL + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb b/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb deleted file mode 100644 index 7cc4dce92b..0000000000 --- a/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb +++ /dev/null @@ -1,190 +0,0 @@ -# frozen_string_literal: true - -require 'active_record/connection_adapters/abstract_adapter' -require 'active_record/connection_adapters/postgresql_adapter' -require 'discourse' -require 'sidekiq/pausable' - -class PostgreSQLFallbackHandler - include Singleton - - attr_reader :masters_down - attr_accessor :initialized - - DATABASE_DOWN_CHANNEL = '/global/database_down' - - def initialize - @masters_down = DistributedCache.new('masters_down', namespace: false) - @mutex = Mutex.new - @initialized = false - - MessageBus.subscribe(DATABASE_DOWN_CHANNEL) do |payload| - if @initialized && payload.data["pid"].to_i != Process.pid - begin - RailsMultisite::ConnectionManagement.with_connection(payload.data['db']) do - clear_connections - end - rescue PG::UnableToSend - # Site has already failed over - end - end - end - end - - def verify_master - synchronize do - return if @thread && @thread.alive? - - @thread = Thread.new do - while true do - thread = Thread.new { initiate_fallback_to_master } - thread.abort_on_exception = true - thread.join - break if synchronize { @masters_down.hash.empty? } - sleep 5 - end - end - - @thread.abort_on_exception = true - end - end - - def master_down? - synchronize { @masters_down[namespace] } - end - - def master_down - synchronize do - @masters_down[namespace] = true - Sidekiq.pause!("pg_failover") if !Sidekiq.paused? - MessageBus.publish(DATABASE_DOWN_CHANNEL, db: namespace, pid: Process.pid) - end - end - - def master_up(namespace) - synchronize { @masters_down.delete(namespace, publish: false) } - end - - def initiate_fallback_to_master - begin - unless @initialized - @initialized = true - return - end - - @masters_down.hash.keys.each do |key| - RailsMultisite::ConnectionManagement.with_connection(key) do - begin - logger.warn "#{log_prefix}: Checking master server..." - is_connection_active = false - - begin - connection = ActiveRecord::Base.postgresql_connection(config) - is_connection_active = connection.active? - ensure - connection.disconnect! if connection - end - - if is_connection_active - logger.warn "#{log_prefix}: Master server is active. Reconnecting..." - self.master_up(key) - clear_connections - disable_readonly_mode - Sidekiq.unpause! - end - rescue => e - logger.warn "#{log_prefix}: Connection to master PostgreSQL server failed with '#{e.message}'" - end - end - end - rescue => e - logger.warn "#{e.class} #{e.message}: #{e.backtrace.join("\n")}" - end - end - - # Use for testing - def setup! - @masters_down.clear - disable_readonly_mode - end - - def clear_connections - ActiveRecord::Base.clear_all_connections! - end - - private - - def disable_readonly_mode - Discourse.disable_readonly_mode(Discourse::PG_READONLY_MODE_KEY) - end - - def config - ActiveRecord::Base.connection_config - end - - def logger - Rails.logger - end - - def log_prefix - "#{self.class} [#{namespace}]" - end - - def namespace - RailsMultisite::ConnectionManagement.current_db - end - - def synchronize - @mutex.synchronize { yield } - end -end - -module ActiveRecord - module ConnectionHandling - def postgresql_fallback_connection(config) - return postgresql_connection(config) if ARGV.include?("db:migrate") - fallback_handler = ::PostgreSQLFallbackHandler.instance - config = config.symbolize_keys - - if fallback_handler.master_down? - Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY) - fallback_handler.verify_master - connection = replica_postgresql_connection(config) - else - begin - connection = postgresql_connection(config) - fallback_handler.initialized ||= true - rescue ::ActiveRecord::NoDatabaseError, PG::ConnectionBad => e - fallback_handler.master_down - fallback_handler.verify_master - - if !fallback_handler.initialized - return postgresql_fallback_connection(config) - else - raise e - end - end - end - - connection - end - - def replica_postgresql_connection(config) - config = config.dup.merge( - host: config[:replica_host], - port: config[:replica_port] - ) - - connection = postgresql_connection(config) - verify_replica(connection) - connection - end - - private - - def verify_replica(connection) - value = connection.exec_query("SELECT pg_is_in_recovery()").rows[0][0] - raise "Replica database server is not in recovery mode." if !value - end - end -end diff --git a/lib/admin_confirmation.rb b/lib/admin_confirmation.rb index dc132b72f7..28f305b5ad 100644 --- a/lib/admin_confirmation.rb +++ b/lib/admin_confirmation.rb @@ -43,7 +43,7 @@ class AdminConfirmation end def self.exists_for?(user_id) - Discourse.redis.exists "admin-confirmation:#{user_id}" + Discourse.redis.exists? "admin-confirmation:#{user_id}" end def self.find_by_code(token) diff --git a/lib/backup_restore.rb b/lib/backup_restore.rb index 4d75734c27..5b18ef603b 100644 --- a/lib/backup_restore.rb +++ b/lib/backup_restore.rb @@ -82,6 +82,10 @@ module BackupRestore ActiveRecord::Migrator.current_version end + def self.postgresql_major_version + DB.query_single("SHOW server_version").first[/\d+/].to_i + end + def self.move_tables_between_schemas(source, destination) owner = database_configuration.username diff --git a/lib/backup_restore/database_restorer.rb b/lib/backup_restore/database_restorer.rb index 929e318a9f..9ccb6a5f15 100644 --- a/lib/backup_restore/database_restorer.rb +++ b/lib/backup_restore/database_restorer.rb @@ -95,7 +95,8 @@ module BackupRestore raise DatabaseRestoreError.new("psql failed: #{last_line}") if Process.last_status&.exitstatus != 0 end - # Removes unwanted SQL added by certain versions of pg_dump. + # Removes unwanted SQL added by certain versions of pg_dump and modifies + # the dump so that it works on the current version of PostgreSQL. def sed_command unwanted_sql = [ "DROP SCHEMA", # Discourse <= v1.5 @@ -104,11 +105,15 @@ module BackupRestore "SET default_table_access_method" # PostgreSQL 12 ].join("|") - "sed -E '/^(#{unwanted_sql})/d'" + command = "sed -E '/^(#{unwanted_sql})/d' #{@db_dump_path}" + if BackupRestore.postgresql_major_version < 11 + command = "#{command} | sed -E 's/^(CREATE TRIGGER.+EXECUTE) FUNCTION/\\1 PROCEDURE/'" + end + command end def restore_dump_command - "#{sed_command} #{@db_dump_path} | #{self.class.psql_command} 2>&1" + "#{sed_command} | #{self.class.psql_command} 2>&1" end def self.psql_command diff --git a/lib/backup_restore/s3_backup_store.rb b/lib/backup_restore/s3_backup_store.rb index 108cb661ba..359167b97c 100644 --- a/lib/backup_restore/s3_backup_store.rb +++ b/lib/backup_restore/s3_backup_store.rb @@ -53,9 +53,11 @@ module BackupRestore def vacate_legacy_prefix legacy_s3_helper = S3Helper.new(s3_bucket_name_with_legacy_prefix, '', @s3_options.clone) - legacy_keys = legacy_s3_helper.list.map { |o| o.key } + bucket, prefix = s3_bucket_name_with_prefix.split('/', 2) + legacy_keys = legacy_s3_helper.list + .reject { |o| o.key.starts_with? prefix } + .map { |o| o.key } legacy_keys.each do |legacy_key| - bucket, prefix = s3_bucket_name_with_prefix.split('/', 2) @s3_helper.s3_client.copy_object({ copy_source: File.join(bucket, legacy_key), bucket: bucket, diff --git a/lib/cache.rb b/lib/cache.rb index 9e76ea6eac..faae643f4c 100644 --- a/lib/cache.rb +++ b/lib/cache.rb @@ -56,7 +56,7 @@ class Cache def exist?(name) key = normalize_key(name) - redis.exists(key) + redis.exists?(key) end # this removes a bunch of stuff we do not need like instrumentation and versioning diff --git a/lib/discourse.rb b/lib/discourse.rb index 67ac64c297..bcdcecc800 100644 --- a/lib/discourse.rb +++ b/lib/discourse.rb @@ -428,19 +428,21 @@ module Discourse alias_method :base_url_no_path, :base_url_no_prefix end - READONLY_MODE_KEY_TTL ||= 60 - READONLY_MODE_KEY ||= 'readonly_mode' - PG_READONLY_MODE_KEY ||= 'readonly_mode:postgres' - USER_READONLY_MODE_KEY ||= 'readonly_mode:user' + READONLY_MODE_KEY_TTL ||= 60 + READONLY_MODE_KEY ||= 'readonly_mode' + PG_READONLY_MODE_KEY ||= 'readonly_mode:postgres' + USER_READONLY_MODE_KEY ||= 'readonly_mode:user' + PG_FORCE_READONLY_MODE_KEY ||= 'readonly_mode:postgres_force' READONLY_KEYS ||= [ READONLY_MODE_KEY, PG_READONLY_MODE_KEY, - USER_READONLY_MODE_KEY + USER_READONLY_MODE_KEY, + PG_FORCE_READONLY_MODE_KEY ] def self.enable_readonly_mode(key = READONLY_MODE_KEY) - if key == USER_READONLY_MODE_KEY + if key == USER_READONLY_MODE_KEY || key == PG_FORCE_READONLY_MODE_KEY Discourse.redis.set(key, 1) else Discourse.redis.setex(key, READONLY_MODE_KEY_TTL, 1) @@ -448,7 +450,6 @@ module Discourse end MessageBus.publish(readonly_channel, true) - Site.clear_anon_cache! true end @@ -484,12 +485,29 @@ module Discourse def self.disable_readonly_mode(key = READONLY_MODE_KEY) Discourse.redis.del(key) MessageBus.publish(readonly_channel, false) - Site.clear_anon_cache! + true + end + + def self.enable_pg_force_readonly_mode + RailsMultisite::ConnectionManagement.each_connection do + enable_readonly_mode(PG_FORCE_READONLY_MODE_KEY) + Sidekiq.pause!("pg_failover") if !Sidekiq.paused? + end + + true + end + + def self.disable_pg_force_readonly_mode + RailsMultisite::ConnectionManagement.each_connection do + disable_readonly_mode(PG_FORCE_READONLY_MODE_KEY) + Sidekiq.unpause! + end + true end def self.readonly_mode?(keys = READONLY_KEYS) - recently_readonly? || Discourse.redis.exists(*keys) + recently_readonly? || Discourse.redis.exists?(*keys) end def self.pg_readonly_mode? @@ -666,7 +684,7 @@ module Discourse Discourse.cache.reconnect Logster.store.redis.reconnect # shuts down all connections in the pool - Sidekiq.redis_pool.shutdown { |conn| conn.close } + Sidekiq.redis_pool.shutdown { |conn| conn.disconnect! } # re-establish Sidekiq.redis = sidekiq_redis_config @@ -745,7 +763,7 @@ module Discourse ) else # no logster ... fallback - Rails.logger.warn("#{message} #{e}") + Rails.logger.warn("#{message} #{e}\n#{e.backtrace.join("\n")}") end rescue STDERR.puts "Failed to report exception #{e} #{message}" diff --git a/lib/discourse_plugin_registry.rb b/lib/discourse_plugin_registry.rb index ab382a4d15..7383849661 100644 --- a/lib/discourse_plugin_registry.rb +++ b/lib/discourse_plugin_registry.rb @@ -66,6 +66,7 @@ class DiscoursePluginRegistry define_register :seed_path_builders, Set define_register :vendored_pretty_text, Set define_register :vendored_core_pretty_text, Set + define_register :seedfu_filter, Set define_filtered_register :staff_user_custom_fields define_filtered_register :public_user_custom_fields @@ -198,6 +199,10 @@ class DiscoursePluginRegistry result.uniq end + def self.register_seedfu_filter(filter = nil) + self.seedfu_filter << filter + end + VENDORED_CORE_PRETTY_TEXT_MAP = { "moment.js" => "vendor/assets/javascripts/moment.js", "moment-timezone.js" => "vendor/assets/javascripts/moment-timezone-with-data.js" diff --git a/lib/discourse_redis.rb b/lib/discourse_redis.rb index 096c86b574..33390d4ca6 100644 --- a/lib/discourse_redis.rb +++ b/lib/discourse_redis.rb @@ -5,141 +5,6 @@ # class DiscourseRedis - class FallbackHandler - include Singleton - - MASTER_ROLE_STATUS = "role:master" - MASTER_LOADING_STATUS = "loading:1" - MASTER_LOADED_STATUS = "loading:0" - CONNECTION_TYPES = %w{normal pubsub} - - def initialize - @master = true - @running = false - @mutex = Mutex.new - @slave_config = DiscourseRedis.slave_config - @message_bus_keepalive_interval = MessageBus.keepalive_interval - end - - def verify_master - synchronize do - return if @thread && @thread.alive? - - @thread = Thread.new do - loop do - begin - thread = Thread.new { initiate_fallback_to_master } - thread.join - break if synchronize { @master } - sleep 5 - ensure - thread.kill - end - end - end - end - end - - def initiate_fallback_to_master - success = false - - begin - redis_config = DiscourseRedis.config.dup - redis_config.delete(:connector) - master_client = ::Redis::Client.new(redis_config) - logger.warn "#{log_prefix}: Checking connection to master server..." - info = master_client.call([:info]) - - if info.include?(MASTER_LOADED_STATUS) && info.include?(MASTER_ROLE_STATUS) - begin - logger.warn "#{log_prefix}: Master server is active, killing all connections to slave..." - - self.master = true - slave_client = ::Redis::Client.new(@slave_config) - - CONNECTION_TYPES.each do |connection_type| - slave_client.call([:client, [:kill, 'type', connection_type]]) - end - - MessageBus.keepalive_interval = @message_bus_keepalive_interval - Discourse.clear_readonly! - Discourse.request_refresh! - success = true - ensure - slave_client&.disconnect - end - end - rescue => e - logger.warn "#{log_prefix}: Connection to Master server failed with '#{e.message}'" - ensure - master_client&.disconnect - end - - success - end - - def master - synchronize { @master } - end - - def master=(args) - synchronize do - @master = args - - # Disables MessageBus keepalive when Redis is in readonly mode - MessageBus.keepalive_interval = 0 if !@master - end - end - - private - - def synchronize - @mutex.synchronize { yield } - end - - def logger - Rails.logger - end - - def log_prefix - "#{self.class}" - end - end - - class Connector < Redis::Client::Connector - def initialize(options) - super(options) - @slave_options = DiscourseRedis.slave_config(options) - @fallback_handler = DiscourseRedis::FallbackHandler.instance - end - - def resolve(client = nil) - if !@fallback_handler.master - @fallback_handler.verify_master - return @slave_options - end - - begin - options = @options.dup - options.delete(:connector) - client ||= Redis::Client.new(options) - - loading = client.call([:info, :persistence]).include?( - DiscourseRedis::FallbackHandler::MASTER_LOADING_STATUS - ) - - loading ? @slave_options : @options - rescue Redis::ConnectionError, Redis::CannotConnectError, RuntimeError => ex - raise ex if ex.class == RuntimeError && ex.message != "Name or service not known" - @fallback_handler.master = false - @fallback_handler.verify_master - raise ex - ensure - client.disconnect - end - end - end - def self.raw_connection(config = nil) config ||= self.config Redis.new(config) @@ -149,20 +14,12 @@ class DiscourseRedis GlobalSetting.redis_config end - def self.slave_config(options = config) - options.dup.merge!(host: options[:slave_host], port: options[:slave_port]) - end - def initialize(config = nil, namespace: true) @config = config || DiscourseRedis.config @redis = DiscourseRedis.raw_connection(@config.dup) @namespace = namespace end - def self.fallback_handler - @fallback_handler ||= DiscourseRedis::FallbackHandler.instance - end - def without_namespace # Only use this if you want to store and fetch data that's shared between sites @redis @@ -172,10 +29,6 @@ class DiscourseRedis yield rescue Redis::CommandError => ex if ex.message =~ /READONLY/ - if !ENV["REDIS_RAILS_FAILOVER"] - fallback_handler.verify_master if !fallback_handler.master - end - Discourse.received_redis_readonly! nil else @@ -207,17 +60,14 @@ class DiscourseRedis end end - # Implement our own because https://github.com/redis/redis-rb/issues/698 has stalled - def exists(*keys) - keys.map! { |a| "#{namespace}:#{a}" } if @namespace + def exists(*args) + args.map! { |a| "#{namespace}:#{a}" } if @namespace + DiscourseRedis.ignore_readonly { @redis.exists(*args) } + end - DiscourseRedis.ignore_readonly do - @redis.synchronize do |client| - client.call([:exists, *keys]) do |value| - value > 0 - end - end - end + def exists?(*args) + args.map! { |a| "#{namespace}:#{a}" } if @namespace + DiscourseRedis.ignore_readonly { @redis.exists?(*args) } end def mget(*args) diff --git a/lib/email/sender.rb b/lib/email/sender.rb index 8cd3c613fd..df3d519c13 100644 --- a/lib/email/sender.rb +++ b/lib/email/sender.rb @@ -209,6 +209,8 @@ module Email email_log.message_id = @message.message_id + DiscourseEvent.trigger(:before_email_send, @message, @email_type) + begin @message.deliver_now rescue *SMTP_CLIENT_ERRORS => e diff --git a/lib/email_updater.rb b/lib/email_updater.rb index 23f0a5c09b..d615f7ba8a 100644 --- a/lib/email_updater.rb +++ b/lib/email_updater.rb @@ -38,7 +38,7 @@ class EmailUpdater if @guardian.is_staff? && @guardian.user != @user StaffActionLogger.new(@guardian.user).log_add_email(@user) else - UserHistory.create!(action: UserHistory.actions[:add_email], target_user_id: @user.id) + UserHistory.create!(action: UserHistory.actions[:add_email], acting_user_id: @user.id) end if @guardian.is_staff? && !@user.staff? @@ -54,7 +54,7 @@ class EmailUpdater change_req.new_email = email end - if change_req.change_state.blank? + if change_req.change_state.blank? || change_req.change_state == EmailChangeRequest.states[:complete] change_req.change_state = if @user.staff? # Staff users must confirm their old email address first. EmailChangeRequest.states[:authorizing_old] diff --git a/lib/file_store/base_store.rb b/lib/file_store/base_store.rb index 7d22640b13..504267ebf4 100644 --- a/lib/file_store/base_store.rb +++ b/lib/file_store/base_store.rb @@ -76,13 +76,13 @@ module FileStore not_implemented end - def download(upload) + def download(upload, max_file_size_kb: nil) DistributedMutex.synchronize("download_#{upload.sha1}", validity: 3.minutes) do filename = "#{upload.sha1}#{File.extname(upload.original_filename)}" file = get_from_cache(filename) if !file - max_file_size_kb = [SiteSetting.max_image_size_kb, SiteSetting.max_attachment_size_kb].max.kilobytes + max_file_size_kb ||= [SiteSetting.max_image_size_kb, SiteSetting.max_attachment_size_kb].max.kilobytes url = upload.secure? ? Discourse.store.signed_url_for_path(upload.url) : diff --git a/lib/file_store/s3_store.rb b/lib/file_store/s3_store.rb index 5007b741e8..ef4717f3f3 100644 --- a/lib/file_store/s3_store.rb +++ b/lib/file_store/s3_store.rb @@ -53,8 +53,16 @@ module FileStore cache_control: 'max-age=31556952, public, immutable', content_type: opts[:content_type].presence || MiniMime.lookup_by_filename(filename)&.content_type } - # add a "content disposition" header for "attachments" - options[:content_disposition] = "attachment; filename=\"#{filename}\"" unless FileHelper.is_supported_media?(filename) + + # add a "content disposition: attachment" header with the original filename + # for everything but images. audio and video will still stream correctly in + # HTML players, and when a direct link is provided to any file but an image + # it will download correctly in the browser. + if !FileHelper.is_supported_image?(filename) + options[:content_disposition] = ActionDispatch::Http::ContentDisposition.format( + disposition: "attachment", filename: filename + ) + end path.prepend(File.join(upload_path, "/")) if Rails.configuration.multisite @@ -80,7 +88,7 @@ module FileStore return false if url.blank? begin - parsed_url = URI.parse(URI.encode(url)) + parsed_url = URI.parse(UrlHelper.encode(url)) rescue URI::InvalidURIError, URI::InvalidComponentError return false end diff --git a/lib/file_store/to_s3_migration.rb b/lib/file_store/to_s3_migration.rb index 6f19f2d00f..0235375928 100644 --- a/lib/file_store/to_s3_migration.rb +++ b/lib/file_store/to_s3_migration.rb @@ -224,8 +224,9 @@ module FileStore upload = Upload.find_by(url: "/#{file}") if upload&.original_filename - options[:content_disposition] = - %Q{attachment; filename="#{upload.original_filename}"} + options[:content_disposition] = ActionDispatch::Http::ContentDisposition.format( + disposition: "attachment", filename: upload.original_filename + ) end if upload&.secure diff --git a/lib/freedom_patches/postgresql_adapter.rb b/lib/freedom_patches/postgresql_adapter.rb deleted file mode 100644 index c790461f93..0000000000 --- a/lib/freedom_patches/postgresql_adapter.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -# Awaiting decision on https://github.com/rails/rails/issues/31190 -if ENV['DISABLE_MIGRATION_ADVISORY_LOCK'] - class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter - def supports_advisory_locks? - false - end - end -end diff --git a/lib/freedom_patches/rails_multisite.rb b/lib/freedom_patches/rails_multisite.rb index c4627daa2a..35c6b82624 100644 --- a/lib/freedom_patches/rails_multisite.rb +++ b/lib/freedom_patches/rails_multisite.rb @@ -6,6 +6,22 @@ module RailsMultisite self.each_connection do |db| begin yield(db) if block_given? + rescue PG::ConnectionBad, PG::UnableToSend, PG::ServerError + break if !defined?(RailsFailover::ActiveRecord) + break if db == RailsMultisite::ConnectionManagement::DEFAULT + + reading_role = :"#{db}_#{ActiveRecord::Base.reading_role}" + spec = RailsMultisite::ConnectionManagement.connection_spec(db: db) + + ActiveRecord::Base.connection_handlers[reading_role] ||= begin + handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new + RailsFailover::ActiveRecord.establish_reading_connection(handler, spec) + handler + end + + ActiveRecord::Base.connected_to(role: reading_role) do + yield(db) if block_given? + end rescue => e STDERR.puts "URGENT: Failed to initialize site #{db}: "\ "#{e.class} #{e.message}\n#{e.backtrace.join("\n")}" diff --git a/lib/freedom_patches/zeitwerk.rb b/lib/freedom_patches/zeitwerk.rb index cf1ddc186d..92a066b833 100644 --- a/lib/freedom_patches/zeitwerk.rb +++ b/lib/freedom_patches/zeitwerk.rb @@ -9,7 +9,6 @@ module ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector 'onpdiff' => 'ONPDiff', 'onceoff' => 'Jobs', 'pop3_polling_enabled_setting_validator' => 'POP3PollingEnabledSettingValidator', - 'postgresql_fallback_adapter' => 'PostgreSQLFallbackHandler', 'regular' => 'Jobs', 'scheduled' => 'Jobs', 'topic_query_sql' => 'TopicQuerySQL', diff --git a/lib/guardian/post_guardian.rb b/lib/guardian/post_guardian.rb index 2bbc48f88f..d05296ef33 100644 --- a/lib/guardian/post_guardian.rb +++ b/lib/guardian/post_guardian.rb @@ -220,7 +220,7 @@ module PostGuardian end authenticated? && - (is_staff? || @user.has_trust_level?(TrustLevel[4]) || @user.id == post.user_id) && + (is_staff? || @user.id == post.user_id) && can_see_post?(post) end diff --git a/lib/guardian/topic_guardian.rb b/lib/guardian/topic_guardian.rb index e4df0a1cf2..842f44c0cf 100644 --- a/lib/guardian/topic_guardian.rb +++ b/lib/guardian/topic_guardian.rb @@ -5,6 +5,7 @@ module TopicGuardian def can_remove_allowed_users?(topic, target_user = nil) is_staff? || + (topic.user == @user && @user.has_trust_level?(TrustLevel[2])) || ( topic.allowed_users.count > 1 && topic.user != target_user && diff --git a/lib/inline_oneboxer.rb b/lib/inline_oneboxer.rb index edfd746562..26f3ecc9ba 100644 --- a/lib/inline_oneboxer.rb +++ b/lib/inline_oneboxer.rb @@ -13,7 +13,7 @@ class InlineOneboxer @urls.map { |url| InlineOneboxer.lookup(url, @opts) }.compact end - def self.purge(url) + def self.invalidate(url) Discourse.cache.delete(cache_key(url)) end @@ -65,14 +65,8 @@ class InlineOneboxer private def self.onebox_for(url, title, opts) - onebox = { - url: url, - title: title && Emoji.gsub_emoji_to_unicode(title) - } - unless opts[:skip_cache] - Discourse.cache.write(cache_key(url), onebox, expires_in: 1.day) - end - + onebox = { url: url, title: title && Emoji.gsub_emoji_to_unicode(title) } + Discourse.cache.write(cache_key(url), onebox, expires_in: 1.day) if !opts[:skip_cache] onebox end diff --git a/lib/middleware/request_tracker.rb b/lib/middleware/request_tracker.rb index 4fbe3d1b2a..a346b44112 100644 --- a/lib/middleware/request_tracker.rb +++ b/lib/middleware/request_tracker.rb @@ -145,7 +145,11 @@ class Middleware::RequestTracker def self.populate_request_queue_seconds!(env) if !env['REQUEST_QUEUE_SECONDS'] if queue_start = env['HTTP_X_REQUEST_START'] - queue_start = queue_start.split("t=")[1].to_f + queue_start = if queue_start.start_with?("t=") + queue_start.split("t=")[1].to_f + else + queue_start.to_f / 1000.0 + end queue_time = (Time.now.to_f - queue_start) env['REQUEST_QUEUE_SECONDS'] = queue_time end diff --git a/lib/oneboxer.rb b/lib/oneboxer.rb index d3625f19d8..107e6d0610 100644 --- a/lib/oneboxer.rb +++ b/lib/oneboxer.rb @@ -219,9 +219,7 @@ module Oneboxer end end - topic = Topic.find_by(id: route[:topic_id]) - - return unless topic + return unless topic = Topic.find_by(id: route[:id] || route[:topic_id]) return if topic.private_message? if current_category.blank? || current_category.id != topic.category_id @@ -315,7 +313,8 @@ module Oneboxer options = { max_width: 695, - sanitize_config: Onebox::DiscourseOneboxSanitizeConfig::Config::DISCOURSE_ONEBOX + sanitize_config: Onebox::DiscourseOneboxSanitizeConfig::Config::DISCOURSE_ONEBOX, + hostname: GlobalSetting.hostname, } options[:cookie] = fd.cookie if fd.cookie diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index 11f866f937..20419fe3ca 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -78,6 +78,10 @@ class Plugin::Instance @seed_data ||= HashWithIndifferentAccess.new({}) end + def seed_fu_filter(filter = nil) + @seed_fu_filter = filter + end + def self.find_all(parent_path) [].tap { |plugins| # also follows symlinks - http://stackoverflow.com/q/357754 @@ -415,6 +419,10 @@ class Plugin::Instance SeedFu.fixture_paths.concat(paths) end + def register_seedfu_filter(filter = nil) + DiscoursePluginRegistry.register_seedfu_filter(filter) + end + def listen_for(event_name) return unless self.respond_to?(event_name) DiscourseEvent.on(event_name, &self.method(event_name)) @@ -540,6 +548,9 @@ class Plugin::Instance if transpile_js DiscourseJsProcessor.plugin_transpile_paths << root_path.sub(Rails.root.to_s, '').sub(/^\/*/, '') DiscourseJsProcessor.plugin_transpile_paths << admin_path.sub(Rails.root.to_s, '').sub(/^\/*/, '') + + test_path = "#{root_dir_name}/test/javascripts" + DiscourseJsProcessor.plugin_transpile_paths << test_path.sub(Rails.root.to_s, '').sub(/^\/*/, '') end end diff --git a/lib/post_creator.rb b/lib/post_creator.rb index c3b9556df2..6a9e4ca873 100644 --- a/lib/post_creator.rb +++ b/lib/post_creator.rb @@ -96,7 +96,7 @@ class PostCreator end if @opts[:target_usernames].present? && !skip_validations? && !@user.staff? - names = @opts[:target_usernames].split(',') + names = @opts[:target_usernames].split(',').flatten.map(&:downcase) # Make sure max_allowed_message_recipients setting is respected max_allowed_message_recipients = SiteSetting.max_allowed_message_recipients @@ -111,7 +111,7 @@ class PostCreator end # Make sure none of the users have muted the creator - users = User.where(username: names).pluck(:id, :username).to_h + users = User.where(username_lower: names).pluck(:id, :username).to_h User .joins("LEFT JOIN user_options ON user_options.user_id = users.id") diff --git a/lib/pretty_text/helpers.rb b/lib/pretty_text/helpers.rb index d207e01eed..9633a4e8ea 100644 --- a/lib/pretty_text/helpers.rb +++ b/lib/pretty_text/helpers.rb @@ -41,7 +41,7 @@ module PrettyText def category_hashtag_lookup(category_slug) if category = Category.query_from_hashtag_slug(category_slug) - [category.url_with_id, category_slug] + [category.url, category_slug] else nil end @@ -106,7 +106,7 @@ module PrettyText is_tag = text =~ /#{tag_postfix}$/ if !is_tag && category = Category.query_from_hashtag_slug(text) - [category.url_with_id, text] + [category.url, text] elsif (!is_tag && tag = Tag.find_by(name: text)) || (is_tag && tag = Tag.find_by(name: text.gsub!("#{tag_postfix}", ''))) ["#{Discourse.base_url}/tag/#{tag.name}", text] diff --git a/lib/promotion.rb b/lib/promotion.rb index d96b304d5a..c39d13f44f 100644 --- a/lib/promotion.rb +++ b/lib/promotion.rb @@ -126,8 +126,8 @@ class Promotion # Then consider the group locked level user_group_granted_trust_level = user.group_granted_trust_level - unless user_group_granted_trust_level.blank? - return user.update!( + if user_group_granted_trust_level.present? + return user.update( trust_level: user_group_granted_trust_level ) end diff --git a/lib/rate_limiter.rb b/lib/rate_limiter.rb index 091eea3c28..7f3094e11a 100644 --- a/lib/rate_limiter.rb +++ b/lib/rate_limiter.rb @@ -102,6 +102,12 @@ class RateLimiter def rollback! return if RateLimiter.disabled? redis.lpop(prefixed_key) + rescue Redis::CommandError => e + if e.message =~ /READONLY/ + # TODO,switch to in-memory rate limiter + else + raise + end end def remaining diff --git a/lib/shrink_uploaded_image.rb b/lib/shrink_uploaded_image.rb new file mode 100644 index 0000000000..e5f57eb883 --- /dev/null +++ b/lib/shrink_uploaded_image.rb @@ -0,0 +1,236 @@ +# frozen_string_literal: true + +class ShrinkUploadedImage + attr_reader :upload, :path + + def initialize(upload:, path:, max_pixels:, verbose: false, interactive: false) + @upload = upload + @path = path + @max_pixels = max_pixels + @verbose = verbose + @interactive = interactive + end + + def perform + OptimizedImage.downsize(path, path, "#{@max_pixels}@", filename: upload.original_filename) + sha1 = Upload.generate_digest(path) + + if sha1 == upload.sha1 + log "No sha1 change" + return false + end + + w, h = FastImage.size(path, timeout: 15, raise_on_failure: true) + + if !w || !h + log "Invalid image dimensions after resizing" + return false + end + + # Neither #dup or #clone provide a complete copy + original_upload = Upload.find(upload.id) + ww, hh = ImageSizer.resize(w, h) + + # A different upload record that matches the sha1 of the downsized image + existing_upload = Upload.find_by(sha1: sha1) + @upload = existing_upload if existing_upload + + upload.attributes = { + sha1: sha1, + width: w, + height: h, + thumbnail_width: ww, + thumbnail_height: hh, + filesize: File.size(path) + } + + if upload.filesize > upload.filesize_was + log "No filesize reduction" + return false + end + + unless existing_upload + url = Discourse.store.store_upload(File.new(path), upload) + + unless url + log "Couldn't store the upload" + return false + end + + upload.url = url + end + + log "base62: #{original_upload.base62_sha1} -> #{Upload.base62_sha1(sha1)}" + log "sha: #{original_upload.sha1} -> #{sha1}" + log "(an exisiting upload)" if existing_upload + + success = true + posts = Post.unscoped.joins(:post_uploads).where(post_uploads: { upload_id: original_upload.id }).uniq.sort_by(&:created_at) + + posts.each do |post| + transform_post(post, original_upload, upload) + + if post.custom_fields[Post::DOWNLOADED_IMAGES].present? + downloaded_images = JSON.parse(post.custom_fields[Post::DOWNLOADED_IMAGES]) + end + + if post.raw_changed? + log "Updating post" + elsif downloaded_images&.has_value?(original_upload.id) + log "A hotlinked, unreferenced image" + elsif post.raw.include?(upload.short_url) + log "Already processed" + elsif post.trashed? + log "A deleted post" + elsif !post.topic || post.topic.trashed? + log "A deleted topic" + elsif post.cooked.include?(original_upload.sha1) + if post.raw.include?("#{Discourse.base_url.sub(/^https?:\/\//i, "")}/t/") + log "Updating a topic onebox" + else + log "Updating an external onebox" + end + else + log "Could not find the upload URL" + success = false + end + + log "#{Discourse.base_url}/p/#{post.id}" + end + + if posts.empty? + log "Upload not used in any posts" + + if User.where(uploaded_avatar_id: original_upload.id).exists? + log "Used as a User avatar" + elsif UserAvatar.where(gravatar_upload_id: original_upload.id).exists? + log "Used as a UserAvatar gravatar" + elsif UserAvatar.where(custom_upload_id: original_upload.id).exists? + log "Used as a UserAvatar custom upload" + elsif UserProfile.where(profile_background_upload_id: original_upload.id).exists? + log "Used as a UserProfile profile background" + elsif UserProfile.where(card_background_upload_id: original_upload.id).exists? + log "Used as a UserProfile card background" + elsif Category.where(uploaded_logo_id: original_upload.id).exists? + log "Used as a Category logo" + elsif Category.where(uploaded_background_id: original_upload.id).exists? + log "Used as a Category background" + elsif CustomEmoji.where(upload_id: original_upload.id).exists? + log "Used as a CustomEmoji" + elsif ThemeField.where(upload_id: original_upload.id).exists? + log "Used as a ThemeField" + else + success = false + end + end + + unless success + if @interactive + print "Press any key to continue with the upload" + STDIN.beep + STDIN.getch + puts " k" + else + if !existing_upload && !Upload.where(url: upload.url).exists? + # We're bailing, so clean up the just uploaded file + Discourse.store.remove_upload(upload) + end + + log "⏩ Skipping" + return false + end + end + + unless upload.save + if !existing_upload && !Upload.where(url: upload.url).exists? + # We're bailing, so clean up the just uploaded file + Discourse.store.remove_upload(upload) + end + + log "⏩ Skipping an invalid upload" + return false + end + + if existing_upload + begin + PostUpload.where(upload_id: original_upload.id).update_all(upload_id: upload.id) + rescue ActiveRecord::RecordNotUnique, PG::UniqueViolation + end + + User.where(uploaded_avatar_id: original_upload.id).update_all(uploaded_avatar_id: upload.id) + UserAvatar.where(gravatar_upload_id: original_upload.id).update_all(gravatar_upload_id: upload.id) + UserAvatar.where(custom_upload_id: original_upload.id).update_all(custom_upload_id: upload.id) + UserProfile.where(profile_background_upload_id: original_upload.id).update_all(profile_background_upload_id: upload.id) + UserProfile.where(card_background_upload_id: original_upload.id).update_all(card_background_upload_id: upload.id) + Category.where(uploaded_logo_id: original_upload.id).update_all(uploaded_logo_id: upload.id) + Category.where(uploaded_background_id: original_upload.id).update_all(uploaded_background_id: upload.id) + CustomEmoji.where(upload_id: original_upload.id).update_all(upload_id: upload.id) + ThemeField.where(upload_id: original_upload.id).update_all(upload_id: upload.id) + else + upload.optimized_images.each(&:destroy!) + end + + posts.each do |post| + DistributedMutex.synchronize("process_post_#{post.id}") do + current_post = Post.unscoped.find(post.id) + + # If the post became outdated, reapply changes + if current_post.updated_at != post.updated_at + transform_post(current_post, original_upload, upload) + post = current_post + end + + if post.raw_changed? + post.update_columns( + raw: post.raw, + updated_at: Time.zone.now + ) + end + + if existing_upload && post.custom_fields[Post::DOWNLOADED_IMAGES].present? + downloaded_images = JSON.parse(post.custom_fields[Post::DOWNLOADED_IMAGES]) + + downloaded_images.transform_values! do |upload_id| + upload_id == original_upload.id ? upload.id : upload_id + end + + post.custom_fields[Post::DOWNLOADED_IMAGES] = downloaded_images.to_json if downloaded_images.present? + post.save_custom_fields + end + + post.rebake! + end + end + + if existing_upload + original_upload.reload.destroy! + else + Discourse.store.remove_upload(original_upload) + end + + true + end + + private + + def transform_post(post, upload_before, upload_after) + post.raw.gsub!(/upload:\/\/#{upload_before.base62_sha1}(\.#{upload_before.extension})?/i, upload_after.short_url) + post.raw.gsub!(Discourse.store.cdn_url(upload_before.url), Discourse.store.cdn_url(upload_after.url)) + post.raw.gsub!("#{Discourse.base_url}#{upload_before.short_path}", "#{Discourse.base_url}#{upload_after.short_path}") + + if SiteSetting.enable_s3_uploads + post.raw.gsub!(Discourse.store.url_for(upload_before), Discourse.store.url_for(upload_after)) + + path = SiteSetting.Upload.s3_upload_bucket.split("/", 2)[1] + post.raw.gsub!(/\d+)x(?\d+).*?\" alt=\"(?.*?)\"\/?>/i) do + "![#{$~[:alt]}|#{$~[:width]}x#{$~[:height]}](#{upload_after.short_url})" + end + end + + post.raw.gsub!(/!\[(.*?)\]\(\/uploads\/.+?\/#{upload_before.sha1}(\.#{upload_before.extension})?\)/i, "![\\1](#{upload_after.short_url})") + end + + def log(*args) + puts(*args) if @verbose + end +end diff --git a/lib/site_settings/deprecated_settings.rb b/lib/site_settings/deprecated_settings.rb index 9eaa03f1a5..a414c7ef91 100644 --- a/lib/site_settings/deprecated_settings.rb +++ b/lib/site_settings/deprecated_settings.rb @@ -4,16 +4,6 @@ module SiteSettings; end module SiteSettings::DeprecatedSettings SETTINGS = [ - ['logo_url', 'logo', false, '2.3'], - ['logo_small_url', 'logo_small', false, '2.3'], - ['digest_logo_url', 'digest_logo', false, '2.3'], - ['mobile_logo_url', 'mobile_logo', false, '2.3'], - ['large_icon_url', 'large_icon', false, '2.3'], - ['favicon_url', 'favicon', false, '2.3'], - ['apple_touch_icon_url', 'apple_touch_icon', false, '2.3'], - ['default_opengraph_image_url', 'opengraph_image', false, '2.3'], - ['twitter_summary_large_image_url', 'twitter_summary_large_image', false, '2.3'], - ['push_notifications_icon_url', 'push_notifications_icon', false, '2.3'], ['show_email_on_profile', 'moderators_view_emails', true, '2.4'], ['allow_moderators_to_create_categories', 'moderators_create_categories', true, '2.4'], ['disable_edit_notifications', 'disable_system_edit_notifications', true, '2.4'] diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake index 67788e3cf8..87a32da0c5 100644 --- a/lib/tasks/assets.rake +++ b/lib/tasks/assets.rake @@ -68,6 +68,14 @@ task 'assets:precompile:css' => 'environment' do end end +task 'assets:flush_sw' => 'environment' do + begin + # Pending due to test failures. + rescue + STDERR.puts "Warning: unable to flush service worker script" + end +end + def assets_path "#{Rails.root}/public/assets" end diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index 5a6c67c918..4e5469db40 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -107,48 +107,63 @@ task 'multisite:migrate' => ['db:load_config', 'environment', 'set_locale'] do | puts "Multisite migrator is running using #{concurrency} threads" puts - queue = Queue.new exceptions = Queue.new old_stdout = $stdout $stdout = StdOutDemux.new($stdout) - RailsMultisite::ConnectionManagement.each_connection do |db| - queue << db - end - - concurrency.times { queue << :done } - SeedFu.quiet = true - (1..concurrency).map do - Thread.new { - while true - db = queue.pop - break if db == :done + def execute_concurently(concurrency, exceptions) + queue = Queue.new - RailsMultisite::ConnectionManagement.with_connection(db) do - begin - puts "Migrating #{db}" - ActiveRecord::Tasks::DatabaseTasks.migrate - SeedFu.seed(DiscoursePluginRegistry.seed_paths) - if !Discourse.skip_post_deployment_migrations? && ENV['SKIP_OPTIMIZE_ICONS'] != '1' - SiteIconManager.ensure_optimized! - end - rescue => e - exceptions << [db, e] - ensure + RailsMultisite::ConnectionManagement.each_connection do |db| + queue << db + end + + concurrency.times { queue << :done } + + (1..concurrency).map do + Thread.new { + while true + db = queue.pop + break if db == :done + + RailsMultisite::ConnectionManagement.with_connection(db) do begin - $stdout.finish_chunk - rescue => ex - STDERR.puts ex.inspect - STDERR.puts ex.backtrace + yield(db) if block_given? + rescue => e + exceptions << [db, e] + ensure + begin + $stdout.finish_chunk + rescue => ex + STDERR.puts ex.inspect + STDERR.puts ex.backtrace + end end end end - end - } - end.each(&:join) + } + end.each(&:join) + end + + execute_concurently(concurrency, exceptions) do |db| + puts "Migrating #{db}" + ActiveRecord::Tasks::DatabaseTasks.migrate + end + + seed_paths = DiscoursePluginRegistry.seed_paths + SeedFu.seed(seed_paths, /001_refresh/) + + execute_concurently(concurrency, exceptions) do |db| + puts "Seeding #{db}" + SeedFu.seed(seed_paths) + + if !Discourse.skip_post_deployment_migrations? && ENV['SKIP_OPTIMIZE_ICONS'] != '1' + SiteIconManager.ensure_optimized! + end + end $stdout = old_stdout @@ -172,6 +187,12 @@ end # we need to run seed_fu every time we run rake db:migrate task 'db:migrate' => ['load_config', 'environment', 'set_locale'] do |_, args| + migrations = ActiveRecord::Base.connection.migration_context.migrations + now_timestamp = Time.now.utc.strftime('%Y%m%d%H%M%S').to_i + epoch_timestamp = Time.at(0).utc.strftime('%Y%m%d%H%M%S').to_i + + raise "Migration #{migrations.last.version} is timestamped in the future" if migrations.last.version > now_timestamp + raise "Migration #{migrations.first.version} is timestamped before the epoch" if migrations.first.version < epoch_timestamp ActiveRecord::Tasks::DatabaseTasks.migrate @@ -180,7 +201,12 @@ task 'db:migrate' => ['load_config', 'environment', 'set_locale'] do |_, args| end SeedFu.quiet = true - SeedFu.seed(DiscoursePluginRegistry.seed_paths) + + # Allows a plugin to exclude any specified seed data files from running + filter = DiscoursePluginRegistry.seedfu_filter.any? ? + /^(?!.*(#{DiscoursePluginRegistry.seedfu_filter.to_a.join("|")})).*$/ : nil + + SeedFu.seed(DiscoursePluginRegistry.seed_paths, filter) if !Discourse.skip_post_deployment_migrations? && ENV['SKIP_OPTIMIZE_ICONS'] != '1' SiteIconManager.ensure_optimized! diff --git a/lib/topic_view.rb b/lib/topic_view.rb index 42405f8e33..0ab7c7f060 100644 --- a/lib/topic_view.rb +++ b/lib/topic_view.rb @@ -546,7 +546,7 @@ class TopicView columns = [:id] if !is_mega_topic? - columns << 'EXTRACT(DAYS FROM CURRENT_TIMESTAMP - created_at)::INT AS days_ago' + columns << 'EXTRACT(DAYS FROM CURRENT_TIMESTAMP - posts.created_at)::INT AS days_ago' end posts.pluck(*columns) diff --git a/lib/turbo_tests/json_rows_formatter.rb b/lib/turbo_tests/json_rows_formatter.rb index c83ee32ce7..453edd4264 100644 --- a/lib/turbo_tests/json_rows_formatter.rb +++ b/lib/turbo_tests/json_rows_formatter.rb @@ -9,6 +9,7 @@ module TurboTests :example_failed, :example_passed, :example_pending, + :message, :seed ) @@ -95,6 +96,13 @@ module TurboTests ) end + def message(notification) + output_row( + type: :message, + message: notification.message + ) + end + private def output_row(obj) diff --git a/lib/turbo_tests/reporter.rb b/lib/turbo_tests/reporter.rb index 62a3db2e48..6d02a1fb58 100644 --- a/lib/turbo_tests/reporter.rb +++ b/lib/turbo_tests/reporter.rb @@ -27,6 +27,8 @@ module TurboTests @failed_examples = [] @all_examples = [] @start_time = start_time + @messages = [] + @errors_outside_of_examples_count = 0 end def add(name, outputs) @@ -63,6 +65,15 @@ module TurboTests @failed_examples << example end + def message(message) + delegate_to_formatters(:message, RSpec::Core::Notifications::MessageNotification.new(message)) + @messages << message + end + + def error_outside_of_examples + @errors_outside_of_examples_count += 1 + end + def finish end_time = Time.now @@ -86,7 +97,7 @@ module TurboTests @failed_examples, @pending_examples, 0, - 0 + @errors_outside_of_examples_count ) ) delegate_to_formatters(:close, diff --git a/lib/turbo_tests/runner.rb b/lib/turbo_tests/runner.rb index 89ba1bdbed..808e18a28e 100644 --- a/lib/turbo_tests/runner.rb +++ b/lib/turbo_tests/runner.rb @@ -32,6 +32,7 @@ module TurboTests @messages = Queue.new @threads = [] + @error = false end def run @@ -73,7 +74,7 @@ module TurboTests @threads.each(&:join) - @reporter.failed_examples.empty? + @reporter.failed_examples.empty? && !@error end protected @@ -87,11 +88,14 @@ module TurboTests ActiveRecord::Tasks::DatabaseTasks.migrations_paths = ['db/migrate', 'db/post_migrate'] conn = ActiveRecord::Base.establish_connection(config).connection + begin ActiveRecord::Migration.check_pending!(conn) rescue ActiveRecord::PendingMigrationError puts "There are pending migrations, run rake parallel:migrate" exit 1 + ensure + conn.close end end @@ -168,7 +172,8 @@ module TurboTests STDERR.puts "Process #{process_id}: #{command_str}" end - _stdin, stdout, stderr, _wait_thr = Open3.popen3(env, *command) + stdin, stdout, stderr, wait_thr = Open3.popen3(env, *command) + stdin.close @threads << Thread.new do @@ -186,6 +191,12 @@ module TurboTests @threads << start_copy_thread(stdout, STDOUT) @threads << start_copy_thread(stderr, STDERR) + + @threads << Thread.new do + if wait_thr.value.exitstatus != 0 + @messages << { type: 'error' } + end + end end end @@ -195,6 +206,7 @@ module TurboTests begin msg = src.readpartial(4096) rescue EOFError + src.close break else dst.write(msg) @@ -224,8 +236,13 @@ module TurboTests @threads.each(&:kill) break end + when 'message' + @reporter.message(message[:message]) when 'seed' when 'close' + when 'error' + @reporter.error_outside_of_examples + @error = true when 'exit' exited += 1 if exited == @num_processes + 1 diff --git a/lib/upload_creator.rb b/lib/upload_creator.rb index b806e2fc52..caaacb0a74 100644 --- a/lib/upload_creator.rb +++ b/lib/upload_creator.rb @@ -34,14 +34,14 @@ class UploadCreator return @upload end + @image_info = FastImage.new(@file) rescue nil + is_image = FileHelper.is_supported_image?(@filename) + is_image ||= @image_info && FileHelper.is_supported_image?("test.#{@image_info.type}") + is_image = false if @opts[:for_theme] + + DiscourseEvent.trigger(:before_upload_creation, @file, is_image) + DistributedMutex.synchronize("upload_#{user_id}_#{@filename}") do - # test for image regardless of input - @image_info = FastImage.new(@file) rescue nil - - is_image = FileHelper.is_supported_image?(@filename) - is_image ||= @image_info && FileHelper.is_supported_image?("test.#{@image_info.type}") - is_image = false if @opts[:for_theme] - if is_image extract_image_info! return @upload if @upload.errors.present? diff --git a/lib/validators/selectable_avatars_enabled_validator.rb b/lib/validators/selectable_avatars_enabled_validator.rb new file mode 100644 index 0000000000..065c5bcf98 --- /dev/null +++ b/lib/validators/selectable_avatars_enabled_validator.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class SelectableAvatarsEnabledValidator + def initialize(opts = {}) + @opts = opts + end + + def valid_value?(value) + value == "f" || SiteSetting.selectable_avatars.split("\n").size > 1 + end + + def error_message + I18n.t('site_settings.errors.empty_selectable_avatars') + end +end diff --git a/lib/validators/unique_among_validator.rb b/lib/validators/unique_among_validator.rb index 82fed5c206..ed3d142014 100644 --- a/lib/validators/unique_among_validator.rb +++ b/lib/validators/unique_among_validator.rb @@ -12,7 +12,7 @@ class UniqueAmongValidator < ActiveRecord::Validations::UniquenessValidator # do nothing further unless there were some duplicates. unless new_errors == 0 # now look only in the collection we care about. - dupes = options[:collection].call.where("lower(#{attribute}) = ?", value.downcase) + dupes = options[:collection].call(record).where("lower(#{attribute}) = ?", value.downcase) dupes = dupes.where("id != ?", record.id) if record.persisted? # pop off the error, if it was a false positive diff --git a/lib/version.rb b/lib/version.rb index 6391eb0973..ab83043a00 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -7,9 +7,9 @@ module Discourse unless defined? ::Discourse::VERSION module VERSION #:nodoc: MAJOR = 2 - MINOR = 5 + MINOR = 6 TINY = 0 - PRE = 'beta7' + PRE = 'beta1' 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 78773e8d43..65e7eb3d56 100644 --- a/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 +++ b/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 @@ -1,3 +1,4 @@ +import I18n from "I18n"; import { withPluginApi } from "discourse/lib/plugin-api"; function initializeDetails(api) { diff --git a/plugins/discourse-details/config/locales/client.gl.yml b/plugins/discourse-details/config/locales/client.gl.yml index b56d5594d2..b5ed2e2977 100644 --- a/plugins/discourse-details/config/locales/client.gl.yml +++ b/plugins/discourse-details/config/locales/client.gl.yml @@ -7,5 +7,8 @@ gl: js: + details: + title: Agochar detalles composer: details_title: Resumo + details_text: "Este texto será ocultado" diff --git a/plugins/discourse-details/config/locales/server.pt.yml b/plugins/discourse-details/config/locales/server.pt.yml index d12527a51f..8ed231c890 100644 --- a/plugins/discourse-details/config/locales/server.pt.yml +++ b/plugins/discourse-details/config/locales/server.pt.yml @@ -5,4 +5,8 @@ # To work with us on translations, join this project: # https://www.transifex.com/projects/p/discourse-org/ -pt: {} +pt: + site_settings: + details_enabled: 'Ative a funcionalidade de detalhes. Se alterar isto, deve refazer todas as publicações com: "rake posts:rebake".' + details: + excerpt_details: "(clique para mais detalhes)" diff --git a/plugins/discourse-local-dates/assets/javascripts/discourse/components/discourse-local-dates-create-form.js.es6 b/plugins/discourse-local-dates/assets/javascripts/discourse/components/discourse-local-dates-create-form.js.es6 index 0ba26c48b4..dd4050ee71 100644 --- a/plugins/discourse-local-dates/assets/javascripts/discourse/components/discourse-local-dates-create-form.js.es6 +++ b/plugins/discourse-local-dates/assets/javascripts/discourse/components/discourse-local-dates-create-form.js.es6 @@ -1,3 +1,4 @@ +import I18n from "I18n"; import EmberObject from "@ember/object"; import { isEmpty } from "@ember/utils"; import { schedule } from "@ember/runloop"; diff --git a/plugins/discourse-local-dates/assets/javascripts/lib/local-date-builder.js.es6 b/plugins/discourse-local-dates/assets/javascripts/lib/local-date-builder.js.es6 index 7c4dd7862f..63a9a88478 100644 --- a/plugins/discourse-local-dates/assets/javascripts/lib/local-date-builder.js.es6 +++ b/plugins/discourse-local-dates/assets/javascripts/lib/local-date-builder.js.es6 @@ -1,3 +1,4 @@ +import I18n from "I18n"; import DateWithZoneHelper from "./date-with-zone-helper"; const TIME_FORMAT = "LLL"; diff --git a/plugins/discourse-local-dates/config/locales/client.gl.yml b/plugins/discourse-local-dates/config/locales/client.gl.yml index b6f51baf33..8e0a79bec3 100644 --- a/plugins/discourse-local-dates/config/locales/client.gl.yml +++ b/plugins/discourse-local-dates/config/locales/client.gl.yml @@ -8,7 +8,32 @@ gl: js: discourse_local_dates: + relative_dates: + today: Hoxe %{time} + tomorrow: Mañá %{time} + yesterday: Onte %{time} + countdown: + passed: superouse a data + title: Inserir data e hora create: form: + insert: Inserir + advanced_mode: Modo avanzado + simple_mode: Modo simple + recurring_title: Periodicidade + recurring_none: Sen periodicidade + invalid_date: Data non válida; asegúrate de que data e hora son correctas date_title: Data time_title: Hora + format_title: Formato da data + timezone: Fuso horario + until: Ata... + recurring: + every_day: "Todos os días" + every_week: "Todas as semanas" + every_two_weeks: "Cada dúas semanas" + every_month: "Todos os meses" + every_two_months: "Cada dous meses" + every_three_months: "Cada tres meses" + every_six_months: "Cada seis meses" + every_year: "Todos os anos" diff --git a/plugins/discourse-local-dates/config/locales/client.th.yml b/plugins/discourse-local-dates/config/locales/client.th.yml index 0533e81677..27b39a9789 100644 --- a/plugins/discourse-local-dates/config/locales/client.th.yml +++ b/plugins/discourse-local-dates/config/locales/client.th.yml @@ -20,3 +20,4 @@ th: date_title: วันที่ time_title: เวลา format_title: รูปแบบวันที่ + timezone: เขตเวลา diff --git a/plugins/discourse-local-dates/config/locales/server.pt.yml b/plugins/discourse-local-dates/config/locales/server.pt.yml index d12527a51f..5eb697405b 100644 --- a/plugins/discourse-local-dates/config/locales/server.pt.yml +++ b/plugins/discourse-local-dates/config/locales/server.pt.yml @@ -5,4 +5,7 @@ # To work with us on translations, join this project: # https://www.transifex.com/projects/p/discourse-org/ -pt: {} +pt: + site_settings: + discourse_local_dates_default_timezones: "A lista das zonas horárias predefinida, deve ser TZ válido" + discourse_local_dates_email_format: "O formato utilizado para exibir uma data nas mensagens." diff --git a/plugins/discourse-narrative-bot/config/locales/client.gl.yml b/plugins/discourse-narrative-bot/config/locales/client.gl.yml index e1d3372343..381b7453fe 100644 --- a/plugins/discourse-narrative-bot/config/locales/client.gl.yml +++ b/plugins/discourse-narrative-bot/config/locales/client.gl.yml @@ -9,5 +9,5 @@ gl: js: discourse_narrative_bot: welcome_post_type: - new_user_track: "Comeze o tutorial de novo usuario para todo-los usuarios novos" - welcome_message: "Envíe unha mensaxe de benvida a todo-los usuarios cunha guía de inicio" + new_user_track: "Comezar o novo titorial de usuario para todos os usuarios novos" + welcome_message: "Enviar unha mensaxe de benvida a todos os novos usuarios cunha guía de inicio" diff --git a/plugins/discourse-narrative-bot/config/locales/server.fr.yml b/plugins/discourse-narrative-bot/config/locales/server.fr.yml index 82281e769b..1610cb87c7 100644 --- a/plugins/discourse-narrative-bot/config/locales/server.fr.yml +++ b/plugins/discourse-narrative-bot/config/locales/server.fr.yml @@ -120,7 +120,7 @@ fr: help_trigger: "afficher l'aide" random_mention: reply: |- - Bonjour ! Pour voir ce que je peux faire, dites `@%{discobot_username} `. + Bonjour ! Pour voir ce que je peux faire, dites `@%{discobot_username} %{help_trigger}`. tracks: |- Pour le moment, je sais faire les choses suivantes : @@ -426,7 +426,7 @@ fr: [/details] ``` reply: |- - Bau travail — votre attention aux _détails_ est admirable ! + Beau travail — votre attention aux _détails_ est admirable ! end: message: |- Vous avez suivis ce tutoriel comme un _utiliser avancé_ :bow: diff --git a/plugins/discourse-narrative-bot/config/locales/server.pt.yml b/plugins/discourse-narrative-bot/config/locales/server.pt.yml index ca1df66247..49dfd5aa76 100644 --- a/plugins/discourse-narrative-bot/config/locales/server.pt.yml +++ b/plugins/discourse-narrative-bot/config/locales/server.pt.yml @@ -7,11 +7,11 @@ pt: site_settings: - discourse_narrative_bot_enabled: "Activar o bot do Discourse (discobot)" + discourse_narrative_bot_enabled: "Ativar Discourse Narrative Bot (discobot)" disable_discourse_narrative_bot_welcome_post: "Desativar a publicação de boas-vindas do Discourse Narrative Bot" discourse_narrative_bot_ignored_usernames: "Nomes de utilizador que o Discourse Narrative Bot deverá ignorar" discourse_narrative_bot_disable_public_replies: "Desativar as respostas públicas do Discourse Narrative Bot" - discourse_narrative_bot_welcome_post_type: "O tipo de publicação de boas-vindas que \"Discourse Narrative Bot\" deverá enviar" + discourse_narrative_bot_welcome_post_type: "O tipo de publicação de boas-vindas que Discourse Narrative Bot deverá enviar" discourse_narrative_bot_welcome_post_delay: "Aguardar (n) segundos antes de enviar a publicação de boas-vindas do Discurso Narrativa Bot." badges: certified: @@ -26,7 +26,9 @@ pt: bio: "Olá. Não sou humano. Sou um bot que pode ensiná-lo acerca deste sítio. Para interagir comigo, envie-me uma mensagem ou mencione-me %{discobot_username} em qualquer lado." dice: not_enough_dice: |- - Só tenho %{num_of_dice} dado. [Vergonhoso] http://www.therobotsvoice.com/2009/04/the_10_most_shameful_rpg_dice.php), bem sei! + Eu tenho apenas %{num_of_dice} dado. [Vergonhoso] http://www.therobotsvoice.com/2009/04/the_10_most_shameful_rpg_dice.php), eu sei! + results: |- + > :game_die: %{results} quote: '1': quote: "Entre cada dificuldade há espaço para oportunidade." @@ -45,7 +47,7 @@ pt: '6': author: "A mãe de Forrest Gump" '7': - quote: "Isto é um pequeno passo para o homem, um gigantesco para a humanidade." + quote: "Isto é um pequeno passo para o homem, um salto gigantesco para a humanidade." author: "Neil Armstrong" '8': author: "Eleanor Roosevelt" @@ -65,9 +67,11 @@ pt: '9': "Sim" '12': "Perguntar novamente mais tarde" '13': "É melhor não lhe dizer agora" + '14': "Não pode prever agora" '15': "Concentre-se e pergunte novamente" '17': "A minha resposta é não" '18': "As minhas fontes dizem não" + '20': "Muito duvidoso" result: |- > :crystal_ball: %{result} track_selector: @@ -79,6 +83,8 @@ pt: alt: "Certificado de Realização" advanced_user_narrative: title: ":arrow_up: Funcionalidades de utilizador avançadas" + recover: + deleted_post_raw: "Por que é que @ %{discobot_username} eliminou a minha publicação? :angustiado:" details: reply: |- Ótimo trabalho — a sua atenção para o _detalhe_ é admirável! diff --git a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb index 52f1cdab65..bd6bb02e49 100644 --- a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb +++ b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb @@ -41,7 +41,7 @@ module DiscourseNarrativeBot tutorial_recover: { next_state: :tutorial_category_hashtag, next_instructions: Proc.new do - category = Category.secured.last + category = Category.secured(Guardian.new(@user)).last slug = category.slug if parent_category = category.parent_category diff --git a/plugins/discourse-narrative-bot/spec/lib/certificate_generator_spec.rb b/plugins/discourse-narrative-bot/spec/lib/certificate_generator_spec.rb index 991cd082b3..3db82162e9 100644 --- a/plugins/discourse-narrative-bot/spec/lib/certificate_generator_spec.rb +++ b/plugins/discourse-narrative-bot/spec/lib/certificate_generator_spec.rb @@ -17,7 +17,6 @@ RSpec.describe DiscourseNarrativeBot::CertificateGenerator do describe 'when SiteSetting.site_logo_small_url is blank' do before do SiteSetting.logo_small = '' - SiteSetting.logo_small_url = '' end it 'should not try to fetch a image' do diff --git a/plugins/discourse-presence/config/locales/client.gl.yml b/plugins/discourse-presence/config/locales/client.gl.yml index 695b5cf287..766a10865c 100644 --- a/plugins/discourse-presence/config/locales/client.gl.yml +++ b/plugins/discourse-presence/config/locales/client.gl.yml @@ -5,4 +5,8 @@ # To work with us on translations, join this project: # https://www.transifex.com/projects/p/discourse-org/ -gl: {} +gl: + js: + presence: + replying: "respondendo" + editing: "editando" diff --git a/plugins/discourse-presence/config/locales/server.gl.yml b/plugins/discourse-presence/config/locales/server.gl.yml index 695b5cf287..024fbbd5f0 100644 --- a/plugins/discourse-presence/config/locales/server.gl.yml +++ b/plugins/discourse-presence/config/locales/server.gl.yml @@ -5,4 +5,7 @@ # To work with us on translations, join this project: # https://www.transifex.com/projects/p/discourse-org/ -gl: {} +gl: + site_settings: + presence_enabled: "Quere amosar os usuarios que están respondendo ao tema actual ou editando a publicación actual?" + presence_max_users_shown: "Amósase o número máximo de usuarios." diff --git a/plugins/discourse-presence/config/locales/server.pt.yml b/plugins/discourse-presence/config/locales/server.pt.yml index ead949ccda..5cd4748927 100644 --- a/plugins/discourse-presence/config/locales/server.pt.yml +++ b/plugins/discourse-presence/config/locales/server.pt.yml @@ -7,5 +7,5 @@ pt: site_settings: - presence_enabled: "Mostrar os utilizadores que estão a responder no tópico atual, ou a editar a publicação atual?" + presence_enabled: "Mostrar os utilizadores que estão a responder ao tópico atual, ou a editar a publicação atual?" presence_max_users_shown: "Número máximo de utilizadores exibidos." diff --git a/plugins/discourse-unsupported-browser/assets/javascripts/initializers/discourse-unsupported-browser.js.es6 b/plugins/discourse-unsupported-browser/assets/javascripts/initializers/discourse-unsupported-browser.js.es6 index a2c96deb82..59cdbb1592 100644 --- a/plugins/discourse-unsupported-browser/assets/javascripts/initializers/discourse-unsupported-browser.js.es6 +++ b/plugins/discourse-unsupported-browser/assets/javascripts/initializers/discourse-unsupported-browser.js.es6 @@ -1,3 +1,4 @@ +import I18n from "I18n"; import { withPluginApi } from "discourse/lib/plugin-api"; function initializeInternetExplorerDeprecation(api) { diff --git a/plugins/lazy-yt/plugin.rb b/plugins/lazy-yt/plugin.rb index 06b25ce427..b0ed271e36 100644 --- a/plugins/lazy-yt/plugin.rb +++ b/plugins/lazy-yt/plugin.rb @@ -22,8 +22,11 @@ class Onebox::Engine::YoutubeOnebox def to_html if video_id && !params['list'] - video_width = (params['width'] && params['width'].to_i <= 695) ? params['width'] : 480 # embed width - video_height = (params['height'] && params['height'].to_i <= 500) ? params['height'] : 270 # embed height + + size_restricted = [params['width'], params['height']].any? + video_width = (params['width'] && params['width'].to_i <= 695) ? params['width'] : 690 # embed width + video_height = (params['height'] && params['height'].to_i <= 500) ? params['height'] : 388 # embed height + size_tags = ["width=\"#{video_width}\"", "height=\"#{video_height}\""] og = get_opengraph.data thumbnail_url = og[:image] || "https://img.youtube.com/vi/#{video_id}/hqdefault.jpg" @@ -35,11 +38,13 @@ class Onebox::Engine::YoutubeOnebox EOF diff --git a/plugins/poll/assets/javascripts/controllers/poll-ui-builder.js.es6 b/plugins/poll/assets/javascripts/controllers/poll-ui-builder.js.es6 index a653b8113b..0eca3fa851 100644 --- a/plugins/poll/assets/javascripts/controllers/poll-ui-builder.js.es6 +++ b/plugins/poll/assets/javascripts/controllers/poll-ui-builder.js.es6 @@ -1,3 +1,4 @@ +import I18n from "I18n"; import Controller from "@ember/controller"; import discourseComputed, { observes } from "discourse-common/utils/decorators"; import EmberObject from "@ember/object"; @@ -97,7 +98,7 @@ export default Controller.extend({ .map(g => { // prevents group "everyone" to be listed if (g.id !== 0) { - return { name: g.name, value: g.name }; + return { name: g.name }; } }) .filter(Boolean); @@ -251,7 +252,9 @@ export default Controller.extend({ if (publicPoll) pollHeader += ` public=true`; if (chartType && pollType !== "number") pollHeader += ` chartType=${chartType}`; - if (pollGroups) pollHeader += ` groups=${pollGroups}`; + if (pollGroups && pollGroups.length > 0) { + pollHeader += ` groups=${pollGroups}`; + } if (autoClose) { let closeDate = moment( date + " " + time, diff --git a/plugins/poll/assets/javascripts/discourse/templates/modal/poll-ui-builder.hbs b/plugins/poll/assets/javascripts/discourse/templates/modal/poll-ui-builder.hbs index 28e9f7c8e4..03e08acee7 100644 --- a/plugins/poll/assets/javascripts/discourse/templates/modal/poll-ui-builder.hbs +++ b/plugins/poll/assets/javascripts/discourse/templates/modal/poll-ui-builder.hbs @@ -2,7 +2,7 @@
- + {{combo-box content=pollTypes value=pollType @@ -13,39 +13,43 @@
- + {{combo-box content=pollResults value=pollResult class="poll-result" valueProperty="value" + onChange=(action (mut pollResult)) }}
- - {{combo-box content=siteGroups - value=pollGroups - options=(hash clearable=true) - valueAttribute="value"}} + + {{group-chooser + content=siteGroups + value=pollGroups + onChange=(action (mut pollGroups)) + labelProperty="name" + valueProperty="name"}}
{{#unless isNumber}}
- + {{combo-box class="poll-chart-type" content=pollChartTypes value=chartType - valueAttribute="value" + valueProperty="value" + onChange=(action (mut chartType)) }}
{{/unless}} {{#if showMinMax}}
- - {{input type='number' + + {{input type="number" value=pollMin valueProperty="value" class="poll-options-min"}} @@ -53,8 +57,8 @@ {{input-tip validation=minMaxValueValidation}}
- - {{input type='number' + + {{input type="number" value=pollMax valueProperty="value" class="poll-options-max"}} @@ -62,8 +66,8 @@ {{#if isNumber}}
- - {{input type='number' + + {{input type="number" value=pollStep valueProperty="value" min="1" @@ -75,7 +79,7 @@ {{#unless isNumber}}
- + {{textarea value=pollOptions autocomplete="discourse"}}
{{input-tip validation=minNumOfOptionsValidation}} @@ -84,7 +88,7 @@ {{#unless isPie}}
@@ -116,5 +120,5 @@ {{/d-modal-body}} diff --git a/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 b/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 index 14de1cae4a..61fc52f0f3 100644 --- a/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 +++ b/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 @@ -1,4 +1,5 @@ /*eslint no-bitwise:0 */ +import I18n from "I18n"; const DATA_PREFIX = "data-poll-"; const DEFAULT_POLL_NAME = "poll"; diff --git a/plugins/poll/assets/javascripts/widgets/discourse-poll.js.es6 b/plugins/poll/assets/javascripts/widgets/discourse-poll.js.es6 index 3ca2b793c6..96f6f32003 100644 --- a/plugins/poll/assets/javascripts/widgets/discourse-poll.js.es6 +++ b/plugins/poll/assets/javascripts/widgets/discourse-poll.js.es6 @@ -1,3 +1,4 @@ +import I18n from "I18n"; import { createWidget } from "discourse/widgets/widget"; import { h } from "virtual-dom"; import { iconNode } from "discourse-common/lib/icon-library"; diff --git a/plugins/poll/assets/stylesheets/common/poll-ui-builder.scss b/plugins/poll/assets/stylesheets/common/poll-ui-builder.scss index df3c17eacb..7f38887ed4 100644 --- a/plugins/poll/assets/stylesheets/common/poll-ui-builder.scss +++ b/plugins/poll/assets/stylesheets/common/poll-ui-builder.scss @@ -8,7 +8,8 @@ $poll-margin: 10px; flex-shrink: 0; width: 280px; } - .combo-box { + .combo-box, + .multi-select { min-width: 180px; width: 180px; } diff --git a/plugins/poll/config/locales/client.gl.yml b/plugins/poll/config/locales/client.gl.yml index 0918e71233..9f70ab6571 100644 --- a/plugins/poll/config/locales/client.gl.yml +++ b/plugins/poll/config/locales/client.gl.yml @@ -33,3 +33,6 @@ gl: title: "Pechar a enquisa" label: "Pechar" confirm: "Confirmas o peche desta enquisa?" + ui_builder: + poll_type: + label: Tipo diff --git a/plugins/poll/config/locales/client.it.yml b/plugins/poll/config/locales/client.it.yml index 83768a1ec4..a70cc43ff8 100644 --- a/plugins/poll/config/locales/client.it.yml +++ b/plugins/poll/config/locales/client.it.yml @@ -26,6 +26,18 @@ it: title: "I risultati saranno mostrati a sondaggio chiuso." staff: title: "I risultati saranno mostrati solo ai membri dello staff" + multiple: + help: + at_least_min_options: + one: "Scegli almeno un'opzione %{count} ." + other: "Scegli almeno %{count} opzioni." + up_to_max_options: + one: "Scegli fino a %{count} opzione." + other: "Scegli fino a %{count} opzioni." + x_options: + one: "Scegli %{count} opzione." + other: "Scegli %{count} opzioni." + between_min_and_max_options: "Scegli tra %{min} e %{max} opzioni." cast-votes: title: "Vota" label: "Vota!" diff --git a/plugins/poll/config/locales/client.pt.yml b/plugins/poll/config/locales/client.pt.yml index 128e06ade7..7fe0991943 100644 --- a/plugins/poll/config/locales/client.pt.yml +++ b/plugins/poll/config/locales/client.pt.yml @@ -9,22 +9,34 @@ pt: js: poll: voters: - one: "eleitor" - other: "eleitores" + one: "votante" + other: "votantes" total_votes: one: "total da votação" other: "total de votos" average_rating: "Classificação média: %{average}." public: title: "Os votos são públicos." + multiple: + help: + at_least_min_options: + one: "Escolha pelo menos %{count} opção." + other: "Escolha pelo menos %{count} opções." + up_to_max_options: + one: "Escolha até %{count} opção." + other: "Escolha até %{count} opções." + x_options: + one: "Escolha %{count} opção" + other: "Escolha %{count} opções" + between_min_and_max_options: "Escolha entre as opções %{min} e %{max}." cast-votes: - title: "Votar" + title: "Vote" label: "Vote agora!" show-results: title: "Exibir os resultados da sondagem" label: "Mostrar resultados" hide-results: - title: "Voltar aos meus votos" + title: "Voltar para os seus votos" label: "Mostrar voto" group-results: title: "Agrupar votos por campo de utilizador" @@ -42,18 +54,19 @@ pt: confirm: "Tem a certeza que deseja encerrar esta sondagem?" error_while_toggling_status: "Desculpe, ocorreu um erro ao alternar o estado desta sondagem." error_while_casting_votes: "Desculpe, ocorreu um erro ao submeter os seus votos." - error_while_fetching_voters: "Pedimos desculpa, ocorreu um erro ao apresentar os eleitores." + error_while_fetching_voters: "Desculpe, ocorreu um erro ao exibir os votantes." ui_builder: title: Criar Sondagem insert: Inserir Sondagem help: + options_count: Insira pelo menos uma opção invalid_values: O valor mínimo deve ser menor que o valor máximo. min_step_value: O valor mínimo é 1 poll_type: label: Tipo regular: Escolha Única multiple: Escolha Múltipla - number: Cotação numérica + number: Classificação Numérica poll_result: label: Resultados poll_config: @@ -63,4 +76,4 @@ pt: poll_public: label: Mostrar quem votou poll_options: - label: Escreva uma opção de sondagem por linha + label: Insira uma opção de sondagem por linha diff --git a/plugins/poll/config/locales/server.pt.yml b/plugins/poll/config/locales/server.pt.yml index e8686c92d3..f1804ef16d 100644 --- a/plugins/poll/config/locales/server.pt.yml +++ b/plugins/poll/config/locales/server.pt.yml @@ -9,11 +9,11 @@ pt: site_settings: poll_enabled: "Permitir sondagens?" poll_maximum_options: "Número máximo de opções permitidas numa sondagem." - poll_edit_window_mins: "Número de minutos após criação de publicação durante os quais sondagens podem ser editadas." + poll_edit_window_mins: "O número de minutos depois da criação da publicação durante os quais as sondagens podem ser editadas." poll_minimum_trust_level_to_create: "Defina o nível de confiança mínimo necessário para criar sondagens." poll: - multiple_polls_without_name: "Há múltiplas sondagens sem nome. Utilize o atributo 'nome' para identificar as suas sondagens de maneira única." - multiple_polls_with_same_name: "Há múltiplas sondagens com o mesmo nome: %{name}. Utilize o atributo 'nome' para identificar as suas sondagens de maneira única." + multiple_polls_without_name: "Existem várias sondagens sem nome. Utilize o atributo 'nome' para identificar as suas sondagens de maneira única." + multiple_polls_with_same_name: "Existem várias sondagens com o mesmo nome: %{name}. Utilize o atributo 'nome' para identificar as suas sondagens de maneira única." default_poll_must_have_less_options: one: "A sondagem deve ter menos que %{count} opção." other: "A sondagem deve ter menos que %{count} opções." @@ -26,12 +26,12 @@ pt: named_poll_with_multiple_choices_has_invalid_parameters: "A sondagem com o nome %{name} com escolha múltipla tem parâmetros inválidos." requires_at_least_1_valid_option: "Deve selecionar pelo menos 1 opção válida." no_poll_with_this_name: "Nenhuma sondagem com o nome %{name} está associada a esta publicação." - post_is_deleted: "Não é possível realizar ações em publicações eliminadas." + post_is_deleted: "Não é possível realizar ações na publicação eliminada." user_cant_post_in_topic: "Não pode votar porque não pode publicar neste tópico." - topic_must_be_open_to_vote: "O tópico tem que estar aberto para votar." - poll_must_be_open_to_vote: "A votação deve estar aberta para votação." + topic_must_be_open_to_vote: "O tópico tem que estar aberto para votação." + poll_must_be_open_to_vote: "A sondagem deve estar aberta para votação." topic_must_be_open_to_toggle_status: "O tópico tem que estar aberto para alternar o estado." - only_staff_or_op_can_toggle_status: "Apenas um membro da equipa de apoio ou o autor original pode alternar o estado da sondagem." + only_staff_or_op_can_toggle_status: "Apenas um membro da equipa ou o autor original pode alternar o estado da sondagem." insufficient_rights_to_create: "Não está autorizado para criar sondagens." email: link_to_poll: "Clique para ver a sondagem." diff --git a/public/403.gl.html b/public/403.gl.html index ad924ac008..181633d075 100644 --- a/public/403.gl.html +++ b/public/403.gl.html @@ -19,7 +19,7 @@

403

-

Non podes ver este recurso.

+

Non podes ver este recurso!

Substituirase pola páxina 403 personalizada de Discourse.

diff --git a/public/422.pt.html b/public/422.pt.html index 240dd474de..e67c8ec854 100644 --- a/public/422.pt.html +++ b/public/422.pt.html @@ -20,7 +20,7 @@

A alteração que solicitou foi rejeitada.

-

Talvez tenha tentado alterar algo a que não tem acesso.

+

Talvez tenha tentado alterar algo que não tinha acesso.

diff --git a/public/500.pt.html b/public/500.pt.html index e4f7981f33..8d6502f49e 100644 --- a/public/500.pt.html +++ b/public/500.pt.html @@ -5,8 +5,8 @@ -

Oops

-

O software que sustenta este fórum de discussão encontrou um problema inesperado. Nós pedimos desculpa pelo inconveniente.

+

Ups!

+

O ''software'' que controla este fórum de discussão encontrou um problema inesperado. Nós pedimos desculpa pelo inconveniente.

A informação detalhada sobre o erro foi registada, e foi gerada uma notificação automática. Nós iremos verificar o mesmo.

Nenhuma ação adicional é necessária. No entanto, se a condição de erro persistir, pode fornecer detalhes adicionais, incluindo as etapas para reproduzir o erro, publicando um tópico de discussão na categoria de retorno do sítio.

diff --git a/public/503.pt.html b/public/503.pt.html index aff933211b..b3006565a6 100644 --- a/public/503.pt.html +++ b/public/503.pt.html @@ -1,12 +1,12 @@ -O site está em Manutenção - Discourse.org +O ''site'' está em «Manutenção» - Discourse.org -

Estamos em baixo para realizar uma manutenção planeada do sítio

-

Por favor volte em alguns minutos.

-

Pedimos desculpa pelo inconveniente!

+

Nós estamos em baixo para uma manutenção planeada do ''site''

+

Por favor, volte em alguns minutos.

+

Desculpe pela inconveniência!

diff --git a/script/bulk_import/base.rb b/script/bulk_import/base.rb index 9fc7b1cd17..1253c2d2e4 100644 --- a/script/bulk_import/base.rb +++ b/script/bulk_import/base.rb @@ -77,7 +77,6 @@ class BulkImport::Base db = ActiveRecord::Base.connection_config @encoder = PG::TextEncoder::CopyRow.new @raw_connection = PG.connect(dbname: db[:database], host: db[:host_names]&.first, port: db[:port]) - # @raw_connection = PG.connect(dbname: db[:database], host: db[:host_names]&.first, port: db[:port], password: "discourse") @uploader = ImportScripts::Uploader.new @html_entities = HTMLEntities.new @encoding = CHARSET_MAP[charset] @@ -128,28 +127,44 @@ class BulkImport::Base SQL end + def imported_ids(name) + map = [] + ids = [] + + @raw_connection.send_query("SELECT value, #{name}_id FROM #{name}_custom_fields WHERE name = 'import_id'") + @raw_connection.set_single_row_mode + + @raw_connection.get_result.stream_each do |row| + id = row["value"].to_i + ids << id + map[id] = row["#{name}_id"].to_i + end + + @raw_connection.get_result + + [map, ids] + end + def load_imported_ids puts "Loading imported group ids..." - @groups = GroupCustomField.where(name: "import_id").pluck(:value, :group_id).to_h - @last_imported_group_id = @groups.keys.map(&:to_i).max || -1 + @groups, imported_group_ids = imported_ids("group") + @last_imported_group_id = imported_group_ids.max || -1 puts "Loading imported user ids..." - @users = UserCustomField.where(name: "import_id").pluck(:value, :user_id).to_h - @last_imported_user_id = @users.keys.map(&:to_i).max || -1 + @users, imported_user_ids = imported_ids("user") + @last_imported_user_id = imported_user_ids.max || -1 puts "Loading imported category ids..." - @categories = CategoryCustomField.where(name: "import_id").pluck(:value, :category_id).to_h - @last_imported_category_id = @categories.keys.map(&:to_i).max || -1 + @categories, imported_category_ids = imported_ids("category") + @last_imported_category_id = imported_category_ids.max || -1 puts "Loading imported topic ids..." - @topics = TopicCustomField.where(name: "import_id").pluck(:value, :topic_id).to_h - imported_topic_ids = @topics.keys.map(&:to_i) + @topics, imported_topic_ids = imported_ids("topic") @last_imported_topic_id = imported_topic_ids.select { |id| id < PRIVATE_OFFSET }.max || -1 @last_imported_private_topic_id = imported_topic_ids.select { |id| id > PRIVATE_OFFSET }.max || (PRIVATE_OFFSET - 1) puts "Loading imported post ids..." - @posts = PostCustomField.where(name: "import_id").pluck(:value, :post_id).to_h - imported_post_ids = @posts.keys.map(&:to_i) + @posts, imported_post_ids = imported_ids("post") @last_imported_post_id = imported_post_ids.select { |id| id < PRIVATE_OFFSET }.max || -1 @last_imported_private_post_id = imported_post_ids.select { |id| id > PRIVATE_OFFSET }.max || (PRIVATE_OFFSET - 1) end @@ -159,9 +174,24 @@ class BulkImport::Base [klass.unscoped.maximum(:id) || 0, 0].max end + def load_values(name, column, size) + map = Array.new(size) + + @raw_connection.send_query("SELECT id, #{column} FROM #{name}") + @raw_connection.set_single_row_mode + + @raw_connection.get_result.stream_each do |row| + map[row["id"].to_i] = row[column].to_i + end + + @raw_connection.get_result + + map + end + def load_indexes puts "Loading groups indexes..." - @last_group_id = Group.unscoped.maximum(:id) + @last_group_id = last_id(Group) @group_names = Group.unscoped.pluck(:name).map(&:downcase).to_set puts "Loading users indexes..." @@ -177,12 +207,12 @@ class BulkImport::Base puts "Loading topics indexes..." @last_topic_id = last_id(Topic) - @highest_post_number_by_topic_id = Topic.unscoped.pluck(:id, :highest_post_number).to_h + @highest_post_number_by_topic_id = load_values("topics", "highest_post_number", @last_topic_id) puts "Loading posts indexes..." @last_post_id = last_id(Post) - @post_number_by_post_id = Post.unscoped.pluck(:id, :post_number).to_h - @topic_id_by_post_id = Post.unscoped.pluck(:id, :topic_id).to_h + @post_number_by_post_id = load_values("posts", "post_number", @last_post_id) + @topic_id_by_post_id = load_values("posts", "topic_id", @last_post_id) puts "Loading post actions indexes..." @last_post_action_id = last_id(PostAction) @@ -208,26 +238,33 @@ class BulkImport::Base end def group_id_from_imported_id(id) - @groups[id.to_s] + @groups[id.to_i] end + def user_id_from_imported_id(id) - @users[id.to_s] + @users[id.to_i] end + def category_id_from_imported_id(id) - @categories[id.to_s] + @categories[id.to_i] end + def topic_id_from_imported_id(id) - @topics[id.to_s] + @topics[id.to_i] end + def post_id_from_imported_id(id) - @posts[id.to_s] + @posts[id.to_i] end def post_number_from_imported_id(id) - @post_number_by_post_id[post_id_from_imported_id(id)] + post_id = post_id_from_imported_id(id) + post_id && @post_number_by_post_id[post_id] end + def topic_id_from_imported_post_id(id) - @topic_id_by_post_id[post_id_from_imported_id(id)] + post_id = post_id_from_imported_id(id) + post_id && @topic_id_by_post_id[post_id] end GROUP_COLUMNS ||= %i{ @@ -337,7 +374,7 @@ class BulkImport::Base end def process_group(group) - @groups[group[:imported_id].to_s] = group[:id] = @last_group_id += 1 + @groups[group[:imported_id].to_i] = group[:id] = @last_group_id += 1 group[:name] = fix_name(group[:name]) @@ -356,7 +393,7 @@ class BulkImport::Base end def process_user(user) - @users[user[:imported_id].to_s] = user[:id] = @last_user_id += 1 + @users[user[:imported_id].to_i] = user[:id] = @last_user_id += 1 imported_username = user[:username].dup @@ -392,7 +429,7 @@ class BulkImport::Base def process_user_email(user_email) user_email[:id] = @last_user_email_id += 1 - user_email[:user_id] = @users[user_email[:imported_user_id].to_s] + user_email[:user_id] = @users[user_email[:imported_user_id].to_i] user_email[:primary] = true user_email[:created_at] ||= NOW user_email[:updated_at] ||= user_email[:created_at] @@ -403,7 +440,7 @@ class BulkImport::Base end def process_user_stat(user_stat) - user_stat[:user_id] = @users[user_stat[:imported_user_id].to_s] + user_stat[:user_id] = @users[user_stat[:imported_user_id].to_i] user_stat[:topic_reply_count] = user_stat[:post_count] - user_stat[:topic_count] user_stat[:topics_entered] ||= 0 user_stat[:time_read] ||= 0 @@ -434,7 +471,7 @@ class BulkImport::Base def process_category(category) category[:id] ||= @last_category_id += 1 - @categories[category[:imported_id].to_s] ||= category[:id] + @categories[category[:imported_id].to_i] ||= category[:id] category[:name] = category[:name][0...50].scrub.strip # TODO: unique name category[:name_lower] = category[:name].downcase @@ -447,7 +484,7 @@ class BulkImport::Base end def process_topic(topic) - @topics[topic[:imported_id].to_s] = topic[:id] = @last_topic_id += 1 + @topics[topic[:imported_id].to_i] = topic[:id] = @last_topic_id += 1 topic[:archetype] ||= Archetype.default topic[:title] = topic[:title][0...255].scrub.strip topic[:fancy_title] ||= pre_fancy(topic[:title]) @@ -465,7 +502,7 @@ class BulkImport::Base end def process_post(post) - @posts[post[:imported_id].to_s] = post[:id] = @last_post_id += 1 + @posts[post[:imported_id].to_i] = post[:id] = @last_post_id += 1 post[:user_id] ||= Discourse::SYSTEM_USER_ID post[:last_editor_id] = post[:user_id] @highest_post_number_by_topic_id[post[:topic_id]] ||= 0 @@ -607,9 +644,8 @@ class BulkImport::Base imported_username, imported_postid = $1, $2 username = @mapped_usernames[imported_username] || imported_username - post_id = post_id_from_imported_id(imported_postid) - post_number = @post_number_by_post_id[post_id] - topic_id = @topic_id_by_post_id[post_id] + post_number = post_number_from_imported_id(imported_postid) + topic_id = topic_id_from_imported_post_id(imported_post_id) if post_number && topic_id "\n[quote=\"#{username}, post:#{post_number}, topic:#{topic_id}\"]\n" @@ -654,8 +690,7 @@ class BulkImport::Base @raw_connection.copy_data(sql, @encoder) do rows.each do |row| begin - mapped = yield(row) - next unless mapped + next unless mapped = yield(row) processed = send(process_method_name, mapped) imported_ids << mapped[:imported_id] unless mapped[:imported_id].nil? imported_ids |= mapped[:imported_ids] unless mapped[:imported_ids].nil? @@ -663,7 +698,8 @@ class BulkImport::Base print "\r%7d - %6d/sec" % [imported_ids.size, imported_ids.size.to_f / (Time.now - start)] if imported_ids.size % 5000 == 0 rescue => e puts "\n" - puts "ERROR: #{e.inspect}" + puts "ERROR: #{e.message}" + puts backtrace.join("\n") end end end @@ -691,8 +727,7 @@ class BulkImport::Base sql = "COPY #{table}_custom_fields (#{table}_id, name, value, created_at, updated_at) FROM STDIN" @raw_connection.copy_data(sql, @encoder) do rows.each do |row| - cf = yield row - next unless cf + next unless cf = yield(row) @raw_connection.put_copy_data [cf[:record_id], name, cf[:value], NOW, NOW] end end diff --git a/script/downsize_uploads.rb b/script/downsize_uploads.rb index dc2e7b2a62..7fcb1e6431 100644 --- a/script/downsize_uploads.rb +++ b/script/downsize_uploads.rb @@ -29,225 +29,13 @@ def log(*args) puts(*args) if ENV["VERBOSE"] end -def transform_post(post, upload_before, upload_after) - post.raw.gsub!(/upload:\/\/#{upload_before.base62_sha1}(\.#{upload_before.extension})?/i, upload_after.short_url) - post.raw.gsub!(Discourse.store.cdn_url(upload_before.url), Discourse.store.cdn_url(upload_after.url)) - post.raw.gsub!(Discourse.store.url_for(upload_before), Discourse.store.url_for(upload_after)) - post.raw.gsub!("#{Discourse.base_url}#{upload_before.short_path}", "#{Discourse.base_url}#{upload_after.short_path}") - - path = SiteSetting.Upload.s3_upload_bucket.split("/", 2)[1] - post.raw.gsub!(/\d+)x(?\d+).*?\" alt=\"(?.*?)\"\/?>/i) do - "![#{$~[:alt]}|#{$~[:width]}x#{$~[:height]}](#{upload_after.short_url})" - end - - post.raw.gsub!(/!\[(.*?)\]\(\/uploads\/.+?\/#{upload_before.sha1}(\.#{upload_before.extension})?\)/i, "![\\1](#{upload_after.short_url})") -end - -def downsize_upload(upload, path) - # Make sure the filesize is up to date - upload.filesize = File.size(path) - - OptimizedImage.downsize(path, path, "#{MAX_IMAGE_PIXELS}@", filename: upload.original_filename) - sha1 = Upload.generate_digest(path) - - if sha1 == upload.sha1 - log "No sha1 change" - return - end - - w, h = FastImage.size(path, timeout: 15, raise_on_failure: true) - - if !w || !h - log "Invalid image dimensions after resizing" - return - end - - # Neither #dup or #clone provide a complete copy - original_upload = Upload.find(upload.id) - ww, hh = ImageSizer.resize(w, h) - - # A different upload record that matches the sha1 of the downsized image - existing_upload = Upload.find_by(sha1: sha1) - upload = existing_upload if existing_upload - - upload.attributes = { - sha1: sha1, - width: w, - height: h, - thumbnail_width: ww, - thumbnail_height: hh, - filesize: File.size(path) - } - - if upload.filesize > upload.filesize_was - log "No filesize reduction" - return - end - - unless existing_upload - url = Discourse.store.store_upload(File.new(path), upload) - - unless url - log "Couldn't store the upload" - return - end - - upload.url = url - end - - log "base62: #{original_upload.base62_sha1} -> #{Upload.base62_sha1(sha1)}" - log "sha: #{original_upload.sha1} -> #{sha1}" - log "(an exisiting upload)" if existing_upload - - success = true - posts = Post.unscoped.joins(:post_uploads).where(post_uploads: { upload_id: original_upload.id }).uniq.sort_by(&:created_at) - - posts.each do |post| - transform_post(post, original_upload, upload) - - if post.custom_fields[Post::DOWNLOADED_IMAGES].present? - downloaded_images = JSON.parse(post.custom_fields[Post::DOWNLOADED_IMAGES]) - end - - if post.raw_changed? - log "Updating post" - elsif downloaded_images&.has_value?(original_upload.id) - log "A hotlinked, unreferenced image" - elsif post.raw.include?(upload.short_url) - log "Already processed" - elsif post.trashed? - log "A deleted post" - elsif !post.topic || post.topic.trashed? - log "A deleted topic" - elsif post.cooked.include?(original_upload.sha1) - if post.raw.include?("#{Discourse.base_url.sub(/^https?:\/\//i, "")}/t/") - log "Updating a topic onebox" - else - log "Updating an external onebox" - end - else - log "Could not find the upload URL" - success = false - end - - log "#{Discourse.base_url}/p/#{post.id}" - end - - if posts.empty? - log "Upload not used in any posts" - - if User.where(uploaded_avatar_id: original_upload.id).count - log "Used as a User avatar" - elsif UserAvatar.where(gravatar_upload_id: original_upload.id).count - log "Used as a UserAvatar gravatar" - elsif UserAvatar.where(custom_upload_id: original_upload.id).count - log "Used as a UserAvatar custom upload" - elsif UserProfile.where(profile_background_upload_id: original_upload.id).count - log "Used as a UserProfile profile background" - elsif UserProfile.where(card_background_upload_id: original_upload.id).count - log "Used as a UserProfile card background" - elsif Category.where(uploaded_logo_id: original_upload.id).count - log "Used as a Category logo" - elsif Category.where(uploaded_background_id: original_upload.id).count - log "Used as a Category background" - elsif CustomEmoji.where(upload_id: original_upload.id).count - log "Used as a CustomEmoji" - elsif ThemeField.where(upload_id: original_upload.id).count - log "Used as a ThemeField" - else - success = false - end - end - - unless success - if ENV["INTERACTIVE"] - print "Press any key to continue with the upload" - STDIN.beep - STDIN.getch - puts " k" - elsif !existing_upload && !Upload.where(url: upload.url).exist? - # We're bailing, so clean up the just uploaded file - Discourse.store.remove_upload(upload) - - log "⏩ Skipping" - return - end - end - - upload.save! - - if existing_upload - begin - PostUpload.where(upload_id: original_upload.id).update_all(upload_id: upload.id) - rescue ActiveRecord::RecordNotUnique, PG::UniqueViolation - end - - User.where(uploaded_avatar_id: original_upload.id).update_all(uploaded_avatar_id: upload.id) - UserAvatar.where(gravatar_upload_id: original_upload.id).update_all(gravatar_upload_id: upload.id) - UserAvatar.where(custom_upload_id: original_upload.id).update_all(custom_upload_id: upload.id) - UserProfile.where(profile_background_upload_id: original_upload.id).update_all(profile_background_upload_id: upload.id) - UserProfile.where(card_background_upload_id: original_upload.id).update_all(card_background_upload_id: upload.id) - Category.where(uploaded_logo_id: original_upload.id).update_all(uploaded_logo_id: upload.id) - Category.where(uploaded_background_id: original_upload.id).update_all(uploaded_background_id: upload.id) - CustomEmoji.where(upload_id: original_upload.id).update_all(upload_id: upload.id) - ThemeField.where(upload_id: original_upload.id).update_all(upload_id: upload.id) - else - upload.optimized_images.each(&:destroy!) - end - - posts.each do |post| - DistributedMutex.synchronize("process_post_#{post.id}") do - current_post = Post.unscoped.find(post.id) - - # If the post became outdated, reapply changes - if current_post.updated_at != post.updated_at - transform_post(current_post, original_upload, upload) - post = current_post - end - - if post.raw_changed? - post.update_columns( - raw: post.raw, - updated_at: Time.zone.now - ) - end - - if existing_upload && post.custom_fields[Post::DOWNLOADED_IMAGES].present? - downloaded_images = JSON.parse(post.custom_fields[Post::DOWNLOADED_IMAGES]) - - downloaded_images.transform_values! do |upload_id| - upload_id == original_upload.id ? upload.id : upload_id - end - - post.custom_fields[Post::DOWNLOADED_IMAGES] = downloaded_images.to_json if downloaded_images.present? - post.save_custom_fields - end - - post.rebake! - end - end - - if existing_upload - original_upload.reload.destroy! - else - Discourse.store.remove_upload(original_upload) - end - - true -end - def process_uploads - unless SiteSetting.Upload.enable_s3_uploads - puts "This script supports only S3 uploads" - return - end - puts "", "Downsizing images to no more than #{MAX_IMAGE_PIXELS} pixels" dimensions_count = 0 downsized_count = 0 - scope = Upload.where("LOWER(extension) IN ('jpg', 'jpeg', 'gif', 'png')") + scope = Upload.by_users.where("LOWER(extension) IN ('jpg', 'jpeg', 'gif', 'png')") scope = scope.where(<<-SQL, MAX_IMAGE_PIXELS) COALESCE(width, 0) = 0 OR COALESCE(height, 0) = 0 OR @@ -271,19 +59,20 @@ def process_uploads print "\r#{progress}% Fixed dimensions: #{dimensions_count} Downsized: #{downsized_count} Skipped: #{skipped} (upload id: #{upload.id})" log "\n" - source = upload.local? ? Discourse.store.path_for(upload) : "https:#{upload.url}" + path = if upload.local? + Discourse.store.path_for(upload) + else + (Discourse.store.download(upload, max_file_size_kb: 100.megabytes) rescue nil)&.path + end - unless source - log "No path or URL" + unless path + log "No image path" skipped += 1 next end begin - w, h = FastImage.size(source, timeout: 15, raise_on_failure: true) - rescue FastImage::ImageFetchFailure - log "Retrying image resizing" - w, h = FastImage.size(source, timeout: 15) + w, h = FastImage.size(path, raise_on_failure: true) rescue FastImage::UnknownImageType log "Unknown image type" skipped += 1 @@ -312,13 +101,14 @@ def process_uploads width: w, height: h, thumbnail_width: ww, - thumbnail_height: hh + thumbnail_height: hh, + filesize: File.size(path) } if upload.changed? log "Correcting the upload dimensions" - log "Before: #{upload.width_was}x#{upload.height_was} #{upload.thumbnail_width_was}x#{upload.thumbnail_height_was}" - log "After: #{w}x#{h} #{ww}x#{hh}" + log "Before: #{upload.width_was}x#{upload.height_was} #{upload.thumbnail_width_was}x#{upload.thumbnail_height_was} (#{upload.filesize_was})" + log "After: #{w}x#{h} #{ww}x#{hh} (#{upload.filesize})" dimensions_count += 1 upload.save! @@ -330,15 +120,15 @@ def process_uploads next end - path = upload.local? ? source : (Discourse.store.download(upload) rescue nil)&.path + result = ShrinkUploadedImage.new( + upload: upload, + path: path, + max_pixels: MAX_IMAGE_PIXELS, + verbose: ENV["VERBOSE"], + interactive: ENV["INTERACTIVE"] + ).perform - unless path - log "No image path" - skipped += 1 - next - end - - if downsize_upload(upload, path) + if result downsized_count += 1 else skipped += 1 diff --git a/script/import_scripts/base.rb b/script/import_scripts/base.rb index a42b8c3dda..64de94ba75 100644 --- a/script/import_scripts/base.rb +++ b/script/import_scripts/base.rb @@ -77,6 +77,7 @@ class ImportScripts::Base min_personal_message_post_length: 1, min_personal_message_title_length: 1, allow_duplicate_topic_titles: true, + allow_duplicate_topic_titles_category: false, disable_emails: 'yes', max_attachment_size_kb: 102400, max_image_size_kb: 102400, diff --git a/script/import_scripts/jforum.rb b/script/import_scripts/jforum.rb new file mode 100644 index 0000000000..1f52412c59 --- /dev/null +++ b/script/import_scripts/jforum.rb @@ -0,0 +1,586 @@ +# frozen_string_literal: true + +require "mysql2" +require_relative 'base' + +class ImportScripts::JForum < ImportScripts::Base + BATCH_SIZE = 1000 + REMOTE_AVATAR_REGEX ||= /\Ahttps?:\/\//i + + def initialize + super + + @settings = YAML.load(File.read(ARGV.first), symbolize_names: true) + + @database_client = Mysql2::Client.new( + host: @settings[:database][:host], + port: @settings[:database][:port], + username: @settings[:database][:username], + password: @settings[:database][:password], + database: @settings[:database][:schema], + reconnect: true + ) + end + + def execute + import_users + + if @settings[:import_categories_as_tags] + import_tags + else + import_categories + end + + import_posts + import_likes + import_category_subscriptions + import_topic_subscriptions + mark_topics_as_solved + end + + def import_users + puts '', 'creating users' + total_count = count("SELECT COUNT(1) AS count FROM jforum_users") + last_user_id = 0 + + custom_fields_query = user_custom_fields_query + + batches do |offset| + rows, last_user_id = query(<<~SQL, :user_id) + SELECT user_id, username, user_lastvisit, user_regdate, user_email, user_from, user_active, + user_avatar, COALESCE(user_realname, CONCAT(first_name, ' ', last_name)) AS name + #{custom_fields_query} + FROM jforum_users + WHERE user_id > #{last_user_id} + ORDER BY user_id + LIMIT #{BATCH_SIZE} + SQL + break if rows.size < 1 + + next if all_records_exist?(:users, rows.map { |row| row[:user_id] }) + + create_users(rows, total: total_count, offset: offset) do |row| + { + id: row[:user_id], + email: row[:user_email]&.strip, + name: row[:name], + created_at: row[:user_regdate], + last_seen_at: row[:user_lastvisit], + active: row[:user_active] == 1, + location: row[:user_from], + custom_fields: user_custom_fields(row), + post_create_action: proc do |user| + import_avatar(user, row[:user_avatar]) + end + } + end + end + end + + def user_custom_fields_query + return "" if @settings[:custom_fields].blank? + + columns = [] + @settings[:custom_fields].map do |field| + columns << (field[:alias] ? "#{field[:column]} AS #{field[:alias]}" : field[:column]) + end + ", #{columns.join(', ')}" + end + + def user_fields + @user_fields ||= begin + Hash[UserField.all.map { |field| [field.name, field] }] + end + end + + def user_custom_fields(row) + return nil if @settings[:custom_fields].blank? + + custom_fields = {} + + @settings[:custom_fields].map do |field| + column = field[:alias] || field[:column] + value = row[column.to_sym] + user_field = user_fields[field[:name]] + + case user_field.field_type + when "confirm" + value = value == 1 ? true : nil + when "dropdown" + value = user_field.user_field_options.find { |option| option.value == value } ? value : nil + end + + custom_fields["user_field_#{user_field.id}"] = value if value.present? + end + + custom_fields + end + + def import_avatar(user, avatar_source) + return if avatar_source.blank? + + path = File.join(@settings[:avatar_directory], avatar_source) + + if File.file?(path) + @uploader.create_avatar(user, path) + elsif avatar_source.match?(REMOTE_AVATAR_REGEX) + UserAvatar.import_url_for_user(avatar_source, user) rescue nil + end + end + + def import_tags + puts "", "creating tags" + + @tags_by_import_forum_id = {} + + SiteSetting.tagging_enabled = true + SiteSetting.max_tag_length = 100 + SiteSetting.max_tags_per_topic = 10 + SiteSetting.force_lowercase_tags = false + + additional_tags = Array.wrap(@settings[:additional_tags]) + + rows = query(<<~SQL) + SELECT c.categories_id, c.title AS category_name, f.forum_id, f.forum_name + FROM jforum_forums f + JOIN jforum_categories c ON f.categories_id = c.categories_id + WHERE EXISTS ( + SELECT 1 + FROM jforum_posts p + WHERE p.forum_id = f.forum_id + ) + SQL + + rows.each do |row| + tag_names = [row[:category_name], row[:forum_name]] + + additional_tags.each do |additional_tag| + if additional_tag[:old_category_name].match?(row[:category_name]) + tag_names += additional_tag[:tag_names] + end + end + + tag_names.map! { |t| t.parameterize(preserve_case: true) } + + tag_names.each_with_index do |tag_name, index| + tag = create_tag(tag_name) + next if tag.blank? + + case index + when 0 + url = File.join(@settings[:permalink_prefix], "forums/list/#{row[:categories_id]}.page") + Permalink.create(url: url, tag_id: tag.id) unless Permalink.find_by(url: url) + when 1 + url = File.join(@settings[:permalink_prefix], "forums/show/#{row[:forum_id]}.page") + Permalink.create(url: url, tag_id: tag.id) unless Permalink.find_by(url: url) + end + end + + @tags_by_import_forum_id[row[:forum_id]] = tag_names.uniq + end + + category_mappings = Array.wrap(@settings[:category_mappings]) + + if category_mappings.blank? + rows.each do |row| + category_mappings.each do |mapping| + if mapping[:old_category_name].match?(row[:category_name]) + @lookup.add_category(row[:forum_id], Category.find(mapping[:category_id])) + end + end + end + end + end + + def create_tag(tag_name) + tag = Tag.find_by_name(tag_name) + + if tag + # update if the case is different + tag.update!(name: tag_name) if tag.name != tag_name + nil + else + Tag.create!(name: tag_name) + end + end + + def import_categories + puts "", "creating categories" + + rows = query(<<~SQL) + SELECT categories_id, title, display_order + FROM jforum_categories + ORDER BY display_order + SQL + + create_categories(rows) do |row| + { + id: "C#{row[:categories_id]}", + name: row[:title], + position: row[:display_order], + post_create_action: proc do |category| + url = File.join(@settings[:permalink_prefix], "forums/list/#{row[:categories_id]}.page") + Permalink.create(url: url, category_id: category.id) unless Permalink.find_by(url: url) + end + } + end + + rows = query(<<~SQL) + SELECT forum_id, categories_id, forum_name, forum_desc, forum_order + FROM jforum_categories + ORDER BY categories_id, forum_order + SQL + + create_categories(rows) do |row| + { + id: row[:forum_id], + name: row[:forum_name], + description: row[:forum_desc], + position: row[:forum_order], + parent_category_id: @lookup.category_id_from_imported_category_id("C#{row[:categories_id]}"), + post_create_action: proc do |category| + url = File.join(@settings[:permalink_prefix], "forums/show/#{row[:forum_id]}.page") + Permalink.create(url: url, category_id: category.id) unless Permalink.find_by(url: url) + end + } + end + end + + def import_posts + puts '', 'creating topics and posts' + total_count = count("SELECT COUNT(1) AS count FROM jforum_posts") + last_post_id = 0 + + batches do |offset| + rows, last_post_id = query(<<~SQL, :post_id) + SELECT p.post_id, p.topic_id, p.user_id, t.topic_title, pt.post_text, p.post_time, t.topic_status, + t.topic_type, t.topic_views, p.poster_ip, p.forum_id, t.topic_acceptedanswer_post_id, + EXISTS (SELECT 1 FROM jforum_attach a WHERE a.post_id = p.post_id) AS has_attachments, + COALESCE( + (SELECT x.post_id FROM jforum_posts x WHERE x.post_id = t.topic_first_post_id), + (SELECT MIN(x.post_id) FROM jforum_posts x WHERE x.topic_id = t.topic_id) + ) AS topic_first_post_id + FROM jforum_posts p + JOIN jforum_topics t ON p.topic_id = t.topic_id + LEFT OUTER JOIN jforum_posts_text pt ON p.post_id = pt.post_id + WHERE p.post_id > #{last_post_id} + ORDER BY p.post_id + LIMIT #{BATCH_SIZE} + SQL + break if rows.size < 1 + + next if all_records_exist?(:posts, rows.map { |row| row[:post_id] }) + + create_posts(rows, total: total_count, offset: offset) do |row| + user_id = @lookup.user_id_from_imported_user_id(row[:user_id]) || Discourse::SYSTEM_USER_ID + is_first_post = row[:post_id] == row[:topic_first_post_id] + post_text = fix_bbcodes(row[:post_text]) + + if row[:has_attachments] > 0 + attachments = import_attachments(row[:post_id], user_id) + post_text << "\n" << attachments.join("\n") + end + + mapped = { + id: row[:post_id], + user_id: user_id, + created_at: row[:post_time], + raw: post_text, + import_topic_id: row[:topic_id] + } + + if row[:topic_acceptedanswer_post_id] == row[:post_id] + mapped[:custom_fields] = { is_accepted_answer: "true" } + end + + if is_first_post + map_first_post(row, mapped) + else + map_other_post(row, mapped) + end + end + end + end + + def map_first_post(row, mapped) + mapped[:title] = CGI.unescapeHTML(row[:topic_title]).strip[0...255] + mapped[:views] = row[:topic_views] + mapped[:post_create_action] = proc do |post| + url = File.join(@settings[:permalink_prefix], "posts/list/#{row[:topic_id]}.page") + Permalink.create(url: url, topic_id: post.topic.id) unless Permalink.find_by(url: url) + + TopicViewItem.add(post.topic_id, row[:poster_ip], post.user_id, post.created_at, true) + end + + mapped[:tags] = @tags_by_import_forum_id[row[:forum_id]] if @settings[:import_categories_as_tags] + mapped[:category] = @lookup.category_id_from_imported_category_id(row[:forum_id]) + + mapped + end + + def map_other_post(row, mapped) + parent = @lookup.topic_lookup_from_imported_post_id(row[:topic_first_post_id]) + + if parent.blank? + puts "Parent post #{row[:topic_first_post_id]} doesn't exist. Skipping #{row[:post_id]}: #{row[:topic_title][0..40]}" + return nil + end + + mapped[:topic_id] = parent[:topic_id] + mapped[:post_create_action] = proc do |post| + TopicViewItem.add(post.topic_id, row[:poster_ip], post.user_id, post.created_at, true) + end + + mapped + end + + def import_attachments(post_id, user_id) + rows = query(<<~SQL) + SELECT d.physical_filename, d.real_filename + FROM jforum_attach a + JOIN jforum_attach_desc d USING (attach_id) + WHERE a.post_id = #{post_id} + ORDER BY a.attach_id + SQL + return nil if rows.size < 1 + + attachments = [] + + rows.each do |row| + path = File.join(@settings[:attachment_directory], row[:physical_filename]) + filename = CGI.unescapeHTML(row[:real_filename]) + upload = @uploader.create_upload(user_id, path, filename) + + if upload.nil? || !upload.persisted? + puts "Failed to upload #{path}" + puts upload.errors.inspect if upload + else + attachments << @uploader.html_for_upload(upload, filename) + end + end + + attachments + end + + def mark_topics_as_solved + puts "", "Marking topics as solved..." + + DB.exec <<~SQL + INSERT INTO topic_custom_fields (name, value, topic_id, created_at, updated_at) + SELECT 'accepted_answer_post_id', pcf.post_id, p.topic_id, p.created_at, p.created_at + FROM post_custom_fields pcf + JOIN posts p ON p.id = pcf.post_id + WHERE pcf.name = 'is_accepted_answer' AND pcf.value = 'true' + AND NOT EXISTS ( + SELECT 1 + FROM topic_custom_fields x + WHERE x.topic_id = p.topic_id AND x.name = 'accepted_answer_post_id' + ) + SQL + end + + def import_likes + puts "", "Importing likes..." + total_count = count(<<~SQL) + SELECT COUNT(1) AS count + FROM jforum_karma k + WHERE k.points >= 2 + AND EXISTS (SELECT 1 FROM jforum_posts p WHERE k.post_id = p.post_id) + AND EXISTS (SELECT 1 FROM jforum_users u WHERE k.from_user_id = u.user_id) + SQL + current_index = 0 + last_post_id = 0 + last_user_id = 0 + + batches do |_| + rows, last_post_id, last_user_id = query(<<~SQL, :post_id, :from_user_id) + SELECT k.post_id, k.from_user_id, k.rate_date + FROM jforum_karma k + WHERE k.points >= 2 AND ((k.post_id = #{last_post_id} AND k.from_user_id > #{last_user_id}) OR k.post_id > #{last_post_id}) + AND EXISTS (SELECT 1 FROM jforum_posts p WHERE k.post_id = p.post_id) + AND EXISTS (SELECT 1 FROM jforum_users u WHERE k.from_user_id = u.user_id) + ORDER BY k.post_id, k.from_user_id + LIMIT #{BATCH_SIZE} + SQL + break if rows.size < 1 + + rows.each do |row| + created_by = User.find_by(id: @lookup.user_id_from_imported_user_id(row[:from_user_id])) + post = Post.find_by(id: @lookup.post_id_from_imported_post_id(row[:post_id])) + + if created_by && post + PostActionCreator.create(created_by, post, :like, created_at: row[:rate_date]) + end + + current_index += 1 + print_status(current_index, total_count, get_start_time("likes")) + end + end + end + + def import_category_subscriptions + puts "", "Importing category subscriptions..." + total_count = count(<<~SQL) + SELECT COUNT(1) AS count + FROM ( + SELECT forum_id, user_id + FROM jforum_forums_watch + UNION + SELECT forum_id, user_id + FROM jforum_digest_forums + ) x + WHERE EXISTS (SELECT 1 FROM jforum_forums f WHERE x.forum_id = f.forum_id) + SQL + current_index = 0 + last_forum_id = 0 + last_user_id = 0 + + batches do |_| + rows, last_forum_id, last_user_id = query(<<~SQL, :forum_id, :user_id) + SELECT x.forum_id, x.user_id + FROM jforum_forums_watch x + WHERE ((x.forum_id = #{last_forum_id} AND x.user_id > #{last_user_id}) OR x.forum_id > #{last_forum_id}) + AND EXISTS (SELECT 1 FROM jforum_forums f WHERE x.forum_id = f.forum_id) + UNION + SELECT forum_id, user_id + FROM jforum_digest_forums x + WHERE ((x.forum_id = #{last_forum_id} AND x.user_id > #{last_user_id}) OR x.forum_id > #{last_forum_id}) + AND EXISTS (SELECT 1 FROM jforum_forums f WHERE x.forum_id = f.forum_id) + ORDER BY forum_id, user_id + LIMIT #{BATCH_SIZE} + SQL + break if rows.size < 1 + + tags = Tag.all.pluck(:name, :id).to_h + + rows.each do |row| + user_id = @lookup.user_id_from_imported_user_id(row[:user_id]) + + if @settings[:import_categories_as_tags] + tag_names = @tags_by_import_forum_id[row[:forum_id]] + tag_ids = tag_names ? tag_names.map { |name| tags[name] } : nil + + if user_id && tag_ids.present? + tag_ids.each do |tag_id| + TagUser.change(user_id, tag_id, TagUser.notification_levels[:watching]) + end + end + else + user = User.find_by(id: user_id) + category_id = @lookup.category_id_from_imported_category_id(row[:forum_id]) + + if user && category_id + CategoryUser.set_notification_level_for_category(user, NotificationLevels.all[:watching], category_id) + end + end + + current_index += 1 + print_status(current_index, total_count, get_start_time("category_subscriptions")) + end + end + end + + def import_topic_subscriptions + puts "", "Importing topic subscriptions..." + total_count = count(<<~SQL) + SELECT COUNT(1) AS count + FROM jforum_topics_watch x + WHERE EXISTS (SELECT 1 FROM jforum_topics t WHERE x.topic_id = t.topic_id) + SQL + current_index = 0 + last_topic_id = 0 + last_user_id = 0 + + batches do |_| + rows, last_topic_id, last_user_id = query(<<~SQL, :topic_id, :user_id) + SELECT x.topic_id, x.user_id, + COALESCE( + (SELECT x.post_id FROM jforum_posts x WHERE x.post_id = t.topic_first_post_id), + (SELECT MIN(x.post_id) FROM jforum_posts x WHERE x.topic_id = t.topic_id) + ) AS topic_first_post_id + FROM jforum_topics_watch x + JOIN jforum_topics t ON x.topic_id = t.topic_id + WHERE ((x.topic_id = #{last_topic_id} AND x.user_id > #{last_user_id}) OR x.topic_id > #{last_topic_id}) + ORDER BY topic_id, user_id + LIMIT #{BATCH_SIZE} + SQL + break if rows.size < 1 + + rows.each do |row| + user_id = @lookup.user_id_from_imported_user_id(row[:user_id]) + topic = @lookup.topic_lookup_from_imported_post_id(row[:topic_first_post_id]) + + if user_id && topic + TopicUser.change(user_id, topic[:topic_id], notification_level: NotificationLevels.all[:watching]) + end + + current_index += 1 + print_status(current_index, total_count, get_start_time("topic_subscriptions")) + end + end + end + + def fix_bbcodes(text) + return text if text.blank? + + text = text.dup + text.gsub!(/\r\n/, "\n") + + fix_bbcode_tag!(tag: "quote", text: text) + fix_bbcode_tag!(tag: "code", text: text) + fix_bbcode_tag!(tag: "list", text: text) + fix_bbcode_tag!(tag: "center", text: text) + fix_bbcode_tag!(tag: "right", text: text) + fix_bbcode_tag!(tag: "left", text: text) + + fix_inline_bbcode!(tag: "i", text: text) + fix_inline_bbcode!(tag: "b", text: text) + fix_inline_bbcode!(tag: "s", text: text) + fix_inline_bbcode!(tag: "u", text: text) + fix_inline_bbcode!(tag: "size", text: text) + fix_inline_bbcode!(tag: "font", text: text) + fix_inline_bbcode!(tag: "color", text: text) + + text + end + + def fix_bbcode_tag!(tag:, text:) + text.gsub!(/\s+(\[#{tag}\].*?\[\/#{tag}\])/im, '\1') + + text.gsub!(/(\[#{tag}.*?\])(?!$)/i) { "#{$1}\n" } + text.gsub!(/((?= 2 user' do + fab!(:topic_creator) { build(:user, trust_level: 2) } + fab!(:topic) { Fabricate(:topic, user: topic_creator) } + + before do + topic.allowed_users << topic_creator + topic.allowed_users << another_user + end + + it 'should be true' do + expect(Guardian.new(topic_creator).can_remove_allowed_users?(topic)) + .to eq(true) + end + end + context 'normal user' do - fab!(:topic) { Fabricate(:topic, user: Fabricate(:user)) } + fab!(:topic) { Fabricate(:topic, user: Fabricate(:user, trust_level: 1)) } before do topic.allowed_users << user @@ -3491,6 +3503,21 @@ describe Guardian do end end end + + context "anonymous users" do + fab!(:topic) { Fabricate(:topic) } + + it 'should be false' do + expect(Guardian.new.can_remove_allowed_users?(topic)).to eq(false) + end + + it 'should be false when the topic does not have a user (for example because the user was removed)' do + DB.exec("UPDATE topics SET user_id=NULL WHERE id=#{topic.id}") + topic.reload + + expect(Guardian.new.can_remove_allowed_users?(topic)).to eq(false) + end + end end describe '#auth_token' do diff --git a/spec/components/inline_oneboxer_spec.rb b/spec/components/inline_oneboxer_spec.rb index d99bab6d42..47c5abd6bb 100644 --- a/spec/components/inline_oneboxer_spec.rb +++ b/spec/components/inline_oneboxer_spec.rb @@ -26,7 +26,7 @@ describe InlineOneboxer do fab!(:topic) { Fabricate(:topic) } before do - InlineOneboxer.purge(topic.url) + InlineOneboxer.invalidate(topic.url) end it "puts an entry in the cache" do @@ -34,7 +34,7 @@ describe InlineOneboxer do url = "https://example.com/random-url" stub_request(:get, url).to_return(status: 200, body: "a blog") - InlineOneboxer.purge(url) + InlineOneboxer.invalidate(url) expect(InlineOneboxer.cache_lookup(url)).to be_blank result = InlineOneboxer.lookup(url) @@ -49,7 +49,7 @@ describe InlineOneboxer do SiteSetting.enable_inline_onebox_on_all_domains = true url = "https://example.com/random-url" - InlineOneboxer.purge(url) + InlineOneboxer.invalidate(url) expect(InlineOneboxer.cache_lookup(url)).to be_blank result = InlineOneboxer.lookup(url) diff --git a/spec/components/oneboxer_spec.rb b/spec/components/oneboxer_spec.rb index c5bc2dca86..f1681e5bc2 100644 --- a/spec/components/oneboxer_spec.rb +++ b/spec/components/oneboxer_spec.rb @@ -69,6 +69,9 @@ describe Oneboxer do expect(onebox).to include(%{data-post="2"}) expect(onebox).to include(PrettyText.avatar_img(replier.avatar_template, "tiny")) + short_url = "#{Discourse.base_uri}/t/#{public_topic.id}" + expect(preview(short_url, user, public_category)).to include(public_topic.title) + onebox = preview(public_moderator_action.url, user, public_category) expect(onebox).to include(public_moderator_action.excerpt) expect(onebox).to include(%{data-post="4"}) diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb index 5936959804..27fba7c486 100644 --- a/spec/components/post_creator_spec.rb +++ b/spec/components/post_creator_spec.rb @@ -1203,7 +1203,7 @@ describe PostCreator do end context 'private message to a user that has disabled private messages' do - fab!(:another_user) { Fabricate(:user) } + fab!(:another_user) { Fabricate(:user, username: 'HelloWorld') } before do another_user.user_option.update!(allow_private_messages: false) @@ -1224,6 +1224,18 @@ describe PostCreator do "not_accepting_pms", username: another_user.username )) end + + it 'should not be valid if the name is downcased' do + post_creator = 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: "#{another_user.username.downcase}" + ) + + expect(post_creator).to_not be_valid + end end context "private message to a muted user" do diff --git a/spec/components/pretty_text_spec.rb b/spec/components/pretty_text_spec.rb index 49a3ac90ba..823fb8900c 100644 --- a/spec/components/pretty_text_spec.rb +++ b/spec/components/pretty_text_spec.rb @@ -1106,9 +1106,9 @@ describe PrettyText do [ "#unknown::tag", - "#known", + "#known", "#known", - "#testing" + "#testing" ].each do |element| expect(cooked).to include(element) diff --git a/spec/components/validators/selectable_avatars_enabled_validator_spec.rb b/spec/components/validators/selectable_avatars_enabled_validator_spec.rb new file mode 100644 index 0000000000..2635e2e374 --- /dev/null +++ b/spec/components/validators/selectable_avatars_enabled_validator_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe SelectableAvatarsEnabledValidator do + describe '#valid_value?' do + subject(:validator) { described_class.new } + + it "returns true when disabling" do + SiteSetting.selectable_avatars = "" + expect(validator.valid_value?("f")).to eq(true) + + SiteSetting.selectable_avatars = [Fabricate(:image_upload).url, Fabricate(:image_upload).url].join("\n") + expect(validator.valid_value?("f")).to eq(true) + end + + it "returns true when there are at least two selectable avatars" do + SiteSetting.selectable_avatars = [Fabricate(:image_upload).url, Fabricate(:image_upload).url].join("\n") + expect(validator.valid_value?("t")).to eq(true) + end + + it "returns false when selectable avatars is blank or has one avatar" do + SiteSetting.selectable_avatars = "" + expect(validator.valid_value?("t")).to eq(false) + + SiteSetting.selectable_avatars = Fabricate(:image_upload).url + expect(validator.valid_value?("t")).to eq(false) + end + end +end diff --git a/spec/fabricators/published_page_fabricator.rb b/spec/fabricators/published_page_fabricator.rb index 44f8da98da..0c090ee5d9 100644 --- a/spec/fabricators/published_page_fabricator.rb +++ b/spec/fabricators/published_page_fabricator.rb @@ -2,5 +2,6 @@ Fabricator(:published_page) do topic - slug "published-page-test" + slug "published-page-test-#{SecureRandom.hex}" + public false end diff --git a/spec/fabricators/upload_fabricator.rb b/spec/fabricators/upload_fabricator.rb index 65e4a1bf2f..62272ecb9e 100644 --- a/spec/fabricators/upload_fabricator.rb +++ b/spec/fabricators/upload_fabricator.rb @@ -66,6 +66,20 @@ Fabricator(:upload_s3, from: :upload) do end end +Fabricator(:s3_image_upload, from: :upload_s3) do + after_create do |upload| + file = Tempfile.new(['fabricated', '.png']) + `convert -size #{upload.width}x#{upload.height} xc:white "#{file.path}"` + + Discourse.store.store_upload(file, upload) + upload.sha1 = Upload.generate_digest(file.path) + + WebMock + .stub_request(:get, upload.url) + .to_return(status: 200, body: File.new(file.path)) + end +end + Fabricator(:secure_upload_s3, from: :upload_s3) do secure true sha1 { SecureRandom.hex(20) } diff --git a/spec/fixtures/db/restore/trigger.sql b/spec/fixtures/db/restore/trigger.sql new file mode 100644 index 0000000000..78621ecaf6 --- /dev/null +++ b/spec/fixtures/db/restore/trigger.sql @@ -0,0 +1,55 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 12.2 (Debian 12.2-2.pgdg100+1) +-- Dumped by pg_dump version 12.2 (Debian 12.2-2.pgdg100+1) + +-- Started on 2020-06-15 08:06:34 UTC + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- TOC entry 5 (class 2615 OID 2200) +-- Name: public; Type: SCHEMA; Schema: -; Owner: - +-- + +CREATE SCHEMA public; + + +-- +-- TOC entry 7007 (class 0 OID 0) +-- Dependencies: 5 +-- Name: SCHEMA public; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON SCHEMA public IS 'standard public schema'; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- TOC entry 198 (class 1259 OID 16585) +-- Name: foo; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.foo ( + id integer NOT NULL, + topic_id integer, + user_id integer +); + + +CREATE TRIGGER foo_topic_id_readonly BEFORE INSERT OR UPDATE OF redeemed_at ON public.foo FOR EACH ROW WHEN ((new.topic_id IS NOT NULL)) EXECUTE FUNCTION discourse_functions.raise_foo_topic_id_readonly(); + +CREATE TRIGGER foo_user_id_readonly BEFORE INSERT OR UPDATE OF user_id ON public.foo FOR EACH ROW WHEN ((new.user_id IS NOT NULL)) EXECUTE FUNCTION discourse_functions.raise_foo_user_id_readonly(); diff --git a/spec/fixtures/media/small.mp3 b/spec/fixtures/media/small.mp3 new file mode 100644 index 0000000000..084a7d1f8d Binary files /dev/null and b/spec/fixtures/media/small.mp3 differ diff --git a/spec/fixtures/media/small.mp4 b/spec/fixtures/media/small.mp4 new file mode 100644 index 0000000000..ed139d6d50 Binary files /dev/null and b/spec/fixtures/media/small.mp4 differ diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 7626bbbc39..2ccca114b3 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -342,7 +342,6 @@ describe ApplicationHelper do expect(helper.crawlable_meta_data).to include(SiteSetting.site_logo_url) SiteSetting.logo = nil - SiteSetting.logo_url = nil expect(helper.crawlable_meta_data).to include(Upload.find(SiteIconManager::SKETCH_LOGO_ID).url) end diff --git a/spec/jobs/clean_up_deprecated_url_site_settings_spec.rb b/spec/jobs/clean_up_deprecated_url_site_settings_spec.rb deleted file mode 100644 index fd52644eae..0000000000 --- a/spec/jobs/clean_up_deprecated_url_site_settings_spec.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Jobs::CleanUpDeprecatedUrlSiteSettings do - before do - @original_provider = SiteSetting.provider - SiteSetting.provider = SiteSettings::DbProvider.new(SiteSetting) - end - - after do - SiteSetting.delete_all - SiteSetting.provider = @original_provider - end - - it 'should clean up the old deprecated site settings correctly' do - logo_upload = Fabricate(:upload) - SiteSetting.logo = logo_upload - SiteSetting.set("logo_url", '/test/some/url', warn: false) - SiteSetting.set("logo_small_url", '/test/another/url', warn: false) - - expect do - described_class.new.execute({}) - end.to change { SiteSetting.logo_url }.from("/test/some/url").to("") - - expect(SiteSetting.exists?(name: "logo_url")).to eq(false) - expect(SiteSetting.logo).to eq(logo_upload) - expect(SiteSetting.logo_small_url).to eq('/test/another/url') - end -end diff --git a/spec/jobs/clean_up_uploads_spec.rb b/spec/jobs/clean_up_uploads_spec.rb index 3608e04398..828e1b6c9b 100644 --- a/spec/jobs/clean_up_uploads_spec.rb +++ b/spec/jobs/clean_up_uploads_spec.rb @@ -127,60 +127,18 @@ describe Jobs::CleanUpUploads do end it "does not clean up uploads with URLs used in site settings" do - logo_upload = fabricate_upload - logo_small_upload = fabricate_upload - digest_logo_upload = fabricate_upload - mobile_logo_upload = fabricate_upload - large_icon_upload = fabricate_upload - default_opengraph_image_upload = fabricate_upload - twitter_summary_large_image_upload = fabricate_upload - favicon_upload = fabricate_upload - apple_touch_icon_upload = fabricate_upload avatar1_upload = fabricate_upload avatar2_upload = fabricate_upload - SiteSetting.logo_url = logo_upload.url - SiteSetting.logo_small_url = logo_small_upload.url - SiteSetting.digest_logo_url = digest_logo_upload.url - SiteSetting.mobile_logo_url = mobile_logo_upload.url - SiteSetting.large_icon_url = large_icon_upload.url - SiteSetting.default_opengraph_image_url = default_opengraph_image_upload.url - - SiteSetting.twitter_summary_large_image_url = - twitter_summary_large_image_upload.url - - SiteSetting.favicon_url = favicon_upload.url - SiteSetting.apple_touch_icon_url = apple_touch_icon_upload.url SiteSetting.selectable_avatars = [avatar1_upload.url, avatar2_upload.url].join("\n") Jobs::CleanUpUploads.new.execute(nil) expect(Upload.exists?(id: expired_upload.id)).to eq(false) - expect(Upload.exists?(id: logo_upload.id)).to eq(true) - expect(Upload.exists?(id: logo_small_upload.id)).to eq(true) - expect(Upload.exists?(id: digest_logo_upload.id)).to eq(true) - expect(Upload.exists?(id: mobile_logo_upload.id)).to eq(true) - expect(Upload.exists?(id: large_icon_upload.id)).to eq(true) - expect(Upload.exists?(id: default_opengraph_image_upload.id)).to eq(true) - expect(Upload.exists?(id: twitter_summary_large_image_upload.id)).to eq(true) - expect(Upload.exists?(id: favicon_upload.id)).to eq(true) - expect(Upload.exists?(id: apple_touch_icon_upload.id)).to eq(true) expect(Upload.exists?(id: avatar1_upload.id)).to eq(true) expect(Upload.exists?(id: avatar2_upload.id)).to eq(true) end - it "does not clean up uploads in site settings when they use the CDN" do - Discourse.stubs(:asset_host).returns("//my.awesome.cdn") - - logo_small_upload = fabricate_upload - SiteSetting.logo_small_url = "#{Discourse.asset_host}#{logo_small_upload.url}" - - Jobs::CleanUpUploads.new.execute(nil) - - expect(Upload.exists?(id: expired_upload.id)).to eq(false) - expect(Upload.exists?(id: logo_small_upload.id)).to eq(true) - end - it "does not delete profile background uploads" do profile_background_upload = fabricate_upload UserProfile.last.upload_profile_background(profile_background_upload) diff --git a/spec/jobs/migrate_url_site_settings_spec.rb b/spec/jobs/migrate_url_site_settings_spec.rb deleted file mode 100644 index c3331f0f65..0000000000 --- a/spec/jobs/migrate_url_site_settings_spec.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Jobs::MigrateUrlSiteSettings do - before do - SiteSetting.authorized_extensions = '' - end - - it 'should migrate to the new upload site settings correctly' do - [ - %w{logo_url /test.png}, - %w{logo_small_url https://test.discourse.awesome/test.png}, - %w{favicon_url http://test.discourse.awesome/some.ico}, - %w{digest_logo_url /test.png}, - %w{mobile_logo_url /test.png}, - %w{large_icon_url /test.png}, - %w{apple_touch_icon_url /test.png}, - %w{default_opengraph_image_url /test.png}, - %w{twitter_summary_large_image_url //omg.aws.somestack/test.png}, - %w{push_notifications_icon_url //omg.aws.somestack/test.png} - ].each do |name, value| - - SiteSetting.create!( - name: name, - value: value, - data_type: SiteSettings::TypeSupervisor.types[:string] - ) - end - - %w{ - http://test.localhost/test.png - https://omg.aws.somestack/test.png - }.each do |url| - stub_request(:get, url).to_return( - status: 200, body: file_from_fixtures("smallest.png").read - ) - end - - stub_request(:get, "https://test.discourse.awesome/test.png") - .to_return(status: 200, body: file_from_fixtures("downsized.png").read) - - stub_request(:get, "http://test.discourse.awesome/some.ico") - .to_return(status: 200, body: file_from_fixtures("smallest.ico").read) - - expect do - described_class.new.execute_onceoff({}) - end.to change { Upload.count }.by(3) - - upload = Upload.find_by(original_filename: "logo.png") - upload2 = Upload.find_by(original_filename: "logo_small.png") - upload3 = Upload.find_by(original_filename: "favicon.ico") - - expect(SiteSetting.logo_small).to eq(upload2) - expect(SiteSetting.logo_small.is_a?(Upload)).to eq(true) - - expect(SiteSetting.favicon).to eq(upload3) - expect(SiteSetting.favicon.is_a?(Upload)).to eq(true) - - %i{ - logo - digest_logo - mobile_logo - large_icon - apple_touch_icon - opengraph_image - twitter_summary_large_image - push_notifications_icon - }.each do |setting| - expect(SiteSetting.get(setting)).to eq(upload) - expect(SiteSetting.get(setting).is_a?(Upload)).to eq(true) - end - end -end diff --git a/spec/jobs/pull_hotlinked_images_spec.rb b/spec/jobs/pull_hotlinked_images_spec.rb index 5e6003d0b7..3aebe91a98 100644 --- a/spec/jobs/pull_hotlinked_images_spec.rb +++ b/spec/jobs/pull_hotlinked_images_spec.rb @@ -222,6 +222,16 @@ describe Jobs::PullHotlinkedImages do MD end + it 'works when invalid url in post' do + post = Fabricate(:post, raw: <<~MD) + ![some test](#{image_url}) + ![some test 2]("#{image_url}) + MD + + expect { Jobs::PullHotlinkedImages.new.execute(post_id: post.id) } + .to change { Upload.count }.by(1) + end + it 'replaces bbcode images' do post = Fabricate(:post, raw: <<~MD) [img] @@ -350,6 +360,33 @@ describe Jobs::PullHotlinkedImages do end end + it "returns false for emoji" do + src = Emoji.url_for("testemoji.png") + expect(subject.should_download_image?(src)).to eq(false) + end + + it "returns false for emoji when app and S3 CDNs configured" do + set_cdn_url "https://mydomain.cdn/test" + SiteSetting.s3_upload_bucket = "some-bucket-on-s3" + SiteSetting.s3_access_key_id = "s3-access-key-id" + SiteSetting.s3_secret_access_key = "s3-secret-access-key" + SiteSetting.s3_cdn_url = "https://s3.cdn.com" + SiteSetting.enable_s3_uploads = true + + src = UrlHelper.cook_url(Emoji.url_for("testemoji.png")) + expect(subject.should_download_image?(src)).to eq(false) + end + + it "returns false for plugin assets" do + src = UrlHelper.cook_url("/plugins/discourse-amazing-plugin/myasset.png") + expect(subject.should_download_image?(src)).to eq(false) + end + + it "returns false for local non-uploaded files" do + src = UrlHelper.cook_url("/mycustomroute.png") + expect(subject.should_download_image?(src)).to eq(false) + end + context "when download_remote_images_to_local? is false" do before do SiteSetting.download_remote_images_to_local = false @@ -360,11 +397,6 @@ describe Jobs::PullHotlinkedImages do expect(subject.should_download_image?(src)).to eq(true) end - it "returns false for emoji" do - src = Emoji.url_for("testemoji.png") - expect(subject.should_download_image?(src)).to eq(false) - end - it 'returns false for valid remote URLs' do expect(subject.should_download_image?("http://meta.discourse.org")).to eq(false) end diff --git a/spec/lib/backup_restore/database_restorer_spec.rb b/spec/lib/backup_restore/database_restorer_spec.rb index 8a7b9ec8a9..09c203878b 100644 --- a/spec/lib/backup_restore/database_restorer_spec.rb +++ b/spec/lib/backup_restore/database_restorer_spec.rb @@ -127,6 +127,51 @@ describe BackupRestore::DatabaseRestorer do end end + context "rewrites database dump" do + let(:logger) do + Class.new do + attr_reader :log_messages + + def initialize + @log_messages = [] + end + + def log(message, ex = nil) + @log_messages << message if message + end + end.new + end + + def restore_and_log_output(filename) + path = File.join(Rails.root, "spec/fixtures/db/restore", filename) + BackupRestore::DatabaseRestorer.stubs(:psql_command).returns("cat") + execute_stubbed_restore(stub_psql: false, dump_file_path: path) + logger.log_messages.join("\n") + end + + it "replaces `EXECUTE FUNCTION` when restoring on PostgreSQL < 11" do + BackupRestore.stubs(:postgresql_major_version).returns(10) + log = restore_and_log_output("trigger.sql") + + expect(log).not_to be_blank + expect(log).not_to match(/CREATE SCHEMA public/) + expect(log).not_to match(/EXECUTE FUNCTION/) + expect(log).to match(/^CREATE TRIGGER foo_topic_id_readonly .+? EXECUTE PROCEDURE discourse_functions.raise_foo_topic_id_readonly/) + expect(log).to match(/^CREATE TRIGGER foo_user_id_readonly .+? EXECUTE PROCEDURE discourse_functions.raise_foo_user_id_readonly/) + end + + it "does not replace `EXECUTE FUNCTION` when restoring on PostgreSQL >= 11" do + BackupRestore.stubs(:postgresql_major_version).returns(11) + log = restore_and_log_output("trigger.sql") + + expect(log).not_to be_blank + expect(log).not_to match(/CREATE SCHEMA public/) + expect(log).not_to match(/EXECUTE PROCEDURE/) + expect(log).to match(/^CREATE TRIGGER foo_topic_id_readonly .+? EXECUTE FUNCTION discourse_functions.raise_foo_topic_id_readonly/) + expect(log).to match(/^CREATE TRIGGER foo_user_id_readonly .+? EXECUTE FUNCTION discourse_functions.raise_foo_user_id_readonly/) + end + end + context "database connection" do it 'reconnects to the correct database', type: :multisite do RailsMultisite::ConnectionManagement.establish_connection(db: 'second') diff --git a/spec/lib/shrink_uploaded_image_spec.rb b/spec/lib/shrink_uploaded_image_spec.rb new file mode 100644 index 0000000000..8c8e47165a --- /dev/null +++ b/spec/lib/shrink_uploaded_image_spec.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ShrinkUploadedImage do + context "when local uploads are enabled" do + let(:upload) { Fabricate(:image_upload, width: 200, height: 200) } + + it "resizes the image" do + filesize_before = upload.filesize + post = Fabricate(:post, raw: "") + post.link_post_uploads + + result = ShrinkUploadedImage.new( + upload: upload, + path: Discourse.store.path_for(upload), + max_pixels: 10_000 + ).perform + + expect(result).to be(true) + expect(upload.width).to eq(100) + expect(upload.height).to eq(100) + expect(upload.filesize).to be < filesize_before + end + + it "returns false if the image is not used by any models" do + result = ShrinkUploadedImage.new( + upload: upload, + path: Discourse.store.path_for(upload), + max_pixels: 10_000 + ).perform + + expect(result).to be(false) + end + + it "returns false if the image cannot be shrunk more" do + post = Fabricate(:post, raw: "") + post.link_post_uploads + ShrinkUploadedImage.new( + upload: upload, + path: Discourse.store.path_for(upload), + max_pixels: 10_000 + ).perform + + upload.reload + + result = ShrinkUploadedImage.new( + upload: upload, + path: Discourse.store.path_for(upload), + max_pixels: 10_000 + ).perform + + expect(result).to be(false) + end + + it "returns false when the upload is above the size limit" do + post = Fabricate(:post, raw: "") + post.link_post_uploads + SiteSetting.max_image_size_kb = 0.001 # 1 byte + + result = ShrinkUploadedImage.new( + upload: upload, + path: Discourse.store.path_for(upload), + max_pixels: 10_000 + ).perform + + expect(result).to be(false) + end + end + + context "when S3 uploads are enabled" do + let(:upload) { Fabricate(:s3_image_upload, width: 200, height: 200) } + + before do + SiteSetting.enable_s3_uploads = true + SiteSetting.s3_access_key_id = "fakeid7974664" + SiteSetting.s3_secret_access_key = "fakesecretid7974664" + + store = FileStore::S3Store.new + s3_helper = store.instance_variable_get(:@s3_helper) + client = Aws::S3::Client.new(stub_responses: true) + s3_helper.stubs(:s3_client).returns(client) + Discourse.stubs(:store).returns(store) + end + + it "resizes the image" do + filesize_before = upload.filesize + post = Fabricate(:post, raw: "") + post.link_post_uploads + + result = ShrinkUploadedImage.new( + upload: upload, + path: Discourse.store.download(upload).path, + max_pixels: 10_000 + ).perform + + expect(result).to be(true) + expect(upload.width).to eq(100) + expect(upload.height).to eq(100) + expect(upload.filesize).to be < filesize_before + end + end +end diff --git a/spec/mailers/subscription_mailer_spec.rb b/spec/mailers/subscription_mailer_spec.rb new file mode 100644 index 0000000000..696231d4ff --- /dev/null +++ b/spec/mailers/subscription_mailer_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require "rails_helper" + +describe SubscriptionMailer do + fab!(:user) { Fabricate(:user) } + + subject { SubscriptionMailer.confirm_unsubscribe(user) } + + it "contains the right URL" do + expect(subject.body).to include("#{Discourse.base_url}/email/unsubscribe/#{UnsubscribeKey.last.key}") + end +end diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index 7b550a9c1d..cab079d3cc 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -430,7 +430,7 @@ describe Category do end it "reuses existing permalink when category slug is changed" do - permalink = Permalink.create!(url: "c/#{@category.slug}", category_id: 42) + permalink = Permalink.create!(url: "c/#{@category.slug}/#{@category.id}", category_id: 42) expect { @category.update(slug: 'new-slug') }.to_not change { Permalink.count } expect(permalink.reload.category_id).to eq(@category.id) @@ -695,47 +695,20 @@ describe Category do describe "for normal categories" do it "builds a url" do - expect(category.url).to eq("/c/root") + expect(category.url).to eq("/c/root/#{category.id}") end end describe "for subcategories" do it "builds a url" do - expect(sub_category.url).to eq("/c/root/child") + expect(sub_category.url).to eq("/c/root/child/#{sub_category.id}") end end describe "for sub-sub-categories" do it "builds a url" do expect(sub_sub_category.url) - .to eq("/c/root/child/child-of-child") - end - end - end - - describe "#url_with_id" do - fab!(:category) do - Fabricate( - :category_with_definition, - name: 'cats', - ) - end - - it "includes the id in the URL" do - expect(category.url_with_id).to eq("/c/cats/#{category.id}") - end - - context "child category" do - fab!(:child_category) do - Fabricate( - :category, - parent_category_id: category.id, - name: 'dogs', - ) - end - - it "includes the id in the URL" do - expect(child_category.url_with_id).to eq("/c/cats/dogs/#{child_category.id}") + .to eq("/c/root/child/child-of-child/#{sub_sub_category.id}") end end end @@ -1161,6 +1134,24 @@ describe Category do end end + describe "messageBus" do + it "does not publish notification level when publishing to /categories" do + category = Fabricate(:category) + category.name = "Amazing category" + messages = MessageBus.track_publish("/categories") do + category.save! + end + + expect(messages.length).to eq(1) + message = messages.first + + category_hash = message.data[:categories].first + + expect(category_hash[:name]).to eq(category.name) + expect(category_hash.key?(:notification_level)).to eq(false) + end + end + describe "#ensure_consistency!" do it "creates category topic" do diff --git a/spec/models/embeddable_host_spec.rb b/spec/models/embeddable_host_spec.rb index 449c87aa2f..66b81b9bd4 100644 --- a/spec/models/embeddable_host_spec.rb +++ b/spec/models/embeddable_host_spec.rb @@ -52,6 +52,12 @@ describe EmbeddableHost do expect(eh.host).to eq('discourse.localhost') end + it "supports multiple hyphens" do + eh = EmbeddableHost.new(host: 'deploy-preview-1--example.example.app') + expect(eh).to be_valid + expect(eh.host).to eq('deploy-preview-1--example.example.app') + end + it "rejects misspellings of localhost" do eh = EmbeddableHost.new(host: 'alocalhost') expect(eh).not_to be_valid diff --git a/spec/models/global_setting_spec.rb b/spec/models/global_setting_spec.rb index d923d6e31d..8802418277 100644 --- a/spec/models/global_setting_spec.rb +++ b/spec/models/global_setting_spec.rb @@ -86,7 +86,7 @@ describe GlobalSetting do GlobalSetting.expects(:redis_slave_port).returns(6379).at_least_once GlobalSetting.expects(:redis_slave_host).returns('0.0.0.0').at_least_once - expect(GlobalSetting.redis_config[:connector]).to eq(DiscourseRedis::Connector) + expect(GlobalSetting.redis_config[:connector]).to eq(RailsFailover::Redis::Connector) end end end diff --git a/spec/models/invite_redeemer_spec.rb b/spec/models/invite_redeemer_spec.rb index d29c9b6f57..fd3d52cf2b 100644 --- a/spec/models/invite_redeemer_spec.rb +++ b/spec/models/invite_redeemer_spec.rb @@ -144,9 +144,19 @@ describe InviteRedeemer do expect(user.custom_fields["user_field_#{optional_field.id}"]).to eq('value2') end + it "does not add user to group if inviter does not have permissions" do + group = Fabricate(:group, grant_trust_level: 2) + InvitedGroup.create(group_id: group.id, invite_id: invite.id) + user = InviteRedeemer.new(invite: invite, email: invite.email, username: username, name: name, password: password).redeem + + expect(user.group_users.count).to eq(0) + end + it "adds user to group" do group = Fabricate(:group, grant_trust_level: 2) InvitedGroup.create(group_id: group.id, invite_id: invite.id) + group.add_owner(invite.invited_by) + user = InviteRedeemer.new(invite: invite, email: invite.email, username: username, name: name, password: password).redeem expect(user.group_users.count).to eq(4) diff --git a/spec/models/invite_spec.rb b/spec/models/invite_spec.rb index bd896e0777..047b58cb9f 100644 --- a/spec/models/invite_spec.rb +++ b/spec/models/invite_spec.rb @@ -306,6 +306,7 @@ describe Invite do context "when inviting to groups" do it "add the user to the correct groups" do group = Fabricate(:group) + group.add_owner(invite.invited_by) invite.invited_groups.build(group_id: group.id) invite.save diff --git a/spec/models/permalink_spec.rb b/spec/models/permalink_spec.rb index 869d38fba5..709768e5d0 100644 --- a/spec/models/permalink_spec.rb +++ b/spec/models/permalink_spec.rb @@ -63,7 +63,7 @@ describe Permalink do it "returns a category url when category_id is set" do permalink.category_id = category.id - expect(target_url).to eq("#{category.url}/#{category.id}") + expect(target_url).to eq("#{category.url}") end it "returns nil when category_id is set but category is not found" do diff --git a/spec/models/post_analyzer_spec.rb b/spec/models/post_analyzer_spec.rb index d74b72a4e1..70addd30cd 100644 --- a/spec/models/post_analyzer_spec.rb +++ b/spec/models/post_analyzer_spec.rb @@ -31,6 +31,7 @@ describe PostAnalyzer do it 'invalidates the oneboxes for urls in the post' do Oneboxer.expects(:invalidate).with url + InlineOneboxer.expects(:invalidate).with url post_analyzer.cook(raw, options) end end diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index fe4fe1add1..24c89305dd 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -1375,6 +1375,16 @@ describe Post do let(:post) { Fabricate(:post, raw: raw_multiple) } + it "removes post uploads on destroy" do + post.link_post_uploads + + post.trash! + expect(PostUpload.count).to eq(6) + + post.destroy! + expect(PostUpload.count).to eq(0) + end + context "#link_post_uploads" do it "finds all the uploads in the post" do post.custom_fields[Post::DOWNLOADED_IMAGES] = { diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index d1d5d1cc91..ead96218b2 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -255,19 +255,27 @@ describe Topic do end context 'topic title uniqueness' do + let!(:category1) { Fabricate(:category) } + let!(:category2) { Fabricate(:category) } - let!(:topic) { Fabricate(:topic) } - let(:new_topic) { Fabricate.build(:topic, title: topic.title) } + let!(:topic) { Fabricate(:topic, category: category1) } + let(:new_topic) { Fabricate.build(:topic, title: topic.title, category: category1) } + let(:new_topic_different_cat) { Fabricate.build(:topic, title: topic.title, category: category2) } context "when duplicates aren't allowed" do before do - SiteSetting.expects(:allow_duplicate_topic_titles?).returns(false) + SiteSetting.allow_duplicate_topic_titles = false + SiteSetting.allow_duplicate_topic_titles_category = false end it "won't allow another topic to be created with the same name" do expect(new_topic).not_to be_valid end + it "won't even allow another topic to be created with the same name but different category" do + expect(new_topic_different_cat).not_to be_valid + end + it "won't allow another topic with an upper case title to be created" do new_topic.title = new_topic.title.upcase expect(new_topic).not_to be_valid @@ -286,7 +294,8 @@ describe Topic do context "when duplicates are allowed" do before do - SiteSetting.expects(:allow_duplicate_topic_titles?).returns(true) + SiteSetting.allow_duplicate_topic_titles = true + SiteSetting.allow_duplicate_topic_titles_category = false end it "will allow another topic to be created with the same name" do @@ -294,6 +303,21 @@ describe Topic do end end + context "when duplicates are allowed if the category is different" do + before do + SiteSetting.allow_duplicate_topic_titles = false + SiteSetting.allow_duplicate_topic_titles_category = true + end + + it "will allow another topic to be created with the same name but different category" do + expect(new_topic_different_cat).to be_valid + end + + it "won't allow another topic to be created with the same name in same category" do + expect(new_topic).not_to be_valid + end + end + end context 'html in title' do diff --git a/spec/models/topic_tracking_state_spec.rb b/spec/models/topic_tracking_state_spec.rb index ae0f852d63..7baf794b04 100644 --- a/spec/models/topic_tracking_state_spec.rb +++ b/spec/models/topic_tracking_state_spec.rb @@ -585,6 +585,14 @@ describe TopicTrackingState do expect(row.tags).to contain_exactly("apples", "bananas") TopicTrackingState.include_tags_in_report = false + SiteSetting.show_filter_by_tag = true + + report = TopicTrackingState.report(user) + expect(report.length).to eq(1) + row = report[0] + expect(row.tags).to contain_exactly("apples", "bananas") + + SiteSetting.show_filter_by_tag = false report = TopicTrackingState.report(user) expect(report.length).to eq(1) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 2a50cd82c1..791153b43f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -164,6 +164,30 @@ describe User do end end + context 'enqueue_staff_welcome_message' do + let!(:first_admin) { Fabricate(:admin) } + let(:user) { Fabricate(:user) } + + it 'enqueues message for admin' do + expect { + user.grant_admin! + }.to change { Jobs::SendSystemMessage.jobs.count }.by 1 + end + + it 'enqueues message for moderator' do + expect { + user.grant_moderation! + }.to change { Jobs::SendSystemMessage.jobs.count }.by 1 + end + + it 'skips the message if already an admin' do + user.update(admin: true) + expect { + user.grant_admin! + }.to change { Jobs::SendSystemMessage.jobs.count }.by 0 + end + end + context '.set_default_tags_preferences' do let(:tag) { Fabricate(:tag) } @@ -2009,8 +2033,8 @@ describe User do it "sets a random avatar when selectable avatars is enabled" do avatar1 = Fabricate(:upload) avatar2 = Fabricate(:upload) - SiteSetting.selectable_avatars_enabled = true SiteSetting.selectable_avatars = [avatar1.url, avatar2.url].join("\n") + SiteSetting.selectable_avatars_enabled = true user = Fabricate(:user) expect(user.uploaded_avatar_id).not_to be(nil) @@ -2200,6 +2224,7 @@ describe User do UserAction.create!(user_id: user.id, action_type: UserAction::LIKE) UserAction.create!(user_id: -1, action_type: UserAction::LIKE, target_user_id: user.id) UserAction.create!(user_id: -1, action_type: UserAction::LIKE, acting_user_id: user.id) + Developer.create!(user_id: user.id) user.reload @@ -2209,6 +2234,7 @@ describe User do expect(UserAction.where(target_user_id: user.id).length).to eq(0) expect(UserAction.where(acting_user_id: user.id).length).to eq(0) expect(PostAction.with_deleted.where(user_id: user.id).length).to eq(0) + expect(Developer.where(user_id: user.id).length).to eq(0) end end diff --git a/spec/multisite/s3_store_spec.rb b/spec/multisite/s3_store_spec.rb index 5681a1df8d..c857e3e9dd 100644 --- a/spec/multisite/s3_store_spec.rb +++ b/spec/multisite/s3_store_spec.rb @@ -4,12 +4,13 @@ require 'rails_helper' require 'file_store/s3_store' RSpec.describe 'Multisite s3 uploads', type: :multisite do - let(:uploaded_file) { file_from_fixtures("smallest.png") } + let(:original_filename) { "smallest.png" } + let(:uploaded_file) { file_from_fixtures(original_filename) } let(:upload_sha1) { Digest::SHA1.hexdigest(File.read(uploaded_file)) } let(:upload_path) { Discourse.store.upload_path } def build_upload - Fabricate.build(:upload, sha1: upload_sha1, id: 1) + Fabricate.build(:upload, sha1: upload_sha1, id: 1, original_filename: original_filename) end context 'uploading to s3' do @@ -24,6 +25,55 @@ RSpec.describe 'Multisite s3 uploads', type: :multisite do let(:s3_client) { Aws::S3::Client.new(stub_responses: true) } let(:s3_helper) { S3Helper.new(SiteSetting.s3_upload_bucket, '', client: s3_client) } let(:store) { FileStore::S3Store.new(s3_helper) } + let(:upload_opts) do + { + acl: "public-read", + cache_control: "max-age=31556952, public, immutable", + content_type: "image/png" + } + end + + it "does not provide a content_disposition for images" do + s3_helper.expects(:upload).with(uploaded_file, kind_of(String), upload_opts).returns(["path", "etag"]) + upload = build_upload + store.store_upload(uploaded_file, upload) + end + + context "when the file is a PDF" do + let(:original_filename) { "small.pdf" } + let(:uploaded_file) { file_from_fixtures("small.pdf", "pdf") } + + it "adds an attachment content-disposition with the original filename" do + disp_opts = { content_disposition: "attachment; filename=\"#{original_filename}\"; filename*=UTF-8''#{original_filename}", content_type: "application/pdf" } + s3_helper.expects(:upload).with(uploaded_file, kind_of(String), upload_opts.merge(disp_opts)).returns(["path", "etag"]) + upload = build_upload + store.store_upload(uploaded_file, upload) + end + end + + context "when the file is a video" do + let(:original_filename) { "small.mp4" } + let(:uploaded_file) { file_from_fixtures("small.mp4", "media") } + + it "adds an attachment content-disposition with the original filename" do + disp_opts = { content_disposition: "attachment; filename=\"#{original_filename}\"; filename*=UTF-8''#{original_filename}", content_type: "application/mp4" } + s3_helper.expects(:upload).with(uploaded_file, kind_of(String), upload_opts.merge(disp_opts)).returns(["path", "etag"]) + upload = build_upload + store.store_upload(uploaded_file, upload) + end + end + + context "when the file is audio" do + let(:original_filename) { "small.mp3" } + let(:uploaded_file) { file_from_fixtures("small.mp3", "media") } + + it "adds an attachment content-disposition with the original filename" do + disp_opts = { content_disposition: "attachment; filename=\"#{original_filename}\"; filename*=UTF-8''#{original_filename}", content_type: "audio/mpeg" } + s3_helper.expects(:upload).with(uploaded_file, kind_of(String), upload_opts.merge(disp_opts)).returns(["path", "etag"]) + upload = build_upload + store.store_upload(uploaded_file, upload) + end + end it "returns the correct url for default and second multisite db" do test_multisite_connection('default') do diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index dd4879d7fe..6b6d1265b0 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -8,11 +8,9 @@ end require 'rubygems' require 'rbtrace' -if ENV['IMPROVED_SPEC_DEBUGGING'] - require 'pry' - require 'pry-byebug' - require 'pry-rails' -end +require 'pry' +require 'pry-byebug' +require 'pry-rails' # Loading more in this block will cause your tests to run faster. However, # if you change any configuration or code from libraries loaded here, you'll diff --git a/spec/requests/admin/site_settings_controller_spec.rb b/spec/requests/admin/site_settings_controller_spec.rb index 7962ab295d..1b74fb9f64 100644 --- a/spec/requests/admin/site_settings_controller_spec.rb +++ b/spec/requests/admin/site_settings_controller_spec.rb @@ -97,8 +97,9 @@ describe Admin::SiteSettingsController do end describe 'default categories' do - let(:user1) { Fabricate(:user) } - let(:user2) { Fabricate(:user) } + fab!(:user1) { Fabricate(:user) } + fab!(:user2) { Fabricate(:user) } + fab!(:staged_user) { Fabricate(:staged) } let(:watching) { NotificationLevels.all[:watching] } let(:tracking) { NotificationLevels.all[:tracking] } @@ -120,7 +121,7 @@ describe Admin::SiteSettingsController do } expect(CategoryUser.where(category_id: category_ids.first, notification_level: watching).count).to eq(0) - expect(CategoryUser.where(category_id: category_ids.last, notification_level: watching).count).to eq(User.count - 1) + expect(CategoryUser.where(category_id: category_ids.last, notification_level: watching).count).to eq(User.real.where(staged: false).count - 1) end it 'should not update existing users user preference' do @@ -135,8 +136,9 @@ describe Admin::SiteSettingsController do end describe 'default tags' do - let(:user1) { Fabricate(:user) } - let(:user2) { Fabricate(:user) } + fab!(:user1) { Fabricate(:user) } + fab!(:user2) { Fabricate(:user) } + fab!(:staged_user) { Fabricate(:staged) } let(:watching) { NotificationLevels.all[:watching] } let(:tracking) { NotificationLevels.all[:tracking] } @@ -158,7 +160,7 @@ describe Admin::SiteSettingsController do } expect(TagUser.where(tag_id: tags.first.id, notification_level: watching).count).to eq(0) - expect(TagUser.where(tag_id: tags.last.id, notification_level: watching).count).to eq(User.count - 1) + expect(TagUser.where(tag_id: tags.last.id, notification_level: watching).count).to eq(User.real.where(staged: false).count - 1) end it 'should not update existing users user preference' do @@ -173,7 +175,8 @@ describe Admin::SiteSettingsController do end describe '#user_count' do - let(:user) { Fabricate(:user) } + fab!(:user) { Fabricate(:user) } + fab!(:staged_user) { Fabricate(:staged) } let(:tracking) { NotificationLevels.all[:tracking] } it 'should return correct user count for default categories change' do @@ -183,7 +186,7 @@ describe Admin::SiteSettingsController do default_categories_watching: category_id } - expect(response.parsed_body["user_count"]).to eq(User.count) + expect(response.parsed_body["user_count"]).to eq(User.real.where(staged: false).count) CategoryUser.create!(category_id: category_id, notification_level: tracking, user: user) @@ -191,7 +194,7 @@ describe Admin::SiteSettingsController do default_categories_watching: category_id } - expect(response.parsed_body["user_count"]).to eq(User.count - 1) + expect(response.parsed_body["user_count"]).to eq(User.real.where(staged: false).count - 1) SiteSetting.setting(:default_categories_watching, "") end @@ -203,7 +206,7 @@ describe Admin::SiteSettingsController do default_tags_watching: tag.name } - expect(response.parsed_body["user_count"]).to eq(User.count) + expect(response.parsed_body["user_count"]).to eq(User.real.where(staged: false).count) TagUser.create!(tag_id: tag.id, notification_level: tracking, user: user) @@ -211,7 +214,7 @@ describe Admin::SiteSettingsController do default_tags_watching: tag.name } - expect(response.parsed_body["user_count"]).to eq(User.count - 1) + expect(response.parsed_body["user_count"]).to eq(User.real.where(staged: false).count - 1) SiteSetting.setting(:default_tags_watching, "") end diff --git a/spec/requests/categories_controller_spec.rb b/spec/requests/categories_controller_spec.rb index a4825fb101..d920723b14 100644 --- a/spec/requests/categories_controller_spec.rb +++ b/spec/requests/categories_controller_spec.rb @@ -13,7 +13,7 @@ describe CategoriesController do get '/categories', headers: { 'HTTP_USER_AGENT' => 'Googlebot' } html = Nokogiri::HTML5(response.body) expect(html.css('body.crawler')).to be_present - expect(html.css("a[href=\"/forum/c/#{category.slug}\"]")).to be_present + expect(html.css("a[href=\"/forum/c/#{category.slug}/#{category.id}\"]")).to be_present end it "properly preloads topic list" do diff --git a/spec/requests/category_hashtags_controller_spec.rb b/spec/requests/category_hashtags_controller_spec.rb index f2f62a82ea..7676ba5642 100644 --- a/spec/requests/category_hashtags_controller_spec.rb +++ b/spec/requests/category_hashtags_controller_spec.rb @@ -18,7 +18,7 @@ describe CategoryHashtagsController do expect(response.status).to eq(200) expect(response.parsed_body).to eq( - "valid" => [{ "slug" => category.hashtag_slug, "url" => category.url_with_id }] + "valid" => [{ "slug" => category.hashtag_slug, "url" => category.url }] ) end @@ -45,7 +45,7 @@ describe CategoryHashtagsController do expect(response.status).to eq(200) expect(response.parsed_body).to eq( - "valid" => [{ "slug" => private_category.hashtag_slug, "url" => private_category.url_with_id }] + "valid" => [{ "slug" => private_category.hashtag_slug, "url" => private_category.url }] ) end end diff --git a/spec/requests/list_controller_spec.rb b/spec/requests/list_controller_spec.rb index 710b044467..2fea625c05 100644 --- a/spec/requests/list_controller_spec.rb +++ b/spec/requests/list_controller_spec.rb @@ -142,6 +142,16 @@ RSpec.describe ListController do expect(response.status).to eq(404) end + it 'should fail for staff users if disabled' do + SiteSetting.allow_staff_to_tag_pms = false + + [moderator, admin].each do |user| + sign_in(user) + get "/topics/private-messages-tags/#{user.username}/#{tag.name}.json" + expect(response.status).to eq(404) + end + end + it 'should be success for staff users' do [moderator, admin].each do |user| sign_in(user) diff --git a/spec/requests/post_action_users_controller_spec.rb b/spec/requests/post_action_users_controller_spec.rb index bc053524fe..ec6bc28592 100644 --- a/spec/requests/post_action_users_controller_spec.rb +++ b/spec/requests/post_action_users_controller_spec.rb @@ -59,6 +59,22 @@ describe PostActionUsersController do expect(response.status).to eq(200) end + it 'will return an unknown attribute for muted users' do + ignored_user = Fabricate(:user) + PostActionCreator.like(ignored_user, post) + regular_user = Fabricate(:user) + PostActionCreator.like(regular_user, post) + IgnoredUser.create(user: user, ignored_user: ignored_user) + + get "/post_action_users.json", params: { + id: post.id, post_action_type_id: PostActionType.types[:like] + } + expect(response.status).to eq(200) + json_users = response.parsed_body['post_action_users'] + expect(json_users.find { |u| u['id'] == regular_user.id }['unknown']).to be_blank + expect(json_users.find { |u| u['id'] == ignored_user.id }['unknown']).to eq(true) + end + it "paginates post actions" do user_ids = [] 5.times do diff --git a/spec/requests/posts_controller_spec.rb b/spec/requests/posts_controller_spec.rb index f5ef93c53f..6ccc7380d8 100644 --- a/spec/requests/posts_controller_spec.rb +++ b/spec/requests/posts_controller_spec.rb @@ -1323,10 +1323,10 @@ describe PostsController do expect(response.status).to eq(200) end - it "ensures trust level 4 can see the revisions" do + it "ensures trust level 4 cannot see the revisions" do sign_in(Fabricate(:user, trust_level: 4)) get "/posts/#{post_revision.post_id}/revisions/#{post_revision.number}.json" - expect(response.status).to eq(200) + expect(response.status).to eq(403) end end diff --git a/spec/requests/published_pages_controller_spec.rb b/spec/requests/published_pages_controller_spec.rb index 6793761791..d5fed80819 100644 --- a/spec/requests/published_pages_controller_spec.rb +++ b/spec/requests/published_pages_controller_spec.rb @@ -59,6 +59,17 @@ RSpec.describe PublishedPagesController do expect(response.status).to eq(403) end + context "published page is public" do + fab!(:public_published_page) { + Fabricate(:published_page, public: true, slug: "a-public-page") + } + + it "returns 200 for a topic you can't see" do + get public_published_page.path + expect(response.status).to eq(200) + end + end + context "as an admin" do before do sign_in(admin) @@ -89,7 +100,42 @@ RSpec.describe PublishedPagesController do it "defines correct css classes on body" do get published_page.path - expect(response.body).to include("") + expect(response.body).to include("") + end + + context "login is required" do + before do + SiteSetting.login_required = true + SiteSetting.show_published_pages_login_required = false + end + + context "a user is connected" do + before do + sign_in(user) + end + + it "returns 200" do + get published_page.path + expect(response.status).to eq(200) + end + end + + context "no user connected" do + it "redirects to login page" do + expect(get(published_page.path)).to redirect_to("/login") + end + + context "show public pages with login required is enabled" do + before do + SiteSetting.show_published_pages_login_required = true + end + + it "returns 200" do + get published_page.path + expect(response.status).to eq(200) + end + end + end end end end @@ -113,6 +159,7 @@ RSpec.describe PublishedPagesController do expect(response).to be_successful expect(response.parsed_body['published_page']).to be_present expect(response.parsed_body['published_page']['slug']).to eq("i-hate-salt") + expect(response.parsed_body['published_page']['public']).to eq(false) expect(PublishedPage.exists?(topic_id: response.parsed_body['published_page']['id'])).to eq(true) expect(UserHistory.exists?( @@ -122,6 +169,16 @@ RSpec.describe PublishedPagesController do )).to be(true) end + it "allows to set public field" do + put "/pub/by-topic/#{topic.id}.json", params: { published_page: { slug: 'i-hate-salt', public: true } } + expect(response).to be_successful + expect(response.parsed_body['published_page']).to be_present + expect(response.parsed_body['published_page']['slug']).to eq("i-hate-salt") + expect(response.parsed_body['published_page']['public']).to eq(true) + + expect(PublishedPage.exists?(topic_id: response.parsed_body['published_page']['id'])).to eq(true) + end + it "returns an error if the slug is already taken" do PublishedPage.create!(slug: 'i-hate-salt', topic: Fabricate(:topic)) put "/pub/by-topic/#{topic.id}.json", params: { published_page: { slug: 'i-hate-salt' } } diff --git a/spec/requests/tags_controller_spec.rb b/spec/requests/tags_controller_spec.rb index 926e506e35..53b1cf96ba 100644 --- a/spec/requests/tags_controller_spec.rb +++ b/spec/requests/tags_controller_spec.rb @@ -33,6 +33,55 @@ describe TagsController do end end + context "with allow_staff_to_tag_pms" do + fab!(:admin) { Fabricate(:admin) } + fab!(:topic) { Fabricate(:topic, tags: [topic_tag]) } + fab!(:pm) do + Fabricate( + :private_message_topic, + tags: [test_tag], + topic_allowed_users: [ + Fabricate.build(:topic_allowed_user, user: admin) + ] + ) + end + + context "enabled" do + before do + SiteSetting.allow_staff_to_tag_pms = true + sign_in(admin) + end + + it "shows topic tags and pm tags" do + get "/tags.json" + tags = response.parsed_body["tags"] + expect(tags.length).to eq(2) + + serialized_tag = tags.find { |t| t["id"] == topic_tag.name } + expect(serialized_tag["count"]).to eq(2) + expect(serialized_tag["pm_count"]).to eq(0) + + serialized_tag = tags.find { |t| t["id"] == test_tag.name } + expect(serialized_tag["count"]).to eq(0) + expect(serialized_tag["pm_count"]).to eq(1) + end + end + + context "disabled" do + before do + SiteSetting.allow_staff_to_tag_pms = false + sign_in(admin) + end + + it "hides pm tags" do + get "/tags.json" + tags = response.parsed_body["tags"] + expect(tags.length).to eq(1) + expect(tags[0]["id"]).to eq(topic_tag.name) + end + end + end + context "with tags_listed_by_group enabled" do before { SiteSetting.tags_listed_by_group = true } include_examples "successfully retrieve tags with topic_count > 0" diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index e6295dcb18..b5a13429be 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -2290,19 +2290,18 @@ describe UsersController do context 'selectable avatars is enabled' do - before { SiteSetting.selectable_avatars_enabled = true } + before do + SiteSetting.selectable_avatars = [avatar1.url, avatar2.url].join("\n") + SiteSetting.selectable_avatars_enabled = true + end it 'raises an error when selectable avatars is empty' do + SiteSetting.selectable_avatars = "" put "/u/#{user.username}/preferences/avatar/select.json", params: { url: url } expect(response.status).to eq(422) end context 'selectable avatars is properly setup' do - - before do - SiteSetting.selectable_avatars = [avatar1.url, avatar2.url].join("\n") - end - it 'raises an error when url is not in selectable avatars list' do put "/u/#{user.username}/preferences/avatar/select.json", params: { url: url } expect(response.status).to eq(422) @@ -2414,6 +2413,22 @@ describe UsersController do let!(:ignored_user) { Fabricate(:ignored_user, user: user, ignored_user: another_user) } let!(:muted_user) { Fabricate(:muted_user, user: user, muted_user: another_user) } + context "when you can't change the notification" do + fab!(:staff_user) { Fabricate(:admin) } + + it "ignoring includes a helpful error message" do + put "/u/#{staff_user.username}/notification_level.json", params: { notification_level: 'ignore' } + expect(response.status).to eq(422) + expect(response.parsed_body['errors'][0]).to eq(I18n.t("notification_level.ignore_error")) + end + + it "muting includes a helpful error message" do + put "/u/#{staff_user.username}/notification_level.json", params: { notification_level: 'mute' } + expect(response.status).to eq(422) + expect(response.parsed_body['errors'][0]).to eq(I18n.t("notification_level.mute_error")) + end + end + context 'when changing notification level to normal' do it 'changes notification level to normal' do put "/u/#{another_user.username}/notification_level.json", params: { notification_level: "normal" } @@ -2519,6 +2534,7 @@ describe UsersController do it "returns emails and associated_accounts for self" do user = Fabricate(:user) + Fabricate(:email_change_request, user: user) sign_in(user) get "/u/#{user.username}/emails.json" @@ -2527,11 +2543,13 @@ describe UsersController do json = response.parsed_body expect(json["email"]).to eq(user.email) expect(json["secondary_emails"]).to eq(user.secondary_emails) + expect(json["unconfirmed_emails"]).to eq(user.unconfirmed_emails) expect(json["associated_accounts"]).to eq([]) end it "returns emails and associated_accounts when you're allowed to see them" do user = Fabricate(:user) + Fabricate(:email_change_request, user: user) sign_in_admin get "/u/#{user.username}/emails.json" @@ -2540,11 +2558,13 @@ describe UsersController do json = response.parsed_body expect(json["email"]).to eq(user.email) expect(json["secondary_emails"]).to eq(user.secondary_emails) + expect(json["unconfirmed_emails"]).to eq(user.unconfirmed_emails) expect(json["associated_accounts"]).to eq([]) end it "works on inactive users" do inactive_user = Fabricate(:user, active: false) + Fabricate(:email_change_request, user: inactive_user) sign_in_admin get "/u/#{inactive_user.username}/emails.json" @@ -2553,6 +2573,7 @@ describe UsersController do json = response.parsed_body expect(json["email"]).to eq(inactive_user.email) expect(json["secondary_emails"]).to eq(inactive_user.secondary_emails) + expect(json["unconfirmed_emails"]).to eq(inactive_user.unconfirmed_emails) expect(json["associated_accounts"]).to eq([]) end end @@ -2575,7 +2596,8 @@ describe UsersController do expect(user_email.reload.primary).to eq(true) expect(other_email.reload.primary).to eq(false) - put "/u/#{user.username}/preferences/primary-email.json", params: { email: other_email.email } + expect { put "/u/#{user.username}/preferences/primary-email.json", params: { email: other_email.email } } + .to change { UserHistory.where(action: UserHistory.actions[:update_email], acting_user_id: user.id).count }.by(1) expect(response.status).to eq(200) expect(user_email.reload.primary).to eq(false) expect(other_email.reload.primary).to eq(true) @@ -2598,7 +2620,8 @@ describe UsersController do expect(response.status).to eq(428) expect(user.reload.user_emails.pluck(:email)).to contain_exactly(user_email.email, other_email.email) - delete "/u/#{user.username}/preferences/email.json", params: { email: other_email.email } + expect { delete "/u/#{user.username}/preferences/email.json", params: { email: other_email.email } } + .to change { UserHistory.where(action: UserHistory.actions[:destroy_email], acting_user_id: user.id).count }.by(1) expect(response.status).to eq(200) expect(user.reload.user_emails.pluck(:email)).to contain_exactly(user_email.email) end diff --git a/spec/requests/users_email_controller_spec.rb b/spec/requests/users_email_controller_spec.rb index 92cd157044..06cc9ced98 100644 --- a/spec/requests/users_email_controller_spec.rb +++ b/spec/requests/users_email_controller_spec.rb @@ -49,6 +49,17 @@ describe UsersEmailController do updater.change_to('new.n.cool@example.com') end + it 'includes security_key_allowed_credential_ids in a hidden field' do + key1 = Fabricate(:user_security_key_with_random_credential, user: user) + key2 = Fabricate(:user_security_key_with_random_credential, user: user) + + get "/u/confirm-new-email/#{user.email_tokens.last.token}" + + doc = Nokogiri::HTML5(response.body) + credential_ids = doc.css("#security-key-allowed-credential-ids").first["value"].split(",") + expect(credential_ids).to contain_exactly(key1.credential_id, key2.credential_id) + end + it 'confirms with a correct token' do user.user_stat.update_columns(bounce_score: 42, reset_bounce_score_after: 1.week.from_now) diff --git a/spec/serializers/category_serializer_spec.rb b/spec/serializers/category_serializer_spec.rb index e2a3399990..9e81726f55 100644 --- a/spec/serializers/category_serializer_spec.rb +++ b/spec/serializers/category_serializer_spec.rb @@ -29,9 +29,9 @@ describe CategorySerializer do expect(json[:custom_fields]).to be_present end - it "includes the default notification level" do + it "does not include the default notification level when there is no user" do json = described_class.new(category, scope: Guardian.new, root: false).as_json - expect(json[:notification_level]).to eq(CategoryUser.default_notification_level) + expect(json.key?(:notification_level)).to eq(false) end describe "user notification level" do diff --git a/spec/serializers/topic_view_serializer_spec.rb b/spec/serializers/topic_view_serializer_spec.rb index f6249b275b..55a9652fdd 100644 --- a/spec/serializers/topic_view_serializer_spec.rb +++ b/spec/serializers/topic_view_serializer_spec.rb @@ -312,22 +312,36 @@ describe TopicViewSerializer do context "published_page" do fab!(:published_page) { Fabricate(:published_page, topic: topic) } - it "doesn't return the published page if not enabled" do - json = serialize_topic(topic, admin) - expect(json[:published_page]).to be_blank + context "page publishing is disabled" do + before do + SiteSetting.enable_page_publishing = false + end + + it "doesn't return the published page if not enabled" do + json = serialize_topic(topic, admin) + expect(json[:published_page]).to be_blank + end end - it "doesn't return the published page unless staff" do - SiteSetting.enable_page_publishing = true - json = serialize_topic(topic, user) - expect(json[:published_page]).to be_blank - end + context "page publishing is enabled" do + before do + SiteSetting.enable_page_publishing = true + end - it "returns the published page if enabled and staff" do - SiteSetting.enable_page_publishing = true - json = serialize_topic(topic, admin) - expect(json[:published_page]).to be_present - expect(json[:published_page][:slug]).to eq("published-page-test") + context "not staff" do + it "doesn't return the published page" do + json = serialize_topic(topic, user) + expect(json[:published_page]).to be_blank + end + end + + context "staff" do + it "returns the published page" do + json = serialize_topic(topic, admin) + expect(json[:published_page]).to be_present + expect(json[:published_page][:slug]).to eq(published_page.slug) + end + end end end diff --git a/spec/serializers/user_card_serializer_spec.rb b/spec/serializers/user_card_serializer_spec.rb new file mode 100644 index 0000000000..f6285f2150 --- /dev/null +++ b/spec/serializers/user_card_serializer_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe UserCardSerializer do + context "with a TL0 user seen as anonymous" do + let(:user) { Fabricate.build(:user, trust_level: 0, user_profile: Fabricate.build(:user_profile)) } + let(:serializer) { described_class.new(user, scope: Guardian.new, root: false) } + let(:json) { serializer.as_json } + + it "does not serialize emails" do + expect(json[:secondary_emails]).to be_nil + expect(json[:unconfirmed_emails]).to be_nil + end + end + + context "as current user" do + it "serializes emails correctly" do + user = Fabricate.build(:user, + id: 1, + user_profile: Fabricate.build(:user_profile), + user_option: UserOption.new(dynamic_favicon: true), + user_stat: UserStat.new + ) + json = described_class.new(user, scope: Guardian.new(user), root: false).as_json + expect(json[:secondary_emails]).to eq([]) + expect(json[:unconfirmed_emails]).to eq([]) + end + end + + context "as different user" do + let(:user) { Fabricate(:user, trust_level: 0) } + let(:user2) { Fabricate(:user, trust_level: 1) } + it "does not serialize emails" do + json = described_class.new(user, scope: Guardian.new(user2), root: false).as_json + expect(json[:secondary_emails]).to be_nil + expect(json[:unconfirmed_emails]).to be_nil + end + end +end diff --git a/spec/serializers/user_serializer_spec.rb b/spec/serializers/user_serializer_spec.rb index 2086c351ba..197adb9f9e 100644 --- a/spec/serializers/user_serializer_spec.rb +++ b/spec/serializers/user_serializer_spec.rb @@ -14,6 +14,10 @@ describe UserSerializer do it "doesn't serialize untrusted attributes" do untrusted_attributes.each { |attr| expect(json).not_to have_key(attr) } end + + it "doesn't serialize group_users" do + expect(json[:group_users]).to be_nil + end end context "as current user" do @@ -24,9 +28,10 @@ describe UserSerializer do SiteSetting.default_other_new_topic_duration_minutes = 60 * 24 user = Fabricate.build(:user, - user_profile: Fabricate.build(:user_profile), - user_option: UserOption.new(dynamic_favicon: true), - user_stat: UserStat.new + id: 1, + user_profile: Fabricate.build(:user_profile), + user_option: UserOption.new(dynamic_favicon: true), + user_stat: UserStat.new ) json = UserSerializer.new(user, scope: Guardian.new(user), root: false).as_json @@ -36,6 +41,7 @@ describe UserSerializer do expect(json[:user_option][:auto_track_topics_after_msecs]).to eq(0) expect(json[:user_option][:notification_level_when_replying]).to eq(3) + expect(json[:group_users]).to eq([]) end end diff --git a/spec/serializers/web_hook_post_serializer_spec.rb b/spec/serializers/web_hook_post_serializer_spec.rb index 790a13269b..9e5c1f618d 100644 --- a/spec/serializers/web_hook_post_serializer_spec.rb +++ b/spec/serializers/web_hook_post_serializer_spec.rb @@ -12,7 +12,7 @@ RSpec.describe WebHookPostSerializer do it 'should only include the required keys' do count = serialized_for_user(admin).keys.count - difference = count - 39 + difference = count - 40 expect(difference).to eq(0), lambda { message = +"" diff --git a/spec/services/site_settings_spec.rb b/spec/services/site_settings_spec.rb index c622ad1a39..906a2ac23f 100644 --- a/spec/services/site_settings_spec.rb +++ b/spec/services/site_settings_spec.rb @@ -32,11 +32,11 @@ describe SiteSettingsTask do end it "updates hidden settings" do - yml = "logo_url: /logo.png" + yml = "default_theme_id: 999999999" log, counts = SiteSettingsTask.import(yml) - expect(log[0]).to eq "Changed logo_url FROM: /images/d-logo-sketch.png TO: /logo.png" - expect(counts[:updated]).to eq 1 - expect(SiteSetting.logo_url).to eq "/logo.png" + expect(log[0]).to eq "Changed default_theme_id FROM: 2 TO: 999999999" + expect(counts[:updated]).to eq(1) + expect(SiteSetting.default_theme_id).to eq(999999999) end it "won't update a setting that doesn't exist" do diff --git a/spec/services/user_destroyer_spec.rb b/spec/services/user_destroyer_spec.rb index a26da77d4e..01e6e81027 100644 --- a/spec/services/user_destroyer_spec.rb +++ b/spec/services/user_destroyer_spec.rb @@ -390,6 +390,17 @@ describe UserDestroyer do d.destroy(user) }.to change { User.count }.by(-1) end + + it 'can delete the user if they were to fall into another trust level and have no email' do + g2 = Fabricate(:group, grant_trust_level: 1) + g2.add(user) + + UserEmail.where(user: user).delete_all + user.reload + expect { + UserDestroyer.new(admin).destroy(user) + }.to change { User.count }.by(-1) + end end context 'user has staff action logs' do diff --git a/test/javascripts/acceptance/admin-user-index-test.js b/test/javascripts/acceptance/admin-user-index-test.js index 4c57cbbf97..5e20f3d2ac 100644 --- a/test/javascripts/acceptance/admin-user-index-test.js +++ b/test/javascripts/acceptance/admin-user-index-test.js @@ -86,10 +86,10 @@ QUnit.test("will clear unsaved groups when switching user", async assert => { "the name should be correct" ); - const groupSelector = selectKit(".admin-group-selector"); - await groupSelector.expand(); - await groupSelector.selectRowByValue(42); - assert.equal(groupSelector.header().value(), 42, "group should be set"); + const groupChooser = selectKit(".group-chooser"); + await groupChooser.expand(); + await groupChooser.selectRowByValue(42); + assert.equal(groupChooser.header().value(), 42, "group should be set"); await visit("/admin/users/1/eviltrout"); @@ -102,7 +102,7 @@ QUnit.test("will clear unsaved groups when switching user", async assert => { ); assert.equal( - find('.admin-group-selector span[title="Macdonald"]').length, + find('.group-chooser span[title="Macdonald"]').length, 0, "group should not be set" ); diff --git a/test/javascripts/acceptance/composer-actions-test.js b/test/javascripts/acceptance/composer-actions-test.js index 95060ba67a..2ee96e3af9 100644 --- a/test/javascripts/acceptance/composer-actions-test.js +++ b/test/javascripts/acceptance/composer-actions-test.js @@ -16,6 +16,9 @@ acceptance("Composer Actions", { }, beforeEach() { _clearSnapshots(); + }, + afterEach() { + _clearSnapshots(); } }); @@ -174,6 +177,7 @@ QUnit.test("hide component if no content", async assert => { await composerActions.selectRowByValue("reply_as_private_message"); assert.ok(composerActions.el().hasClass("is-hidden")); + assert.equal(composerActions.el().children().length, 0); await click("button#create-topic"); await composerActions.expand(); @@ -386,6 +390,9 @@ acceptance("Composer Actions With New Topic Draft", { }, beforeEach() { _clearSnapshots(); + }, + afterEach() { + _clearSnapshots(); } }); diff --git a/test/javascripts/acceptance/composer-test.js b/test/javascripts/acceptance/composer-test.js index 50b698e3ae..74f87d5cef 100644 --- a/test/javascripts/acceptance/composer-test.js +++ b/test/javascripts/acceptance/composer-test.js @@ -271,6 +271,24 @@ QUnit.test("Create a Reply", async assert => { ); }); +QUnit.test("Can edit a post after starting a reply", async assert => { + await visit("/t/internationalization-localization/280"); + + await click("#topic-footer-buttons .create"); + await fillIn(".d-editor-input", "this is the content of my reply"); + + await click(".topic-post:eq(0) button.show-more-actions"); + await click(".topic-post:eq(0) button.edit"); + + await click("a[data-handler='0']"); + + assert.ok(!visible(".bootbox.modal")); + assert.equal( + find(".d-editor-input").val(), + "this is the content of my reply" + ); +}); + QUnit.test("Posting on a different topic", async assert => { await visit("/t/internationalization-localization/280"); await click("#topic-footer-buttons .btn.create"); diff --git a/test/javascripts/acceptance/group-test.js b/test/javascripts/acceptance/group-test.js index 530774b0d6..a44c390ebf 100644 --- a/test/javascripts/acceptance/group-test.js +++ b/test/javascripts/acceptance/group-test.js @@ -28,7 +28,7 @@ QUnit.test("Anonymous Viewing Group", async assert => { assert.equal( count(".nav-pills li a[title='Messages']"), 0, - "it deos not show group messages navigation link" + "it does not show group messages navigation link" ); await click(".nav-pills li a[title='Activity']"); @@ -83,7 +83,7 @@ QUnit.test("Anonymous Viewing Automatic Group", async assert => { assert.equal( count(".nav-pills li a[title='Manage']"), 0, - "it deos not show group messages navigation link" + "it does not show group messages navigation link" ); }); diff --git a/test/javascripts/components/select-kit/mini-tag-chooser-test.js b/test/javascripts/components/select-kit/mini-tag-chooser-test.js index 76265e7f83..c17b01bd6a 100644 --- a/test/javascripts/components/select-kit/mini-tag-chooser-test.js +++ b/test/javascripts/components/select-kit/mini-tag-chooser-test.js @@ -31,7 +31,20 @@ componentTest("create a tag", { assert.equal(this.subject.header().value(), "foo,bar"); await this.subject.expand(); - await this.subject.fillInFilter("monkey"); + await this.subject.fillInFilter("mon"); + assert.equal( + find(".select-kit-row") + .text() + .trim(), + "monkey x1" + ); + await this.subject.fillInFilter("key"); + assert.equal( + find(".select-kit-row") + .text() + .trim(), + "monkey x1" + ); await this.subject.keyboard("enter"); assert.equal(this.subject.header().value(), "foo,bar,monkey"); diff --git a/test/javascripts/controllers/history-test.js b/test/javascripts/controllers/history-test.js index 6d8ccae7cf..0d8788239d 100644 --- a/test/javascripts/controllers/history-test.js +++ b/test/javascripts/controllers/history-test.js @@ -40,6 +40,17 @@ QUnit.test("displayEdit", async function(assert) { const html = `

" width="276" height="183">

+ @@ -58,6 +69,17 @@ QUnit.test("displayEdit", async function(assert) { const expectedOutput = `

" width="276" height="183">

+
@@ -85,5 +107,9 @@ QUnit.test("displayEdit", async function(assert) { await HistoryController.bodyDiffChanged(); const output = HistoryController.get("bodyDiff"); - assert.equal(output, expectedOutput, "it keeps safe HTML"); + assert.equal( + output, + expectedOutput, + "it keeps HTML safe and doesn't strip onebox tags" + ); }); diff --git a/test/javascripts/helpers/component-test.js b/test/javascripts/helpers/component-test.js index 84f382a3b4..0330f6e91a 100644 --- a/test/javascripts/helpers/component-test.js +++ b/test/javascripts/helpers/component-test.js @@ -55,12 +55,12 @@ export default function(name, opts) { }); andThen(() => { - try { - opts.test.call(this, assert); - } finally { - if (opts.afterEach) { - opts.afterEach.call(opts); - } + return opts.test.call(this, assert); + }).finally(() => { + if (opts.afterEach) { + andThen(() => { + return opts.afterEach.call(opts); + }); } }); }); diff --git a/test/javascripts/lib/pretty-text-test.js b/test/javascripts/lib/pretty-text-test.js index a5619bcc77..c1304f3657 100644 --- a/test/javascripts/lib/pretty-text-test.js +++ b/test/javascripts/lib/pretty-text-test.js @@ -1030,6 +1030,7 @@ QUnit.test("video - secure media enabled", assert => { "![baby shark|video](upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp4)", { siteSettings: { secure_media: true } }, `

+

baby shark