diff --git a/.eslintrc b/.eslintrc index 4aee50ed2a..1c3b2b261c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,8 @@ "extends": "eslint-config-discourse", "rules": { "discourse-ember/global-ember": 2, - "eol-last": 2 + "eol-last": 2, + "no-restricted-globals": 0 }, "globals": { "_": "off", diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index ab85796b3c..ea69b83263 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -53,5 +53,8 @@ ce3fe2f4c4ddf166949ee3cec3d9ecbf9108ab52 # DEV: Tidy up imports. (#11364) 1c2358ba162eb9f9ba9095c9afe30cf51dd85e04 -# DEV: Sort imports alphabetically (#11382) +# DEV: Sort imports alphabetically (#11382) bbe5d8d5cf1220165842985c0e2cd4c454d501cd + +# DEV: Template colocation for sidebar files +95c7cdab941a56686ac5831d2a5c5eca38d780c5 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index aefab9fadb..a0f06bf462 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,42 +1,50 @@ version: 2 updates: -- package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" -- package-ecosystem: bundler - directory: "/" - schedule: - interval: daily - time: "08:00" - timezone: Australia/Sydney - open-pull-requests-limit: 10 - versioning-strategy: lockfile-only - allow: - - dependency-type: direct - - dependency-type: indirect - ignore: - - dependency-name: aws-partitions - versions: - - "> 1.329.0" - - "< 2" - - dependency-name: aws-sdk-core - versions: - - "> 3.99.1" - - "< 4" - - dependency-name: aws-sdk-kms - versions: - - "> 1.31.0" - - "< 2" - - dependency-name: aws-sdk-s3 - versions: - - "> 1.66.0" - - "< 2" - - dependency-name: aws-sdk-sns - versions: - - "> 1.25.1" - - "< 2" - - dependency-name: aws-sigv4 - versions: - - "> 1.2.0" - - "< 2" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: bundler + directory: "/" + schedule: + interval: daily + time: "08:00" + timezone: Australia/Sydney + open-pull-requests-limit: 10 + versioning-strategy: lockfile-only + allow: + - dependency-type: direct + - dependency-type: indirect + ignore: + - dependency-name: aws-partitions + versions: + - "> 1.329.0" + - "< 2" + - dependency-name: aws-sdk-core + versions: + - "> 3.99.1" + - "< 4" + - dependency-name: aws-sdk-kms + versions: + - "> 1.31.0" + - "< 2" + - dependency-name: aws-sdk-s3 + versions: + - "> 1.66.0" + - "< 2" + - dependency-name: aws-sdk-sns + versions: + - "> 1.25.1" + - "< 2" + - dependency-name: aws-sigv4 + versions: + - "> 1.2.0" + - "< 2" + - package-ecosystem: "npm" + directory: "/app/assets/javascripts/" + schedule: + interval: daily + time: "08:00" + timezone: Australia/Sydney + open-pull-requests-limit: 20 + versioning-strategy: increase diff --git a/.github/workflows/licenses.yml b/.github/workflows/licenses.yml index 755852add2..adefc3998c 100644 --- a/.github/workflows/licenses.yml +++ b/.github/workflows/licenses.yml @@ -67,7 +67,7 @@ jobs: ${{ runner.os }}-yarn- - name: Check RubyGems Licenses - if: ${{ always() }} + if: ${{ !cancelled() }} run: | licensed cache licensed status @@ -76,14 +76,14 @@ jobs: run: yarn install - name: Check Yarn Licenses - if: ${{ always() }} + if: ${{ !cancelled() }} run: | yarn global add licensee yarn global upgrade licensee licensee --errors-only - name: Check Ember CLI Workspace Licenses - if: ${{ always() }} + if: ${{ !cancelled() }} working-directory: ./app/assets/javascripts run: | licensee --errors-only diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 3ce7b5d5f3..59379f06af 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -64,19 +64,19 @@ jobs: run: yarn install - name: Rubocop - if: ${{ always() }} + if: ${{ !cancelled() }} run: bundle exec rubocop --parallel . - name: ESLint (core) - if: ${{ always() }} + if: ${{ !cancelled() }} run: yarn eslint app/assets/javascripts - name: ESLint (core plugins) - if: ${{ always() }} + if: ${{ !cancelled() }} run: yarn eslint plugins - name: Prettier - if: ${{ always() }} + if: ${{ !cancelled() }} run: | yarn prettier -v yarn pprettier --list-different \ @@ -86,7 +86,7 @@ jobs: "plugins/**/assets/javascripts/**/*.js" - name: Ember template lint - if: ${{ always() }} + if: ${{ !cancelled() }} run: | yarn ember-template-lint \ --no-error-on-unmatched-pattern \ @@ -94,9 +94,9 @@ jobs: "plugins/**/assets/javascripts/**/*.hbs" - name: English locale lint (core) - if: ${{ always() }} + if: ${{ !cancelled() }} run: bundle exec ruby script/i18n_lint.rb "config/**/locales/{client,server}.en.yml" - name: English locale lint (core plugins) - if: ${{ always() }} + if: ${{ !cancelled() }} run: bundle exec ruby script/i18n_lint.rb "plugins/**/locales/{client,server}.en.yml" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a2c9f200b8..f1356bf73b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,9 +18,9 @@ permissions: jobs: build: name: ${{ matrix.target }} ${{ matrix.build_type }} - runs-on: ubuntu-latest - container: discourse/discourse_test:slim${{ startsWith(matrix.build_type, 'frontend') && '-browsers' || '' }} - timeout-minutes: 60 + runs-on: ${{ (matrix.build_type == 'annotations') && 'ubuntu-latest' || 'ubuntu-20.04-8core' }} + container: discourse/discourse_test:slim${{ (matrix.build_type == 'frontend' || matrix.build_type == 'system') && '-browsers' || '' }} + timeout-minutes: 20 env: DISCOURSE_HOSTNAME: www.example.com @@ -28,19 +28,21 @@ jobs: RAILS_ENV: test PGUSER: discourse PGPASSWORD: discourse - USES_PARALLEL_DATABASES: ${{ matrix.build_type == 'backend' && matrix.target == 'core' }} + USES_PARALLEL_DATABASES: ${{ matrix.build_type == 'backend' }} strategy: fail-fast: false matrix: - build_type: [backend, frontend, annotations] + build_type: [backend, frontend, system, annotations] target: [core, plugins] exclude: - build_type: annotations target: plugins - build_type: frontend target: core # Handled by core_frontend_tests job (below) + - build_type: system + target: plugins # Enable once at least 1 plugin has system tests steps: - uses: actions/checkout@v3 @@ -145,19 +147,46 @@ jobs: if: steps.app-cache.outputs.cache-hit != 'true' run: rm -rf tmp/app-cache/uploads && cp -r public/uploads tmp/app-cache/uploads + - name: Fetch turbo_rspec_runtime.log cache + uses: actions/cache@v3 + id: test-runtime-cache + if: matrix.build_type == 'backend' && matrix.target == 'core' + with: + path: tmp/turbo_rspec_runtime.log + key: rspec-runtime-backend-core + - name: Core RSpec if: matrix.build_type == 'backend' && matrix.target == 'core' run: bin/turbo_rspec --verbose - name: Plugin RSpec if: matrix.build_type == 'backend' && matrix.target == 'plugins' - run: bin/rake plugin:spec + run: bin/rake plugin:turbo_spec - name: Plugin QUnit if: matrix.build_type == 'frontend' && matrix.target == 'plugins' - run: bin/rake plugin:qunit['*','1200000'] + run: QUNIT_PARALLEL=3 bin/rake plugin:qunit['*','1200000'] timeout-minutes: 30 + - name: Ember Build for System Tests + if: matrix.build_type == 'system' + run: bin/ember-cli --build + + - name: Core System Tests + if: matrix.build_type == 'system' && matrix.target == 'core' + run: bin/system_rspec + + - name: Plugin System Tests + if: matrix.build_type == 'system' && matrix.target == 'plugins' + run: bin/system_rspec plugins/*/spec/system + + - name: Upload failed system test screenshots + uses: actions/upload-artifact@v3 + if: matrix.build_type == 'system' && failure() + with: + name: failed-system-test-screenshots + path: tmp/screenshots/*.png + - name: Check Annotations if: matrix.build_type == 'annotations' run: | @@ -177,14 +206,21 @@ jobs: core_frontend_tests: name: core frontend (${{ matrix.browser }}) - runs-on: ubuntu-latest - container: discourse/discourse_test:slim-browsers - timeout-minutes: 30 + runs-on: ubuntu-20.04-8core + container: + image: discourse/discourse_test:slim-browsers + options: --user discourse + + timeout-minutes: 35 strategy: fail-fast: false matrix: - browser: ["Chrome", "Firefox", "Headless Firefox"] + browser: ["Chrome", "Firefox ESR", "Firefox Evergreen"] + + env: + TESTEM_BROWSER: ${{ (startsWith(matrix.browser, 'Firefox') && 'Firefox') || matrix.browser }} + TESTEM_FIREFOX_PATH: ${{ (matrix.browser == 'Firefox Evergreen') && '/opt/firefox-evergreen/firefox' }} steps: - uses: actions/checkout@v2 @@ -216,23 +252,16 @@ jobs: - name: Ember Build working-directory: ./app/assets/javascripts/discourse run: | - sudo -E -u discourse mkdir /tmp/emberbuild - sudo -E -u discourse -H yarn ember build --environment=test -o /tmp/emberbuild + mkdir /tmp/emberbuild + yarn ember build --environment=test -o /tmp/emberbuild - - name: Core QUnit 1 - if: ${{ always() }} + - name: Core QUnit working-directory: ./app/assets/javascripts/discourse - run: sudo -E -u discourse -H yarn ember exam --path /tmp/emberbuild --split=3 --partition=1 --launch "${{ matrix.browser }}" --random - timeout-minutes: 20 + run: yarn ember exam --path /tmp/emberbuild --load-balance --parallel=5 --launch "${{ env.TESTEM_BROWSER }}" --write-execution-file --random + timeout-minutes: 15 - - name: Core QUnit 2 + - uses: actions/upload-artifact@v3 if: ${{ always() }} - working-directory: ./app/assets/javascripts/discourse - run: sudo -E -u discourse -H yarn ember exam --path /tmp/emberbuild --split=3 --partition=2 --launch "${{ matrix.browser }}" --random - timeout-minutes: 20 - - - name: Core QUnit 3 - if: ${{ always() }} - working-directory: ./app/assets/javascripts/discourse - run: sudo -E -u discourse -H yarn ember exam --path /tmp/emberbuild --split=3 --partition=3 --launch "${{ matrix.browser }}" --random - timeout-minutes: 20 + with: + name: ember-exam-execution-${{matrix.browser}} + path: ./app/assets/javascripts/discourse/test-execution-*.json diff --git a/.prettierignore b/.prettierignore index fff97dce44..b33a5618e4 100644 --- a/.prettierignore +++ b/.prettierignore @@ -17,6 +17,7 @@ lib/javascripts/messageformat.js lib/highlight_js/ plugins/**/lib/javascripts/locale public/ +!/app/assets/javascripts/discourse/public vendor/ app/assets/javascripts/discourse/tests/fixtures spec/ diff --git a/Gemfile b/Gemfile index b2116cc8ac..e29c6737be 100644 --- a/Gemfile +++ b/Gemfile @@ -149,11 +149,14 @@ group :assets do end group :test do + gem 'capybara', require: false gem 'webmock', require: false gem 'fakeweb', require: false gem 'minitest', require: false gem 'simplecov', require: false + gem 'selenium-webdriver', require: false gem "test-prof" + gem 'webdrivers', require: false end group :test, :development do @@ -170,7 +173,7 @@ group :test, :development do gem 'shoulda-matchers', require: false gem 'rspec-html-matchers' gem 'byebug', require: ENV['RM_INFO'].nil?, platform: :mri - gem 'rubocop-discourse', require: false, github: 'discourse/rubocop-discourse' + gem 'rubocop-discourse', require: false gem 'parallel_tests' gem 'rswag-specs' diff --git a/Gemfile.lock b/Gemfile.lock index 1478b8c75d..1a47d48853 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,14 +5,6 @@ GIT mail (2.8.0.edge) mini_mime (>= 0.1.1) -GIT - remote: https://github.com/discourse/rubocop-discourse.git - revision: a5aea6e5f150b1eb7765a805bec0ff618cb718b3 - specs: - rubocop-discourse (2.5.0) - rubocop (>= 1.1.0) - rubocop-rspec (>= 2.0.0) - GEM remote: https://rubygems.org/ specs: @@ -56,8 +48,8 @@ GEM i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) annotate (3.2.0) activerecord (>= 3.2, < 8.0) rake (>= 10.4, < 14.0) @@ -93,17 +85,27 @@ GEM bootsnap (1.13.0) msgpack (~> 1.2) builder (3.2.4) - bullet (7.0.2) + bullet (7.0.3) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) byebug (11.1.3) + capybara (3.37.1) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) cbor (0.5.9.6) certified (1.0.0) + childprocess (4.1.0) chunky_png (1.4.0) coderay (1.1.3) colored2 (3.1.2) concurrent-ruby (1.1.10) - connection_pool (2.2.5) + connection_pool (2.3.0) cose (1.2.1) cbor (~> 0.5.9) openssl-signature_algorithm (~> 1.0) @@ -111,12 +113,11 @@ GEM crack (0.4.5) rexml crass (1.0.6) - css_parser (1.11.0) + css_parser (1.12.0) addressable debug_inspector (1.1.0) diff-lcs (1.5.0) diffy (3.4.2) - digest (3.1.0) discourse-ember-rails (0.18.6) active_model_serializers ember-data-source (>= 1.0.0.beta.5) @@ -140,36 +141,17 @@ GEM sprockets (>= 3.3, < 4.1) ember-source (2.18.2) erubi (1.11.0) - excon (0.92.4) + excon (0.92.5) execjs (2.8.1) exifr (1.3.9) fabrication (2.30.0) - faker (2.22.0) + faker (2.23.0) i18n (>= 1.8.11, < 2) fakeweb (1.3.0) - faraday (1.10.0) - faraday-em_http (~> 1.0) - faraday-em_synchrony (~> 1.0) - faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0) - faraday-multipart (~> 1.0) - faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.0) - faraday-patron (~> 1.0) - faraday-rack (~> 1.0) - faraday-retry (~> 1.0) + faraday (2.5.2) + faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) - faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) - faraday-excon (1.1.0) - faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) - faraday-net_http (1.0.1) - faraday-net_http_persistent (1.2.0) - faraday-patron (1.0.0) - faraday-rack (1.0.0) - faraday-retry (1.0.3) + faraday-net_http (3.0.0) fast_blank (1.0.1) fast_xs (0.8.0) fastimage (2.2.6) @@ -194,7 +176,7 @@ GEM image_size (>= 1.5, < 4) in_threads (~> 1.3) progress (~> 3.0, >= 3.0.1) - image_size (3.0.2) + image_size (3.1.0) in_threads (1.6.0) jmespath (1.6.1) jquery-rails (4.5.0) @@ -209,7 +191,7 @@ GEM hana (~> 1.3) regexp_parser (~> 2.0) uri_template (~> 0.7) - jwt (2.4.1) + jwt (2.5.0) kgio (2.11.4) libv8-node (16.10.0.0) libv8-node (16.10.0.0-aarch64-linux) @@ -229,12 +211,13 @@ GEM logstash-event (1.2.02) logstash-logger (0.26.1) logstash-event (~> 1.2) - logster (2.11.2) - loofah (2.18.0) + logster (2.11.3) + loofah (2.19.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) lru_redux (1.1.0) lz4-ruby (0.3.3) + matrix (0.4.2) maxminddb (0.1.22) memory_profiler (1.0.0) message_bus (4.2.0) @@ -242,36 +225,29 @@ GEM method_source (1.0.0) mini_mime (1.1.2) mini_portile2 (2.8.0) - mini_racer (0.6.2) + mini_racer (0.6.3) libv8-node (~> 16.10.0.0) mini_scheduler (0.14.0) sidekiq (>= 4.2.3) mini_sql (1.4.0) mini_suffix (0.3.3) ffi (~> 1.9) - minitest (5.16.2) - mocha (1.14.0) - msgpack (1.5.4) + minitest (5.16.3) + mocha (1.15.0) + msgpack (1.5.6) multi_json (1.15.0) multi_xml (0.6.0) - multipart-post (2.2.3) mustache (1.1.1) net-http (0.2.2) uri - net-imap (0.2.3) - digest + net-imap (0.3.0) net-protocol - strscan - net-pop (0.1.1) - digest + net-pop (0.1.2) net-protocol - timeout net-protocol (0.1.3) timeout - net-smtp (0.3.1) - digest + net-smtp (0.3.2) net-protocol - timeout nio4r (2.5.8) nokogiri (1.13.8) mini_portile2 (~> 2.8.0) @@ -284,15 +260,20 @@ GEM racc (~> 1.4) nokogiri (1.13.8-x86_64-linux) racc (~> 1.4) - oauth (0.5.10) - oauth2 (1.4.7) - faraday (>= 0.8, < 2.0) + oauth (1.1.0) + oauth-tty (~> 1.0, >= 1.0.1) + snaky_hash (~> 2.0) + version_gem (~> 1.1) + oauth-tty (1.0.3) + version_gem (~> 1.1) + oauth2 (1.4.11) + faraday (>= 0.17.3, < 3.0) jwt (>= 1.0, < 3.0) multi_json (~> 1.3) multi_xml (~> 0.5) - rack (>= 1.2, < 3) + rack (>= 1.2, < 4) oj (3.13.14) - omniauth (1.9.1) + omniauth (1.9.2) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) omniauth-facebook (9.0.0) @@ -308,40 +289,40 @@ GEM omniauth-oauth (1.2.0) oauth omniauth (>= 1.0, < 3) - omniauth-oauth2 (1.7.2) - oauth2 (~> 1.4) + omniauth-oauth2 (1.7.3) + oauth2 (>= 1.4, < 3) omniauth (>= 1.9, < 3) omniauth-twitter (1.4.0) omniauth-oauth (~> 1.1) rack - openssl (3.0.0) + openssl (3.0.1) openssl-signature_algorithm (1.2.1) openssl (> 2.0, < 3.1) optimist (3.0.1) parallel (1.22.1) - parallel_tests (3.11.1) + parallel_tests (3.13.0) parallel parser (3.1.2.1) ast (~> 2.4.1) pg (1.4.3) progress (3.6.0) - pry (0.13.1) + pry (0.14.1) coderay (~> 1.1) method_source (~> 1.0) - pry-byebug (3.9.0) + pry-byebug (3.10.1) byebug (~> 11.0) - pry (~> 0.13.0) + pry (>= 0.13, < 0.15) pry-rails (0.3.9) pry (>= 0.10.4) - public_suffix (4.0.7) - puma (5.6.4) + public_suffix (5.0.0) + puma (5.6.5) nio4r (~> 2.0) r2 (0.2.7) racc (1.6.0) rack (2.2.4) rack-mini-profiler (3.0.0) rack (>= 1.2.0) - rack-protection (2.2.2) + rack-protection (3.0.1) rack rack-test (2.0.2) rack (>= 1.3) @@ -367,7 +348,7 @@ GEM rainbow (3.1.1) raindrops (0.20.0) rake (13.0.6) - rb-fsevent (0.11.1) + rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) rbtrace (0.4.14) @@ -376,9 +357,9 @@ GEM optimist (>= 3.0.0) rchardet (1.8.0) redis (4.7.1) - redis-namespace (1.8.2) - redis (>= 3.0.4) - regexp_parser (2.5.0) + redis-namespace (1.9.0) + redis (>= 4) + regexp_parser (2.6.0) request_store (1.5.1) rack (>= 1.4) rexml (3.2.5) @@ -394,7 +375,7 @@ GEM rspec-mocks (~> 3.11.0) rspec-core (3.11.0) rspec-support (~> 3.11.0) - rspec-expectations (3.11.0) + rspec-expectations (3.11.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.11.0) rspec-html-matchers (0.10.0) @@ -411,27 +392,30 @@ GEM rspec-expectations (~> 3.10) rspec-mocks (~> 3.10) rspec-support (~> 3.10) - rspec-support (3.11.0) + rspec-support (3.11.1) rss (0.2.9) rexml - rswag-specs (2.5.1) + rswag-specs (2.6.0) activesupport (>= 3.1, < 7.1) json-schema (~> 2.2) railties (>= 3.1, < 7.1) - rubocop (1.34.1) + rubocop (1.36.0) json (~> 2.3) parallel (~> 1.10) parser (>= 3.1.2.1) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.20.0, < 2.0) + rubocop-ast (>= 1.20.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 3.0) rubocop-ast (1.21.0) parser (>= 3.1.1.0) - rubocop-rspec (2.12.1) - rubocop (~> 1.31) + rubocop-discourse (3.0) + rubocop (>= 1.1.0) + rubocop-rspec (>= 2.0.0) + rubocop-rspec (2.13.2) + rubocop (~> 1.33) ruby-prof (1.4.3) ruby-progressbar (1.11.0) ruby-readability (0.7.0) @@ -454,18 +438,26 @@ GEM seed-fu (2.3.9) activerecord (>= 3.1) activesupport (>= 3.1) - shoulda-matchers (5.1.0) + selenium-webdriver (4.5.0) + childprocess (>= 0.5, < 5.0) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 3.0) + websocket (~> 1.0) + shoulda-matchers (5.2.0) activesupport (>= 5.2.0) - sidekiq (6.5.4) - connection_pool (>= 2.2.2) + sidekiq (6.5.7) + connection_pool (>= 2.2.5) rack (~> 2.0) - redis (>= 4.5.0) + redis (>= 4.5.0, < 5) simplecov (0.21.2) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + snaky_hash (2.0.0) + hashie + version_gem (~> 1.1) sprockets (3.7.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) @@ -474,9 +466,8 @@ GEM activesupport (>= 5.2) sprockets (>= 3.0.0) sshkey (2.0.0) - stackprof (0.2.20) - strscan (3.0.4) - test-prof (1.0.9) + stackprof (0.2.21) + test-prof (1.0.10) thor (1.2.1) tilt (2.0.11) timeout (0.3.0) @@ -487,21 +478,29 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.8.2) - unicode-display_width (2.2.0) + unicode-display_width (2.3.0) unicorn (6.1.0) kgio (~> 2.6) raindrops (~> 0.7) uniform_notifier (1.16.0) uri (0.11.0) uri_template (0.7.0) - webmock (3.17.1) + version_gem (1.1.0) + webdrivers (5.1.0) + nokogiri (~> 1.6) + rubyzip (>= 1.3.0) + selenium-webdriver (~> 4.0) + webmock (3.18.1) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) webpush (1.1.0) hkdf (~> 0.2) jwt (~> 2.0) + websocket (1.2.9) xorcist (1.1.3) + xpath (3.2.0) + nokogiri (~> 1.8) yaml-lint (0.0.10) zeitwerk (2.6.0) @@ -533,6 +532,7 @@ DEPENDENCIES bootsnap bullet byebug + capybara cbor certified colored2 @@ -617,7 +617,7 @@ DEPENDENCIES rspec-rails rss rswag-specs - rubocop-discourse! + rubocop-discourse ruby-prof ruby-readability rubyzip @@ -625,6 +625,7 @@ DEPENDENCIES sassc (= 2.0.1) sassc-rails seed-fu + selenium-webdriver shoulda-matchers sidekiq simplecov @@ -637,6 +638,7 @@ DEPENDENCIES uglifier unf unicorn + webdrivers webmock webpush xorcist diff --git a/README.md b/README.md index e40a099058..c5b36997e3 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,9 @@ To learn more about the philosophy and goals of the project, [visit **discourse. ## Screenshots - + Boing Boing - - Mobile @@ -111,7 +109,7 @@ Discourse logo and “Discourse Forum” ®, Civilized Discourse Construction Ki ## Accessibility -To guide our ongoing effort to build accessible software we follow the [W3C’s Web Content Accessibility Guidelines (WCAG)](https://www.w3.org/TR/WCAG21/). If you'd like to report an accessibility issue that makes it difficult for you to use Discourse, email accessibility@discourse.org. For more information visit [discourse.org/accessibility](https://discourse.org/accessibility). +To guide our ongoing effort to build accessible software we follow the [W3C’s Web Content Accessibility Guidelines (WCAG)](https://www.w3.org/TR/WCAG21/). If you'd like to report an accessibility issue that makes it difficult for you to use Discourse, email accessibility@discourse.org. For more information visit [discourse.org/accessibility](https://discourse.org/accessibility). ## Dedication diff --git a/app/assets/javascripts/admin-plugins.js.erb b/app/assets/javascripts/admin-plugins.js.erb deleted file mode 100644 index 70010c4644..0000000000 --- a/app/assets/javascripts/admin-plugins.js.erb +++ /dev/null @@ -1,11 +0,0 @@ -<% -DiscoursePluginRegistry.admin_javascripts.each { |js| require_asset(js) } - -DiscoursePluginRegistry.each_globbed_asset(admin: true) do |f| - if File.directory?(f) - depend_on(f) - else - require_asset(f) - end -end -%> diff --git a/app/assets/javascripts/admin/addon/components/admin-watched-word.js b/app/assets/javascripts/admin/addon/components/admin-watched-word.js index f0523d374c..7de7e3d8ab 100644 --- a/app/assets/javascripts/admin/addon/components/admin-watched-word.js +++ b/app/assets/javascripts/admin/addon/components/admin-watched-word.js @@ -1,12 +1,13 @@ import Component from "@ember/component"; import { alias, equal } from "@ember/object/computed"; -import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; import { action } from "@ember/object"; import I18n from "I18n"; +import { inject as service } from "@ember/service"; export default Component.extend({ classNames: ["watched-word"], + dialog: service(), isReplace: equal("actionKey", "replace"), isTag: equal("actionKey", "tag"), @@ -26,7 +27,7 @@ export default Component.extend({ this.action(this.word); }) .catch((e) => { - bootbox.alert( + this.dialog.alert( I18n.t("generic_error_with_reason", { error: `http: ${e.status} - ${e.body}`, }) diff --git a/app/assets/javascripts/admin/addon/components/admin-web-hook-event.js b/app/assets/javascripts/admin/addon/components/admin-web-hook-event.js index fbcf1594e0..dd13384a2d 100644 --- a/app/assets/javascripts/admin/addon/components/admin-web-hook-event.js +++ b/app/assets/javascripts/admin/addon/components/admin-web-hook-event.js @@ -2,15 +2,16 @@ import { ensureJSON, plainJSON, prettyJSON } from "discourse/lib/formatter"; import Component from "@ember/component"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { inject as service } from "@ember/service"; export default Component.extend({ tagName: "li", expandDetails: null, expandDetailsRequestKey: "request", expandDetailsResponseKey: "response", + dialog: service(), @discourseComputed("model.status") statusColorClasses(status) { @@ -52,25 +53,21 @@ export default Component.extend({ actions: { redeliver() { - return bootbox.confirm( - I18n.t("admin.web_hooks.events.redeliver_confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - ajax( - `/admin/api/web_hooks/${this.get( - "model.web_hook_id" - )}/events/${this.get("model.id")}/redeliver`, - { type: "POST" } - ) - .then((json) => { - this.set("model", json.web_hook_event); - }) - .catch(popupAjaxError); - } - } - ); + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.web_hooks.events.redeliver_confirm"), + didConfirm: () => { + return ajax( + `/admin/api/web_hooks/${this.get( + "model.web_hook_id" + )}/events/${this.get("model.id")}/redeliver`, + { type: "POST" } + ) + .then((json) => { + this.set("model", json.web_hook_event); + }) + .catch(popupAjaxError); + }, + }); }, toggleRequest() { diff --git a/app/assets/javascripts/admin/addon/components/email-styles-editor.js b/app/assets/javascripts/admin/addon/components/email-styles-editor.js index e3e980e632..48621b41cf 100644 --- a/app/assets/javascripts/admin/addon/components/email-styles-editor.js +++ b/app/assets/javascripts/admin/addon/components/email-styles-editor.js @@ -1,10 +1,11 @@ import Component from "@ember/component"; import I18n from "I18n"; -import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; import { reads } from "@ember/object/computed"; +import { inject as service } from "@ember/service"; export default Component.extend({ + dialog: service(), editorId: reads("fieldName"), @discourseComputed("fieldName") @@ -33,22 +34,18 @@ export default Component.extend({ actions: { reset() { - bootbox.confirm( - I18n.t("admin.customize.email_style.reset_confirm", { + this.dialog.yesNoConfirm({ + message: I18n.t("admin.customize.email_style.reset_confirm", { fieldName: I18n.t(`admin.customize.email_style.${this.fieldName}`), }), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - this.styles.setField( - this.fieldName, - this.styles.get(`default_${this.fieldName}`) - ); - this.notifyPropertyChange("editorContents"); - } - } - ); + didConfirm: () => { + this.styles.setField( + this.fieldName, + this.styles.get(`default_${this.fieldName}`) + ); + this.notifyPropertyChange("editorContents"); + }, + }); }, save() { this.attrs.save(); diff --git a/app/assets/javascripts/admin/addon/components/ip-lookup.js b/app/assets/javascripts/admin/addon/components/ip-lookup.js index 920cd39069..222e04b9ab 100644 --- a/app/assets/javascripts/admin/addon/components/ip-lookup.js +++ b/app/assets/javascripts/admin/addon/components/ip-lookup.js @@ -3,13 +3,15 @@ import Component from "@ember/component"; import EmberObject from "@ember/object"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; import copyText from "discourse/lib/copy-text"; import discourseComputed from "discourse-common/utils/decorators"; import discourseLater from "discourse-common/lib/later"; +import { inject as service } from "@ember/service"; +import { popupAjaxError } from "discourse/lib/ajax-error"; export default Component.extend({ classNames: ["ip-lookup"], + dialog: service(), @discourseComputed("other_accounts.length", "totalOthersWithSameIP") otherAccountsToDelete(otherAccountsLength, totalOthersWithSameIP) { @@ -89,29 +91,27 @@ export default Component.extend({ }, deleteOtherAccounts() { - bootbox.confirm( - I18n.t("ip_lookup.confirm_delete_other_accounts"), - I18n.t("no_value"), - I18n.t("yes_value"), - (confirmed) => { - if (confirmed) { - this.setProperties({ - other_accounts: null, - otherAccountsLoading: true, - totalOthersWithSameIP: null, - }); + this.dialog.yesNoConfirm({ + message: I18n.t("ip_lookup.confirm_delete_other_accounts"), + didConfirm: () => { + this.setProperties({ + other_accounts: null, + otherAccountsLoading: true, + totalOthersWithSameIP: null, + }); - ajax("/admin/users/delete-others-with-same-ip.json", { - type: "DELETE", - data: { - ip: this.ip, - exclude: this.userId, - order: "trust_level DESC", - }, - }).then(() => this.send("lookup")); - } - } - ); + ajax("/admin/users/delete-others-with-same-ip.json", { + type: "DELETE", + data: { + ip: this.ip, + exclude: this.userId, + order: "trust_level DESC", + }, + }) + .catch(popupAjaxError) + .finally(this.send("lookup")); + }, + }); }, }, }); diff --git a/app/assets/javascripts/admin/addon/components/permalink-form.js b/app/assets/javascripts/admin/addon/components/permalink-form.js index 62c62bdf74..9c0c64de6b 100644 --- a/app/assets/javascripts/admin/addon/components/permalink-form.js +++ b/app/assets/javascripts/admin/addon/components/permalink-form.js @@ -1,14 +1,15 @@ import Component from "@ember/component"; import I18n from "I18n"; import Permalink from "admin/models/permalink"; -import bootbox from "bootbox"; import discourseComputed, { bind } from "discourse-common/utils/decorators"; import { fmt } from "discourse/lib/computed"; import { schedule } from "@ember/runloop"; import { action } from "@ember/object"; +import { inject as service } from "@ember/service"; export default Component.extend({ tagName: "", + dialog: service(), formSubmitted: false, permalinkType: "topic_id", permalinkTypePlaceholder: fmt("permalinkType", "admin.permalink.%@"), @@ -29,7 +30,7 @@ export default Component.extend({ @bind focusPermalink() { schedule("afterRender", () => - this.element.querySelector(".permalink-url")?.focus() + document.querySelector(".permalink-url")?.focus() ); }, @@ -74,7 +75,12 @@ export default Component.extend({ } else { error = I18n.t("generic_error"); } - bootbox.alert(error, this.focusPermalink); + + this.dialog.alert({ + message: error, + didConfirm: () => this.focusPermalink(), + didCancel: () => this.focusPermalink(), + }); } ); } diff --git a/app/assets/javascripts/admin/addon/components/screened-ip-address-form.js b/app/assets/javascripts/admin/addon/components/screened-ip-address-form.js index ae965dd26e..ab553b6a21 100644 --- a/app/assets/javascripts/admin/addon/components/screened-ip-address-form.js +++ b/app/assets/javascripts/admin/addon/components/screened-ip-address-form.js @@ -2,8 +2,8 @@ import discourseComputed from "discourse-common/utils/decorators"; import Component from "@ember/component"; import I18n from "I18n"; import ScreenedIpAddress from "admin/models/screened-ip-address"; -import bootbox from "bootbox"; import { schedule } from "@ember/runloop"; +import { inject as service } from "@ember/service"; /** A form to create an IP address that will be blocked or allowed. @@ -18,6 +18,7 @@ import { schedule } from "@ember/runloop"; export default Component.extend({ tagName: "form", + dialog: service(), classNames: ["screened-ip-address-form", "inline-form"], formSubmitted: false, actionName: "block", @@ -47,6 +48,12 @@ export default Component.extend({ } }, + focusInput() { + schedule("afterRender", () => { + this.element.querySelector("input").focus(); + }); + }, + actions: { submit() { if (!this.formSubmitted) { @@ -60,22 +67,20 @@ export default Component.extend({ .then((result) => { this.setProperties({ ip_address: "", formSubmitted: false }); this.action(ScreenedIpAddress.create(result.screened_ip_address)); - schedule("afterRender", () => - this.element.querySelector("input").focus() - ); + this.focusInput(); }) .catch((e) => { this.set("formSubmitted", false); - const msg = e.jqXHR.responseJSON?.errors + const message = e.jqXHR.responseJSON?.errors ? I18n.t("generic_error_with_reason", { error: e.jqXHR.responseJSON.errors.join(". "), }) : I18n.t("generic_error"); - bootbox.alert(msg, () => - schedule("afterRender", () => - this.element.querySelector("input").focus() - ) - ); + this.dialog.alert({ + message, + didConfirm: () => this.focusInput(), + didCancel: () => this.focusInput(), + }); }); } }, diff --git a/app/assets/javascripts/admin/addon/components/tags-uploader.js b/app/assets/javascripts/admin/addon/components/tags-uploader.js index dcd57a45fd..39425b9b65 100644 --- a/app/assets/javascripts/admin/addon/components/tags-uploader.js +++ b/app/assets/javascripts/admin/addon/components/tags-uploader.js @@ -2,10 +2,11 @@ import Component from "@ember/component"; import I18n from "I18n"; import UppyUploadMixin from "discourse/mixins/uppy-upload"; import { alias } from "@ember/object/computed"; -import bootbox from "bootbox"; +import { inject as service } from "@ember/service"; export default Component.extend(UppyUploadMixin, { type: "csv", + dialog: service(), uploadUrl: "/tags/upload", addDisabled: alias("uploading"), elementId: "tag-uploader", @@ -16,9 +17,8 @@ export default Component.extend(UppyUploadMixin, { }, uploadDone() { - bootbox.alert(I18n.t("tagging.upload_successful"), () => { - this.refresh(); - this.closeModal(); - }); + this.closeModal(); + this.refresh(); + this.dialog.alert(I18n.t("tagging.upload_successful")); }, }); diff --git a/app/assets/javascripts/admin/addon/components/watched-word-form.js b/app/assets/javascripts/admin/addon/components/watched-word-form.js index e00032f22c..1d6ba8ccba 100644 --- a/app/assets/javascripts/admin/addon/components/watched-word-form.js +++ b/app/assets/javascripts/admin/addon/components/watched-word-form.js @@ -2,13 +2,14 @@ import discourseComputed, { observes } from "discourse-common/utils/decorators"; import Component from "@ember/component"; import I18n from "I18n"; import WatchedWord from "admin/models/watched-word"; -import bootbox from "bootbox"; import { equal } from "@ember/object/computed"; import { isEmpty } from "@ember/utils"; import { schedule } from "@ember/runloop"; +import { inject as service } from "@ember/service"; export default Component.extend({ tagName: "form", + dialog: service(), classNames: ["watched-word-form"], formSubmitted: false, actionKey: null, @@ -55,6 +56,10 @@ export default Component.extend({ }); }, + focusInput() { + schedule("afterRender", () => this.element.querySelector("input").focus()); + }, + actions: { changeSelectedTags(tags) { this.setProperties({ @@ -98,22 +103,20 @@ export default Component.extend({ isCaseSensitive: false, }); this.action(WatchedWord.create(result)); - schedule("afterRender", () => - this.element.querySelector("input").focus() - ); + this.focusInput(); }) .catch((e) => { this.set("formSubmitted", false); - const msg = e.jqXHR.responseJSON?.errors + const message = e.jqXHR.responseJSON?.errors ? I18n.t("generic_error_with_reason", { error: e.jqXHR.responseJSON.errors.join(". "), }) : I18n.t("generic_error"); - bootbox.alert(msg, () => - schedule("afterRender", () => - this.element.querySelector("input").focus() - ) - ); + this.dialog.alert({ + message, + didConfirm: () => this.focusInput(), + didCancel: () => this.focusInput(), + }); }); } }, diff --git a/app/assets/javascripts/admin/addon/components/watched-word-uploader.js b/app/assets/javascripts/admin/addon/components/watched-word-uploader.js index efbacb9c0b..27c43ad576 100644 --- a/app/assets/javascripts/admin/addon/components/watched-word-uploader.js +++ b/app/assets/javascripts/admin/addon/components/watched-word-uploader.js @@ -2,7 +2,7 @@ import Component from "@ember/component"; import I18n from "I18n"; import UppyUploadMixin from "discourse/mixins/uppy-upload"; import { alias } from "@ember/object/computed"; -import bootbox from "bootbox"; +import { dialog } from "discourse/lib/uploads"; export default Component.extend(UppyUploadMixin, { type: "txt", @@ -21,7 +21,7 @@ export default Component.extend(UppyUploadMixin, { uploadDone() { if (this) { - bootbox.alert(I18n.t("admin.watched_words.form.upload_successful")); + dialog.alert(I18n.t("admin.watched_words.form.upload_successful")); this.done(); } }, diff --git a/app/assets/javascripts/admin/addon/controllers/admin-backups-index.js b/app/assets/javascripts/admin/addon/controllers/admin-backups-index.js index c53adeecf9..72a1bd18a5 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-backups-index.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-backups-index.js @@ -3,11 +3,13 @@ import { alias, equal } from "@ember/object/computed"; import { i18n, setting } from "discourse/lib/computed"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; + import discourseComputed from "discourse-common/utils/decorators"; +import { inject as service } from "@ember/service"; export default Controller.extend({ adminBackups: controller(), + dialog: service(), status: alias("adminBackups.model"), uploadLabel: i18n("admin.backups.upload.label"), backupLocation: setting("backup_location"), @@ -27,17 +29,13 @@ export default Controller.extend({ actions: { toggleReadOnlyMode() { if (!this.site.get("isReadOnly")) { - bootbox.confirm( - I18n.t("admin.backups.read_only.enable.confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (confirmed) => { - if (confirmed) { - this.set("currentUser.hideReadOnlyAlert", true); - this._toggleReadOnlyMode(true); - } - } - ); + this.dialog.yesNoConfirm({ + message: I18n.t("admin.backups.read_only.enable.confirm"), + didConfirm: () => { + this.set("currentUser.hideReadOnlyAlert", true); + this._toggleReadOnlyMode(true); + }, + }); } else { this._toggleReadOnlyMode(false); } @@ -46,7 +44,7 @@ export default Controller.extend({ download(backup) { const link = backup.get("filename"); ajax(`/admin/backups/${link}`, { type: "PUT" }).then(() => - bootbox.alert(I18n.t("admin.backups.operations.download.alert")) + this.dialog.alert(I18n.t("admin.backups.operations.download.alert")) ); }, }, diff --git a/app/assets/javascripts/admin/addon/controllers/admin-badges/award.js b/app/assets/javascripts/admin/addon/controllers/admin-badges/award.js index e564840115..93745bd79e 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-badges/award.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-badges/award.js @@ -1,12 +1,13 @@ import Controller from "@ember/controller"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; import { extractError } from "discourse/lib/ajax-error"; import { action } from "@ember/object"; import { tracked } from "@glimmer/tracking"; +import { inject as service } from "@ember/service"; export default class AdminBadgesAwardController extends Controller { + @service dialog; @tracked saving = false; @tracked replaceBadgeOwners = false; @tracked grantExistingHolders = false; @@ -84,7 +85,7 @@ export default class AdminBadgesAwardController extends Controller { }) .finally(() => (this.saving = false)); } else { - bootbox.alert(I18n.t("admin.badges.mass_award.aborted")); + this.dialog.alert(I18n.t("admin.badges.mass_award.aborted")); } } } diff --git a/app/assets/javascripts/admin/addon/controllers/admin-badges/show.js b/app/assets/javascripts/admin/addon/controllers/admin-badges/show.js index 29d95f2c0f..2b38081826 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-badges/show.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-badges/show.js @@ -1,7 +1,7 @@ import Controller, { inject as controller } from "@ember/controller"; import { observes } from "discourse-common/utils/decorators"; import I18n from "I18n"; -import bootbox from "bootbox"; + import { bufferedProperty } from "discourse/mixins/buffered-content"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { next } from "@ember/runloop"; @@ -17,8 +17,9 @@ const ICON = "icon"; export default class AdminBadgesShowController extends Controller.extend( bufferedProperty("model") ) { - @controller adminBadges; @service router; + @service dialog; + @controller adminBadges; @tracked saving = false; @tracked savingStatus = ""; @@ -81,8 +82,8 @@ export default class AdminBadgesShowController extends Controller.extend( } get hasQuery() { - let modelQuery = this.model.query; - let bufferedQuery = this.bufferedQuery; + let modelQuery = this.model.get("query"); + let bufferedQuery = this.buffered.get("query"); if (bufferedQuery) { return bufferedQuery.trim().length > 0; @@ -216,23 +217,19 @@ export default class AdminBadgesShowController extends Controller.extend( return; } - return bootbox.confirm( - I18n.t("admin.badges.delete_confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - model - .destroy() - .then(() => { - adminBadges.removeObject(model); - this.transitionToRoute("adminBadges.index"); - }) - .catch(() => { - bootbox.alert(I18n.t("generic_error")); - }); - } - } - ); + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.badges.delete_confirm"), + didConfirm: () => { + model + .destroy() + .then(() => { + adminBadges.removeObject(model); + this.transitionToRoute("adminBadges.index"); + }) + .catch(() => { + this.dialog.alert(I18n.t("generic_error")); + }); + }, + }); } } diff --git a/app/assets/javascripts/admin/addon/controllers/admin-customize-colors-show.js b/app/assets/javascripts/admin/addon/controllers/admin-customize-colors-show.js index 80b5e465c2..3df2ee25d4 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-customize-colors-show.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-customize-colors-show.js @@ -1,11 +1,12 @@ import Controller from "@ember/controller"; import I18n from "I18n"; -import bootbox from "bootbox"; import discourseLater from "discourse-common/lib/later"; import { action, computed } from "@ember/object"; import { clipboardCopy } from "discourse/lib/utilities"; +import { inject as service } from "@ember/service"; export default class AdminCustomizeColorsShowController extends Controller { + @service dialog; onlyOverridden = false; @computed("model.colors.[]", "onlyOverridden") @@ -73,18 +74,14 @@ export default class AdminCustomizeColorsShowController extends Controller { @action destroy() { - return bootbox.confirm( - I18n.t("admin.customize.colors.delete_confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - this.model.destroy().then(() => { - this.allColors.removeObject(this.model); - this.replaceRoute("adminCustomize.colors"); - }); - } - } - ); + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.customize.colors.delete_confirm"), + didConfirm: () => { + return this.model.destroy().then(() => { + this.allColors.removeObject(this.model); + this.replaceRoute("adminCustomize.colors"); + }); + }, + }); } } diff --git a/app/assets/javascripts/admin/addon/controllers/admin-customize-email-style-edit.js b/app/assets/javascripts/admin/addon/controllers/admin-customize-email-style-edit.js index 79813399b2..ad664f79b5 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-customize-email-style-edit.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-customize-email-style-edit.js @@ -1,9 +1,11 @@ import Controller from "@ember/controller"; import I18n from "I18n"; -import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; +import { inject as service } from "@ember/service"; export default Controller.extend({ + dialog: service(), + @discourseComputed("model.isSaving") saveButtonText(isSaving) { return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save"); @@ -27,7 +29,7 @@ export default Controller.extend({ error: e.jqXHR.responseJSON.errors.join(". "), }) : I18n.t("generic_error"); - bootbox.alert(msg); + this.dialog.alert(msg); }) .finally(() => this.set("model.changed", false)); } diff --git a/app/assets/javascripts/admin/addon/controllers/admin-customize-themes-show.js b/app/assets/javascripts/admin/addon/controllers/admin-customize-themes-show.js index 2418c785e0..61ffda925e 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-customize-themes-show.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-customize-themes-show.js @@ -16,10 +16,12 @@ import { makeArray } from "discourse-common/lib/helpers"; import { popupAjaxError } from "discourse/lib/ajax-error"; import showModal from "discourse/lib/show-modal"; import { url } from "discourse/lib/computed"; +import { inject as service } from "@ember/service"; const THEME_UPLOAD_VAR = 2; export default Controller.extend({ + dialog: service(), downloadUrl: url("model.id", "/admin/customize/themes/%@/export"), previewUrl: url("model.id", "/admin/themes/%@/preview"), addButtonDisabled: empty("selectedChildThemeId"), @@ -345,16 +347,10 @@ export default Controller.extend({ }, removeUpload(upload) { - return bootbox.confirm( - I18n.t("admin.customize.theme.delete_upload_confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - this.model.removeField(upload); - } - } - ); + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.customize.theme.delete_upload_confirm"), + didConfirm: () => this.model.removeField(upload), + }); }, removeChildTheme(theme) { @@ -364,23 +360,19 @@ export default Controller.extend({ }, destroy() { - return bootbox.confirm( - I18n.t("admin.customize.delete_confirm", { + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.customize.delete_confirm", { theme_name: this.get("model.name"), }), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - const model = this.model; - model.setProperties({ recentlyInstalled: false }); - model.destroyRecord().then(() => { - this.allThemes.removeObject(model); - this.transitionToRoute("adminCustomizeThemes"); - }); - } - } - ); + didConfirm: () => { + const model = this.model; + model.setProperties({ recentlyInstalled: false }); + model.destroyRecord().then(() => { + this.allThemes.removeObject(model); + this.transitionToRoute("adminCustomizeThemes"); + }); + }, + }); }, switchType() { @@ -398,16 +390,10 @@ export default Controller.extend({ }); } - bootbox.confirm( + return this.dialog.yesNoConfirm({ message, - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - this.commitSwitchType(); - } - } - ); + didConfirm: () => this.commitSwitchType(), + }); }, enableComponent() { diff --git a/app/assets/javascripts/admin/addon/controllers/admin-email-index.js b/app/assets/javascripts/admin/addon/controllers/admin-email-index.js index 91161bbe60..dddec41d1c 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-email-index.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-email-index.js @@ -1,11 +1,15 @@ import Controller from "@ember/controller"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; import { empty } from "@ember/object/computed"; import { observes } from "discourse-common/utils/decorators"; +import { inject as service } from "@ember/service"; +import { htmlSafe } from "@ember/template"; +import { escapeExpression } from "discourse/lib/utilities"; export default Controller.extend({ + dialog: service(), + /** Is the "send test email" button disabled? @@ -44,13 +48,17 @@ export default Controller.extend({ ) .catch((e) => { if (e.jqXHR.responseJSON?.errors) { - bootbox.alert( - I18n.t("admin.email.error", { - server_error: e.jqXHR.responseJSON.errors[0], - }) - ); + this.dialog.alert({ + message: htmlSafe( + I18n.t("admin.email.error", { + server_error: escapeExpression( + e.jqXHR.responseJSON.errors[0] + ), + }) + ), + }); } else { - bootbox.alert(I18n.t("admin.email.test_error")); + this.dialog.alert({ message: I18n.t("admin.email.test_error") }); } }) .finally(() => this.set("sendingEmail", false)); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-email-preview-digest.js b/app/assets/javascripts/admin/addon/controllers/admin-email-preview-digest.js index 1a6fbf2184..50d74d35d8 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-email-preview-digest.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-email-preview-digest.js @@ -1,14 +1,14 @@ import { empty, notEmpty, or } from "@ember/object/computed"; import Controller from "@ember/controller"; import EmailPreview from "admin/models/email-preview"; -import bootbox from "bootbox"; import { get } from "@ember/object"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { inject as service } from "@ember/service"; export default Controller.extend({ + dialog: service(), username: null, lastSeen: null, - emailEmpty: empty("email"), sendEmailDisabled: or("emailEmpty", "sendingEmail"), showSendEmailForm: notEmpty("model.html_content"), @@ -50,7 +50,7 @@ export default Controller.extend({ EmailPreview.sendDigest(this.username, this.lastSeen, this.email) .then((result) => { if (result.errors) { - bootbox.alert(result.errors); + this.dialog.alert(result.errors); } else { this.set("sentEmail", true); } diff --git a/app/assets/javascripts/admin/addon/controllers/admin-emojis.js b/app/assets/javascripts/admin/addon/controllers/admin-emojis.js index 7ab8590163..eab68cf088 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-emojis.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-emojis.js @@ -2,12 +2,13 @@ import EmberObject, { action, computed } from "@ember/object"; import Controller from "@ember/controller"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; import { sort } from "@ember/object/computed"; +import { inject as service } from "@ember/service"; const ALL_FILTER = "all"; export default Controller.extend({ + dialog: service(), filter: null, sorting: null, @@ -72,19 +73,17 @@ export default Controller.extend({ @action destroyEmoji(emoji) { - return bootbox.confirm( - I18n.t("admin.emoji.delete_confirm", { name: emoji.get("name") }), - I18n.t("no_value"), - I18n.t("yes_value"), - (destroy) => { - if (destroy) { - return ajax("/admin/customize/emojis/" + emoji.get("name"), { - type: "DELETE", - }).then(() => { - this.model.removeObject(emoji); - }); - } - } - ); + this.dialog.yesNoConfirm({ + message: I18n.t("admin.emoji.delete_confirm", { + name: emoji.get("name"), + }), + didConfirm: () => { + return ajax("/admin/customize/emojis/" + emoji.get("name"), { + type: "DELETE", + }).then(() => { + this.model.removeObject(emoji); + }); + }, + }); }, }); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-logs-screened-ip-addresses.js b/app/assets/javascripts/admin/addon/controllers/admin-logs-screened-ip-addresses.js index df734004ec..0e8b43f9c1 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-logs-screened-ip-addresses.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-logs-screened-ip-addresses.js @@ -2,13 +2,14 @@ import Controller from "@ember/controller"; import I18n from "I18n"; import { INPUT_DELAY } from "discourse-common/config/environment"; import ScreenedIpAddress from "admin/models/screened-ip-address"; -import bootbox from "bootbox"; import discourseDebounce from "discourse-common/lib/debounce"; import { exportEntity } from "discourse/lib/export-csv"; import { observes } from "discourse-common/utils/decorators"; import { outputExportResult } from "discourse/lib/export-result"; +import { inject as service } from "@ember/service"; export default Controller.extend({ + dialog: service(), loading: false, filter: null, savedIpAddress: null, @@ -59,13 +60,13 @@ export default Controller.extend({ .then(() => this.set("savedIpAddress", null)) .catch((e) => { if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) { - bootbox.alert( + this.dialog.alert( I18n.t("generic_error_with_reason", { error: e.jqXHR.responseJSON.errors.join(". "), }) ); } else { - bootbox.alert(I18n.t("generic_error")); + this.dialog.alert(I18n.t("generic_error")); } if (wasEditing) { record.set("editing", true); @@ -74,33 +75,29 @@ export default Controller.extend({ }, destroy(record) { - return bootbox.confirm( - I18n.t("admin.logs.screened_ips.delete_confirm", { + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.logs.screened_ips.delete_confirm", { ip_address: record.get("ip_address"), }), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - record - .destroy() - .then((deleted) => { - if (deleted) { - this.model.removeObject(record); - } else { - bootbox.alert(I18n.t("generic_error")); - } - }) - .catch((e) => { - bootbox.alert( - I18n.t("generic_error_with_reason", { - error: `http: ${e.status} - ${e.body}`, - }) - ); - }); - } - } - ); + didConfirm: () => { + return record + .destroy() + .then((deleted) => { + if (deleted) { + this.model.removeObject(record); + } else { + this.dialog.alert(I18n.t("generic_error")); + } + }) + .catch((e) => { + this.dialog.alert( + I18n.t("generic_error_with_reason", { + error: `http: ${e.status} - ${e.body}`, + }) + ); + }); + }, + }); }, recordAdded(arg) { diff --git a/app/assets/javascripts/admin/addon/controllers/admin-permalinks.js b/app/assets/javascripts/admin/addon/controllers/admin-permalinks.js index 9993a19fe5..07372d2f10 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-permalinks.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-permalinks.js @@ -2,12 +2,13 @@ import Controller from "@ember/controller"; import I18n from "I18n"; import { INPUT_DELAY } from "discourse-common/config/environment"; import Permalink from "admin/models/permalink"; -import bootbox from "bootbox"; import discourseDebounce from "discourse-common/lib/debounce"; import { observes } from "discourse-common/utils/decorators"; import { clipboardCopy } from "discourse/lib/utilities"; +import { inject as service } from "@ember/service"; export default Controller.extend({ + dialog: service(), loading: false, filter: null, @@ -34,27 +35,23 @@ export default Controller.extend({ }, destroy(record) { - return bootbox.confirm( - I18n.t("admin.permalink.delete_confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - record.destroy().then( - (deleted) => { - if (deleted) { - this.model.removeObject(record); - } else { - bootbox.alert(I18n.t("generic_error")); - } - }, - function () { - bootbox.alert(I18n.t("generic_error")); + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.permalink.delete_confirm"), + didConfirm: () => { + return record.destroy().then( + (deleted) => { + if (deleted) { + this.model.removeObject(record); + } else { + this.dialog.alert(I18n.t("generic_error")); } - ); - } - } - ); + }, + function () { + this.dialog.alert(I18n.t("generic_error")); + } + ); + }, + }); }, }, }); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-site-text-edit.js b/app/assets/javascripts/admin/addon/controllers/admin-site-text-edit.js index cc7bac3267..8bcfc9b9da 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-site-text-edit.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-site-text-edit.js @@ -1,11 +1,13 @@ import Controller from "@ember/controller"; import I18n from "I18n"; -import bootbox from "bootbox"; import { bufferedProperty } from "discourse/mixins/buffered-content"; import discourseComputed from "discourse-common/utils/decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { action } from "@ember/object"; +import { inject as service } from "@ember/service"; export default Controller.extend(bufferedProperty("siteText"), { + dialog: service(), saved: false, queryParams: ["locale"], @@ -14,35 +16,36 @@ export default Controller.extend(bufferedProperty("siteText"), { return this.siteText.value === value; }, - actions: { - saveChanges() { - const attrs = this.buffered.getProperties("value"); - attrs.locale = this.locale; + @action + saveChanges() { + const attrs = this.buffered.getProperties("value"); + attrs.locale = this.locale; - this.siteText - .save(attrs) - .then(() => { - this.commitBuffer(); - this.set("saved", true); - }) - .catch(popupAjaxError); - }, + this.siteText + .save(attrs) + .then(() => { + this.commitBuffer(); + this.set("saved", true); + }) + .catch(popupAjaxError); + }, - revertChanges() { - this.set("saved", false); + @action + revertChanges() { + this.set("saved", false); - bootbox.confirm(I18n.t("admin.site_text.revert_confirm"), (result) => { - if (result) { - this.siteText - .revert(this.locale) - .then((props) => { - const buffered = this.buffered; - buffered.setProperties(props); - this.commitBuffer(); - }) - .catch(popupAjaxError); - } - }); - }, + this.dialog.yesNoConfirm({ + message: I18n.t("admin.site_text.revert_confirm"), + didConfirm: () => { + this.siteText + .revert(this.locale) + .then((props) => { + const buffered = this.buffered; + buffered.setProperties(props); + this.commitBuffer(); + }) + .catch(popupAjaxError); + }, + }); }, }); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-site-text-index.js b/app/assets/javascripts/admin/addon/controllers/admin-site-text-index.js index 2f2b708d17..1ec7abbbea 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-site-text-index.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-site-text-index.js @@ -42,21 +42,11 @@ export default Controller.extend({ } }, - @discourseComputed("locale") - showFallbackLocaleWarning() { - return ( - this.siteSettings.allow_user_locale && - this.siteSettings.set_locale_from_accept_language_header && - this.fallbackLocaleFullName - ); - }, - actions: { edit(siteText) { this.transitionToRoute("adminSiteText.edit", siteText.get("id"), { queryParams: { locale: this.locale, - localeFullName: this.availableLocales[this.locale], }, }); }, diff --git a/app/assets/javascripts/admin/addon/controllers/admin-user-badges.js b/app/assets/javascripts/admin/addon/controllers/admin-user-badges.js index 9461374085..b36a22af0c 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-user-badges.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-user-badges.js @@ -2,13 +2,14 @@ import Controller, { inject as controller } from "@ember/controller"; import { alias, sort } from "@ember/object/computed"; import GrantBadgeController from "discourse/mixins/grant-badge-controller"; import I18n from "I18n"; -import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; import { next } from "@ember/runloop"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { inject as service } from "@ember/service"; export default Controller.extend(GrantBadgeController, { adminUser: controller(), + dialog: service(), user: alias("adminUser.model"), userBadges: alias("model"), allBadges: alias("badges"), @@ -90,18 +91,14 @@ export default Controller.extend(GrantBadgeController, { }, revokeBadge(userBadge) { - return bootbox.confirm( - I18n.t("admin.badges.revoke_confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - userBadge.revoke().then(() => { - this.model.removeObject(userBadge); - }); - } - } - ); + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.badges.revoke_confirm"), + didConfirm: () => { + return userBadge.revoke().then(() => { + this.model.removeObject(userBadge); + }); + }, + }); }, }, }); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-user-index.js b/app/assets/javascripts/admin/addon/controllers/admin-user-index.js index 807bb39932..b6859b9ce0 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-user-index.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-user-index.js @@ -6,17 +6,16 @@ import CanCheckEmails from "discourse/mixins/can-check-emails"; import Controller from "@ember/controller"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; import getURL from "discourse-common/lib/get-url"; import { htmlSafe } from "@ember/template"; -import { iconHTML } from "discourse-common/lib/icon-library"; import { extractError, popupAjaxError } from "discourse/lib/ajax-error"; import { inject as service } from "@ember/service"; import showModal from "discourse/lib/show-modal"; export default Controller.extend(CanCheckEmails, { router: service(), + dialog: service(), adminTools: service(), originalPrimaryGroupId: null, customGroupIdsBuffer: null, @@ -130,7 +129,7 @@ export default Controller.extend(CanCheckEmails, { groupAdded(added) { this.model .groupAdded(added) - .catch(() => bootbox.alert(I18n.t("generic_error"))); + .catch(() => this.dialog.alert(I18n.t("generic_error"))); }, groupRemoved(groupId) { @@ -141,7 +140,7 @@ export default Controller.extend(CanCheckEmails, { this.set("originalPrimaryGroupId", null); } }) - .catch(() => bootbox.alert(I18n.t("generic_error"))); + .catch(() => this.dialog.alert(I18n.t("generic_error"))); }, @discourseComputed("ssoLastPayload") @@ -156,16 +155,16 @@ export default Controller.extend(CanCheckEmails, { .then(() => DiscourseURL.redirectTo("/")) .catch((e) => { if (e.status === 404) { - bootbox.alert(I18n.t("admin.impersonate.not_found")); + this.dialog.alert(I18n.t("admin.impersonate.not_found")); } else { - bootbox.alert(I18n.t("admin.impersonate.invalid")); + this.dialog.alert(I18n.t("admin.impersonate.invalid")); } }); }, logOut() { return this.model .logOut() - .then(() => bootbox.alert(I18n.t("admin.user.logged_out"))); + .then(() => this.dialog.alert(I18n.t("admin.user.logged_out"))); }, resetBounceScore() { return this.model.resetBounceScore(); @@ -188,13 +187,15 @@ export default Controller.extend(CanCheckEmails, { const error = I18n.t("admin.user.deactivate_failed", { error: this._formatError(e), }); - bootbox.alert(error); + this.dialog.alert(error); }); }, sendActivationEmail() { return this.model .sendActivationEmail() - .then(() => bootbox.alert(I18n.t("admin.user.activation_email_sent"))) + .then(() => + this.dialog.alert(I18n.t("admin.user.activation_email_sent")) + ) .catch(popupAjaxError); }, activate() { @@ -210,7 +211,7 @@ export default Controller.extend(CanCheckEmails, { const error = I18n.t("admin.user.activate_failed", { error: this._formatError(e), }); - bootbox.alert(error); + this.dialog.alert(error); }); }, revokeAdmin() { @@ -221,7 +222,7 @@ export default Controller.extend(CanCheckEmails, { .grantAdmin() .then((result) => { if (result.email_confirmation_required) { - bootbox.alert(I18n.t("admin.user.grant_admin_confirm")); + this.dialog.alert(I18n.t("admin.user.grant_admin_confirm")); } }) .catch((error) => { @@ -255,7 +256,7 @@ export default Controller.extend(CanCheckEmails, { I18n.t("admin.user.trust_level_change_failed", { error: this._formatError(e), }); - bootbox.alert(error); + this.dialog.alert(error); }); }, restoreTrustLevel() { @@ -275,7 +276,7 @@ export default Controller.extend(CanCheckEmails, { I18n.t("admin.user.trust_level_change_failed", { error: this._formatError(e), }); - bootbox.alert(error); + this.dialog.alert(error); }); }, unsilence() { @@ -287,7 +288,6 @@ export default Controller.extend(CanCheckEmails, { anonymize() { const user = this.model; - const message = I18n.t("admin.user.anonymize_confirm"); const performAnonymize = () => { this.model @@ -302,31 +302,32 @@ export default Controller.extend(CanCheckEmails, { document.location = getURL("/admin/users/list/active"); } } else { - bootbox.alert(I18n.t("admin.user.anonymize_failed")); + this.dialog.alert(I18n.t("admin.user.anonymize_failed")); if (data.user) { user.setProperties(data.user); } } }) - .catch(() => bootbox.alert(I18n.t("admin.user.anonymize_failed"))); + .catch(() => + this.dialog.alert(I18n.t("admin.user.anonymize_failed")) + ); }; - const buttons = [ - { - label: I18n.t("composer.cancel"), - class: "cancel", - link: true, - }, - { - label: I18n.t("admin.user.anonymize_yes"), - class: "btn btn-danger", - icon: iconHTML("exclamation-triangle"), - callback: () => { - performAnonymize(); - }, - }, - ]; - bootbox.dialog(message, buttons, { classes: "delete-user-modal" }); + this.dialog.alert({ + message: I18n.t("admin.user.anonymize_confirm"), + class: "delete-user-modal", + buttons: [ + { + icon: "exclamation-triangle", + label: I18n.t("admin.user.anonymize_yes"), + class: "btn-danger", + action: () => performAnonymize(), + }, + { + label: I18n.t("composer.cancel"), + }, + ], + }); }, disableSecondFactor() { @@ -345,11 +346,10 @@ export default Controller.extend(CanCheckEmails, { destroy() { const postCount = this.get("model.post_count"); const maxPostCount = this.siteSettings.delete_all_posts_max; - const message = I18n.t("admin.user.delete_confirm"); const location = document.location.pathname; const performDestroy = (block) => { - bootbox.dialog(I18n.t("admin.user.deleting_user")); + this.dialog.notice(I18n.t("admin.user.deleting_user")); let formData = { context: location }; if (block) { formData["block_email"] = true; @@ -369,38 +369,39 @@ export default Controller.extend(CanCheckEmails, { document.location = getURL("/admin/users/list/active"); } } else { - bootbox.alert(I18n.t("admin.user.delete_failed")); + this.dialog.alert(I18n.t("admin.user.delete_failed")); } }) .catch(() => { - bootbox.alert(I18n.t("admin.user.delete_failed")); + this.dialog.alert(I18n.t("admin.user.delete_failed")); }); }; - const buttons = [ - { - label: I18n.t("composer.cancel"), - class: "btn", - link: true, - }, - { - icon: iconHTML("exclamation-triangle"), - label: I18n.t("admin.user.delete_and_block"), - class: "btn btn-danger", - callback: () => { - performDestroy(true); + this.dialog.alert({ + title: I18n.t("admin.user.delete_confirm_title"), + message: I18n.t("admin.user.delete_confirm"), + class: "delete-user-modal", + buttons: [ + { + label: I18n.t("admin.user.delete_dont_block"), + class: "btn-primary", + action: () => { + return performDestroy(false); + }, }, - }, - { - label: I18n.t("admin.user.delete_dont_block"), - class: "btn btn-primary", - callback: () => { - performDestroy(false); + { + icon: "exclamation-triangle", + label: I18n.t("admin.user.delete_and_block"), + class: "btn-danger", + action: () => { + return performDestroy(true); + }, }, - }, - ]; - - bootbox.dialog(message, buttons, { classes: "delete-user-modal" }); + { + label: I18n.t("composer.cancel"), + }, + ], + }); }, promptTargetUser() { @@ -439,12 +440,12 @@ export default Controller.extend(CanCheckEmails, { model: this.model, }); } else { - bootbox.alert(I18n.t("admin.user.merge_failed")); + this.dialog.alert(I18n.t("admin.user.merge_failed")); } }) .catch(() => { AdminUser.find(user.id).then((u) => user.setProperties(u)); - bootbox.alert(I18n.t("admin.user.merge_failed")); + this.dialog.alert(I18n.t("admin.user.merge_failed")); }); }, @@ -532,7 +533,7 @@ export default Controller.extend(CanCheckEmails, { data: { primary_group_id: primaryGroupId }, }) .then(() => this.set("originalPrimaryGroupId", primaryGroupId)) - .catch(() => bootbox.alert(I18n.t("generic_error"))); + .catch(() => this.dialog.alert(I18n.t("generic_error"))); }, resetPrimaryGroup() { @@ -540,16 +541,10 @@ export default Controller.extend(CanCheckEmails, { }, deleteSSORecord() { - return bootbox.confirm( - I18n.t("admin.user.discourse_connect.confirm_delete"), - I18n.t("no_value"), - I18n.t("yes_value"), - (confirmed) => { - if (confirmed) { - return this.model.deleteSSORecord(); - } - } - ); + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.user.discourse_connect.confirm_delete"), + didConfirm: () => this.model.deleteSSORecord(), + }); }, checkSsoEmail() { @@ -607,7 +602,7 @@ export default Controller.extend(CanCheckEmails, { let error; AdminUser.find(user.get("id")).then((u) => user.setProperties(u)); error = extractError(e) || I18n.t("admin.user.delete_posts_failed"); - bootbox.alert(error); + this.dialog.alert(error); }); }; diff --git a/app/assets/javascripts/admin/addon/controllers/admin-users-list-show.js b/app/assets/javascripts/admin/addon/controllers/admin-users-list-show.js index abd59ab1f1..e51e7c3a5c 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-users-list-show.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-users-list-show.js @@ -59,10 +59,10 @@ export default Controller.extend(CanCheckEmails, { page, }) .then((result) => { - if (result && result.length > 0) { - this._results[page] = result; - this.set("model", this._results.flat()); - } else { + this._results[page] = result; + this.set("model", this._results.flat()); + + if (result.length === 0) { this._canLoadMore = false; } }) diff --git a/app/assets/javascripts/admin/addon/controllers/admin-watched-words-action.js b/app/assets/javascripts/admin/addon/controllers/admin-watched-words-action.js index d84d80615d..a1b158a677 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-watched-words-action.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-watched-words-action.js @@ -2,16 +2,17 @@ import Controller, { inject as controller } from "@ember/controller"; import I18n from "I18n"; import WatchedWord from "admin/models/watched-word"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; import { fmt } from "discourse/lib/computed"; import { or } from "@ember/object/computed"; import { schedule } from "@ember/runloop"; import showModal from "discourse/lib/show-modal"; +import { inject as service } from "@ember/service"; export default Controller.extend({ adminWatchedWords: controller(), actionNameKey: null, + dialog: service(), downloadLink: fmt( "actionNameKey", "/admin/customize/watched_words/action/%@/download" @@ -93,25 +94,21 @@ export default Controller.extend({ clearAll() { const actionKey = this.actionNameKey; - bootbox.confirm( - I18n.t("admin.watched_words.clear_all_confirm", { + this.dialog.yesNoConfirm({ + message: I18n.t("admin.watched_words.clear_all_confirm", { action: I18n.t("admin.watched_words.actions." + actionKey), }), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - ajax(`/admin/customize/watched_words/action/${actionKey}.json`, { - type: "DELETE", - }).then(() => { - const action = this.findAction(actionKey); - if (action) { - action.set("words", []); - } - }); - } - } - ); + didConfirm: () => { + ajax(`/admin/customize/watched_words/action/${actionKey}.json`, { + type: "DELETE", + }).then(() => { + const action = this.findAction(actionKey); + if (action) { + action.set("words", []); + } + }); + }, + }); }, }, }); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-show.js b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-show.js index a952f4e546..ba75e29199 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-show.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-show.js @@ -2,15 +2,16 @@ import Controller, { inject as controller } from "@ember/controller"; import EmberObject from "@ember/object"; import I18n from "I18n"; import { alias } from "@ember/object/computed"; -import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; import { extractDomainFromUrl } from "discourse/lib/utilities"; import { isAbsoluteURL } from "discourse-common/lib/get-url"; import { isEmpty } from "@ember/utils"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { inject as service } from "@ember/service"; export default Controller.extend({ adminWebHooks: controller(), + dialog: service(), eventTypes: alias("adminWebHooks.eventTypes"), defaultEventTypes: alias("adminWebHooks.defaultEventTypes"), contentTypes: alias("adminWebHooks.contentTypes"), @@ -113,39 +114,28 @@ export default Controller.extend({ domain.match(/127\.\d+\.\d+\.\d+/) || isAbsoluteURL(url) ) { - return bootbox.confirm( - I18n.t("admin.web_hooks.warn_local_payload_url"), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - return saveWebHook(); - } - } - ); + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.web_hooks.warn_local_payload_url"), + didConfirm: () => saveWebHook(), + }); } return saveWebHook(); }, destroy() { - return bootbox.confirm( - I18n.t("admin.web_hooks.delete_confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - const model = this.model; - model - .destroyRecord() - .then(() => { - this.adminWebHooks.get("model").removeObject(model); - this.transitionToRoute("adminWebHooks"); - }) - .catch(popupAjaxError); - } - } - ); + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.web_hooks.delete_confirm"), + didConfirm: () => { + this.model + .destroyRecord() + .then(() => { + this.adminWebHooks.get("model").removeObject(this.model); + this.transitionToRoute("adminWebHooks"); + }) + .catch(popupAjaxError); + }, + }); }, }, }); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks.js b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks.js index 6e1acf97dc..405f859413 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks.js @@ -1,30 +1,29 @@ import Controller from "@ember/controller"; import I18n from "I18n"; -import bootbox from "bootbox"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { inject as service } from "@ember/service"; +import { action } from "@ember/object"; export default Controller.extend({ - actions: { - destroy(webhook) { - return bootbox.confirm( - I18n.t("admin.web_hooks.delete_confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - webhook - .destroyRecord() - .then(() => { - this.model.removeObject(webhook); - }) - .catch(popupAjaxError); - } - } - ); - }, + dialog: service(), - loadMore() { - this.model.loadMore(); - }, + @action + destroy(webhook) { + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.web_hooks.delete_confirm"), + didConfirm: () => { + webhook + .destroyRecord() + .then(() => { + this.model.removeObject(webhook); + }) + .catch(popupAjaxError); + }, + }); + }, + + @action + loadMore() { + this.model.loadMore(); }, }); diff --git a/app/assets/javascripts/admin/addon/controllers/modals/admin-edit-badge-groupings.js b/app/assets/javascripts/admin/addon/controllers/modals/admin-edit-badge-groupings.js index aa7d5665fa..c453a4f8b4 100644 --- a/app/assets/javascripts/admin/addon/controllers/modals/admin-edit-badge-groupings.js +++ b/app/assets/javascripts/admin/addon/controllers/modals/admin-edit-badge-groupings.js @@ -3,10 +3,12 @@ import Controller from "@ember/controller"; import I18n from "I18n"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; import { observes } from "discourse-common/utils/decorators"; +import { inject as service } from "@ember/service"; export default Controller.extend(ModalFunctionality, { + dialog: service(), + @observes("model") modelChanged() { const model = this.model; @@ -78,7 +80,7 @@ export default Controller.extend(ModalFunctionality, { this.setProperties({ model: null, workingCopy: null }); this.send("closeModal"); }, - () => bootbox.alert(I18n.t("generic_error")) + () => this.dialog.alert(I18n.t("generic_error")) ); }, }, diff --git a/app/assets/javascripts/admin/addon/controllers/modals/admin-install-theme.js b/app/assets/javascripts/admin/addon/controllers/modals/admin-install-theme.js index 0290760180..d42446ddbb 100644 --- a/app/assets/javascripts/admin/addon/controllers/modals/admin-install-theme.js +++ b/app/assets/javascripts/admin/addon/controllers/modals/admin-install-theme.js @@ -24,7 +24,7 @@ export default Controller.extend(ModalFunctionality, { keyGenUrl: "/admin/themes/generate_key_pair", importUrl: "/admin/themes/import", recordType: "theme", - checkPrivate: match("uploadUrl", /^ssh\:\/\/.*\@.*\.git$|.*\@.*\:.*\.git$/), + checkPrivate: match("uploadUrl", /^ssh:\/\/.+@.+$|.+@.+:.+$/), localFile: null, uploadUrl: null, uploadName: null, @@ -93,10 +93,7 @@ export default Controller.extend(ModalFunctionality, { this._keyLoading = true; ajax(this.keyGenUrl, { type: "POST" }) .then((pair) => { - this.setProperties({ - privateKey: pair.private_key, - publicKey: pair.public_key, - }); + this.set("publicKey", pair.public_key); }) .catch(popupAjaxError) .finally(() => { @@ -139,7 +136,6 @@ export default Controller.extend(ModalFunctionality, { this.setProperties({ duplicateRemoteThemeWarning: null, privateChecked: false, - privateKey: null, localFile: null, uploadUrl: null, publicKey: null, @@ -216,7 +212,7 @@ export default Controller.extend(ModalFunctionality, { }; if (this.privateChecked) { - options.data.private_key = this.privateKey; + options.data.public_key = this.publicKey; } } @@ -239,10 +235,10 @@ export default Controller.extend(ModalFunctionality, { this.send("closeModal"); }) .then(() => { - this.setProperties({ privateKey: null, publicKey: null }); + this.set("publicKey", null); }) .catch((error) => { - if (!this.privateKey || this.themeCannotBeInstalled) { + if (!this.publicKey || this.themeCannotBeInstalled) { return popupAjaxError(error); } diff --git a/app/assets/javascripts/admin/addon/controllers/modals/admin-reseed.js b/app/assets/javascripts/admin/addon/controllers/modals/admin-reseed.js index 672f6d8db3..744921b02a 100644 --- a/app/assets/javascripts/admin/addon/controllers/modals/admin-reseed.js +++ b/app/assets/javascripts/admin/addon/controllers/modals/admin-reseed.js @@ -2,9 +2,10 @@ import Controller from "@ember/controller"; import I18n from "I18n"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; +import { inject as service } from "@ember/service"; export default Controller.extend(ModalFunctionality, { + dialog: service(), loading: true, reseeding: false, categories: null, @@ -35,11 +36,11 @@ export default Controller.extend(ModalFunctionality, { }, type: "POST", }) - .then( - () => this.send("closeModal"), - () => bootbox.alert(I18n.t("generic_error")) - ) - .finally(() => this.set("reseeding", false)); + .catch(() => this.dialog.alert(I18n.t("generic_error"))) + .finally(() => { + this.set("reseeding", false); + this.send("closeModal"); + }); }, }, }); diff --git a/app/assets/javascripts/admin/addon/routes/admin-backups.js b/app/assets/javascripts/admin/addon/routes/admin-backups.js index 063eeec9d7..c78ef4ca1c 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-backups.js +++ b/app/assets/javascripts/admin/addon/routes/admin-backups.js @@ -6,14 +6,15 @@ import I18n from "I18n"; import PreloadStore from "discourse/lib/preload-store"; import User from "discourse/models/user"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; import { extractError } from "discourse/lib/ajax-error"; import getURL from "discourse-common/lib/get-url"; import showModal from "discourse/lib/show-modal"; - +import { inject as service } from "@ember/service"; const LOG_CHANNEL = "/admin/backups/logs"; export default DiscourseRoute.extend({ + dialog: service(), + activate() { this.messageBus.subscribe(LOG_CHANNEL, (log) => { if (log.message === "[STARTED]") { @@ -28,7 +29,7 @@ export default DiscourseRoute.extend({ "model.isOperationRunning", false ); - bootbox.alert( + this.dialog.alert( I18n.t("admin.backups.operations.failed", { operation: log.operation, }) @@ -77,88 +78,72 @@ export default DiscourseRoute.extend({ this.transitionTo("admin.backups.logs"); Backup.start(withUploads).then((result) => { if (!result.success) { - bootbox.alert(result.message); + this.dialog.alert(result.message); } }); }, destroyBackup(backup) { - bootbox.confirm( - I18n.t("admin.backups.operations.destroy.confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (confirmed) => { - if (confirmed) { - backup - .destroy() - .then(() => - this.controllerFor("adminBackupsIndex") - .get("model") - .removeObject(backup) - ); - } - } - ); + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.backups.operations.destroy.confirm"), + didConfirm: () => { + backup + .destroy() + .then(() => + this.controllerFor("adminBackupsIndex") + .get("model") + .removeObject(backup) + ); + }, + }); }, startRestore(backup) { - bootbox.confirm( - I18n.t("admin.backups.operations.restore.confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (confirmed) => { - if (confirmed) { - this.transitionTo("admin.backups.logs"); - backup.restore(); - } - } - ); + this.dialog.yesNoConfirm({ + message: I18n.t("admin.backups.operations.restore.confirm"), + didConfirm: () => { + this.transitionTo("admin.backups.logs"); + backup.restore(); + }, + }); }, cancelOperation() { - bootbox.confirm( - I18n.t("admin.backups.operations.cancel.confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (confirmed) => { - if (confirmed) { - Backup.cancel().then(() => { - this.controllerFor("adminBackups").set( - "model.isOperationRunning", - false - ); - }); - } - } - ); + this.dialog.yesNoConfirm({ + message: I18n.t("admin.backups.operations.cancel.confirm"), + didConfirm: () => { + Backup.cancel().then(() => { + this.controllerFor("adminBackups").set( + "model.isOperationRunning", + false + ); + }); + }, + }); }, rollback() { - bootbox.confirm( - I18n.t("admin.backups.operations.rollback.confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (confirmed) => { - if (confirmed) { - Backup.rollback().then((result) => { - if (!result.success) { - bootbox.alert(result.message); - } else { - // redirect to homepage (session might be lost) - window.location = getURL("/"); - } - }); - } - } - ); + return this.dialog.yesNoConfirm({ + message: I18n.t("admin.backups.operations.rollback.confirm"), + didConfirm: () => { + Backup.rollback().then((result) => { + if (!result.success) { + this.dialog.alert(result.message); + } else { + // redirect to homepage (session might be lost) + window.location = getURL("/"); + } + }); + }, + }); }, uploadSuccess(filename) { - bootbox.alert(I18n.t("admin.backups.upload.success", { filename })); + this.dialog.alert(I18n.t("admin.backups.upload.success", { filename })); }, uploadError(filename, message) { - bootbox.alert( + this.dialog.alert( I18n.t("admin.backups.upload.error", { filename, message }) ); }, @@ -173,7 +158,7 @@ export default DiscourseRoute.extend({ ); }) .catch((error) => { - bootbox.alert( + this.dialog.alert( I18n.t("admin.backups.backup_storage_error", { error_message: extractError(error), }) diff --git a/app/assets/javascripts/admin/addon/routes/admin-badges/show.js b/app/assets/javascripts/admin/addon/routes/admin-badges/show.js index 4d1eb1db76..b17d253b66 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-badges/show.js +++ b/app/assets/javascripts/admin/addon/routes/admin-badges/show.js @@ -2,11 +2,13 @@ import Badge from "discourse/models/badge"; import I18n from "I18n"; import Route from "@ember/routing/route"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; import { action, get } from "@ember/object"; import showModal from "discourse/lib/show-modal"; +import { inject as service } from "@ember/service"; export default class AdminBadgesShowRoute extends Route { + @service dialog; + serialize(m) { return { badge_id: get(m, "id") || "new" }; } @@ -58,7 +60,7 @@ export default class AdminBadgesShowRoute extends Route { badge.set("preview_loading", false); // eslint-disable-next-line no-console console.error(error); - bootbox.alert("Network error"); + this.dialog.alert("Network error"); }); } } diff --git a/app/assets/javascripts/admin/addon/services/admin-tools.js b/app/assets/javascripts/admin/addon/services/admin-tools.js index 17266be822..3d06845508 100644 --- a/app/assets/javascripts/admin/addon/services/admin-tools.js +++ b/app/assets/javascripts/admin/addon/services/admin-tools.js @@ -1,7 +1,7 @@ import AdminUser from "admin/models/admin-user"; import I18n from "I18n"; import { Promise } from "rsvp"; -import Service from "@ember/service"; +import Service, { inject as service } from "@ember/service"; import { ajax } from "discourse/lib/ajax"; import bootbox from "bootbox"; import { getOwner } from "discourse-common/lib/get-owner"; @@ -12,6 +12,8 @@ import showModal from "discourse/lib/show-modal"; // and the admin application. Use this if you need front end code to access admin // modules. Inject it optionally, and if it exists go to town! export default Service.extend({ + dialog: service(), + showActionLogs(target, filters) { const controller = getOwner(target).lookup( "controller:adminLogs.staffActionLogs" @@ -120,7 +122,7 @@ export default Service.extend({ } }) .catch(() => { - bootbox.alert(I18n.t("admin.user.delete_failed")); + this.dialog.alert(I18n.t("admin.user.delete_failed")); reject(); }); }, diff --git a/app/assets/javascripts/admin/addon/templates/admin-badges/show.hbs b/app/assets/javascripts/admin/addon/templates/admin-badges/show.hbs index 1cf2bbab5a..31b16af4cc 100644 --- a/app/assets/javascripts/admin/addon/templates/admin-badges/show.hbs +++ b/app/assets/javascripts/admin/addon/templates/admin-badges/show.hbs @@ -97,21 +97,21 @@
-
diff --git a/app/assets/javascripts/admin/addon/templates/components/composer-fullscreen-prompt.hbs b/app/assets/javascripts/admin/addon/templates/components/composer-fullscreen-prompt.hbs new file mode 100644 index 0000000000..e75db03048 --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/components/composer-fullscreen-prompt.hbs @@ -0,0 +1,3 @@ +
+ {{html-safe (i18n "composer.exit_fullscreen_prompt")}} +
diff --git a/app/assets/javascripts/admin/addon/templates/logs/screened-ip-addresses.hbs b/app/assets/javascripts/admin/addon/templates/logs/screened-ip-addresses.hbs index 56af8c935f..63489dcdee 100644 --- a/app/assets/javascripts/admin/addon/templates/logs/screened-ip-addresses.hbs +++ b/app/assets/javascripts/admin/addon/templates/logs/screened-ip-addresses.hbs @@ -63,9 +63,7 @@ {{#if item.editing}} - - {{i18n "cancel"}} - + {{else}} diff --git a/app/assets/javascripts/admin/addon/templates/site-text-index.hbs b/app/assets/javascripts/admin/addon/templates/site-text-index.hbs index b10fa0d239..ff74b4cf7f 100644 --- a/app/assets/javascripts/admin/addon/templates/site-text-index.hbs +++ b/app/assets/javascripts/admin/addon/templates/site-text-index.hbs @@ -1,39 +1,60 @@

{{i18n "admin.site_text.description"}}

- +
- +

- +

- {{#if this.showFallbackLocaleWarning}} -
- {{d-icon "exclamation-circle"}} - {{i18n "admin.site_text.fallback_locale_warning" fallback=this.fallbackLocaleFullName}} -
- {{/if}} - {{#if this.siteTexts.extras.recommended}}

{{i18n "admin.site_text.recommended"}}

{{/if}} {{#each this.siteTexts as |siteText|}} - + {{/each}} {{#if this.siteTexts.extras.has_more}} diff --git a/app/assets/javascripts/admin/package.json b/app/assets/javascripts/admin/package.json index 3d66a9d06c..aa8025a052 100644 --- a/app/assets/javascripts/admin/package.json +++ b/app/assets/javascripts/admin/package.json @@ -17,9 +17,9 @@ "dependencies": { "ember-auto-import": "^2.4.2", "ember-cli-babel": "^7.26.10", - "ember-cli-htmlbars": "^6.1.0", - "webpack": "^5.73.0", - "xss": "^1.0.13" + "ember-cli-htmlbars": "^6.1.1", + "webpack": "^5.74.0", + "xss": "^1.0.14" }, "devDependencies": { "@ember/optional-features": "^2.0.0", diff --git a/app/assets/javascripts/discourse-common/addon/lib/icon-library.js b/app/assets/javascripts/discourse-common/addon/lib/icon-library.js index f7434318f5..a969a2a116 100644 --- a/app/assets/javascripts/discourse-common/addon/lib/icon-library.js +++ b/app/assets/javascripts/discourse-common/addon/lib/icon-library.js @@ -27,7 +27,7 @@ const REPLACEMENTS = { "notification.group_mentioned": "users", "notification.quoted": "quote-right", "notification.replied": "reply", - "notification.posted": "reply", + "notification.posted": "discourse-bell-exclamation", "notification.edited": "pencil-alt", "notification.bookmark_reminder": "discourse-bookmark-clock", "notification.liked": "heart", diff --git a/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js b/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js index f49e427317..6d805d3366 100644 --- a/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js +++ b/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js @@ -73,9 +73,10 @@ if (Handlebars.Compiler) { RawHandlebars.JavaScriptCompiler; RawHandlebars.JavaScriptCompiler.prototype.namespace = "RawHandlebars"; - RawHandlebars.precompile = function (value, asObject) { + RawHandlebars.precompile = function (value, asObject, { plugins = [] } = {}) { let ast = Handlebars.parse(value); replaceGet(ast); + plugins.forEach((plugin) => plugin(ast)); let options = { knownHelpers: { @@ -96,9 +97,10 @@ if (Handlebars.Compiler) { ); }; - RawHandlebars.compile = function (string) { + RawHandlebars.compile = function (string, { plugins = [] } = {}) { let ast = Handlebars.parse(string); replaceGet(ast); + plugins.forEach((plugin) => plugin(ast)); // this forces us to rewrite helpers let options = { data: true, stringParams: true }; diff --git a/app/assets/javascripts/discourse-common/addon/resolver.js b/app/assets/javascripts/discourse-common/addon/resolver.js index 88f2bdceb1..462bec5212 100644 --- a/app/assets/javascripts/discourse-common/addon/resolver.js +++ b/app/assets/javascripts/discourse-common/addon/resolver.js @@ -38,55 +38,68 @@ const DEPRECATED_MODULES = new Map( since: "2.4.0", dropFrom: "2.9.0.beta1", }, + // Deprecations below are silenced because they're in widespread use, and upgrading + // themes/plugins right now would break their compatibility with the stable branch. + // These should be unsilenced for the release of 2.9.0 stable. "store:main": { newName: "service:store", since: "2.8.0.beta8", dropFrom: "2.9.0.beta1", + silent: true, }, "search-service:main": { newName: "service:search", since: "2.8.0.beta8", dropFrom: "2.9.0.beta1", + silent: true, }, "key-value-store:main": { newName: "service:key-value-store", since: "2.9.0.beta7", dropFrom: "3.0.0", + silent: true, }, "pm-topic-tracking-state:main": { newName: "service:pm-topic-tracking-state", since: "2.9.0.beta7", dropFrom: "3.0.0", + silent: true, }, "message-bus:main": { newName: "service:message-bus", since: "2.9.0.beta7", dropFrom: "3.0.0", + silent: true, }, "site-settings:main": { newName: "service:site-settings", since: "2.9.0.beta7", dropFrom: "3.0.0", + silent: true, }, "current-user:main": { newName: "service:current-user", since: "2.9.0.beta7", dropFrom: "3.0.0", + silent: true, }, "session:main": { newName: "service:session", since: "2.9.0.beta7", dropFrom: "3.0.0", + silent: true, }, "site:main": { newName: "service:site", since: "2.9.0.beta7", dropFrom: "3.0.0", + silent: true, }, "topic-tracking-state:main": { newName: "service:topic-tracking-state", since: "2.9.0.beta7", dropFrom: "3.0.0", + silent: true, }, }) ); @@ -138,13 +151,15 @@ export function buildResolver(baseName) { _normalize(fullName) { const deprecationInfo = DEPRECATED_MODULES.get(fullName); if (deprecationInfo) { - deprecated( - `"${fullName}" is deprecated, use "${deprecationInfo.newName}" instead`, - { - since: deprecationInfo.since, - dropFrom: deprecationInfo.dropFrom, - } - ); + if (!deprecationInfo.silent) { + deprecated( + `"${fullName}" is deprecated, use "${deprecationInfo.newName}" instead`, + { + since: deprecationInfo.since, + dropFrom: deprecationInfo.dropFrom, + } + ); + } fullName = deprecationInfo.newName; } diff --git a/app/assets/javascripts/discourse-common/addon/utils/handle-descriptor.js b/app/assets/javascripts/discourse-common/addon/utils/handle-descriptor.js index eb15763279..d37e19111f 100644 --- a/app/assets/javascripts/discourse-common/addon/utils/handle-descriptor.js +++ b/app/assets/javascripts/discourse-common/addon/utils/handle-descriptor.js @@ -1,17 +1,18 @@ -import EmberObject, { computed, get } from "@ember/object"; +import CoreObject from "@ember/object/core"; +import { computed, get } from "@ember/object"; import extractValue from "./extract-value"; export default function handleDescriptor(target, key, desc, params = []) { const val = extractValue(desc); - if (typeof val === "function" && target instanceof EmberObject) { + if (typeof val === "function" && target instanceof CoreObject) { // We're in a native class, so convert the method to a getter first desc.writable = false; desc.initializer = undefined; desc.value = undefined; desc.get = callUserSuppliedGet(params, val); - return computed(target, key, desc); + return computed(...params)(target, key, desc); } else { return { enumerable: desc.enumerable, diff --git a/app/assets/javascripts/discourse-common/package.json b/app/assets/javascripts/discourse-common/package.json index e4302cbfbc..54748e892f 100644 --- a/app/assets/javascripts/discourse-common/package.json +++ b/app/assets/javascripts/discourse-common/package.json @@ -23,11 +23,11 @@ "@uppy/xhr-upload": "^2.1.2", "ember-auto-import": "^2.4.2", "ember-cli-babel": "^7.26.10", - "ember-cli-htmlbars": "^6.1.0", + "ember-cli-htmlbars": "^6.1.1", "ember-resolver": "^8.0.3", "handlebars": "^4.7.0", "truth-helpers": "^1.0.0", - "webpack": "^5.73.0" + "webpack": "^5.74.0" }, "devDependencies": { "@ember/optional-features": "^2.0.0", diff --git a/app/assets/javascripts/discourse-hbr/package.json b/app/assets/javascripts/discourse-hbr/package.json index 9a194a88f5..b0fd547a63 100644 --- a/app/assets/javascripts/discourse-hbr/package.json +++ b/app/assets/javascripts/discourse-hbr/package.json @@ -17,9 +17,9 @@ "dependencies": { "ember-auto-import": "^2.4.2", "ember-cli-babel": "^7.26.10", - "ember-cli-htmlbars": "^6.1.0", + "ember-cli-htmlbars": "^6.1.1", "handlebars": "^4.7.6", - "webpack": "^5.73.0" + "webpack": "^5.74.0" }, "devDependencies": { "@ember/optional-features": "^2.0.0", diff --git a/app/assets/javascripts/discourse-hbr/raw-handlebars-compiler.js b/app/assets/javascripts/discourse-hbr/raw-handlebars-compiler.js index f6376ca5db..06dce15943 100644 --- a/app/assets/javascripts/discourse-hbr/raw-handlebars-compiler.js +++ b/app/assets/javascripts/discourse-hbr/raw-handlebars-compiler.js @@ -134,7 +134,19 @@ TemplateCompiler.prototype.initializeFeatures = function initializeFeatures() {}; TemplateCompiler.prototype.processString = function (string, relativePath) { - let filename = relativePath.replace(/^templates\//, "").replace(/\.hbr$/, ""); + let filename; + + const pluginName = relativePath.match(/^discourse\/plugins\/([^\/]+)\//)?.[1]; + + if (pluginName) { + filename = relativePath + .replace(`discourse/plugins/${pluginName}/`, "") + .replace(/^(discourse\/)?templates\//, "javascripts/"); + } else { + filename = relativePath.replace(/^templates\//, ""); + } + + filename = filename.replace(/\.hbr$/, ""); return ( 'import { template as compiler } from "discourse-common/lib/raw-handlebars";\n' + diff --git a/app/assets/javascripts/discourse-js-processor.js b/app/assets/javascripts/discourse-js-processor.js new file mode 100644 index 0000000000..5deb20f011 --- /dev/null +++ b/app/assets/javascripts/discourse-js-processor.js @@ -0,0 +1,110 @@ +/* global Babel:true */ + +// This is executed in mini_racer to provide the JS logic for lib/discourse_js_processor.rb + +const makeEmberTemplateCompilerPlugin = + require("babel-plugin-ember-template-compilation").default; +const precompile = require("ember-template-compiler").precompile; +const Handlebars = require("handlebars").default; + +function manipulateAstNodeForTheme(node, themeId) { + // Magically add theme id as the first param for each of these helpers) + if ( + node.path.parts && + ["theme-i18n", "theme-prefix", "theme-setting"].includes(node.path.parts[0]) + ) { + if (node.params.length === 1) { + node.params.unshift({ + type: "NumberLiteral", + value: themeId, + original: themeId, + loc: { start: {}, end: {} }, + }); + } + } +} + +function buildEmberTemplateManipulatorPlugin(themeId) { + return function () { + return { + name: "theme-template-manipulator", + visitor: { + SubExpression: (node) => manipulateAstNodeForTheme(node, themeId), + MustacheStatement: (node) => manipulateAstNodeForTheme(node, themeId), + }, + }; + }; +} + +function buildTemplateCompilerBabelPlugins({ themeId }) { + let compileFunction = precompile; + if (themeId) { + compileFunction = (src, opts) => { + return precompile(src, { + ...opts, + plugins: { + ast: [buildEmberTemplateManipulatorPlugin(themeId)], + }, + }); + }; + } + + return [ + require("widget-hbs-compiler").WidgetHbsCompiler, + [ + makeEmberTemplateCompilerPlugin(() => compileFunction), + { enableLegacyModules: ["ember-cli-htmlbars"] }, + ], + ]; +} + +function buildThemeRawHbsTemplateManipulatorPlugin(themeId) { + return function (ast) { + ["SubExpression", "MustacheStatement"].forEach((pass) => { + let visitor = new Handlebars.Visitor(); + visitor.mutating = true; + visitor[pass] = (node) => manipulateAstNodeForTheme(node, themeId); + visitor.accept(ast); + }); + }; +} + +exports.compileRawTemplate = function (source, themeId) { + try { + const RawHandlebars = require("raw-handlebars").default; + const plugins = []; + if (themeId) { + plugins.push(buildThemeRawHbsTemplateManipulatorPlugin(themeId)); + } + return RawHandlebars.precompile(source, false, { plugins }).toString(); + } catch (error) { + // Workaround for https://github.com/rubyjs/mini_racer/issues/262 + error.message = JSON.stringify(error.message); + throw error; + } +}; + +exports.transpile = function ( + source, + { moduleId, filename, skipModule, themeId, commonPlugins } = {} +) { + const plugins = []; + plugins.push(...buildTemplateCompilerBabelPlugins({ themeId })); + if (moduleId && !skipModule) { + plugins.push(["transform-modules-amd", { noInterop: true }]); + } + plugins.push(...commonPlugins); + + try { + return Babel.transform(source, { + moduleId, + filename, + ast: false, + plugins, + }).code; + } catch (error) { + // Workaround for https://github.com/rubyjs/mini_racer/issues/262 + error.message = JSON.stringify(error.message); + throw error; + } +}; diff --git a/app/assets/javascripts/discourse-plugins/index.js b/app/assets/javascripts/discourse-plugins/index.js new file mode 100644 index 0000000000..0f3612cbfe --- /dev/null +++ b/app/assets/javascripts/discourse-plugins/index.js @@ -0,0 +1,213 @@ +"use strict"; + +const path = require("path"); +const WatchedDir = require("broccoli-source").WatchedDir; +const Funnel = require("broccoli-funnel"); +const mergeTrees = require("broccoli-merge-trees"); +const fs = require("fs"); +const concat = require("broccoli-concat"); +const RawHandlebarsCompiler = require("discourse-hbr/raw-handlebars-compiler"); + +function fixLegacyExtensions(tree) { + return new Funnel(tree, { + getDestinationPath: function (relativePath) { + if (relativePath.endsWith(".es6")) { + return relativePath.slice(0, -4); + } else if (relativePath.endsWith(".raw.hbs")) { + return relativePath.replace(".raw.hbs", ".hbr"); + } + return relativePath; + }, + }); +} + +const COLOCATED_CONNECTOR_REGEX = + /^(?.*)\/connectors\/(?[^\/]+)\/(?[^\/\.]+)\.(?.+)$/; + +// Having connector templates and js in the same directory causes a clash +// when outputting es6 modules. This shim separates colocated connectors +// into separate js / template locations. +function unColocateConnectors(tree) { + return new Funnel(tree, { + getDestinationPath: function (relativePath) { + const match = relativePath.match(COLOCATED_CONNECTOR_REGEX); + if ( + match && + match.groups.extension === "hbs" && + !match.groups.prefix.endsWith("/templates") + ) { + const { prefix, outlet, name } = match.groups; + return `${prefix}/templates/connectors/${outlet}/${name}.hbs`; + } + if ( + match && + match.groups.extension === "js" && + match.groups.prefix.endsWith("/templates") + ) { + // Some plugins are colocating connector JS under `/templates` + const { prefix, outlet, name } = match.groups; + const newPrefix = prefix.slice(0, -"/templates".length); + return `${newPrefix}/connectors/${outlet}/${name}.js`; + } + return relativePath; + }, + }); +} + +function namespaceModules(tree, pluginDirectoryName) { + return new Funnel(tree, { + getDestinationPath: function (relativePath) { + return `discourse/plugins/${pluginDirectoryName}/${relativePath}`; + }, + }); +} + +function parsePluginName(pluginRbPath) { + const pluginRb = fs.readFileSync(pluginRbPath, "utf8"); + // Match parsing logic in `lib/plugin/metadata.rb` + for (const line of pluginRb.split("\n")) { + if (line.startsWith("#")) { + const [attribute, value] = line.slice(1).split(":", 2); + if (attribute.trim() === "name") { + return value.trim(); + } + } + } + throw new Error( + `Unable to parse plugin name from metadata in ${pluginRbPath}` + ); +} + +module.exports = { + name: require("./package").name, + + pluginInfos() { + const root = path.resolve("../../../../plugins"); + const pluginDirectories = fs + .readdirSync(root, { withFileTypes: true }) + .filter( + (dirent) => + (dirent.isDirectory() || dirent.isSymbolicLink()) && + !dirent.name.startsWith(".") && + fs.existsSync(path.resolve(root, dirent.name, "plugin.rb")) + ); + + return pluginDirectories.map((directory) => { + const directoryName = directory.name; + const pluginName = parsePluginName( + path.resolve(root, directoryName, "plugin.rb") + ); + const jsDirectory = path.resolve( + root, + directoryName, + "assets/javascripts" + ); + const adminJsDirectory = path.resolve( + root, + directoryName, + "admin/assets/javascripts" + ); + const testDirectory = path.resolve( + root, + directoryName, + "test/javascripts" + ); + const hasJs = fs.existsSync(jsDirectory); + const hasAdminJs = fs.existsSync(adminJsDirectory); + const hasTests = fs.existsSync(testDirectory); + return { + pluginName, + directoryName, + jsDirectory, + adminJsDirectory, + testDirectory, + hasJs, + hasAdminJs, + hasTests, + }; + }); + }, + + generatePluginsTree() { + const appTree = this._generatePluginAppTree(); + const testTree = this._generatePluginTestTree(); + const adminTree = this._generatePluginAdminTree(); + return mergeTrees([appTree, testTree, adminTree]); + }, + + _generatePluginAppTree() { + const trees = this.pluginInfos() + .filter((p) => p.hasJs) + .map(({ pluginName, directoryName, jsDirectory }) => + this._buildAppTree({ + directory: jsDirectory, + pluginName, + outputFile: `assets/plugins/${directoryName}.js`, + }) + ); + return mergeTrees(trees); + }, + + _generatePluginAdminTree() { + const trees = this.pluginInfos() + .filter((p) => p.hasAdminJs) + .map(({ pluginName, directoryName, adminJsDirectory }) => + this._buildAppTree({ + directory: adminJsDirectory, + pluginName, + outputFile: `assets/plugins/${directoryName}_admin.js`, + }) + ); + return mergeTrees(trees); + }, + + _buildAppTree({ directory, pluginName, outputFile }) { + let tree = new WatchedDir(directory); + + tree = fixLegacyExtensions(tree); + tree = unColocateConnectors(tree); + tree = namespaceModules(tree, pluginName); + + tree = RawHandlebarsCompiler(tree); + tree = this.compileTemplates(tree); + + tree = this.processedAddonJsFiles(tree); + + return concat(mergeTrees([tree]), { + inputFiles: ["**/*.js"], + outputFile, + allowNone: true, + }); + }, + + _generatePluginTestTree() { + const trees = this.pluginInfos() + .filter((p) => p.hasTests) + .map(({ pluginName, directoryName, testDirectory }) => { + let tree = new WatchedDir(testDirectory); + + tree = fixLegacyExtensions(tree); + tree = namespaceModules(tree, pluginName); + tree = this.processedAddonJsFiles(tree); + + return concat(mergeTrees([tree]), { + inputFiles: ["**/*.js"], + outputFile: `assets/plugins/test/${directoryName}_tests.js`, + allowNone: true, + }); + }); + return mergeTrees(trees); + }, + + shouldCompileTemplates() { + // The base Addon implementation checks for template + // files in the addon directories. We need to override that + // check so that the template compiler always runs. + return true; + }, + + treeFor() { + // This addon doesn't contribute any 'real' trees to the app + return; + }, +}; diff --git a/app/assets/javascripts/discourse-plugins/package.json b/app/assets/javascripts/discourse-plugins/package.json new file mode 100644 index 0000000000..3f05f3dada --- /dev/null +++ b/app/assets/javascripts/discourse-plugins/package.json @@ -0,0 +1,25 @@ +{ + "name": "discourse-plugins", + "version": "1.0.0", + "description": "An addon providing a broccoli tree for each Discourse plugin", + "author": "Discourse", + "license": "GPL-2.0-only", + "keywords": [ + "ember-addon" + ], + "repository": "", + "dependencies": { + "ember-auto-import": "^2.4.2", + "ember-cli-babel": "^7.26.10", + "ember-cli-htmlbars": "^6.1.1", + "discourse-widget-hbs": "1.0" + }, + "engines": { + "node": "16.* || >= 18", + "npm": "please-use-yarn", + "yarn": ">= 1.21.1" + }, + "ember": { + "edition": "default" + } +} diff --git a/app/assets/javascripts/discourse-widget-hbs/package.json b/app/assets/javascripts/discourse-widget-hbs/package.json index e3d73242b9..a4e6228951 100644 --- a/app/assets/javascripts/discourse-widget-hbs/package.json +++ b/app/assets/javascripts/discourse-widget-hbs/package.json @@ -17,9 +17,9 @@ "dependencies": { "ember-auto-import": "^2.4.2", "ember-cli-babel": "^7.26.10", - "ember-cli-htmlbars": "^6.1.0", + "ember-cli-htmlbars": "^6.1.1", "handlebars": "^4.7.6", - "webpack": "^5.73.0" + "webpack": "^5.74.0" }, "devDependencies": { "@ember/optional-features": "^2.0.0", diff --git a/app/assets/javascripts/discourse/app/adapters/rest.js b/app/assets/javascripts/discourse/app/adapters/rest.js index fcd7e4175b..6209ea9cca 100644 --- a/app/assets/javascripts/discourse/app/adapters/rest.js +++ b/app/assets/javascripts/discourse/app/adapters/rest.js @@ -47,20 +47,22 @@ export default EmberObject.extend({ appendQueryParams(path, findArgs, extension) { if (findArgs) { if (typeof findArgs === "object") { - const queryString = Object.keys(findArgs) - .reject((k) => !findArgs[k]) - .map((k) => k + "=" + encodeURIComponent(findArgs[k])); + const urlSearchParams = new URLSearchParams(); - if (queryString.length) { - return `${path}${extension ? extension : ""}?${queryString.join( - "&" - )}`; + for (const [key, value] of Object.entries(findArgs)) { + if (value) { + urlSearchParams.set(key, value); + } + } + + const queryString = urlSearchParams.toString(); + + if (queryString) { + return `${path}${extension || ""}?${queryString}`; } } else { // It's serializable as a string if not an object - return `${path}/${encodeURIComponent(findArgs)}${ - extension ? extension : "" - }`; + return `${path}/${encodeURIComponent(findArgs)}${extension || ""}`; } } return path; diff --git a/app/assets/javascripts/discourse/app/adapters/topic-list.js b/app/assets/javascripts/discourse/app/adapters/topic-list.js index fb6a0c80d5..31fbd179dd 100644 --- a/app/assets/javascripts/discourse/app/adapters/topic-list.js +++ b/app/assets/javascripts/discourse/app/adapters/topic-list.js @@ -8,18 +8,18 @@ export function finderFor(filter, params) { let url = getURL("/") + filter + ".json"; if (params) { - const keys = Object.keys(params), - encoded = []; + const urlSearchParams = new URLSearchParams(); - keys.forEach(function (p) { - const value = encodeURI(params[p]); + for (const [key, value] of Object.entries(params)) { if (typeof value !== "undefined") { - encoded.push(p + "=" + value); + urlSearchParams.set(key, value); } - }); + } - if (encoded.length > 0) { - url += "?" + encoded.join("&"); + const queryString = urlSearchParams.toString(); + + if (queryString) { + url += `?${queryString}`; } } return ajax(url); @@ -32,7 +32,7 @@ export default RestAdapter.extend({ const params = findArgs.params; return PreloadStore.getAndRemove( - "topic_list_" + filter, + "topic_list", finderFor(filter, params) ).then(function (result) { result.filter = filter; diff --git a/app/assets/javascripts/discourse/app/components/badge-title.js b/app/assets/javascripts/discourse/app/components/badge-title.js index cb62249521..ec8db2e8da 100644 --- a/app/assets/javascripts/discourse/app/components/badge-title.js +++ b/app/assets/javascripts/discourse/app/components/badge-title.js @@ -2,13 +2,12 @@ import Component from "@ember/component"; import { action } from "@ember/object"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; +import { inject as service } from "@ember/service"; export default Component.extend({ + dialog: service(), tagName: "", - selectableUserBadges: null, - _selectedUserBadgeId: null, _isSaved: false, _isSaving: false, @@ -42,7 +41,7 @@ export default Component.extend({ this.currentUser.set("title", selectedUserBadge?.badge?.name || ""); }, () => { - bootbox.alert(I18n.t("generic_error")); + this.dialog.alert(I18n.t("generic_error")); } ) .finally(() => this.set("_isSaving", false)); diff --git a/app/assets/javascripts/discourse/app/components/basic-topic-list.js b/app/assets/javascripts/discourse/app/components/basic-topic-list.js index 14aa4d5f34..ca8fae3318 100644 --- a/app/assets/javascripts/discourse/app/components/basic-topic-list.js +++ b/app/assets/javascripts/discourse/app/components/basic-topic-list.js @@ -50,11 +50,7 @@ export default Component.extend({ `.indicator-topic-${data.topic_id}` ).classList; - if (data.show_indicator) { - nodeClassList.remove("read"); - } else { - nodeClassList.add("read"); - } + nodeClassList.toggle("read", !data.show_indicator); }); } }); diff --git a/app/assets/javascripts/discourse/app/components/bookmark.js b/app/assets/javascripts/discourse/app/components/bookmark.js index b5739fa66c..0ede10b3c2 100644 --- a/app/assets/javascripts/discourse/app/components/bookmark.js +++ b/app/assets/javascripts/discourse/app/components/bookmark.js @@ -18,14 +18,16 @@ import { and, notEmpty } from "@ember/object/computed"; import { popupAjaxError } from "discourse/lib/ajax-error"; import discourseLater from "discourse-common/lib/later"; +import { inject as service } from "@ember/service"; + const BOOKMARK_BINDINGS = { enter: { handler: "saveAndClose" }, "d d": { handler: "delete" }, }; export default Component.extend({ + dialog: service(), tagName: "", - errorMessage: null, selectedReminderType: null, _closeWithoutSaving: null, @@ -227,7 +229,7 @@ export default Component.extend({ _handleSaveError(e) { this._savingBookmarkManually = false; if (typeof e === "string") { - bootbox.alert(e); + this.dialog.alert(e); } else { popupAjaxError(e); } diff --git a/app/assets/javascripts/discourse/app/components/bootstrap_mode_notice.js b/app/assets/javascripts/discourse/app/components/bootstrap_mode_notice.js index f1328b9eb6..69914cfa04 100644 --- a/app/assets/javascripts/discourse/app/components/bootstrap_mode_notice.js +++ b/app/assets/javascripts/discourse/app/components/bootstrap_mode_notice.js @@ -1,9 +1,11 @@ -import GlimmerComponent from "@glimmer/component"; +import Component from "@glimmer/component"; import { htmlSafe } from "@ember/template"; import I18n from "I18n"; import { inject as service } from "@ember/service"; +import { action } from "@ember/object"; +import showModal from "discourse/lib/show-modal"; -export default class BootstrapModeNotice extends GlimmerComponent { +export default class BootstrapModeNotice extends Component { @service siteSettings; @service site; @@ -19,4 +21,9 @@ export default class BootstrapModeNotice extends GlimmerComponent { return htmlSafe(I18n.t(msg, { count: bootstrapModeMinUsers })); } + + @action + inviteUsers() { + showModal("create-invite"); + } } diff --git a/app/assets/javascripts/discourse/app/components/composer-body.js b/app/assets/javascripts/discourse/app/components/composer-body.js index f343633735..0827c1f3ad 100644 --- a/app/assets/javascripts/discourse/app/components/composer-body.js +++ b/app/assets/javascripts/discourse/app/components/composer-body.js @@ -89,11 +89,6 @@ export default Component.extend(KeyEnterEscape, { passive: false, }); }); - - if (this._visualViewportResizing()) { - this.viewportResize(); - window.visualViewport.addEventListener("resize", this.viewportResize); - } }, @bind @@ -107,6 +102,11 @@ export default Component.extend(KeyEnterEscape, { const minHeight = parseInt(getComputedStyle(this.element).minHeight, 10); size = Math.max(minHeight, size); + this.set("composer.composerHeight", `${size}px`); + this.keyValueStore.set({ + key: "composerHeight", + value: this.get("composer.composerHeight"), + }); document.documentElement.style.setProperty( "--composer-height", size ? `${size}px` : "" @@ -169,42 +169,9 @@ export default Component.extend(KeyEnterEscape, { throttle(this, this.performDragHandler, event, THROTTLE_RATE); }, - @bind - viewportResize() { - const composerVH = window.visualViewport.height * 0.01, - doc = document.documentElement; - - doc.style.setProperty("--composer-vh", `${composerVH}px`); - - const viewportWindowDiff = - this.windowInnerHeight - window.visualViewport.height; - - viewportWindowDiff > 0 - ? doc.classList.add("keyboard-visible") - : doc.classList.remove("keyboard-visible"); - - // adds bottom padding when using a hardware keyboard and the accessory bar is visible - // accessory bar height is 55px, using 75 allows a small buffer - doc.style.setProperty( - "--composer-ipad-padding", - `${viewportWindowDiff < 75 ? viewportWindowDiff : 0}px` - ); - }, - - _visualViewportResizing() { - return ( - (this.capabilities.isIpadOS || this.site.mobileView) && - window.visualViewport !== undefined - ); - }, - didInsertElement() { this._super(...arguments); - if (this._visualViewportResizing()) { - this.set("windowInnerHeight", window.innerHeight); - } - this.setupComposerResizeEvents(); const triggerOpen = () => { @@ -224,10 +191,6 @@ export default Component.extend(KeyEnterEscape, { willDestroyElement() { this._super(...arguments); - if (this._visualViewportResizing()) { - window.visualViewport.removeEventListener("resize", this.viewportResize); - } - START_DRAG_EVENTS.forEach((startDragEvent) => { this.element .querySelector(".grippie") diff --git a/app/assets/javascripts/discourse/app/components/composer-editor.js b/app/assets/javascripts/discourse/app/components/composer-editor.js index 83d14ad641..545039b79d 100644 --- a/app/assets/javascripts/discourse/app/components/composer-editor.js +++ b/app/assets/javascripts/discourse/app/components/composer-editor.js @@ -816,7 +816,6 @@ export default Component.extend(ComposerUploadUppy, { extraButtons(toolbar) { toolbar.addButton({ - tabindex: "0", id: "quote", group: "fontStyles", icon: "far-comment", diff --git a/app/assets/javascripts/discourse/app/components/composer-fullscreen-prompt.js b/app/assets/javascripts/discourse/app/components/composer-fullscreen-prompt.js new file mode 100644 index 0000000000..742bb3c18e --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/composer-fullscreen-prompt.js @@ -0,0 +1,3 @@ +import templateOnly from "@ember/component/template-only"; + +export default templateOnly(); diff --git a/app/assets/javascripts/discourse/app/components/composer-messages.js b/app/assets/javascripts/discourse/app/components/composer-messages.js index 2f00c76a49..40832b5df1 100644 --- a/app/assets/javascripts/discourse/app/components/composer-messages.js +++ b/app/assets/javascripts/discourse/app/components/composer-messages.js @@ -5,8 +5,10 @@ import LinkLookup from "discourse/lib/link-lookup"; import { not } from "@ember/object/computed"; import { scheduleOnce } from "@ember/runloop"; import showModal from "discourse/lib/show-modal"; +import { ajax } from "discourse/lib/ajax"; let _messagesCache = {}; +let _recipient_names = []; export default Component.extend({ classNameBindings: [":composer-popup-container", "hidden"], @@ -18,6 +20,7 @@ export default Component.extend({ _similarTopicsMessage: null, _yourselfConfirm: null, similarTopics: null, + usersNotSeen: null, hidden: not("composer.viewOpenOrFullscreen"), @@ -119,6 +122,53 @@ export default Component.extend({ const composer = this.composer; if (composer.get("privateMessage")) { const recipients = composer.targetRecipientsArray; + const recipient_names = recipients + .filter((r) => r.type === "user") + .map(({ name }) => name); + + if ( + recipient_names.length > 0 && + recipient_names.length !== _recipient_names.length && + !recipient_names.every((v, i) => v === _recipient_names[i]) + ) { + _recipient_names = recipient_names; + + ajax(`/composer_messages/user_not_seen_in_a_while`, { + type: "GET", + data: { + usernames: recipient_names, + }, + }).then((response) => { + if ( + response.user_count > 0 && + this.get("usersNotSeen") !== response.usernames.join("-") + ) { + this.set("usersNotSeen", response.usernames.join("-")); + this.messagesByTemplate["education"] = undefined; + + let usernames = []; + response.usernames.forEach((username, index) => { + usernames[ + index + ] = `@${username}`; + }); + + let body_key = "composer.user_not_seen_in_a_while.single"; + if (response.user_count > 1) { + body_key = "composer.user_not_seen_in_a_while.multiple"; + } + const message = composer.store.createRecord("composer-message", { + id: "user-not-seen", + templateName: "education", + body: I18n.t(body_key, { + usernames: usernames.join(", "), + time_ago: response.time_ago, + }), + }); + this.send("popup", message); + } + }); + } if ( recipients.length > 0 && @@ -128,7 +178,7 @@ export default Component.extend({ this._yourselfConfirm || composer.store.createRecord("composer-message", { id: "yourself_confirm", - templateName: "custom-body", + templateName: "education", title: I18n.t("composer.yourself_confirm.title"), body: I18n.t("composer.yourself_confirm.body"), }); diff --git a/app/assets/javascripts/discourse/app/components/create-topics-notice.js b/app/assets/javascripts/discourse/app/components/create-topics-notice.js index 687cec3228..da6f089ef6 100644 --- a/app/assets/javascripts/discourse/app/components/create-topics-notice.js +++ b/app/assets/javascripts/discourse/app/components/create-topics-notice.js @@ -4,11 +4,13 @@ import I18n from "I18n"; import LivePostCounts from "discourse/models/live-post-counts"; import { alias } from "@ember/object/computed"; import { htmlSafe } from "@ember/template"; +import { inject as service } from "@ember/service"; export default Component.extend({ classNameBindings: ["hidden:hidden", ":create-topics-notice"], enabled: false, + router: service(), publicTopicCount: null, publicPostCount: null, @@ -37,14 +39,16 @@ export default Component.extend({ } }, - @discourseComputed() - shouldSee() { - const user = this.currentUser; + @discourseComputed( + "siteSettings.show_create_topics_notice", + "router.currentRouteName" + ) + shouldSee(showCreateTopicsNotice, currentRouteName) { return ( - user && - user.get("admin") && - this.siteSettings.show_create_topics_notice && - !this.site.get("wizard_required") + this.currentUser?.get("admin") && + showCreateTopicsNotice && + !this.site.get("wizard_required") && + !currentRouteName.startsWith("wizard") ); }, diff --git a/app/assets/javascripts/discourse/app/components/d-document.js b/app/assets/javascripts/discourse/app/components/d-document.js index 76b111a3ec..7e8fef1bd3 100644 --- a/app/assets/javascripts/discourse/app/components/d-document.js +++ b/app/assets/javascripts/discourse/app/components/d-document.js @@ -1,7 +1,6 @@ import Component from "@ember/component"; import I18n from "I18n"; import { bind } from "discourse-common/utils/decorators"; -import bootbox from "bootbox"; import logout from "discourse/lib/logout"; import { inject as service } from "@ember/service"; import { setLogoffCallback } from "discourse/lib/ajax"; @@ -14,6 +13,7 @@ export function addPluginDocumentTitleCounter(counterFunction) { export default Component.extend({ tagName: "", documentTitle: service(), + dialog: service(), _showingLogout: false, didInsertElement() { @@ -44,16 +44,23 @@ export default Component.extend({ ); }, - _updateNotifications() { + _updateNotifications(opts) { if (!this.currentUser) { return; } - const count = - pluginCounterFunctions.reduce((sum, fn) => sum + fn(), 0) + - this.currentUser.unread_notifications + - this.currentUser.unread_high_priority_notifications; - this.documentTitle.updateNotificationCount(count); + let count = pluginCounterFunctions.reduce((sum, fn) => sum + fn(), 0); + if (this.currentUser.redesigned_user_menu_enabled) { + count += this.currentUser.all_unread_notifications_count; + if (this.currentUser.unseen_reviewable_count) { + count += this.currentUser.unseen_reviewable_count; + } + } else { + count += + this.currentUser.unread_notifications + + this.currentUser.unread_high_priority_notifications; + } + this.documentTitle.updateNotificationCount(count, { forced: opts?.forced }); }, @bind @@ -74,13 +81,12 @@ export default Component.extend({ this._showingLogout = true; this.messageBus.stop(); - bootbox.dialog( - I18n.t("logout"), - { label: I18n.t("refresh"), callback: logout }, - { - onEscape: () => logout(), - backdrop: "static", - } - ); + + this.dialog.alert({ + message: I18n.t("logout"), + confirmButtonLabel: "refresh", + didConfirm: () => logout(), + didCancel: () => logout(), + }); }, }); diff --git a/app/assets/javascripts/discourse/app/components/d-editor.js b/app/assets/javascripts/discourse/app/components/d-editor.js index e6fdda2695..f6d800b06d 100644 --- a/app/assets/javascripts/discourse/app/components/d-editor.js +++ b/app/assets/javascripts/discourse/app/components/d-editor.js @@ -50,7 +50,7 @@ let _createCallbacks = []; class Toolbar { constructor(opts) { - const { site, siteSettings } = opts; + const { siteSettings, capabilities } = opts; this.shortcuts = {}; this.context = null; @@ -106,16 +106,16 @@ class Toolbar { }), }); - this.addButton({ - id: "code", - group: "insertions", - shortcut: "E", - preventFocus: true, - trimLeading: true, - action: (...args) => this.context.send("formatCode", args), - }); + if (!capabilities.touch) { + this.addButton({ + id: "code", + group: "insertions", + shortcut: "E", + preventFocus: true, + trimLeading: true, + action: (...args) => this.context.send("formatCode", args), + }); - if (!site.mobileView) { this.addButton({ id: "bullet", group: "extras", @@ -354,7 +354,7 @@ export default Component.extend(TextareaTextManipulation, { @discourseComputed() toolbar() { const toolbar = new Toolbar( - this.getProperties("site", "siteSettings", "showLink") + this.getProperties("site", "siteSettings", "showLink", "capabilities") ); toolbar.context = this; @@ -363,6 +363,12 @@ export default Component.extend(TextareaTextManipulation, { if (this.extraButtons) { this.extraButtons(toolbar); } + + const firstButton = toolbar.groups.mapBy("buttons").flat().firstObject; + if (firstButton) { + firstButton.tabindex = 0; + } + return toolbar; }, @@ -702,6 +708,7 @@ export default Component.extend(TextareaTextManipulation, { this.applySurround(selected, head, tail, exampleKey, opts), applyList: (head, exampleKey, opts) => this._applyList(selected, head, exampleKey, opts), + formatCode: (...args) => this.send("formatCode", args), addText: (text) => this.addText(selected, text), getText: () => this.value, toggleDirection: () => this._toggleDirection(), diff --git a/app/assets/javascripts/discourse/app/components/d-navigation.js b/app/assets/javascripts/discourse/app/components/d-navigation.js index 32f8756b42..2153fc5f9c 100644 --- a/app/assets/javascripts/discourse/app/components/d-navigation.js +++ b/app/assets/javascripts/discourse/app/components/d-navigation.js @@ -1,7 +1,6 @@ import Component from "@ember/component"; import FilterModeMixin from "discourse/mixins/filter-mode"; import NavItem from "discourse/models/nav-item"; -import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; import { NotificationLevels } from "discourse/lib/notification-levels"; import { getOwner } from "discourse-common/lib/get-owner"; @@ -9,7 +8,7 @@ import { inject as service } from "@ember/service"; export default Component.extend(FilterModeMixin, { router: service(), - + dialog: service(), tagName: "", // Should be a `readOnly` instead but some themes/plugins still pass @@ -158,7 +157,7 @@ export default Component.extend(FilterModeMixin, { clickCreateTopicButton() { if (this.categoryReadOnlyBanner && !this.hasDraft) { - bootbox.alert(this.categoryReadOnlyBanner); + this.dialog.alert(this.categoryReadOnlyBanner); } else { this.createTopic(); } diff --git a/app/assets/javascripts/discourse/app/components/d-tooltip.js b/app/assets/javascripts/discourse/app/components/d-tooltip.js index 90d654c833..e462e2d542 100644 --- a/app/assets/javascripts/discourse/app/components/d-tooltip.js +++ b/app/assets/javascripts/discourse/app/components/d-tooltip.js @@ -26,6 +26,7 @@ export default class DiscourseTooltip extends Component { const parent = viewBounds.parentElement; this._tippyInstance = tippy(parent, { content: element, + trigger: this.capabilities.touch ? "click" : "mouseenter", theme: "d-tooltip", arrow: false, placement: "bottom-start", diff --git a/app/assets/javascripts/discourse/app/components/emoji-picker.js b/app/assets/javascripts/discourse/app/components/emoji-picker.js index 8f3aad5fa6..3e0646f893 100644 --- a/app/assets/javascripts/discourse/app/components/emoji-picker.js +++ b/app/assets/javascripts/discourse/app/components/emoji-picker.js @@ -41,6 +41,10 @@ export default Component.extend({ usePopper: true, placement: "auto", // one of popper.js' placements, see https://popper.js.org/docs/v2/constructors/#options initialFilter: "", + elements: { + searchInput: ".emoji-picker-search-container input", + picker: ".emoji-picker-emoji-area", + }, init() { this._super(...arguments); @@ -245,8 +249,116 @@ export default Component.extend({ @action keydown(event) { - if (event.code === "Escape") { + const arrowKeys = ["ArrowDown", "ArrowUp", "ArrowLeft", "ArrowRight"]; + const emojis = document.querySelectorAll(".emoji-picker-emoji-area .emoji"); + + let currentEmoji; + + this.set( + "hoveredEmoji", + this._codeWithDiversity(event.target.title, this.selectedDiversity) + ); + + if ( + event.key === "ArrowDown" && + this._focusedOn(this.elements.searchInput) + ) { + emojis[0].focus(); + event.preventDefault(); + return false; + } + + if (event.key === "Escape") { this.onClose(event); + const path = event.path || (event.composedPath && event.composedPath()); + + const fromChatComposer = path.find((e) => + e?.classList?.contains("chat-composer-container") + ); + + const fromTopicComposer = path.find((e) => + e?.classList?.contains("d-editor") + ); + + if (fromTopicComposer) { + document.querySelector(".d-editor-input")?.focus(); + } else if (fromChatComposer) { + document.querySelector(".chat-composer-input")?.focus(); + } else { + document.querySelector("textarea")?.focus(); + } + + return false; + } + + if (arrowKeys.includes(event.key)) { + if (!this._focusedOn(this.elements.picker)) { + return; + } + + Array.from(emojis).find((e, index) => { + currentEmoji = index; + return e.isEqualNode(event.target); + }); + + if (event.key === "ArrowRight") { + let nextEmoji = currentEmoji + 1; + + if (nextEmoji < emojis.length) { + emojis[nextEmoji].focus(); + } else if (nextEmoji >= emojis.length) { + emojis[0].focus(); + } + } + + if (event.key === "ArrowLeft") { + const previousEmoji = currentEmoji - 1; + if (currentEmoji > 0) { + emojis[previousEmoji].focus(); + } + } + + const active = emojis[currentEmoji]; + + if (event.key === "ArrowDown") { + // source: https://stackoverflow.com/a/49090383/349424 + // look for same element type with + // - higher offsetTop + // - same offsetLeft + const emojiBelow = [...emojis] + .filter((c) => c.offsetTop > active.offsetTop) + .find((c) => c.offsetLeft === active.offsetLeft); + + emojiBelow?.focus(); + } + + if (event.key === "ArrowUp") { + // look for same element type with + // - lower offsetTop + // - same offsetLeft + const emojiAbove = [...emojis] + .reverse() + .filter((c) => c.offsetTop < active.offsetTop) + .find((c) => c.offsetLeft === active.offsetLeft); + + if (emojiAbove) { + emojiAbove.focus(); + } else { + document.querySelector(this.elements.searchInput).focus(); + } + } + + event.preventDefault(); + return false; + } + + if (event.key === "Enter") { + if (!this._focusedOn(".emoji")) { + return; + } + this.onEmojiSelection(event); + this.onClose(event); + event.preventDefault(); return false; } }, @@ -256,6 +368,11 @@ export default Component.extend({ this._applyFilter(event.target.value); }, + _focusedOn(item) { + // returns the item currently being focused on + return document.activeElement.closest(item) ? document.activeElement : null; + }, + _applyFilter(filter) { const emojiPicker = document.querySelector(".emoji-picker"); const results = document.querySelector(".emoji-picker-emoji-area .results"); @@ -286,8 +403,9 @@ export default Component.extend({ _replaceEmoji(code) { const escaped = emojiUnescape(`:${escapeExpression(code)}:`, { lazy: true, + tabIndex: "0", }); - return htmlSafe(`${escaped}`); + return htmlSafe(escaped); }, _codeWithDiversity(code, selectedDiversity) { diff --git a/app/assets/javascripts/discourse/app/components/glimmer.js b/app/assets/javascripts/discourse/app/components/glimmer.js deleted file mode 100644 index b3142a9060..0000000000 --- a/app/assets/javascripts/discourse/app/components/glimmer.js +++ /dev/null @@ -1,24 +0,0 @@ -import GlimmerComponent from "@glimmer/component"; -import { inject as service } from "@ember/service"; - -/* - Glimmer components are not EmberObjects, and therefore do not support automatic - injection of the things defined in `pre-initializers/inject-discourse-objects`. - - This base class provides an alternative. All these references are looked up lazily, - so the performance impact should be negligible -*/ - -export default class DiscourseGlimmerComponent extends GlimmerComponent { - @service appEvents; - @service store; - @service("search") searchService; - @service keyValueStore; - @service pmTopicTrackingState; - @service siteSettings; - @service messageBus; - @service currentUser; - @service session; - @service site; - @service topicTrackingState; -} diff --git a/app/assets/javascripts/discourse/app/components/global-notice.js b/app/assets/javascripts/discourse/app/components/global-notice.js index 170421cb13..c0bd0bcd54 100644 --- a/app/assets/javascripts/discourse/app/components/global-notice.js +++ b/app/assets/javascripts/discourse/app/components/global-notice.js @@ -77,6 +77,7 @@ export default Component.extend({ @discourseComputed( "site.isReadOnly", + "site.isStaffWritesOnly", "siteSettings.login_required", "siteSettings.disable_emails", "siteSettings.global_notice", @@ -85,6 +86,7 @@ export default Component.extend({ ) notices( isReadOnly, + isStaffWritesOnly, loginRequired, disableEmails, globalNotice, @@ -111,7 +113,14 @@ export default Component.extend({ ); } - if (isReadOnly) { + if (isStaffWritesOnly) { + notices.push( + Notice.create({ + text: I18n.t("staff_writes_only_mode.enabled"), + id: "alert-staff-writes-only", + }) + ); + } else if (isReadOnly) { notices.push( Notice.create({ text: I18n.t("read_only_mode.enabled"), diff --git a/app/assets/javascripts/discourse/app/components/group-manage-email-settings.js b/app/assets/javascripts/discourse/app/components/group-manage-email-settings.js index ffa586b32a..786f2a3a5b 100644 --- a/app/assets/javascripts/discourse/app/components/group-manage-email-settings.js +++ b/app/assets/javascripts/discourse/app/components/group-manage-email-settings.js @@ -2,11 +2,12 @@ import Component from "@ember/component"; import { isEmpty } from "@ember/utils"; import discourseComputed, { on } from "discourse-common/utils/decorators"; import I18n from "I18n"; -import bootbox from "bootbox"; +import { inject as service } from "@ember/service"; import { action } from "@ember/object"; export default Component.extend({ tagName: "", + dialog: service(), imapSettingsValid: false, smtpSettingsValid: false, @@ -71,16 +72,11 @@ export default Component.extend({ this.group.smtp_enabled && this._anySmtpFieldsFilled() ) { - bootbox.confirm( - I18n.t("groups.manage.email.smtp_disable_confirm"), - (result) => { - if (!result) { - this.group.set("smtp_enabled", true); - } else { - this.group.set("imap_enabled", false); - } - } - ); + this.dialog.confirm({ + message: I18n.t("groups.manage.email.smtp_disable_confirm"), + didConfirm: () => this.group.set("smtp_enabled", true), + didCancel: () => this.group.set("imap_enabled", false), + }); } this.group.set("smtp_enabled", event.target.checked); @@ -93,14 +89,10 @@ export default Component.extend({ this.group.imap_enabled && this._anyImapFieldsFilled() ) { - bootbox.confirm( - I18n.t("groups.manage.email.imap_disable_confirm"), - (result) => { - if (!result) { - this.group.set("imap_enabled", true); - } - } - ); + this.dialog.confirm({ + message: I18n.t("groups.manage.email.imap_disable_confirm"), + didConfirm: () => this.group.set("imap_enabled", true), + }); } this.group.set("imap_enabled", event.target.checked); diff --git a/app/assets/javascripts/discourse/app/components/group-membership-button.js b/app/assets/javascripts/discourse/app/components/group-membership-button.js index 4c8239aedc..bad2835a19 100644 --- a/app/assets/javascripts/discourse/app/components/group-membership-button.js +++ b/app/assets/javascripts/discourse/app/components/group-membership-button.js @@ -1,13 +1,14 @@ import Component from "@ember/component"; import I18n from "I18n"; -import bootbox from "bootbox"; import cookie from "discourse/lib/cookie"; import discourseComputed from "discourse-common/utils/decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { inject as service } from "@ember/service"; import showModal from "discourse/lib/show-modal"; export default Component.extend({ classNames: ["group-membership-button"], + dialog: service(), @discourseComputed("model.public_admission", "userIsGroupUser") canJoinGroup(publicAdmission, userIsGroupUser) { @@ -73,16 +74,11 @@ export default Component.extend({ if (this.model.public_admission) { this.removeFromGroup(); } else { - return bootbox.confirm( - I18n.t("groups.confirm_leave"), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - result - ? this.removeFromGroup() - : this.set("updatingMembership", false); - } - ); + return this.dialog.yesNoConfirm({ + message: I18n.t("groups.confirm_leave"), + didConfirm: () => this.removeFromGroup(), + didCancel: () => this.set("updatingMembership", false), + }); } }, diff --git a/app/assets/javascripts/discourse/app/components/group-post.js b/app/assets/javascripts/discourse/app/components/group-post.js index 6aba0da4b0..074f856b40 100644 --- a/app/assets/javascripts/discourse/app/components/group-post.js +++ b/app/assets/javascripts/discourse/app/components/group-post.js @@ -3,6 +3,7 @@ import discourseComputed from "discourse-common/utils/decorators"; import getURL from "discourse-common/lib/get-url"; import { prioritizeNameInUx } from "discourse/lib/settings"; import { propertyEqual } from "discourse/lib/computed"; +import { userPath } from "discourse/lib/url"; export default Component.extend({ classNameBindings: [ @@ -35,4 +36,9 @@ export default Component.extend({ return `group-${postUser.primary_group_name}`; } }, + + @discourseComputed("post.user.username") + userUrl(username) { + return userPath(username.toLowerCase()); + }, }); diff --git a/app/assets/javascripts/discourse/app/components/navigation-item.js b/app/assets/javascripts/discourse/app/components/navigation-item.js index 2686d526ce..6c64f2c61b 100644 --- a/app/assets/javascripts/discourse/app/components/navigation-item.js +++ b/app/assets/javascripts/discourse/app/components/navigation-item.js @@ -42,13 +42,14 @@ export default Component.extend(FilterModeMixin, { const content = this.content; let href = content.get("href"); - let queryParams = []; + let urlSearchParams = new URLSearchParams(); + let addParamsEvenIfEmpty = false; // Include the category id if the option is present if (content.get("includeCategoryId")) { let categoryId = this.get("content.category.id"); if (categoryId) { - queryParams.push(`category_id=${categoryId}`); + urlSearchParams.set("category_id", categoryId); } } @@ -56,12 +57,12 @@ export default Component.extend(FilterModeMixin, { // If no query param is present, add an empty one to ensure a ? is // appended to the URL. if (content.currentRouteQueryParams) { - if (content.currentRouteQueryParams.filter && queryParams.length === 0) { - queryParams.push(""); + if (content.currentRouteQueryParams.filter) { + addParamsEvenIfEmpty = true; } if (content.currentRouteQueryParams.f) { - queryParams.push(`f=${content.currentRouteQueryParams.f}`); + urlSearchParams.set("f", content.currentRouteQueryParams.f); } } @@ -69,11 +70,12 @@ export default Component.extend(FilterModeMixin, { this.siteSettings.desktop_category_page_style === "categories_and_latest_topics_created_date" ) { - queryParams.push("order=created"); + urlSearchParams.set("order", "created"); } - if (queryParams.length) { - href += `?${queryParams.join("&")}`; + const queryString = urlSearchParams.toString(); + if (addParamsEvenIfEmpty || queryString) { + href += `?${queryString}`; } this.set("hrefLink", href); diff --git a/app/assets/javascripts/discourse/app/components/notification-consent-banner.js b/app/assets/javascripts/discourse/app/components/notification-consent-banner.js index d19abc998d..23c7b79472 100644 --- a/app/assets/javascripts/discourse/app/components/notification-consent-banner.js +++ b/app/assets/javascripts/discourse/app/components/notification-consent-banner.js @@ -32,7 +32,7 @@ export default DesktopNotificationConfig.extend({ this.siteSettings.push_notifications_prompt && !isNotSupported && this.currentUser && - anyPosts && + (this.capabilities.isPwa || anyPosts) && Notification.permission !== "denied" && Notification.permission !== "granted" && !isEnabled && diff --git a/app/assets/javascripts/discourse/app/components/pick-files-button.js b/app/assets/javascripts/discourse/app/components/pick-files-button.js index 3f2482ad50..991ffe1592 100644 --- a/app/assets/javascripts/discourse/app/components/pick-files-button.js +++ b/app/assets/javascripts/discourse/app/components/pick-files-button.js @@ -1,5 +1,4 @@ import Component from "@ember/component"; -import bootbox from "bootbox"; import { isBlank } from "@ember/utils"; import { authorizedExtensions, @@ -8,6 +7,7 @@ import { import { action } from "@ember/object"; import discourseComputed, { bind } from "discourse-common/utils/decorators"; import I18n from "I18n"; +import { inject as service } from "@ember/service"; // This picker is intended to be used with UppyUploadMixin or with // ComposerUploadUppy, which is why there are no change events registered @@ -18,6 +18,7 @@ import I18n from "I18n"; // is sometimes useful if you need to do something outside the uppy upload with // the file, such as directly using JSON or CSV data from a file in JS. export default Component.extend({ + dialog: service(), fileInputId: null, fileInputClass: null, fileInputDisabled: false, @@ -87,7 +88,7 @@ export default Component.extend({ const message = I18n.t("pick_files_button.unsupported_file_picked", { types: this.acceptedFileTypesString, }); - bootbox.alert(message); + this.dialog.alert(message); return; } this.onFilesPicked(files); diff --git a/app/assets/javascripts/discourse/app/components/reviewable-item.js b/app/assets/javascripts/discourse/app/components/reviewable-item.js index 9843038de4..ff67e672a8 100644 --- a/app/assets/javascripts/discourse/app/components/reviewable-item.js +++ b/app/assets/javascripts/discourse/app/components/reviewable-item.js @@ -151,11 +151,11 @@ export default Component.extend({ // "fast track" to update the current user's reviewable count before the message bus finds out. if (performResult.reviewable_count !== undefined) { - this.currentUser.set( - "reviewable_count", + this.currentUser.updateReviewableCount( performResult.reviewable_count ); } + if (performResult.unseen_reviewable_count !== undefined) { this.currentUser.set( "unseen_reviewable_count", diff --git a/app/assets/javascripts/discourse/app/components/sidebar.hbs b/app/assets/javascripts/discourse/app/components/sidebar.hbs new file mode 100644 index 0000000000..65d3b9240f --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar.hbs @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/javascripts/discourse/app/components/sidebar.js b/app/assets/javascripts/discourse/app/components/sidebar.js index afb309f54f..f4316c392a 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar.js +++ b/app/assets/javascripts/discourse/app/components/sidebar.js @@ -1,15 +1,18 @@ -import GlimmerComponent from "discourse/components/glimmer"; +import Component from "@glimmer/component"; import { bind } from "discourse-common/utils/decorators"; +import { inject as service } from "@ember/service"; + +export default class Sidebar extends Component { + @service appEvents; + @service site; + @service currentUser; -export default class Sidebar extends GlimmerComponent { constructor() { super(...arguments); if (this.site.mobileView) { document.addEventListener("click", this.collapseSidebar); } - // This appEvent handler is experimental and should not be relied on as an extension point yet. - this.appEvents.on("sidebar:scroll-to-element", this, this.#scrollToElement); } @bind @@ -33,68 +36,9 @@ export default class Sidebar extends GlimmerComponent { } } - #scrollToElement(destinationElement) { - const topPadding = 10; - - const sidebarContainerElement = - document.querySelector(".sidebar-container"); - - const distanceFromTop = - document.getElementsByClassName(destinationElement)[0].offsetTop - - topPadding; - - this.#setMissingHeightForScroll(sidebarContainerElement, distanceFromTop); - - sidebarContainerElement.scrollTop = distanceFromTop; - } - - #setMissingHeightForScroll(sidebarContainerElement, distanceFromTop) { - const allSections = document.getElementsByClassName( - "sidebar-section-wrapper" - ); - - const lastSectionElement = allSections[allSections.length - 1]; - - const lastSectionBottomPadding = parseInt( - lastSectionElement.style.paddingBottom?.replace("px", "") || 0, - 10 - ); - - const headerOffset = parseInt( - document.documentElement.style.getPropertyValue("--header-offset"), - 10 - ); - - let allSectionsHeight = 0; - - for (const section of allSections) { - allSectionsHeight += - section.clientHeight + - parseInt( - window.getComputedStyle(section).marginBottom.replace("px", ""), - 10 - ); - } - - const missingHeight = - sidebarContainerElement.clientHeight - - headerOffset + - lastSectionBottomPadding - - (allSectionsHeight - distanceFromTop); - - lastSectionElement.style.paddingBottom = - missingHeight > 0 ? `${missingHeight}px` : null; - } - willDestroy() { if (this.site.mobileView) { document.removeEventListener("click", this.collapseSidebar); } - - this.appEvents.off( - "sidebar:scroll-to-element", - this, - this.#scrollToElement - ); } } diff --git a/app/assets/javascripts/discourse/app/components/sidebar/anonymous/categories-section.hbs b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/categories-section.hbs new file mode 100644 index 0000000000..c59afa73c5 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/categories-section.hbs @@ -0,0 +1,21 @@ + + + {{#each this.sectionLinks as |sectionLink|}} + + + {{/each}} + + + diff --git a/app/assets/javascripts/discourse/app/components/sidebar/anonymous/categories-section.js b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/categories-section.js new file mode 100644 index 0000000000..40043a8171 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/categories-section.js @@ -0,0 +1,31 @@ +import { inject as service } from "@ember/service"; +import { canDisplayCategory } from "discourse/lib/sidebar/helpers"; +import SidebarCommonCategoriesSection from "discourse/components/sidebar/common/categories-section"; + +export default class SidebarAnonymousCategoriesSection extends SidebarCommonCategoriesSection { + @service site; + + get categories() { + let categories = this.site.categoriesList; + + if (this.siteSettings.default_sidebar_categories) { + const defaultCategoryIds = this.siteSettings.default_sidebar_categories + .split("|") + .map((categoryId) => parseInt(categoryId, 10)); + + categories = categories.filter((category) => + defaultCategoryIds.includes(category.id) + ); + } else { + categories = categories + .filter( + (category) => + canDisplayCategory(category, this.siteSettings) && + !category.parent_category_id + ) + .slice(0, 5); + } + + return categories; + } +} diff --git a/app/assets/javascripts/discourse/app/components/sidebar/anonymous/community-section.js b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/community-section.js new file mode 100644 index 0000000000..30d47e5b03 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/community-section.js @@ -0,0 +1,36 @@ +import SidebarCommonCommunitySection from "discourse/components/sidebar/common/community-section"; +import EverythingSectionLink from "discourse/lib/sidebar/common/community-section/everything-section-link"; +import AboutSectionLink from "discourse/lib/sidebar/common/community-section/about-section-link"; +import FAQSectionLink from "discourse/lib/sidebar/common/community-section/faq-section-link"; +import GroupsSectionLink from "discourse/lib/sidebar/common/community-section/groups-section-link"; +import UsersSectionLink from "discourse/lib/sidebar/common/community-section/users-section-link"; +import BadgesSectionLink from "discourse/lib/sidebar/common/community-section/badges-section-link"; + +export default class SidebarAnonymousCommunitySection extends SidebarCommonCommunitySection { + get defaultMainSectionLinks() { + const defaultLinks = [ + EverythingSectionLink, + UsersSectionLink, + FAQSectionLink, + ]; + + defaultLinks.splice( + this.displayShortSiteDescription ? 0 : 2, + 0, + AboutSectionLink + ); + + return defaultLinks; + } + + get displayShortSiteDescription() { + return ( + !this.currentUser && + (this.siteSettings.short_site_description || "").length > 0 + ); + } + + get defaultMoreSectionLinks() { + return [GroupsSectionLink, BadgesSectionLink]; + } +} diff --git a/app/assets/javascripts/discourse/app/components/sidebar/anonymous/sections.hbs b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/sections.hbs new file mode 100644 index 0000000000..68ea9dde5b --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/sections.hbs @@ -0,0 +1,8 @@ + diff --git a/app/assets/javascripts/discourse/app/components/sidebar/anonymous/sections.js b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/sections.js new file mode 100644 index 0000000000..6cb84571db --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/sections.js @@ -0,0 +1,6 @@ +import Component from "@glimmer/component"; +import { inject as service } from "@ember/service"; + +export default class SidebarAnonymousSections extends Component { + @service siteSettings; +} diff --git a/app/assets/javascripts/discourse/app/components/sidebar/anonymous/tags-section.hbs b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/tags-section.hbs new file mode 100644 index 0000000000..b8b339f7e2 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/tags-section.hbs @@ -0,0 +1,18 @@ + + + {{#each this.sectionLinks as |sectionLink|}} + + + {{/each}} + + + diff --git a/app/assets/javascripts/discourse/app/components/sidebar/anonymous/tags-section.js b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/tags-section.js new file mode 100644 index 0000000000..0dc3804ba5 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/anonymous/tags-section.js @@ -0,0 +1,27 @@ +import { cached } from "@glimmer/tracking"; +import Component from "@glimmer/component"; +import { inject as service } from "@ember/service"; +import TagSectionLink from "discourse/lib/sidebar/user/tags-section/tag-section-link"; + +export default class SidebarAnonymousTagsSection extends Component { + @service router; + @service topicTrackingState; + @service site; + + @cached + get sectionLinks() { + let tags; + + if (this.site.anonymous_default_sidebar_tags) { + tags = this.site.anonymous_default_sidebar_tags; + } else { + tags = this.site.top_tags.slice(0, 5); + } + return tags.map((tagName) => { + return new TagSectionLink({ + tagName, + topicTrackingState: this.topicTrackingState, + }); + }); + } +} diff --git a/app/assets/javascripts/discourse/app/components/sidebar/common/all-categories-section-link.hbs b/app/assets/javascripts/discourse/app/components/sidebar/common/all-categories-section-link.hbs new file mode 100644 index 0000000000..9eb404a3e4 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/common/all-categories-section-link.hbs @@ -0,0 +1,7 @@ + diff --git a/app/assets/javascripts/discourse/app/components/sidebar/common/all-categories-section-link.js b/app/assets/javascripts/discourse/app/components/sidebar/common/all-categories-section-link.js new file mode 100644 index 0000000000..742bb3c18e --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/common/all-categories-section-link.js @@ -0,0 +1,3 @@ +import templateOnly from "@ember/component/template-only"; + +export default templateOnly(); diff --git a/app/assets/javascripts/discourse/app/components/sidebar/common/all-tags-section-link.hbs b/app/assets/javascripts/discourse/app/components/sidebar/common/all-tags-section-link.hbs new file mode 100644 index 0000000000..ae342f9d50 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/common/all-tags-section-link.hbs @@ -0,0 +1,7 @@ + diff --git a/app/assets/javascripts/discourse/app/components/sidebar/common/all-tags-section-link.js b/app/assets/javascripts/discourse/app/components/sidebar/common/all-tags-section-link.js new file mode 100644 index 0000000000..742bb3c18e --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/common/all-tags-section-link.js @@ -0,0 +1,3 @@ +import templateOnly from "@ember/component/template-only"; + +export default templateOnly(); diff --git a/app/assets/javascripts/discourse/app/components/sidebar/common/categories-section.js b/app/assets/javascripts/discourse/app/components/sidebar/common/categories-section.js new file mode 100644 index 0000000000..9a9cd4e081 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/common/categories-section.js @@ -0,0 +1,29 @@ +import Component from "@glimmer/component"; +import { cached } from "@glimmer/tracking"; +import { inject as service } from "@ember/service"; + +import CategorySectionLink from "discourse/lib/sidebar/user/categories-section/category-section-link"; + +export default class SidebarCommonCategoriesSection extends Component { + @service topicTrackingState; + @service siteSettings; + + // Override in child + get categories() {} + + @cached + get sectionLinks() { + return this.categories + .sort((a, b) => a.name.localeCompare(b.name)) + .reduce((links, category) => { + links.push( + new CategorySectionLink({ + category, + topicTrackingState: this.topicTrackingState, + }) + ); + + return links; + }, []); + } +} diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/community-section.hbs b/app/assets/javascripts/discourse/app/components/sidebar/common/community-section.hbs similarity index 65% rename from app/assets/javascripts/discourse/app/templates/components/sidebar/community-section.hbs rename to app/assets/javascripts/discourse/app/components/sidebar/common/community-section.hbs index 94696fa648..b7b54e3173 100644 --- a/app/assets/javascripts/discourse/app/templates/components/sidebar/community-section.hbs +++ b/app/assets/javascripts/discourse/app/components/sidebar/common/community-section.hbs @@ -1,13 +1,16 @@ + {{#if this.displayShortSiteDescription}} + + {{this.siteSettings.short_site_description}} + + {{/if}} + {{#each this.sectionLinks as |sectionLink|}} + @models={{sectionLink.models}} + @prefixType={{sectionLink.prefixType}} + @prefixValue={{sectionLink.prefixValue}} /> {{/each}} diff --git a/app/assets/javascripts/discourse/app/components/sidebar/common/community-section.js b/app/assets/javascripts/discourse/app/components/sidebar/common/community-section.js new file mode 100644 index 0000000000..9a2e5174d8 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/common/community-section.js @@ -0,0 +1,94 @@ +import Component from "@glimmer/component"; +import { inject as service } from "@ember/service"; +import { tracked } from "@glimmer/tracking"; + +import { + customSectionLinks, + secondaryCustomSectionLinks, +} from "discourse/lib/sidebar/custom-community-section-links"; + +export default class SidebarCommunitySection extends Component { + @service router; + @service topicTrackingState; + @service currentUser; + @service appEvents; + @service siteSettings; + + @tracked sectionLinks; + @tracked moreSectionLinks; + @tracked moreSecondarySectionLinks; + + callbackId; + headerActionsIcon; + headerActions; + + constructor() { + super(...arguments); + + this.refreshSectionLinks(); + + this.callbackId = this.topicTrackingState.onStateChange(() => { + this.sectionLinks.forEach((sectionLink) => { + sectionLink.onTopicTrackingStateChange(); + }); + }); + } + + willDestroy() { + this.sectionLinks.forEach((sectionLink) => sectionLink.teardown()); + this.topicTrackingState.offStateChange(this.callbackId); + } + + // Override in child + get defaultMainSectionLinks() { + return []; + } + + // Override in child + get defaultMoreSectionLinks() { + return []; + } + + // Override in child + get defaultMoreSecondarySectionLinks() { + return []; + } + + refreshSectionLinks() { + this.moreSectionLinks = this.#initializeSectionLinks([ + ...this.defaultMoreSectionLinks, + ...customSectionLinks, + ]); + + this.moreSecondarySectionLinks = this.#initializeSectionLinks([ + ...this.defaultMoreSecondarySectionLinks, + ...secondaryCustomSectionLinks, + ]); + + this.sectionLinks = this.#initializeSectionLinks( + this.defaultMainSectionLinks + ); + } + + #initializeSectionLinks(sectionLinkClasses) { + return sectionLinkClasses.reduce((links, sectionLinkClass) => { + const sectionLink = this.#initializeSectionLink(sectionLinkClass); + + if (sectionLink.shouldDisplay) { + links.push(sectionLink); + } + + return links; + }, []); + } + + #initializeSectionLink(sectionLinkClass) { + return new sectionLinkClass({ + topicTrackingState: this.topicTrackingState, + currentUser: this.currentUser, + appEvents: this.appEvents, + router: this.router, + siteSettings: this.siteSettings, + }); + } +} diff --git a/app/assets/javascripts/discourse/app/components/sidebar/community-section.js b/app/assets/javascripts/discourse/app/components/sidebar/community-section.js deleted file mode 100644 index e704cfe18d..0000000000 --- a/app/assets/javascripts/discourse/app/components/sidebar/community-section.js +++ /dev/null @@ -1,89 +0,0 @@ -import GlimmerComponent from "discourse/components/glimmer"; -import Composer from "discourse/models/composer"; -import { getOwner } from "discourse-common/lib/get-owner"; -import PermissionType from "discourse/models/permission-type"; -import { - customSectionLinks, - secondaryCustomSectionLinks, -} from "discourse/lib/sidebar/custom-community-section-links"; -import EverythingSectionLink from "discourse/lib/sidebar/community-section/everything-section-link"; -import TrackedSectionLink from "discourse/lib/sidebar/community-section/tracked-section-link"; -import MyPostsSectionLink from "discourse/lib/sidebar/community-section/my-posts-section-link"; -import GroupsSectionLink from "discourse/lib/sidebar/community-section/groups-section-link"; -import UsersSectionLink from "discourse/lib/sidebar/community-section/users-section-link"; -import AboutSectionLink from "discourse/lib/sidebar/community-section/about-section-link"; -import FAQSectionLink from "discourse/lib/sidebar/community-section/faq-section-link"; -import AdminSectionLink from "discourse/lib/sidebar/community-section/admin-section-link"; - -import { inject as service } from "@ember/service"; -import { action } from "@ember/object"; -import { next } from "@ember/runloop"; - -const MAIN_SECTION_LINKS = [ - EverythingSectionLink, - TrackedSectionLink, - MyPostsSectionLink, -]; - -const ADMIN_MAIN_SECTION_LINKS = [AdminSectionLink]; - -const MORE_SECTION_LINKS = [GroupsSectionLink, UsersSectionLink]; -const MORE_SECONDARY_SECTION_LINKS = [AboutSectionLink, FAQSectionLink]; - -export default class SidebarCommunitySection extends GlimmerComponent { - @service router; - - moreSectionLinks = [...MORE_SECTION_LINKS, ...customSectionLinks].map( - (sectionLinkClass) => { - return this.#initializeSectionLink(sectionLinkClass); - } - ); - - moreSecondarySectionLinks = [ - ...MORE_SECONDARY_SECTION_LINKS, - ...secondaryCustomSectionLinks, - ].map((sectionLinkClass) => { - return this.#initializeSectionLink(sectionLinkClass); - }); - - #mainSectionLinks = this.currentUser.staff - ? [...MAIN_SECTION_LINKS, ...ADMIN_MAIN_SECTION_LINKS] - : [...MAIN_SECTION_LINKS]; - - sectionLinks = this.#mainSectionLinks.map((sectionLinkClass) => { - return this.#initializeSectionLink(sectionLinkClass); - }); - - willDestroy() { - this.sectionLinks.forEach((sectionLink) => sectionLink.teardown()); - } - - @action - composeTopic() { - const composerArgs = { - action: Composer.CREATE_TOPIC, - draftKey: Composer.NEW_TOPIC_KEY, - }; - - const controller = getOwner(this).lookup("controller:navigation/category"); - const category = controller.category; - - if (category && category.permission === PermissionType.FULL) { - composerArgs.categoryId = category.id; - } - - next(() => { - getOwner(this).lookup("controller:composer").open(composerArgs); - }); - } - - #initializeSectionLink(sectionLinkClass) { - return new sectionLinkClass({ - topicTrackingState: this.topicTrackingState, - currentUser: this.currentUser, - appEvents: this.appEvents, - router: this.router, - siteSettings: this.siteSettings, - }); - } -} diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/footer.hbs b/app/assets/javascripts/discourse/app/components/sidebar/footer.hbs similarity index 100% rename from app/assets/javascripts/discourse/app/templates/components/sidebar/footer.hbs rename to app/assets/javascripts/discourse/app/components/sidebar/footer.hbs diff --git a/app/assets/javascripts/discourse/app/components/sidebar/footer.js b/app/assets/javascripts/discourse/app/components/sidebar/footer.js new file mode 100644 index 0000000000..68b8c7afe7 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/footer.js @@ -0,0 +1,12 @@ +import Component from "@glimmer/component"; +import { getOwner } from "discourse-common/lib/get-owner"; +import { inject as service } from "@ember/service"; + +export default class SidebarFooter extends Component { + @service site; + @service siteSettings; + + get capabilities() { + return getOwner(this).lookup("capabilities:main"); + } +} diff --git a/app/assets/javascripts/discourse/app/components/sidebar/hamburger-dropdown.hbs b/app/assets/javascripts/discourse/app/components/sidebar/hamburger-dropdown.hbs new file mode 100644 index 0000000000..5262f58f6f --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/hamburger-dropdown.hbs @@ -0,0 +1,12 @@ +
+ +
diff --git a/app/assets/javascripts/discourse/app/components/sidebar/hamburger-dropdown.js b/app/assets/javascripts/discourse/app/components/sidebar/hamburger-dropdown.js new file mode 100644 index 0000000000..a7888ce2d9 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/hamburger-dropdown.js @@ -0,0 +1,13 @@ +import Component from "@glimmer/component"; +import { action } from "@ember/object"; +import { inject as service } from "@ember/service"; + +export default class SidebarHamburgerDropdown extends Component { + @service appEvents; + @service currentUser; + + @action + triggerRenderedAppEvent() { + this.appEvents.trigger("sidebar-hamburger-dropdown:rendered"); + } +} diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/header-sidebar-toggle.hbs b/app/assets/javascripts/discourse/app/components/sidebar/header-sidebar-toggle.hbs similarity index 100% rename from app/assets/javascripts/discourse/app/templates/components/sidebar/header-sidebar-toggle.hbs rename to app/assets/javascripts/discourse/app/components/sidebar/header-sidebar-toggle.hbs diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-link.hbs b/app/assets/javascripts/discourse/app/components/sidebar/more-section-link.hbs similarity index 72% rename from app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-link.hbs rename to app/assets/javascripts/discourse/app/components/sidebar/more-section-link.hbs index 2958b61365..321beab314 100644 --- a/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-link.hbs +++ b/app/assets/javascripts/discourse/app/components/sidebar/more-section-link.hbs @@ -8,4 +8,6 @@ @currentWhen={{@sectionLink.currentWhen}} @badgeText={{@sectionLink.badgeText}} @model={{@sectionLink.model}} - @models={{@sectionLink.models}} /> + @models={{@sectionLink.models}} + @prefixType={{@sectionLink.prefixType}} + @prefixValue={{@sectionLink.prefixValue}} /> diff --git a/app/assets/javascripts/discourse/app/components/sidebar/more-section-links.hbs b/app/assets/javascripts/discourse/app/components/sidebar/more-section-links.hbs new file mode 100644 index 0000000000..154f08b906 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/more-section-links.hbs @@ -0,0 +1,36 @@ +{{#if this.activeSectionLink}} + +{{/if}} + + diff --git a/app/assets/javascripts/discourse/app/components/sidebar/more-section-links.js b/app/assets/javascripts/discourse/app/components/sidebar/more-section-links.js index d339ad6edf..3bcbd787a6 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/more-section-links.js +++ b/app/assets/javascripts/discourse/app/components/sidebar/more-section-links.js @@ -4,12 +4,13 @@ import { inject as service } from "@ember/service"; import { isEmpty } from "@ember/utils"; import { bind } from "discourse-common/utils/decorators"; -import GlimmerComponent from "discourse/components/glimmer"; +import Component from "@glimmer/component"; + +export default class SidebarMoreSectionLinks extends Component { + @service router; -export default class SidebarMoreSectionLinks extends GlimmerComponent { @tracked shouldDisplaySectionLinks = false; @tracked activeSectionLink; - @service router; #allLinks = [...this.args.sectionLinks, ...this.args.secondarySectionLinks]; @@ -72,8 +73,8 @@ export default class SidebarMoreSectionLinks extends GlimmerComponent { } @action - toggleSectionLinks() { - this.shouldDisplaySectionLinks = !this.shouldDisplaySectionLinks; + toggleSectionLinks(element) { + this.shouldDisplaySectionLinks = element.target.hasAttribute("open"); } #removeClickEventListener() { diff --git a/app/assets/javascripts/discourse/app/components/sidebar/section-header.hbs b/app/assets/javascripts/discourse/app/components/sidebar/section-header.hbs new file mode 100644 index 0000000000..55839c39e3 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/section-header.hbs @@ -0,0 +1,13 @@ +{{#if @collapsable}} + + + {{yield}} + +{{else}} + + {{yield}} + +{{/if}} diff --git a/app/assets/javascripts/discourse/app/components/sidebar/section-header.js b/app/assets/javascripts/discourse/app/components/sidebar/section-header.js new file mode 100644 index 0000000000..742bb3c18e --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/section-header.js @@ -0,0 +1,3 @@ +import templateOnly from "@ember/component/template-only"; + +export default templateOnly(); diff --git a/app/assets/javascripts/discourse/app/components/sidebar/section-link-prefix.hbs b/app/assets/javascripts/discourse/app/components/sidebar/section-link-prefix.hbs new file mode 100644 index 0000000000..0e4d9600d3 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/section-link-prefix.hbs @@ -0,0 +1,21 @@ +{{#if @prefixValue}} + + {{#if (eq @prefixType "image")}} + + {{/if}} + + {{#if (eq @prefixType "text")}} + + {{@prefixValue}} + + {{/if}} + + {{#if (eq @prefixType "icon")}} + {{d-icon @prefixValue class="prefix-icon"}} + {{/if}} + + {{#if @prefixBadge}} + {{d-icon @prefixBadge class="prefix-badge"}} + {{/if}} + +{{/if}} diff --git a/app/assets/javascripts/discourse/app/components/sidebar/section-link-prefix.js b/app/assets/javascripts/discourse/app/components/sidebar/section-link-prefix.js new file mode 100644 index 0000000000..742bb3c18e --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/section-link-prefix.js @@ -0,0 +1,3 @@ +import templateOnly from "@ember/component/template-only"; + +export default templateOnly(); diff --git a/app/assets/javascripts/discourse/app/components/sidebar/section-link.hbs b/app/assets/javascripts/discourse/app/components/sidebar/section-link.hbs new file mode 100644 index 0000000000..570e57590f --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/section-link.hbs @@ -0,0 +1,68 @@ + diff --git a/app/assets/javascripts/discourse/app/components/sidebar/section-link.js b/app/assets/javascripts/discourse/app/components/sidebar/section-link.js index 32dc9eae3b..16385ec1f9 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/section-link.js +++ b/app/assets/javascripts/discourse/app/components/sidebar/section-link.js @@ -1,7 +1,7 @@ -import GlimmerComponent from "@glimmer/component"; +import Component from "@glimmer/component"; import { htmlSafe } from "@ember/template"; -export default class SectionLink extends GlimmerComponent { +export default class SectionLink extends Component { willDestroy() { if (this.args.willDestroy) { this.args.willDestroy(); @@ -9,7 +9,17 @@ export default class SectionLink extends GlimmerComponent { } get classNames() { - return `${this.args.class} sidebar-section-link sidebar-section-link-${this.args.linkName}`; + let classNames = [ + "sidebar-section-link", + `sidebar-section-link-${this.args.linkName}`, + "sidebar-row", + ]; + + if (this.args.class) { + classNames.push(this.args.class); + } + + return classNames.join(" "); } get models() { diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/section-message.hbs b/app/assets/javascripts/discourse/app/components/sidebar/section-message.hbs similarity index 54% rename from app/assets/javascripts/discourse/app/templates/components/sidebar/section-message.hbs rename to app/assets/javascripts/discourse/app/components/sidebar/section-message.hbs index d3d92dad94..cb81be1053 100644 --- a/app/assets/javascripts/discourse/app/templates/components/sidebar/section-message.hbs +++ b/app/assets/javascripts/discourse/app/components/sidebar/section-message.hbs @@ -1,4 +1,4 @@ -
@@ -834,224 +834,224 @@ {{i18n "emoji_picker.travel_&_places"}}
- {{replace-emoji ":earth_africa:" (hash lazy=true)}} - {{replace-emoji ":earth_americas:" (hash lazy=true)}} - {{replace-emoji ":earth_asia:" (hash lazy=true)}} - {{replace-emoji ":globe_with_meridians:" (hash lazy=true)}} - {{replace-emoji ":world_map:" (hash lazy=true)}} - {{replace-emoji ":japan:" (hash lazy=true)}} - {{replace-emoji ":compass:" (hash lazy=true)}} - {{replace-emoji ":mountain_snow:" (hash lazy=true)}} - {{replace-emoji ":mountain:" (hash lazy=true)}} - {{replace-emoji ":volcano:" (hash lazy=true)}} - {{replace-emoji ":mount_fuji:" (hash lazy=true)}} - {{replace-emoji ":camping:" (hash lazy=true)}} - {{replace-emoji ":beach_umbrella:" (hash lazy=true)}} - {{replace-emoji ":desert:" (hash lazy=true)}} - {{replace-emoji ":desert_island:" (hash lazy=true)}} - {{replace-emoji ":national_park:" (hash lazy=true)}} - {{replace-emoji ":stadium:" (hash lazy=true)}} - {{replace-emoji ":classical_building:" (hash lazy=true)}} - {{replace-emoji ":building_construction:" (hash lazy=true)}} - {{replace-emoji ":brick:" (hash lazy=true)}} - {{replace-emoji ":rock:" (hash lazy=true)}} - {{replace-emoji ":wood:" (hash lazy=true)}} - {{replace-emoji ":hut:" (hash lazy=true)}} - {{replace-emoji ":houses:" (hash lazy=true)}} - {{replace-emoji ":derelict_house:" (hash lazy=true)}} - {{replace-emoji ":house:" (hash lazy=true)}} - {{replace-emoji ":house_with_garden:" (hash lazy=true)}} - {{replace-emoji ":office:" (hash lazy=true)}} - {{replace-emoji ":post_office:" (hash lazy=true)}} - {{replace-emoji ":european_post_office:" (hash lazy=true)}} - {{replace-emoji ":hospital:" (hash lazy=true)}} - {{replace-emoji ":bank:" (hash lazy=true)}} - {{replace-emoji ":hotel:" (hash lazy=true)}} - {{replace-emoji ":love_hotel:" (hash lazy=true)}} - {{replace-emoji ":convenience_store:" (hash lazy=true)}} - {{replace-emoji ":school:" (hash lazy=true)}} - {{replace-emoji ":department_store:" (hash lazy=true)}} - {{replace-emoji ":factory:" (hash lazy=true)}} - {{replace-emoji ":japanese_castle:" (hash lazy=true)}} - {{replace-emoji ":european_castle:" (hash lazy=true)}} - {{replace-emoji ":wedding:" (hash lazy=true)}} - {{replace-emoji ":tokyo_tower:" (hash lazy=true)}} - {{replace-emoji ":statue_of_liberty:" (hash lazy=true)}} - {{replace-emoji ":church:" (hash lazy=true)}} - {{replace-emoji ":mosque:" (hash lazy=true)}} - {{replace-emoji ":hindu_temple:" (hash lazy=true)}} - {{replace-emoji ":synagogue:" (hash lazy=true)}} - {{replace-emoji ":shinto_shrine:" (hash lazy=true)}} - {{replace-emoji ":kaaba:" (hash lazy=true)}} - {{replace-emoji ":fountain:" (hash lazy=true)}} - {{replace-emoji ":tent:" (hash lazy=true)}} - {{replace-emoji ":foggy:" (hash lazy=true)}} - {{replace-emoji ":night_with_stars:" (hash lazy=true)}} - {{replace-emoji ":cityscape:" (hash lazy=true)}} - {{replace-emoji ":sunrise_over_mountains:" (hash lazy=true)}} - {{replace-emoji ":sunrise:" (hash lazy=true)}} - {{replace-emoji ":city_sunset:" (hash lazy=true)}} - {{replace-emoji ":city_sunrise:" (hash lazy=true)}} - {{replace-emoji ":bridge_at_night:" (hash lazy=true)}} - {{replace-emoji ":hotsprings:" (hash lazy=true)}} - {{replace-emoji ":carousel_horse:" (hash lazy=true)}} - {{replace-emoji ":playground_slide:" (hash lazy=true)}} - {{replace-emoji ":ferris_wheel:" (hash lazy=true)}} - {{replace-emoji ":roller_coaster:" (hash lazy=true)}} - {{replace-emoji ":barber:" (hash lazy=true)}} - {{replace-emoji ":circus_tent:" (hash lazy=true)}} - {{replace-emoji ":steam_locomotive:" (hash lazy=true)}} - {{replace-emoji ":railway_car:" (hash lazy=true)}} - {{replace-emoji ":bullettrain_side:" (hash lazy=true)}} - {{replace-emoji ":bullettrain_front:" (hash lazy=true)}} - {{replace-emoji ":train2:" (hash lazy=true)}} - {{replace-emoji ":metro:" (hash lazy=true)}} - {{replace-emoji ":light_rail:" (hash lazy=true)}} - {{replace-emoji ":station:" (hash lazy=true)}} - {{replace-emoji ":tram:" (hash lazy=true)}} - {{replace-emoji ":monorail:" (hash lazy=true)}} - {{replace-emoji ":mountain_railway:" (hash lazy=true)}} - {{replace-emoji ":train:" (hash lazy=true)}} - {{replace-emoji ":bus:" (hash lazy=true)}} - {{replace-emoji ":oncoming_bus:" (hash lazy=true)}} - {{replace-emoji ":trolleybus:" (hash lazy=true)}} - {{replace-emoji ":minibus:" (hash lazy=true)}} - {{replace-emoji ":ambulance:" (hash lazy=true)}} - {{replace-emoji ":fire_engine:" (hash lazy=true)}} - {{replace-emoji ":police_car:" (hash lazy=true)}} - {{replace-emoji ":oncoming_police_car:" (hash lazy=true)}} - {{replace-emoji ":taxi:" (hash lazy=true)}} - {{replace-emoji ":oncoming_taxi:" (hash lazy=true)}} - {{replace-emoji ":red_car:" (hash lazy=true)}} - {{replace-emoji ":oncoming_automobile:" (hash lazy=true)}} - {{replace-emoji ":blue_car:" (hash lazy=true)}} - {{replace-emoji ":pickup_truck:" (hash lazy=true)}} - {{replace-emoji ":truck:" (hash lazy=true)}} - {{replace-emoji ":articulated_lorry:" (hash lazy=true)}} - {{replace-emoji ":tractor:" (hash lazy=true)}} - {{replace-emoji ":racing_car:" (hash lazy=true)}} - {{replace-emoji ":motorcycle:" (hash lazy=true)}} - {{replace-emoji ":motor_scooter:" (hash lazy=true)}} - {{replace-emoji ":manual_wheelchair:" (hash lazy=true)}} - {{replace-emoji ":motorized_wheelchair:" (hash lazy=true)}} - {{replace-emoji ":auto_rickshaw:" (hash lazy=true)}} - {{replace-emoji ":bike:" (hash lazy=true)}} - {{replace-emoji ":kick_scooter:" (hash lazy=true)}} - {{replace-emoji ":skateboard:" (hash lazy=true)}} - {{replace-emoji ":roller_skate:" (hash lazy=true)}} - {{replace-emoji ":busstop:" (hash lazy=true)}} - {{replace-emoji ":motorway:" (hash lazy=true)}} - {{replace-emoji ":railway_track:" (hash lazy=true)}} - {{replace-emoji ":oil_drum:" (hash lazy=true)}} - {{replace-emoji ":fuelpump:" (hash lazy=true)}} - {{replace-emoji ":wheel:" (hash lazy=true)}} - {{replace-emoji ":rotating_light:" (hash lazy=true)}} - {{replace-emoji ":traffic_light:" (hash lazy=true)}} - {{replace-emoji ":vertical_traffic_light:" (hash lazy=true)}} - {{replace-emoji ":stop_sign:" (hash lazy=true)}} - {{replace-emoji ":construction:" (hash lazy=true)}} - {{replace-emoji ":anchor:" (hash lazy=true)}} - {{replace-emoji ":ring_buoy:" (hash lazy=true)}} - {{replace-emoji ":sailboat:" (hash lazy=true)}} - {{replace-emoji ":canoe:" (hash lazy=true)}} - {{replace-emoji ":speedboat:" (hash lazy=true)}} - {{replace-emoji ":passenger_ship:" (hash lazy=true)}} - {{replace-emoji ":ferry:" (hash lazy=true)}} - {{replace-emoji ":motor_boat:" (hash lazy=true)}} - {{replace-emoji ":ship:" (hash lazy=true)}} - {{replace-emoji ":airplane:" (hash lazy=true)}} - {{replace-emoji ":small_airplane:" (hash lazy=true)}} - {{replace-emoji ":flight_departure:" (hash lazy=true)}} - {{replace-emoji ":flight_arrival:" (hash lazy=true)}} - {{replace-emoji ":parachute:" (hash lazy=true)}} - {{replace-emoji ":seat:" (hash lazy=true)}} - {{replace-emoji ":helicopter:" (hash lazy=true)}} - {{replace-emoji ":suspension_railway:" (hash lazy=true)}} - {{replace-emoji ":mountain_cableway:" (hash lazy=true)}} - {{replace-emoji ":aerial_tramway:" (hash lazy=true)}} - {{replace-emoji ":artificial_satellite:" (hash lazy=true)}} - {{replace-emoji ":rocket:" (hash lazy=true)}} - {{replace-emoji ":flying_saucer:" (hash lazy=true)}} - {{replace-emoji ":bellhop_bell:" (hash lazy=true)}} - {{replace-emoji ":luggage:" (hash lazy=true)}} - {{replace-emoji ":hourglass:" (hash lazy=true)}} - {{replace-emoji ":hourglass_flowing_sand:" (hash lazy=true)}} - {{replace-emoji ":watch:" (hash lazy=true)}} - {{replace-emoji ":alarm_clock:" (hash lazy=true)}} - {{replace-emoji ":stopwatch:" (hash lazy=true)}} - {{replace-emoji ":timer_clock:" (hash lazy=true)}} - {{replace-emoji ":mantelpiece_clock:" (hash lazy=true)}} - {{replace-emoji ":clock12:" (hash lazy=true)}} - {{replace-emoji ":clock1230:" (hash lazy=true)}} - {{replace-emoji ":clock1:" (hash lazy=true)}} - {{replace-emoji ":clock130:" (hash lazy=true)}} - {{replace-emoji ":clock2:" (hash lazy=true)}} - {{replace-emoji ":clock230:" (hash lazy=true)}} - {{replace-emoji ":clock3:" (hash lazy=true)}} - {{replace-emoji ":clock330:" (hash lazy=true)}} - {{replace-emoji ":clock4:" (hash lazy=true)}} - {{replace-emoji ":clock430:" (hash lazy=true)}} - {{replace-emoji ":clock5:" (hash lazy=true)}} - {{replace-emoji ":clock530:" (hash lazy=true)}} - {{replace-emoji ":clock6:" (hash lazy=true)}} - {{replace-emoji ":clock630:" (hash lazy=true)}} - {{replace-emoji ":clock7:" (hash lazy=true)}} - {{replace-emoji ":clock730:" (hash lazy=true)}} - {{replace-emoji ":clock8:" (hash lazy=true)}} - {{replace-emoji ":clock830:" (hash lazy=true)}} - {{replace-emoji ":clock9:" (hash lazy=true)}} - {{replace-emoji ":clock930:" (hash lazy=true)}} - {{replace-emoji ":clock10:" (hash lazy=true)}} - {{replace-emoji ":clock1030:" (hash lazy=true)}} - {{replace-emoji ":clock11:" (hash lazy=true)}} - {{replace-emoji ":clock1130:" (hash lazy=true)}} - {{replace-emoji ":new_moon:" (hash lazy=true)}} - {{replace-emoji ":waxing_crescent_moon:" (hash lazy=true)}} - {{replace-emoji ":first_quarter_moon:" (hash lazy=true)}} - {{replace-emoji ":waxing_gibbous_moon:" (hash lazy=true)}} - {{replace-emoji ":full_moon:" (hash lazy=true)}} - {{replace-emoji ":waning_gibbous_moon:" (hash lazy=true)}} - {{replace-emoji ":last_quarter_moon:" (hash lazy=true)}} - {{replace-emoji ":waning_crescent_moon:" (hash lazy=true)}} - {{replace-emoji ":crescent_moon:" (hash lazy=true)}} - {{replace-emoji ":new_moon_with_face:" (hash lazy=true)}} - {{replace-emoji ":first_quarter_moon_with_face:" (hash lazy=true)}} - {{replace-emoji ":last_quarter_moon_with_face:" (hash lazy=true)}} - {{replace-emoji ":thermometer:" (hash lazy=true)}} - {{replace-emoji ":sunny:" (hash lazy=true)}} - {{replace-emoji ":full_moon_with_face:" (hash lazy=true)}} - {{replace-emoji ":sun_with_face:" (hash lazy=true)}} - {{replace-emoji ":ringer_planet:" (hash lazy=true)}} - {{replace-emoji ":star:" (hash lazy=true)}} - {{replace-emoji ":star2:" (hash lazy=true)}} - {{replace-emoji ":stars:" (hash lazy=true)}} - {{replace-emoji ":milky_way:" (hash lazy=true)}} - {{replace-emoji ":cloud:" (hash lazy=true)}} - {{replace-emoji ":partly_sunny:" (hash lazy=true)}} - {{replace-emoji ":cloud_with_lightning_and_rain:" (hash lazy=true)}} - {{replace-emoji ":sun_behind_small_cloud:" (hash lazy=true)}} - {{replace-emoji ":sun_behind_large_cloud:" (hash lazy=true)}} - {{replace-emoji ":sun_behind_rain_cloud:" (hash lazy=true)}} - {{replace-emoji ":cloud_with_rain:" (hash lazy=true)}} - {{replace-emoji ":cloud_with_snow:" (hash lazy=true)}} - {{replace-emoji ":cloud_with_lightning:" (hash lazy=true)}} - {{replace-emoji ":tornado:" (hash lazy=true)}} - {{replace-emoji ":fog:" (hash lazy=true)}} - {{replace-emoji ":wind_face:" (hash lazy=true)}} - {{replace-emoji ":cyclone:" (hash lazy=true)}} - {{replace-emoji ":rainbow:" (hash lazy=true)}} - {{replace-emoji ":closed_umbrella:" (hash lazy=true)}} - {{replace-emoji ":open_umbrella:" (hash lazy=true)}} - {{replace-emoji ":umbrella:" (hash lazy=true)}} - {{replace-emoji ":parasol_on_ground:" (hash lazy=true)}} - {{replace-emoji ":zap:" (hash lazy=true)}} - {{replace-emoji ":snowflake:" (hash lazy=true)}} - {{replace-emoji ":snowman_with_snow:" (hash lazy=true)}} - {{replace-emoji ":snowman:" (hash lazy=true)}} - {{replace-emoji ":comet:" (hash lazy=true)}} - {{replace-emoji ":fire:" (hash lazy=true)}} - {{replace-emoji ":droplet:" (hash lazy=true)}} - {{replace-emoji ":ocean:" (hash lazy=true)}} + {{replace-emoji ":earth_africa:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":earth_americas:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":earth_asia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":globe_with_meridians:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":world_map:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":japan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":compass:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mountain_snow:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mountain:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":volcano:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mount_fuji:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":camping:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":beach_umbrella:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":desert:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":desert_island:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":national_park:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":stadium:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":classical_building:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":building_construction:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":brick:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":rock:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wood:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hut:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":houses:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":derelict_house:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":house:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":house_with_garden:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":office:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":post_office:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":european_post_office:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hospital:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bank:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hotel:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":love_hotel:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":convenience_store:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":school:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":department_store:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":factory:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":japanese_castle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":european_castle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wedding:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tokyo_tower:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":statue_of_liberty:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":church:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mosque:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hindu_temple:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":synagogue:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":shinto_shrine:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":kaaba:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fountain:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tent:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":foggy:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":night_with_stars:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cityscape:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sunrise_over_mountains:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sunrise:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":city_sunset:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":city_sunrise:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bridge_at_night:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hotsprings:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":carousel_horse:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":playground_slide:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ferris_wheel:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":roller_coaster:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":barber:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":circus_tent:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":steam_locomotive:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":railway_car:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bullettrain_side:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bullettrain_front:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":train2:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":metro:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":light_rail:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":station:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tram:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":monorail:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mountain_railway:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":train:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bus:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":oncoming_bus:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":trolleybus:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":minibus:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ambulance:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fire_engine:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":police_car:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":oncoming_police_car:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":taxi:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":oncoming_taxi:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":red_car:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":oncoming_automobile:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":blue_car:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pickup_truck:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":truck:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":articulated_lorry:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tractor:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":racing_car:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":motorcycle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":motor_scooter:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":manual_wheelchair:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":motorized_wheelchair:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":auto_rickshaw:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bike:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":kick_scooter:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":skateboard:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":roller_skate:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":busstop:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":motorway:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":railway_track:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":oil_drum:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fuelpump:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wheel:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":rotating_light:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":traffic_light:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":vertical_traffic_light:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":stop_sign:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":construction:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":anchor:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ring_buoy:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sailboat:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":canoe:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":speedboat:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":passenger_ship:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ferry:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":motor_boat:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ship:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":airplane:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":small_airplane:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":flight_departure:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":flight_arrival:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":parachute:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":seat:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":helicopter:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":suspension_railway:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mountain_cableway:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":aerial_tramway:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":artificial_satellite:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":rocket:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":flying_saucer:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bellhop_bell:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":luggage:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hourglass:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hourglass_flowing_sand:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":watch:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":alarm_clock:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":stopwatch:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":timer_clock:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mantelpiece_clock:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock12:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock1230:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock1:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock130:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock2:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock230:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock3:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock330:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock4:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock430:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock5:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock530:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock6:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock630:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock7:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock730:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock8:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock830:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock9:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock930:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock10:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock1030:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock11:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clock1130:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":new_moon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":waxing_crescent_moon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":first_quarter_moon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":waxing_gibbous_moon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":full_moon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":waning_gibbous_moon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":last_quarter_moon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":waning_crescent_moon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":crescent_moon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":new_moon_with_face:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":first_quarter_moon_with_face:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":last_quarter_moon_with_face:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":thermometer:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sunny:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":full_moon_with_face:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sun_with_face:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ringer_planet:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":star:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":star2:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":stars:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":milky_way:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cloud:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":partly_sunny:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cloud_with_lightning_and_rain:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sun_behind_small_cloud:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sun_behind_large_cloud:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sun_behind_rain_cloud:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cloud_with_rain:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cloud_with_snow:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cloud_with_lightning:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tornado:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fog:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wind_face:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cyclone:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":rainbow:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":closed_umbrella:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":open_umbrella:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":umbrella:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":parasol_on_ground:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":zap:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":snowflake:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":snowman_with_snow:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":snowman:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":comet:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fire:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":droplet:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ocean:" (hash lazy=true tabIndex="0")}}
@@ -1059,92 +1059,92 @@ {{i18n "emoji_picker.activities"}}
- {{replace-emoji ":jack_o_lantern:" (hash lazy=true)}} - {{replace-emoji ":christmas_tree:" (hash lazy=true)}} - {{replace-emoji ":fireworks:" (hash lazy=true)}} - {{replace-emoji ":sparkler:" (hash lazy=true)}} - {{replace-emoji ":firecracker:" (hash lazy=true)}} - {{replace-emoji ":sparkles:" (hash lazy=true)}} - {{replace-emoji ":balloon:" (hash lazy=true)}} - {{replace-emoji ":tada:" (hash lazy=true)}} - {{replace-emoji ":confetti_ball:" (hash lazy=true)}} - {{replace-emoji ":tanabata_tree:" (hash lazy=true)}} - {{replace-emoji ":bamboo:" (hash lazy=true)}} - {{replace-emoji ":dolls:" (hash lazy=true)}} - {{replace-emoji ":flags:" (hash lazy=true)}} - {{replace-emoji ":wind_chime:" (hash lazy=true)}} - {{replace-emoji ":rice_scene:" (hash lazy=true)}} - {{replace-emoji ":red_gift_envelope:" (hash lazy=true)}} - {{replace-emoji ":ribbon:" (hash lazy=true)}} - {{replace-emoji ":gift:" (hash lazy=true)}} - {{replace-emoji ":reminder_ribbon:" (hash lazy=true)}} - {{replace-emoji ":tickets:" (hash lazy=true)}} - {{replace-emoji ":ticket:" (hash lazy=true)}} - {{replace-emoji ":medal_military:" (hash lazy=true)}} - {{replace-emoji ":trophy:" (hash lazy=true)}} - {{replace-emoji ":medal_sports:" (hash lazy=true)}} - {{replace-emoji ":1st_place_medal:" (hash lazy=true)}} - {{replace-emoji ":2nd_place_medal:" (hash lazy=true)}} - {{replace-emoji ":3rd_place_medal:" (hash lazy=true)}} - {{replace-emoji ":soccer:" (hash lazy=true)}} - {{replace-emoji ":baseball:" (hash lazy=true)}} - {{replace-emoji ":softball:" (hash lazy=true)}} - {{replace-emoji ":basketball:" (hash lazy=true)}} - {{replace-emoji ":volleyball:" (hash lazy=true)}} - {{replace-emoji ":football:" (hash lazy=true)}} - {{replace-emoji ":rugby_football:" (hash lazy=true)}} - {{replace-emoji ":tennis:" (hash lazy=true)}} - {{replace-emoji ":flying_disc:" (hash lazy=true)}} - {{replace-emoji ":bowling:" (hash lazy=true)}} - {{replace-emoji ":cricket_bat_and_ball:" (hash lazy=true)}} - {{replace-emoji ":field_hockey:" (hash lazy=true)}} - {{replace-emoji ":ice_hockey:" (hash lazy=true)}} - {{replace-emoji ":lacrosse:" (hash lazy=true)}} - {{replace-emoji ":ping_pong:" (hash lazy=true)}} - {{replace-emoji ":badminton:" (hash lazy=true)}} - {{replace-emoji ":boxing_glove:" (hash lazy=true)}} - {{replace-emoji ":martial_arts_uniform:" (hash lazy=true)}} - {{replace-emoji ":goal_net:" (hash lazy=true)}} - {{replace-emoji ":golf:" (hash lazy=true)}} - {{replace-emoji ":ice_skate:" (hash lazy=true)}} - {{replace-emoji ":fishing_pole_and_fish:" (hash lazy=true)}} - {{replace-emoji ":diving_mask:" (hash lazy=true)}} - {{replace-emoji ":running_shirt_with_sash:" (hash lazy=true)}} - {{replace-emoji ":ski:" (hash lazy=true)}} - {{replace-emoji ":sled:" (hash lazy=true)}} - {{replace-emoji ":curling_stone:" (hash lazy=true)}} - {{replace-emoji ":dart:" (hash lazy=true)}} - {{replace-emoji ":yo-yo:" (hash lazy=true)}} - {{replace-emoji ":kite:" (hash lazy=true)}} - {{replace-emoji ":8ball:" (hash lazy=true)}} - {{replace-emoji ":crystal_ball:" (hash lazy=true)}} - {{replace-emoji ":magic_wand:" (hash lazy=true)}} - {{replace-emoji ":nazar_amulet:" (hash lazy=true)}} - {{replace-emoji ":hamsa:" (hash lazy=true)}} - {{replace-emoji ":video_game:" (hash lazy=true)}} - {{replace-emoji ":joystick:" (hash lazy=true)}} - {{replace-emoji ":slot_machine:" (hash lazy=true)}} - {{replace-emoji ":game_die:" (hash lazy=true)}} - {{replace-emoji ":jigsaw:" (hash lazy=true)}} - {{replace-emoji ":teddy_bear:" (hash lazy=true)}} - {{replace-emoji ":piñata:" (hash lazy=true)}} - {{replace-emoji ":mirror_ball:" (hash lazy=true)}} - {{replace-emoji ":nesting_dolls:" (hash lazy=true)}} - {{replace-emoji ":spades:" (hash lazy=true)}} - {{replace-emoji ":hearts:" (hash lazy=true)}} - {{replace-emoji ":diamonds:" (hash lazy=true)}} - {{replace-emoji ":clubs:" (hash lazy=true)}} - {{replace-emoji ":chess_pawn:" (hash lazy=true)}} - {{replace-emoji ":black_joker:" (hash lazy=true)}} - {{replace-emoji ":mahjong:" (hash lazy=true)}} - {{replace-emoji ":flower_playing_cards:" (hash lazy=true)}} - {{replace-emoji ":performing_arts:" (hash lazy=true)}} - {{replace-emoji ":framed_picture:" (hash lazy=true)}} - {{replace-emoji ":art:" (hash lazy=true)}} - {{replace-emoji ":thread:" (hash lazy=true)}} - {{replace-emoji ":sewing_needle:" (hash lazy=true)}} - {{replace-emoji ":yarn:" (hash lazy=true)}} - {{replace-emoji ":knot:" (hash lazy=true)}} + {{replace-emoji ":jack_o_lantern:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":christmas_tree:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fireworks:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sparkler:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":firecracker:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sparkles:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":balloon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tada:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":confetti_ball:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tanabata_tree:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bamboo:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":dolls:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":flags:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wind_chime:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":rice_scene:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":red_gift_envelope:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ribbon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":gift:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":reminder_ribbon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tickets:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ticket:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":medal_military:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":trophy:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":medal_sports:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":1st_place_medal:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":2nd_place_medal:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":3rd_place_medal:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":soccer:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":baseball:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":softball:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":basketball:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":volleyball:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":football:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":rugby_football:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tennis:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":flying_disc:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bowling:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cricket_bat_and_ball:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":field_hockey:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ice_hockey:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":lacrosse:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ping_pong:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":badminton:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":boxing_glove:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":martial_arts_uniform:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":goal_net:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":golf:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ice_skate:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fishing_pole_and_fish:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":diving_mask:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":running_shirt_with_sash:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ski:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sled:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":curling_stone:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":dart:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":yo-yo:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":kite:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":8ball:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":crystal_ball:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":magic_wand:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":nazar_amulet:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hamsa:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":video_game:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":joystick:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":slot_machine:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":game_die:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":jigsaw:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":teddy_bear:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":piñata:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mirror_ball:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":nesting_dolls:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":spades:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hearts:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":diamonds:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clubs:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":chess_pawn:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":black_joker:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mahjong:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":flower_playing_cards:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":performing_arts:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":framed_picture:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":art:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":thread:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sewing_needle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":yarn:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":knot:" (hash lazy=true tabIndex="0")}}
@@ -1152,261 +1152,261 @@ {{i18n "emoji_picker.objects"}}
- {{replace-emoji ":eyeglasses:" (hash lazy=true)}} - {{replace-emoji ":dark_sunglasses:" (hash lazy=true)}} - {{replace-emoji ":goggles:" (hash lazy=true)}} - {{replace-emoji ":lab_coat:" (hash lazy=true)}} - {{replace-emoji ":safety_vest:" (hash lazy=true)}} - {{replace-emoji ":necktie:" (hash lazy=true)}} - {{replace-emoji ":tshirt:" (hash lazy=true)}} - {{replace-emoji ":jeans:" (hash lazy=true)}} - {{replace-emoji ":scarf:" (hash lazy=true)}} - {{replace-emoji ":gloves:" (hash lazy=true)}} - {{replace-emoji ":coat:" (hash lazy=true)}} - {{replace-emoji ":socks:" (hash lazy=true)}} - {{replace-emoji ":dress:" (hash lazy=true)}} - {{replace-emoji ":kimono:" (hash lazy=true)}} - {{replace-emoji ":sari:" (hash lazy=true)}} - {{replace-emoji ":one_piece_swimsuit:" (hash lazy=true)}} - {{replace-emoji ":briefs:" (hash lazy=true)}} - {{replace-emoji ":shorts:" (hash lazy=true)}} - {{replace-emoji ":bikini:" (hash lazy=true)}} - {{replace-emoji ":womans_clothes:" (hash lazy=true)}} - {{replace-emoji ":purse:" (hash lazy=true)}} - {{replace-emoji ":handbag:" (hash lazy=true)}} - {{replace-emoji ":pouch:" (hash lazy=true)}} - {{replace-emoji ":shopping:" (hash lazy=true)}} - {{replace-emoji ":school_satchel:" (hash lazy=true)}} - {{replace-emoji ":thong_sandal:" (hash lazy=true)}} - {{replace-emoji ":mans_shoe:" (hash lazy=true)}} - {{replace-emoji ":athletic_shoe:" (hash lazy=true)}} - {{replace-emoji ":hiking_boot:" (hash lazy=true)}} - {{replace-emoji ":flat_shoe:" (hash lazy=true)}} - {{replace-emoji ":high_heel:" (hash lazy=true)}} - {{replace-emoji ":sandal:" (hash lazy=true)}} - {{replace-emoji ":ballet_shoes:" (hash lazy=true)}} - {{replace-emoji ":boot:" (hash lazy=true)}} - {{replace-emoji ":crown:" (hash lazy=true)}} - {{replace-emoji ":womans_hat:" (hash lazy=true)}} - {{replace-emoji ":tophat:" (hash lazy=true)}} - {{replace-emoji ":mortar_board:" (hash lazy=true)}} - {{replace-emoji ":billed_cap:" (hash lazy=true)}} - {{replace-emoji ":military_helmet:" (hash lazy=true)}} - {{replace-emoji ":rescue_worker_helmet:" (hash lazy=true)}} - {{replace-emoji ":prayer_beads:" (hash lazy=true)}} - {{replace-emoji ":lipstick:" (hash lazy=true)}} - {{replace-emoji ":ring:" (hash lazy=true)}} - {{replace-emoji ":gem:" (hash lazy=true)}} - {{replace-emoji ":mute:" (hash lazy=true)}} - {{replace-emoji ":speaker:" (hash lazy=true)}} - {{replace-emoji ":sound:" (hash lazy=true)}} - {{replace-emoji ":loud_sound:" (hash lazy=true)}} - {{replace-emoji ":loudspeaker:" (hash lazy=true)}} - {{replace-emoji ":mega:" (hash lazy=true)}} - {{replace-emoji ":postal_horn:" (hash lazy=true)}} - {{replace-emoji ":bell:" (hash lazy=true)}} - {{replace-emoji ":no_bell:" (hash lazy=true)}} - {{replace-emoji ":musical_score:" (hash lazy=true)}} - {{replace-emoji ":musical_note:" (hash lazy=true)}} - {{replace-emoji ":notes:" (hash lazy=true)}} - {{replace-emoji ":studio_microphone:" (hash lazy=true)}} - {{replace-emoji ":level_slider:" (hash lazy=true)}} - {{replace-emoji ":control_knobs:" (hash lazy=true)}} - {{replace-emoji ":microphone:" (hash lazy=true)}} - {{replace-emoji ":headphones:" (hash lazy=true)}} - {{replace-emoji ":radio:" (hash lazy=true)}} - {{replace-emoji ":saxophone:" (hash lazy=true)}} - {{replace-emoji ":accordion:" (hash lazy=true)}} - {{replace-emoji ":guitar:" (hash lazy=true)}} - {{replace-emoji ":musical_keyboard:" (hash lazy=true)}} - {{replace-emoji ":trumpet:" (hash lazy=true)}} - {{replace-emoji ":violin:" (hash lazy=true)}} - {{replace-emoji ":banjo:" (hash lazy=true)}} - {{replace-emoji ":drum:" (hash lazy=true)}} - {{replace-emoji ":long_drum:" (hash lazy=true)}} - {{replace-emoji ":iphone:" (hash lazy=true)}} - {{replace-emoji ":calling:" (hash lazy=true)}} - {{replace-emoji ":phone:" (hash lazy=true)}} - {{replace-emoji ":telephone_receiver:" (hash lazy=true)}} - {{replace-emoji ":pager:" (hash lazy=true)}} - {{replace-emoji ":fax:" (hash lazy=true)}} - {{replace-emoji ":battery:" (hash lazy=true)}} - {{replace-emoji ":low_battery:" (hash lazy=true)}} - {{replace-emoji ":electric_plug:" (hash lazy=true)}} - {{replace-emoji ":computer:" (hash lazy=true)}} - {{replace-emoji ":desktop_computer:" (hash lazy=true)}} - {{replace-emoji ":printer:" (hash lazy=true)}} - {{replace-emoji ":keyboard:" (hash lazy=true)}} - {{replace-emoji ":computer_mouse:" (hash lazy=true)}} - {{replace-emoji ":trackball:" (hash lazy=true)}} - {{replace-emoji ":minidisc:" (hash lazy=true)}} - {{replace-emoji ":floppy_disk:" (hash lazy=true)}} - {{replace-emoji ":cd:" (hash lazy=true)}} - {{replace-emoji ":dvd:" (hash lazy=true)}} - {{replace-emoji ":abacus:" (hash lazy=true)}} - {{replace-emoji ":movie_camera:" (hash lazy=true)}} - {{replace-emoji ":film_strip:" (hash lazy=true)}} - {{replace-emoji ":film_projector:" (hash lazy=true)}} - {{replace-emoji ":clapper:" (hash lazy=true)}} - {{replace-emoji ":tv:" (hash lazy=true)}} - {{replace-emoji ":camera:" (hash lazy=true)}} - {{replace-emoji ":camera_flash:" (hash lazy=true)}} - {{replace-emoji ":video_camera:" (hash lazy=true)}} - {{replace-emoji ":vhs:" (hash lazy=true)}} - {{replace-emoji ":mag:" (hash lazy=true)}} - {{replace-emoji ":mag_right:" (hash lazy=true)}} - {{replace-emoji ":candle:" (hash lazy=true)}} - {{replace-emoji ":bulb:" (hash lazy=true)}} - {{replace-emoji ":flashlight:" (hash lazy=true)}} - {{replace-emoji ":izakaya_lantern:" (hash lazy=true)}} - {{replace-emoji ":diya_lamp:" (hash lazy=true)}} - {{replace-emoji ":notebook_with_decorative_cover:" (hash lazy=true)}} - {{replace-emoji ":closed_book:" (hash lazy=true)}} - {{replace-emoji ":open_book:" (hash lazy=true)}} - {{replace-emoji ":green_book:" (hash lazy=true)}} - {{replace-emoji ":blue_book:" (hash lazy=true)}} - {{replace-emoji ":orange_book:" (hash lazy=true)}} - {{replace-emoji ":books:" (hash lazy=true)}} - {{replace-emoji ":notebook:" (hash lazy=true)}} - {{replace-emoji ":ledger:" (hash lazy=true)}} - {{replace-emoji ":page_with_curl:" (hash lazy=true)}} - {{replace-emoji ":scroll:" (hash lazy=true)}} - {{replace-emoji ":page_facing_up:" (hash lazy=true)}} - {{replace-emoji ":newspaper:" (hash lazy=true)}} - {{replace-emoji ":newspaper_roll:" (hash lazy=true)}} - {{replace-emoji ":bookmark_tabs:" (hash lazy=true)}} - {{replace-emoji ":bookmark:" (hash lazy=true)}} - {{replace-emoji ":label:" (hash lazy=true)}} - {{replace-emoji ":moneybag:" (hash lazy=true)}} - {{replace-emoji ":coin:" (hash lazy=true)}} - {{replace-emoji ":yen:" (hash lazy=true)}} - {{replace-emoji ":dollar:" (hash lazy=true)}} - {{replace-emoji ":euro:" (hash lazy=true)}} - {{replace-emoji ":pound:" (hash lazy=true)}} - {{replace-emoji ":money_with_wings:" (hash lazy=true)}} - {{replace-emoji ":credit_card:" (hash lazy=true)}} - {{replace-emoji ":receipt:" (hash lazy=true)}} - {{replace-emoji ":chart:" (hash lazy=true)}} - {{replace-emoji ":email:" (hash lazy=true)}} - {{replace-emoji ":e-mail:" (hash lazy=true)}} - {{replace-emoji ":incoming_envelope:" (hash lazy=true)}} - {{replace-emoji ":envelope_with_arrow:" (hash lazy=true)}} - {{replace-emoji ":outbox_tray:" (hash lazy=true)}} - {{replace-emoji ":inbox_tray:" (hash lazy=true)}} - {{replace-emoji ":package:" (hash lazy=true)}} - {{replace-emoji ":mailbox:" (hash lazy=true)}} - {{replace-emoji ":mailbox_closed:" (hash lazy=true)}} - {{replace-emoji ":mailbox_with_mail:" (hash lazy=true)}} - {{replace-emoji ":mailbox_with_no_mail:" (hash lazy=true)}} - {{replace-emoji ":postbox:" (hash lazy=true)}} - {{replace-emoji ":ballot_box:" (hash lazy=true)}} - {{replace-emoji ":pencil2:" (hash lazy=true)}} - {{replace-emoji ":black_nib:" (hash lazy=true)}} - {{replace-emoji ":fountain_pen:" (hash lazy=true)}} - {{replace-emoji ":pen:" (hash lazy=true)}} - {{replace-emoji ":paintbrush:" (hash lazy=true)}} - {{replace-emoji ":crayon:" (hash lazy=true)}} - {{replace-emoji ":memo:" (hash lazy=true)}} - {{replace-emoji ":briefcase:" (hash lazy=true)}} - {{replace-emoji ":file_folder:" (hash lazy=true)}} - {{replace-emoji ":open_file_folder:" (hash lazy=true)}} - {{replace-emoji ":card_index_dividers:" (hash lazy=true)}} - {{replace-emoji ":date:" (hash lazy=true)}} - {{replace-emoji ":calendar:" (hash lazy=true)}} - {{replace-emoji ":spiral_notepad:" (hash lazy=true)}} - {{replace-emoji ":spiral_calendar:" (hash lazy=true)}} - {{replace-emoji ":card_index:" (hash lazy=true)}} - {{replace-emoji ":chart_with_upwards_trend:" (hash lazy=true)}} - {{replace-emoji ":chart_with_downwards_trend:" (hash lazy=true)}} - {{replace-emoji ":bar_chart:" (hash lazy=true)}} - {{replace-emoji ":clipboard:" (hash lazy=true)}} - {{replace-emoji ":pushpin:" (hash lazy=true)}} - {{replace-emoji ":round_pushpin:" (hash lazy=true)}} - {{replace-emoji ":paperclip:" (hash lazy=true)}} - {{replace-emoji ":paperclips:" (hash lazy=true)}} - {{replace-emoji ":straight_ruler:" (hash lazy=true)}} - {{replace-emoji ":triangular_ruler:" (hash lazy=true)}} - {{replace-emoji ":scissors:" (hash lazy=true)}} - {{replace-emoji ":card_file_box:" (hash lazy=true)}} - {{replace-emoji ":file_cabinet:" (hash lazy=true)}} - {{replace-emoji ":wastebasket:" (hash lazy=true)}} - {{replace-emoji ":lock:" (hash lazy=true)}} - {{replace-emoji ":unlock:" (hash lazy=true)}} - {{replace-emoji ":lock_with_ink_pen:" (hash lazy=true)}} - {{replace-emoji ":closed_lock_with_key:" (hash lazy=true)}} - {{replace-emoji ":key:" (hash lazy=true)}} - {{replace-emoji ":old_key:" (hash lazy=true)}} - {{replace-emoji ":hammer:" (hash lazy=true)}} - {{replace-emoji ":axe:" (hash lazy=true)}} - {{replace-emoji ":pick:" (hash lazy=true)}} - {{replace-emoji ":hammer_and_pick:" (hash lazy=true)}} - {{replace-emoji ":hammer_and_wrench:" (hash lazy=true)}} - {{replace-emoji ":dagger:" (hash lazy=true)}} - {{replace-emoji ":crossed_swords:" (hash lazy=true)}} - {{replace-emoji ":gun:" (hash lazy=true)}} - {{replace-emoji ":boomerang:" (hash lazy=true)}} - {{replace-emoji ":bow_and_arrow:" (hash lazy=true)}} - {{replace-emoji ":shield:" (hash lazy=true)}} - {{replace-emoji ":carpentry_saw:" (hash lazy=true)}} - {{replace-emoji ":wrench:" (hash lazy=true)}} - {{replace-emoji ":screwdriver:" (hash lazy=true)}} - {{replace-emoji ":nut_and_bolt:" (hash lazy=true)}} - {{replace-emoji ":gear:" (hash lazy=true)}} - {{replace-emoji ":clamp:" (hash lazy=true)}} - {{replace-emoji ":balance_scale:" (hash lazy=true)}} - {{replace-emoji ":probing_cane:" (hash lazy=true)}} - {{replace-emoji ":link:" (hash lazy=true)}} - {{replace-emoji ":chains:" (hash lazy=true)}} - {{replace-emoji ":hook:" (hash lazy=true)}} - {{replace-emoji ":toolbox:" (hash lazy=true)}} - {{replace-emoji ":magnet:" (hash lazy=true)}} - {{replace-emoji ":ladder:" (hash lazy=true)}} - {{replace-emoji ":alembic:" (hash lazy=true)}} - {{replace-emoji ":test_tube:" (hash lazy=true)}} - {{replace-emoji ":petri_dish:" (hash lazy=true)}} - {{replace-emoji ":dna:" (hash lazy=true)}} - {{replace-emoji ":microscope:" (hash lazy=true)}} - {{replace-emoji ":telescope:" (hash lazy=true)}} - {{replace-emoji ":satellite:" (hash lazy=true)}} - {{replace-emoji ":syringe:" (hash lazy=true)}} - {{replace-emoji ":drop_of_blood:" (hash lazy=true)}} - {{replace-emoji ":pill:" (hash lazy=true)}} - {{replace-emoji ":adhesive_bandage:" (hash lazy=true)}} - {{replace-emoji ":crutch:" (hash lazy=true)}} - {{replace-emoji ":stethoscope:" (hash lazy=true)}} - {{replace-emoji ":xray:" (hash lazy=true)}} - {{replace-emoji ":door:" (hash lazy=true)}} - {{replace-emoji ":elevator:" (hash lazy=true)}} - {{replace-emoji ":mirror:" (hash lazy=true)}} - {{replace-emoji ":window:" (hash lazy=true)}} - {{replace-emoji ":bed:" (hash lazy=true)}} - {{replace-emoji ":couch_and_lamp:" (hash lazy=true)}} - {{replace-emoji ":chair:" (hash lazy=true)}} - {{replace-emoji ":toilet:" (hash lazy=true)}} - {{replace-emoji ":plunger:" (hash lazy=true)}} - {{replace-emoji ":shower:" (hash lazy=true)}} - {{replace-emoji ":bathtub:" (hash lazy=true)}} - {{replace-emoji ":mouse_trap:" (hash lazy=true)}} - {{replace-emoji ":razor:" (hash lazy=true)}} - {{replace-emoji ":lotion_bottle:" (hash lazy=true)}} - {{replace-emoji ":safety_pin:" (hash lazy=true)}} - {{replace-emoji ":broom:" (hash lazy=true)}} - {{replace-emoji ":basket:" (hash lazy=true)}} - {{replace-emoji ":roll_of_toilet_paper:" (hash lazy=true)}} - {{replace-emoji ":bucket:" (hash lazy=true)}} - {{replace-emoji ":soap:" (hash lazy=true)}} - {{replace-emoji ":bubbles:" (hash lazy=true)}} - {{replace-emoji ":toothbrush:" (hash lazy=true)}} - {{replace-emoji ":sponge:" (hash lazy=true)}} - {{replace-emoji ":fire_extinguisher:" (hash lazy=true)}} - {{replace-emoji ":shopping_cart:" (hash lazy=true)}} - {{replace-emoji ":smoking:" (hash lazy=true)}} - {{replace-emoji ":coffin:" (hash lazy=true)}} - {{replace-emoji ":headstone:" (hash lazy=true)}} - {{replace-emoji ":funeral_urn:" (hash lazy=true)}} - {{replace-emoji ":moyai:" (hash lazy=true)}} - {{replace-emoji ":placard:" (hash lazy=true)}} - {{replace-emoji ":identification_card:" (hash lazy=true)}} + {{replace-emoji ":eyeglasses:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":dark_sunglasses:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":goggles:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":lab_coat:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":safety_vest:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":necktie:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tshirt:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":jeans:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":scarf:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":gloves:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":coat:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":socks:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":dress:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":kimono:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sari:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":one_piece_swimsuit:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":briefs:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":shorts:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bikini:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":womans_clothes:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":purse:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":handbag:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pouch:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":shopping:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":school_satchel:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":thong_sandal:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mans_shoe:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":athletic_shoe:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hiking_boot:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":flat_shoe:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":high_heel:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sandal:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ballet_shoes:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":boot:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":crown:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":womans_hat:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tophat:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mortar_board:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":billed_cap:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":military_helmet:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":rescue_worker_helmet:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":prayer_beads:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":lipstick:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ring:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":gem:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mute:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":speaker:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sound:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":loud_sound:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":loudspeaker:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mega:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":postal_horn:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bell:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":no_bell:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":musical_score:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":musical_note:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":notes:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":studio_microphone:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":level_slider:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":control_knobs:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":microphone:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":headphones:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":radio:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":saxophone:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":accordion:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":guitar:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":musical_keyboard:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":trumpet:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":violin:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":banjo:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":drum:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":long_drum:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":iphone:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":calling:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":phone:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":telephone_receiver:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pager:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fax:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":battery:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":low_battery:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":electric_plug:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":computer:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":desktop_computer:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":printer:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":keyboard:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":computer_mouse:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":trackball:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":minidisc:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":floppy_disk:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cd:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":dvd:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":abacus:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":movie_camera:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":film_strip:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":film_projector:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clapper:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tv:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":camera:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":camera_flash:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":video_camera:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":vhs:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mag:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mag_right:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":candle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bulb:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":flashlight:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":izakaya_lantern:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":diya_lamp:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":notebook_with_decorative_cover:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":closed_book:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":open_book:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":green_book:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":blue_book:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":orange_book:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":books:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":notebook:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ledger:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":page_with_curl:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":scroll:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":page_facing_up:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":newspaper:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":newspaper_roll:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bookmark_tabs:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bookmark:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":label:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":moneybag:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":coin:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":yen:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":dollar:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":euro:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pound:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":money_with_wings:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":credit_card:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":receipt:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":chart:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":email:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":e-mail:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":incoming_envelope:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":envelope_with_arrow:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":outbox_tray:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":inbox_tray:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":package:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mailbox:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mailbox_closed:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mailbox_with_mail:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mailbox_with_no_mail:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":postbox:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ballot_box:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pencil2:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":black_nib:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fountain_pen:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pen:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":paintbrush:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":crayon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":memo:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":briefcase:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":file_folder:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":open_file_folder:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":card_index_dividers:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":date:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":calendar:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":spiral_notepad:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":spiral_calendar:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":card_index:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":chart_with_upwards_trend:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":chart_with_downwards_trend:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bar_chart:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clipboard:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pushpin:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":round_pushpin:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":paperclip:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":paperclips:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":straight_ruler:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":triangular_ruler:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":scissors:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":card_file_box:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":file_cabinet:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wastebasket:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":lock:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":unlock:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":lock_with_ink_pen:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":closed_lock_with_key:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":key:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":old_key:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hammer:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":axe:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pick:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hammer_and_pick:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hammer_and_wrench:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":dagger:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":crossed_swords:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":gun:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":boomerang:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bow_and_arrow:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":shield:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":carpentry_saw:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wrench:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":screwdriver:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":nut_and_bolt:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":gear:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clamp:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":balance_scale:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":probing_cane:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":link:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":chains:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hook:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":toolbox:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":magnet:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ladder:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":alembic:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":test_tube:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":petri_dish:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":dna:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":microscope:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":telescope:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":satellite:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":syringe:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":drop_of_blood:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pill:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":adhesive_bandage:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":crutch:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":stethoscope:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":xray:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":door:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":elevator:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mirror:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":window:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bed:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":couch_and_lamp:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":chair:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":toilet:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":plunger:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":shower:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bathtub:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mouse_trap:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":razor:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":lotion_bottle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":safety_pin:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":broom:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":basket:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":roll_of_toilet_paper:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bucket:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":soap:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bubbles:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":toothbrush:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sponge:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fire_extinguisher:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":shopping_cart:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":smoking:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":coffin:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":headstone:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":funeral_urn:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":moyai:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":placard:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":identification_card:" (hash lazy=true tabIndex="0")}}
@@ -1414,227 +1414,227 @@ {{i18n "emoji_picker.symbols"}}
- {{replace-emoji ":atm:" (hash lazy=true)}} - {{replace-emoji ":put_litter_in_its_place:" (hash lazy=true)}} - {{replace-emoji ":potable_water:" (hash lazy=true)}} - {{replace-emoji ":wheelchair:" (hash lazy=true)}} - {{replace-emoji ":mens:" (hash lazy=true)}} - {{replace-emoji ":womens:" (hash lazy=true)}} - {{replace-emoji ":restroom:" (hash lazy=true)}} - {{replace-emoji ":baby_symbol:" (hash lazy=true)}} - {{replace-emoji ":wc:" (hash lazy=true)}} - {{replace-emoji ":passport_control:" (hash lazy=true)}} - {{replace-emoji ":customs:" (hash lazy=true)}} - {{replace-emoji ":baggage_claim:" (hash lazy=true)}} - {{replace-emoji ":left_luggage:" (hash lazy=true)}} - {{replace-emoji ":warning:" (hash lazy=true)}} - {{replace-emoji ":children_crossing:" (hash lazy=true)}} - {{replace-emoji ":no_entry:" (hash lazy=true)}} - {{replace-emoji ":no_entry_sign:" (hash lazy=true)}} - {{replace-emoji ":no_bicycles:" (hash lazy=true)}} - {{replace-emoji ":no_smoking:" (hash lazy=true)}} - {{replace-emoji ":do_not_litter:" (hash lazy=true)}} - {{replace-emoji ":non-potable_water:" (hash lazy=true)}} - {{replace-emoji ":no_pedestrians:" (hash lazy=true)}} - {{replace-emoji ":no_mobile_phones:" (hash lazy=true)}} - {{replace-emoji ":underage:" (hash lazy=true)}} - {{replace-emoji ":radioactive:" (hash lazy=true)}} - {{replace-emoji ":biohazard:" (hash lazy=true)}} - {{replace-emoji ":arrow_up:" (hash lazy=true)}} - {{replace-emoji ":arrow_upper_right:" (hash lazy=true)}} - {{replace-emoji ":arrow_right:" (hash lazy=true)}} - {{replace-emoji ":arrow_lower_right:" (hash lazy=true)}} - {{replace-emoji ":arrow_down:" (hash lazy=true)}} - {{replace-emoji ":arrow_lower_left:" (hash lazy=true)}} - {{replace-emoji ":arrow_left:" (hash lazy=true)}} - {{replace-emoji ":arrow_upper_left:" (hash lazy=true)}} - {{replace-emoji ":arrow_up_down:" (hash lazy=true)}} - {{replace-emoji ":left_right_arrow:" (hash lazy=true)}} - {{replace-emoji ":leftwards_arrow_with_hook:" (hash lazy=true)}} - {{replace-emoji ":arrow_right_hook:" (hash lazy=true)}} - {{replace-emoji ":arrow_heading_up:" (hash lazy=true)}} - {{replace-emoji ":arrow_heading_down:" (hash lazy=true)}} - {{replace-emoji ":arrows_clockwise:" (hash lazy=true)}} - {{replace-emoji ":arrows_counterclockwise:" (hash lazy=true)}} - {{replace-emoji ":back:" (hash lazy=true)}} - {{replace-emoji ":end:" (hash lazy=true)}} - {{replace-emoji ":on:" (hash lazy=true)}} - {{replace-emoji ":soon:" (hash lazy=true)}} - {{replace-emoji ":top:" (hash lazy=true)}} - {{replace-emoji ":place_of_worship:" (hash lazy=true)}} - {{replace-emoji ":atom_symbol:" (hash lazy=true)}} - {{replace-emoji ":om:" (hash lazy=true)}} - {{replace-emoji ":star_of_david:" (hash lazy=true)}} - {{replace-emoji ":wheel_of_dharma:" (hash lazy=true)}} - {{replace-emoji ":yin_yang:" (hash lazy=true)}} - {{replace-emoji ":latin_cross:" (hash lazy=true)}} - {{replace-emoji ":orthodox_cross:" (hash lazy=true)}} - {{replace-emoji ":star_and_crescent:" (hash lazy=true)}} - {{replace-emoji ":peace_symbol:" (hash lazy=true)}} - {{replace-emoji ":menorah:" (hash lazy=true)}} - {{replace-emoji ":six_pointed_star:" (hash lazy=true)}} - {{replace-emoji ":aries:" (hash lazy=true)}} - {{replace-emoji ":taurus:" (hash lazy=true)}} - {{replace-emoji ":gemini:" (hash lazy=true)}} - {{replace-emoji ":cancer:" (hash lazy=true)}} - {{replace-emoji ":leo:" (hash lazy=true)}} - {{replace-emoji ":virgo:" (hash lazy=true)}} - {{replace-emoji ":libra:" (hash lazy=true)}} - {{replace-emoji ":scorpius:" (hash lazy=true)}} - {{replace-emoji ":sagittarius:" (hash lazy=true)}} - {{replace-emoji ":capricorn:" (hash lazy=true)}} - {{replace-emoji ":aquarius:" (hash lazy=true)}} - {{replace-emoji ":pisces:" (hash lazy=true)}} - {{replace-emoji ":ophiuchus:" (hash lazy=true)}} - {{replace-emoji ":twisted_rightwards_arrows:" (hash lazy=true)}} - {{replace-emoji ":repeat:" (hash lazy=true)}} - {{replace-emoji ":repeat_one:" (hash lazy=true)}} - {{replace-emoji ":arrow_forward:" (hash lazy=true)}} - {{replace-emoji ":fast_forward:" (hash lazy=true)}} - {{replace-emoji ":next_track_button:" (hash lazy=true)}} - {{replace-emoji ":play_or_pause_button:" (hash lazy=true)}} - {{replace-emoji ":arrow_backward:" (hash lazy=true)}} - {{replace-emoji ":rewind:" (hash lazy=true)}} - {{replace-emoji ":previous_track_button:" (hash lazy=true)}} - {{replace-emoji ":arrow_up_small:" (hash lazy=true)}} - {{replace-emoji ":arrow_double_up:" (hash lazy=true)}} - {{replace-emoji ":arrow_down_small:" (hash lazy=true)}} - {{replace-emoji ":arrow_double_down:" (hash lazy=true)}} - {{replace-emoji ":pause_button:" (hash lazy=true)}} - {{replace-emoji ":stop_button:" (hash lazy=true)}} - {{replace-emoji ":record_button:" (hash lazy=true)}} - {{replace-emoji ":eject_button:" (hash lazy=true)}} - {{replace-emoji ":cinema:" (hash lazy=true)}} - {{replace-emoji ":low_brightness:" (hash lazy=true)}} - {{replace-emoji ":high_brightness:" (hash lazy=true)}} - {{replace-emoji ":signal_strength:" (hash lazy=true)}} - {{replace-emoji ":vibration_mode:" (hash lazy=true)}} - {{replace-emoji ":mobile_phone_off:" (hash lazy=true)}} - {{replace-emoji ":female_sign:" (hash lazy=true)}} - {{replace-emoji ":male_sign:" (hash lazy=true)}} - {{replace-emoji ":transgender_symbol:" (hash lazy=true)}} - {{replace-emoji ":heavy_multiplication_x:" (hash lazy=true)}} - {{replace-emoji ":heavy_plus_sign:" (hash lazy=true)}} - {{replace-emoji ":heavy_minus_sign:" (hash lazy=true)}} - {{replace-emoji ":heavy_division_sign:" (hash lazy=true)}} - {{replace-emoji ":heavy_equals_sign:" (hash lazy=true)}} - {{replace-emoji ":infinity:" (hash lazy=true)}} - {{replace-emoji ":bangbang:" (hash lazy=true)}} - {{replace-emoji ":interrobang:" (hash lazy=true)}} - {{replace-emoji ":question:" (hash lazy=true)}} - {{replace-emoji ":grey_question:" (hash lazy=true)}} - {{replace-emoji ":grey_exclamation:" (hash lazy=true)}} - {{replace-emoji ":exclamation:" (hash lazy=true)}} - {{replace-emoji ":wavy_dash:" (hash lazy=true)}} - {{replace-emoji ":currency_exchange:" (hash lazy=true)}} - {{replace-emoji ":heavy_dollar_sign:" (hash lazy=true)}} - {{replace-emoji ":medical_symbol:" (hash lazy=true)}} - {{replace-emoji ":recycle:" (hash lazy=true)}} - {{replace-emoji ":fleur_de_lis:" (hash lazy=true)}} - {{replace-emoji ":trident:" (hash lazy=true)}} - {{replace-emoji ":name_badge:" (hash lazy=true)}} - {{replace-emoji ":beginner:" (hash lazy=true)}} - {{replace-emoji ":o:" (hash lazy=true)}} - {{replace-emoji ":white_check_mark:" (hash lazy=true)}} - {{replace-emoji ":ballot_box_with_check:" (hash lazy=true)}} - {{replace-emoji ":heavy_check_mark:" (hash lazy=true)}} - {{replace-emoji ":x:" (hash lazy=true)}} - {{replace-emoji ":negative_squared_cross_mark:" (hash lazy=true)}} - {{replace-emoji ":curly_loop:" (hash lazy=true)}} - {{replace-emoji ":loop:" (hash lazy=true)}} - {{replace-emoji ":part_alternation_mark:" (hash lazy=true)}} - {{replace-emoji ":eight_spoked_asterisk:" (hash lazy=true)}} - {{replace-emoji ":eight_pointed_black_star:" (hash lazy=true)}} - {{replace-emoji ":sparkle:" (hash lazy=true)}} - {{replace-emoji ":copyright:" (hash lazy=true)}} - {{replace-emoji ":registered:" (hash lazy=true)}} - {{replace-emoji ":tm:" (hash lazy=true)}} - {{replace-emoji ":hash:" (hash lazy=true)}} - {{replace-emoji ":asterisk:" (hash lazy=true)}} - {{replace-emoji ":zero:" (hash lazy=true)}} - {{replace-emoji ":one:" (hash lazy=true)}} - {{replace-emoji ":two:" (hash lazy=true)}} - {{replace-emoji ":three:" (hash lazy=true)}} - {{replace-emoji ":four:" (hash lazy=true)}} - {{replace-emoji ":five:" (hash lazy=true)}} - {{replace-emoji ":six:" (hash lazy=true)}} - {{replace-emoji ":seven:" (hash lazy=true)}} - {{replace-emoji ":eight:" (hash lazy=true)}} - {{replace-emoji ":nine:" (hash lazy=true)}} - {{replace-emoji ":keycap_ten:" (hash lazy=true)}} - {{replace-emoji ":capital_abcd:" (hash lazy=true)}} - {{replace-emoji ":abcd:" (hash lazy=true)}} - {{replace-emoji ":1234:" (hash lazy=true)}} - {{replace-emoji ":symbols:" (hash lazy=true)}} - {{replace-emoji ":abc:" (hash lazy=true)}} - {{replace-emoji ":a:" (hash lazy=true)}} - {{replace-emoji ":ab:" (hash lazy=true)}} - {{replace-emoji ":b:" (hash lazy=true)}} - {{replace-emoji ":cl:" (hash lazy=true)}} - {{replace-emoji ":cool:" (hash lazy=true)}} - {{replace-emoji ":free:" (hash lazy=true)}} - {{replace-emoji ":information_source:" (hash lazy=true)}} - {{replace-emoji ":id:" (hash lazy=true)}} - {{replace-emoji ":m:" (hash lazy=true)}} - {{replace-emoji ":new:" (hash lazy=true)}} - {{replace-emoji ":ng:" (hash lazy=true)}} - {{replace-emoji ":o2:" (hash lazy=true)}} - {{replace-emoji ":ok:" (hash lazy=true)}} - {{replace-emoji ":parking:" (hash lazy=true)}} - {{replace-emoji ":sos:" (hash lazy=true)}} - {{replace-emoji ":up:" (hash lazy=true)}} - {{replace-emoji ":vs:" (hash lazy=true)}} - {{replace-emoji ":koko:" (hash lazy=true)}} - {{replace-emoji ":sa:" (hash lazy=true)}} - {{replace-emoji ":u6708:" (hash lazy=true)}} - {{replace-emoji ":u6709:" (hash lazy=true)}} - {{replace-emoji ":u6307:" (hash lazy=true)}} - {{replace-emoji ":ideograph_advantage:" (hash lazy=true)}} - {{replace-emoji ":u5272:" (hash lazy=true)}} - {{replace-emoji ":u7121:" (hash lazy=true)}} - {{replace-emoji ":u7981:" (hash lazy=true)}} - {{replace-emoji ":accept:" (hash lazy=true)}} - {{replace-emoji ":u7533:" (hash lazy=true)}} - {{replace-emoji ":u5408:" (hash lazy=true)}} - {{replace-emoji ":u7a7a:" (hash lazy=true)}} - {{replace-emoji ":congratulations:" (hash lazy=true)}} - {{replace-emoji ":secret:" (hash lazy=true)}} - {{replace-emoji ":u55b6:" (hash lazy=true)}} - {{replace-emoji ":u6e80:" (hash lazy=true)}} - {{replace-emoji ":red_circle:" (hash lazy=true)}} - {{replace-emoji ":orange_circle:" (hash lazy=true)}} - {{replace-emoji ":yellow_circle:" (hash lazy=true)}} - {{replace-emoji ":green_circle:" (hash lazy=true)}} - {{replace-emoji ":large_blue_circle:" (hash lazy=true)}} - {{replace-emoji ":purple_circle:" (hash lazy=true)}} - {{replace-emoji ":brown_circle:" (hash lazy=true)}} - {{replace-emoji ":black_circle:" (hash lazy=true)}} - {{replace-emoji ":white_circle:" (hash lazy=true)}} - {{replace-emoji ":red_square:" (hash lazy=true)}} - {{replace-emoji ":orange_square:" (hash lazy=true)}} - {{replace-emoji ":yellow_square:" (hash lazy=true)}} - {{replace-emoji ":green_square:" (hash lazy=true)}} - {{replace-emoji ":blue_square:" (hash lazy=true)}} - {{replace-emoji ":purple_square:" (hash lazy=true)}} - {{replace-emoji ":brown_square:" (hash lazy=true)}} - {{replace-emoji ":black_large_square:" (hash lazy=true)}} - {{replace-emoji ":white_large_square:" (hash lazy=true)}} - {{replace-emoji ":black_medium_square:" (hash lazy=true)}} - {{replace-emoji ":white_medium_square:" (hash lazy=true)}} - {{replace-emoji ":black_medium_small_square:" (hash lazy=true)}} - {{replace-emoji ":white_medium_small_square:" (hash lazy=true)}} - {{replace-emoji ":black_small_square:" (hash lazy=true)}} - {{replace-emoji ":white_small_square:" (hash lazy=true)}} - {{replace-emoji ":large_orange_diamond:" (hash lazy=true)}} - {{replace-emoji ":large_blue_diamond:" (hash lazy=true)}} - {{replace-emoji ":small_orange_diamond:" (hash lazy=true)}} - {{replace-emoji ":small_blue_diamond:" (hash lazy=true)}} - {{replace-emoji ":small_red_triangle:" (hash lazy=true)}} - {{replace-emoji ":small_red_triangle_down:" (hash lazy=true)}} - {{replace-emoji ":diamond_shape_with_a_dot_inside:" (hash lazy=true)}} - {{replace-emoji ":radio_button:" (hash lazy=true)}} - {{replace-emoji ":white_square_button:" (hash lazy=true)}} - {{replace-emoji ":black_square_button:" (hash lazy=true)}} + {{replace-emoji ":atm:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":put_litter_in_its_place:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":potable_water:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wheelchair:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mens:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":womens:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":restroom:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":baby_symbol:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wc:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":passport_control:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":customs:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":baggage_claim:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":left_luggage:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":warning:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":children_crossing:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":no_entry:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":no_entry_sign:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":no_bicycles:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":no_smoking:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":do_not_litter:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":non-potable_water:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":no_pedestrians:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":no_mobile_phones:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":underage:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":radioactive:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":biohazard:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_up:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_upper_right:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_right:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_lower_right:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_down:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_lower_left:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_left:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_upper_left:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_up_down:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":left_right_arrow:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":leftwards_arrow_with_hook:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_right_hook:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_heading_up:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_heading_down:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrows_clockwise:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrows_counterclockwise:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":back:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":end:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":on:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":soon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":top:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":place_of_worship:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":atom_symbol:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":om:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":star_of_david:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wheel_of_dharma:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":yin_yang:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":latin_cross:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":orthodox_cross:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":star_and_crescent:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":peace_symbol:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":menorah:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":six_pointed_star:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":aries:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":taurus:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":gemini:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cancer:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":leo:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":virgo:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":libra:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":scorpius:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sagittarius:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":capricorn:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":aquarius:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pisces:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ophiuchus:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":twisted_rightwards_arrows:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":repeat:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":repeat_one:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_forward:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fast_forward:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":next_track_button:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":play_or_pause_button:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_backward:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":rewind:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":previous_track_button:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_up_small:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_double_up:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_down_small:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":arrow_double_down:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pause_button:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":stop_button:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":record_button:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":eject_button:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cinema:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":low_brightness:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":high_brightness:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":signal_strength:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":vibration_mode:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mobile_phone_off:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":female_sign:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":male_sign:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":transgender_symbol:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":heavy_multiplication_x:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":heavy_plus_sign:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":heavy_minus_sign:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":heavy_division_sign:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":heavy_equals_sign:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":infinity:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bangbang:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":interrobang:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":question:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":grey_question:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":grey_exclamation:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":exclamation:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wavy_dash:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":currency_exchange:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":heavy_dollar_sign:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":medical_symbol:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":recycle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fleur_de_lis:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":trident:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":name_badge:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":beginner:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":o:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":white_check_mark:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ballot_box_with_check:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":heavy_check_mark:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":x:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":negative_squared_cross_mark:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":curly_loop:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":loop:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":part_alternation_mark:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":eight_spoked_asterisk:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":eight_pointed_black_star:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sparkle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":copyright:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":registered:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tm:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hash:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":asterisk:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":zero:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":one:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":two:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":three:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":four:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":five:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":six:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":seven:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":eight:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":nine:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":keycap_ten:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":capital_abcd:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":abcd:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":1234:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":symbols:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":abc:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":a:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ab:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":b:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cl:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cool:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":free:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":information_source:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":id:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":m:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":new:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ng:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":o2:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ok:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":parking:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sos:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":up:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":vs:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":koko:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sa:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":u6708:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":u6709:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":u6307:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ideograph_advantage:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":u5272:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":u7121:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":u7981:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":accept:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":u7533:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":u5408:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":u7a7a:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":congratulations:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":secret:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":u55b6:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":u6e80:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":red_circle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":orange_circle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":yellow_circle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":green_circle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":large_blue_circle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":purple_circle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":brown_circle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":black_circle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":white_circle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":red_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":orange_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":yellow_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":green_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":blue_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":purple_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":brown_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":black_large_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":white_large_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":black_medium_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":white_medium_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":black_medium_small_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":white_medium_small_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":black_small_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":white_small_square:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":large_orange_diamond:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":large_blue_diamond:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":small_orange_diamond:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":small_blue_diamond:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":small_red_triangle:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":small_red_triangle_down:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":diamond_shape_with_a_dot_inside:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":radio_button:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":white_square_button:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":black_square_button:" (hash lazy=true tabIndex="0")}}
@@ -1642,274 +1642,274 @@ {{i18n "emoji_picker.flags"}}
- {{replace-emoji ":checkered_flag:" (hash lazy=true)}} - {{replace-emoji ":triangular_flag_on_post:" (hash lazy=true)}} - {{replace-emoji ":crossed_flags:" (hash lazy=true)}} - {{replace-emoji ":black_flag:" (hash lazy=true)}} - {{replace-emoji ":white_flag:" (hash lazy=true)}} - {{replace-emoji ":rainbow_flag:" (hash lazy=true)}} - {{replace-emoji ":transgender_flag:" (hash lazy=true)}} - {{replace-emoji ":pirate_flag:" (hash lazy=true)}} - {{replace-emoji ":ascension_island:" (hash lazy=true)}} - {{replace-emoji ":andorra:" (hash lazy=true)}} - {{replace-emoji ":united_arab_emirates:" (hash lazy=true)}} - {{replace-emoji ":afghanistan:" (hash lazy=true)}} - {{replace-emoji ":antigua_barbuda:" (hash lazy=true)}} - {{replace-emoji ":anguilla:" (hash lazy=true)}} - {{replace-emoji ":albania:" (hash lazy=true)}} - {{replace-emoji ":armenia:" (hash lazy=true)}} - {{replace-emoji ":angola:" (hash lazy=true)}} - {{replace-emoji ":antarctica:" (hash lazy=true)}} - {{replace-emoji ":argentina:" (hash lazy=true)}} - {{replace-emoji ":american_samoa:" (hash lazy=true)}} - {{replace-emoji ":austria:" (hash lazy=true)}} - {{replace-emoji ":australia:" (hash lazy=true)}} - {{replace-emoji ":aruba:" (hash lazy=true)}} - {{replace-emoji ":aland_islands:" (hash lazy=true)}} - {{replace-emoji ":azerbaijan:" (hash lazy=true)}} - {{replace-emoji ":bosnia_herzegovina:" (hash lazy=true)}} - {{replace-emoji ":barbados:" (hash lazy=true)}} - {{replace-emoji ":bangladesh:" (hash lazy=true)}} - {{replace-emoji ":belgium:" (hash lazy=true)}} - {{replace-emoji ":burkina_faso:" (hash lazy=true)}} - {{replace-emoji ":bulgaria:" (hash lazy=true)}} - {{replace-emoji ":bahrain:" (hash lazy=true)}} - {{replace-emoji ":burundi:" (hash lazy=true)}} - {{replace-emoji ":benin:" (hash lazy=true)}} - {{replace-emoji ":st_barthelemy:" (hash lazy=true)}} - {{replace-emoji ":bermuda:" (hash lazy=true)}} - {{replace-emoji ":brunei:" (hash lazy=true)}} - {{replace-emoji ":bolivia:" (hash lazy=true)}} - {{replace-emoji ":caribbean_netherlands:" (hash lazy=true)}} - {{replace-emoji ":brazil:" (hash lazy=true)}} - {{replace-emoji ":bahamas:" (hash lazy=true)}} - {{replace-emoji ":bhutan:" (hash lazy=true)}} - {{replace-emoji ":bouvet_island:" (hash lazy=true)}} - {{replace-emoji ":botswana:" (hash lazy=true)}} - {{replace-emoji ":belarus:" (hash lazy=true)}} - {{replace-emoji ":belize:" (hash lazy=true)}} - {{replace-emoji ":canada:" (hash lazy=true)}} - {{replace-emoji ":cocos_islands:" (hash lazy=true)}} - {{replace-emoji ":congo_kinshasa:" (hash lazy=true)}} - {{replace-emoji ":central_african_republic:" (hash lazy=true)}} - {{replace-emoji ":congo_brazzaville:" (hash lazy=true)}} - {{replace-emoji ":switzerland:" (hash lazy=true)}} - {{replace-emoji ":cote_divoire:" (hash lazy=true)}} - {{replace-emoji ":cook_islands:" (hash lazy=true)}} - {{replace-emoji ":chile:" (hash lazy=true)}} - {{replace-emoji ":cameroon:" (hash lazy=true)}} - {{replace-emoji ":cn:" (hash lazy=true)}} - {{replace-emoji ":colombia:" (hash lazy=true)}} - {{replace-emoji ":clipperton_island:" (hash lazy=true)}} - {{replace-emoji ":costa_rica:" (hash lazy=true)}} - {{replace-emoji ":cuba:" (hash lazy=true)}} - {{replace-emoji ":cape_verde:" (hash lazy=true)}} - {{replace-emoji ":curacao:" (hash lazy=true)}} - {{replace-emoji ":christmas_island:" (hash lazy=true)}} - {{replace-emoji ":cyprus:" (hash lazy=true)}} - {{replace-emoji ":czech_republic:" (hash lazy=true)}} - {{replace-emoji ":de:" (hash lazy=true)}} - {{replace-emoji ":diego_garcia:" (hash lazy=true)}} - {{replace-emoji ":djibouti:" (hash lazy=true)}} - {{replace-emoji ":denmark:" (hash lazy=true)}} - {{replace-emoji ":dominica:" (hash lazy=true)}} - {{replace-emoji ":dominican_republic:" (hash lazy=true)}} - {{replace-emoji ":algeria:" (hash lazy=true)}} - {{replace-emoji ":ceuta_and_melilla:" (hash lazy=true)}} - {{replace-emoji ":ecuador:" (hash lazy=true)}} - {{replace-emoji ":estonia:" (hash lazy=true)}} - {{replace-emoji ":egypt:" (hash lazy=true)}} - {{replace-emoji ":western_sahara:" (hash lazy=true)}} - {{replace-emoji ":eritrea:" (hash lazy=true)}} - {{replace-emoji ":es:" (hash lazy=true)}} - {{replace-emoji ":ethiopia:" (hash lazy=true)}} - {{replace-emoji ":eu:" (hash lazy=true)}} - {{replace-emoji ":finland:" (hash lazy=true)}} - {{replace-emoji ":fiji:" (hash lazy=true)}} - {{replace-emoji ":falkland_islands:" (hash lazy=true)}} - {{replace-emoji ":micronesia:" (hash lazy=true)}} - {{replace-emoji ":faroe_islands:" (hash lazy=true)}} - {{replace-emoji ":fr:" (hash lazy=true)}} - {{replace-emoji ":gabon:" (hash lazy=true)}} - {{replace-emoji ":uk:" (hash lazy=true)}} - {{replace-emoji ":grenada:" (hash lazy=true)}} - {{replace-emoji ":georgia:" (hash lazy=true)}} - {{replace-emoji ":french_guiana:" (hash lazy=true)}} - {{replace-emoji ":guernsey:" (hash lazy=true)}} - {{replace-emoji ":ghana:" (hash lazy=true)}} - {{replace-emoji ":gibraltar:" (hash lazy=true)}} - {{replace-emoji ":greenland:" (hash lazy=true)}} - {{replace-emoji ":gambia:" (hash lazy=true)}} - {{replace-emoji ":guinea:" (hash lazy=true)}} - {{replace-emoji ":guadeloupe:" (hash lazy=true)}} - {{replace-emoji ":equatorial_guinea:" (hash lazy=true)}} - {{replace-emoji ":greece:" (hash lazy=true)}} - {{replace-emoji ":south_georgia_south_sandwich_islands:" (hash lazy=true)}} - {{replace-emoji ":guatemala:" (hash lazy=true)}} - {{replace-emoji ":guam:" (hash lazy=true)}} - {{replace-emoji ":guinea_bissau:" (hash lazy=true)}} - {{replace-emoji ":guyana:" (hash lazy=true)}} - {{replace-emoji ":hong_kong:" (hash lazy=true)}} - {{replace-emoji ":heard_and_mc_donald_islands:" (hash lazy=true)}} - {{replace-emoji ":honduras:" (hash lazy=true)}} - {{replace-emoji ":croatia:" (hash lazy=true)}} - {{replace-emoji ":haiti:" (hash lazy=true)}} - {{replace-emoji ":hungary:" (hash lazy=true)}} - {{replace-emoji ":canary_islands:" (hash lazy=true)}} - {{replace-emoji ":indonesia:" (hash lazy=true)}} - {{replace-emoji ":ireland:" (hash lazy=true)}} - {{replace-emoji ":israel:" (hash lazy=true)}} - {{replace-emoji ":isle_of_man:" (hash lazy=true)}} - {{replace-emoji ":india:" (hash lazy=true)}} - {{replace-emoji ":british_indian_ocean_territory:" (hash lazy=true)}} - {{replace-emoji ":iraq:" (hash lazy=true)}} - {{replace-emoji ":iran:" (hash lazy=true)}} - {{replace-emoji ":iceland:" (hash lazy=true)}} - {{replace-emoji ":it:" (hash lazy=true)}} - {{replace-emoji ":jersey:" (hash lazy=true)}} - {{replace-emoji ":jamaica:" (hash lazy=true)}} - {{replace-emoji ":jordan:" (hash lazy=true)}} - {{replace-emoji ":jp:" (hash lazy=true)}} - {{replace-emoji ":kenya:" (hash lazy=true)}} - {{replace-emoji ":kyrgyzstan:" (hash lazy=true)}} - {{replace-emoji ":cambodia:" (hash lazy=true)}} - {{replace-emoji ":kiribati:" (hash lazy=true)}} - {{replace-emoji ":comoros:" (hash lazy=true)}} - {{replace-emoji ":st_kitts_nevis:" (hash lazy=true)}} - {{replace-emoji ":north_korea:" (hash lazy=true)}} - {{replace-emoji ":kr:" (hash lazy=true)}} - {{replace-emoji ":kuwait:" (hash lazy=true)}} - {{replace-emoji ":cayman_islands:" (hash lazy=true)}} - {{replace-emoji ":kazakhstan:" (hash lazy=true)}} - {{replace-emoji ":laos:" (hash lazy=true)}} - {{replace-emoji ":lebanon:" (hash lazy=true)}} - {{replace-emoji ":st_lucia:" (hash lazy=true)}} - {{replace-emoji ":liechtenstein:" (hash lazy=true)}} - {{replace-emoji ":sri_lanka:" (hash lazy=true)}} - {{replace-emoji ":liberia:" (hash lazy=true)}} - {{replace-emoji ":lesotho:" (hash lazy=true)}} - {{replace-emoji ":lithuania:" (hash lazy=true)}} - {{replace-emoji ":luxembourg:" (hash lazy=true)}} - {{replace-emoji ":latvia:" (hash lazy=true)}} - {{replace-emoji ":libya:" (hash lazy=true)}} - {{replace-emoji ":morocco:" (hash lazy=true)}} - {{replace-emoji ":monaco:" (hash lazy=true)}} - {{replace-emoji ":moldova:" (hash lazy=true)}} - {{replace-emoji ":montenegro:" (hash lazy=true)}} - {{replace-emoji ":st_martin:" (hash lazy=true)}} - {{replace-emoji ":madagascar:" (hash lazy=true)}} - {{replace-emoji ":marshall_islands:" (hash lazy=true)}} - {{replace-emoji ":macedonia:" (hash lazy=true)}} - {{replace-emoji ":mali:" (hash lazy=true)}} - {{replace-emoji ":myanmar:" (hash lazy=true)}} - {{replace-emoji ":mongolia:" (hash lazy=true)}} - {{replace-emoji ":macau:" (hash lazy=true)}} - {{replace-emoji ":northern_mariana_islands:" (hash lazy=true)}} - {{replace-emoji ":martinique:" (hash lazy=true)}} - {{replace-emoji ":mauritania:" (hash lazy=true)}} - {{replace-emoji ":montserrat:" (hash lazy=true)}} - {{replace-emoji ":malta:" (hash lazy=true)}} - {{replace-emoji ":mauritius:" (hash lazy=true)}} - {{replace-emoji ":maldives:" (hash lazy=true)}} - {{replace-emoji ":malawi:" (hash lazy=true)}} - {{replace-emoji ":mexico:" (hash lazy=true)}} - {{replace-emoji ":malaysia:" (hash lazy=true)}} - {{replace-emoji ":mozambique:" (hash lazy=true)}} - {{replace-emoji ":namibia:" (hash lazy=true)}} - {{replace-emoji ":new_caledonia:" (hash lazy=true)}} - {{replace-emoji ":niger:" (hash lazy=true)}} - {{replace-emoji ":norfolk_island:" (hash lazy=true)}} - {{replace-emoji ":nigeria:" (hash lazy=true)}} - {{replace-emoji ":nicaragua:" (hash lazy=true)}} - {{replace-emoji ":netherlands:" (hash lazy=true)}} - {{replace-emoji ":norway:" (hash lazy=true)}} - {{replace-emoji ":nepal:" (hash lazy=true)}} - {{replace-emoji ":nauru:" (hash lazy=true)}} - {{replace-emoji ":niue:" (hash lazy=true)}} - {{replace-emoji ":new_zealand:" (hash lazy=true)}} - {{replace-emoji ":oman:" (hash lazy=true)}} - {{replace-emoji ":panama:" (hash lazy=true)}} - {{replace-emoji ":peru:" (hash lazy=true)}} - {{replace-emoji ":french_polynesia:" (hash lazy=true)}} - {{replace-emoji ":papua_new_guinea:" (hash lazy=true)}} - {{replace-emoji ":philippines:" (hash lazy=true)}} - {{replace-emoji ":pakistan:" (hash lazy=true)}} - {{replace-emoji ":poland:" (hash lazy=true)}} - {{replace-emoji ":st_pierre_miquelon:" (hash lazy=true)}} - {{replace-emoji ":pitcairn_islands:" (hash lazy=true)}} - {{replace-emoji ":puerto_rico:" (hash lazy=true)}} - {{replace-emoji ":palestinian_territories:" (hash lazy=true)}} - {{replace-emoji ":portugal:" (hash lazy=true)}} - {{replace-emoji ":palau:" (hash lazy=true)}} - {{replace-emoji ":paraguay:" (hash lazy=true)}} - {{replace-emoji ":qatar:" (hash lazy=true)}} - {{replace-emoji ":reunion:" (hash lazy=true)}} - {{replace-emoji ":romania:" (hash lazy=true)}} - {{replace-emoji ":serbia:" (hash lazy=true)}} - {{replace-emoji ":ru:" (hash lazy=true)}} - {{replace-emoji ":rwanda:" (hash lazy=true)}} - {{replace-emoji ":saudi_arabia:" (hash lazy=true)}} - {{replace-emoji ":solomon_islands:" (hash lazy=true)}} - {{replace-emoji ":seychelles:" (hash lazy=true)}} - {{replace-emoji ":sudan:" (hash lazy=true)}} - {{replace-emoji ":sweden:" (hash lazy=true)}} - {{replace-emoji ":singapore:" (hash lazy=true)}} - {{replace-emoji ":st_helena:" (hash lazy=true)}} - {{replace-emoji ":slovenia:" (hash lazy=true)}} - {{replace-emoji ":svalbard_and_jan_mayen:" (hash lazy=true)}} - {{replace-emoji ":slovakia:" (hash lazy=true)}} - {{replace-emoji ":sierra_leone:" (hash lazy=true)}} - {{replace-emoji ":san_marino:" (hash lazy=true)}} - {{replace-emoji ":senegal:" (hash lazy=true)}} - {{replace-emoji ":somalia:" (hash lazy=true)}} - {{replace-emoji ":suriname:" (hash lazy=true)}} - {{replace-emoji ":south_sudan:" (hash lazy=true)}} - {{replace-emoji ":sao_tome_principe:" (hash lazy=true)}} - {{replace-emoji ":el_salvador:" (hash lazy=true)}} - {{replace-emoji ":sint_maarten:" (hash lazy=true)}} - {{replace-emoji ":syria:" (hash lazy=true)}} - {{replace-emoji ":swaziland:" (hash lazy=true)}} - {{replace-emoji ":tristan_da_cunha:" (hash lazy=true)}} - {{replace-emoji ":turks_caicos_islands:" (hash lazy=true)}} - {{replace-emoji ":chad:" (hash lazy=true)}} - {{replace-emoji ":french_southern_territories:" (hash lazy=true)}} - {{replace-emoji ":togo:" (hash lazy=true)}} - {{replace-emoji ":thailand:" (hash lazy=true)}} - {{replace-emoji ":tajikistan:" (hash lazy=true)}} - {{replace-emoji ":tokelau:" (hash lazy=true)}} - {{replace-emoji ":timor_leste:" (hash lazy=true)}} - {{replace-emoji ":turkmenistan:" (hash lazy=true)}} - {{replace-emoji ":tunisia:" (hash lazy=true)}} - {{replace-emoji ":tonga:" (hash lazy=true)}} - {{replace-emoji ":tr:" (hash lazy=true)}} - {{replace-emoji ":trinidad_tobago:" (hash lazy=true)}} - {{replace-emoji ":tuvalu:" (hash lazy=true)}} - {{replace-emoji ":taiwan:" (hash lazy=true)}} - {{replace-emoji ":tanzania:" (hash lazy=true)}} - {{replace-emoji ":ukraine:" (hash lazy=true)}} - {{replace-emoji ":uganda:" (hash lazy=true)}} - {{replace-emoji ":us_outlying_islands:" (hash lazy=true)}} - {{replace-emoji ":united_nations:" (hash lazy=true)}} - {{replace-emoji ":us:" (hash lazy=true)}} - {{replace-emoji ":uruguay:" (hash lazy=true)}} - {{replace-emoji ":uzbekistan:" (hash lazy=true)}} - {{replace-emoji ":vatican_city:" (hash lazy=true)}} - {{replace-emoji ":st_vincent_grenadines:" (hash lazy=true)}} - {{replace-emoji ":venezuela:" (hash lazy=true)}} - {{replace-emoji ":british_virgin_islands:" (hash lazy=true)}} - {{replace-emoji ":us_virgin_islands:" (hash lazy=true)}} - {{replace-emoji ":vietnam:" (hash lazy=true)}} - {{replace-emoji ":vanuatu:" (hash lazy=true)}} - {{replace-emoji ":wallis_futuna:" (hash lazy=true)}} - {{replace-emoji ":samoa:" (hash lazy=true)}} - {{replace-emoji ":kosovo:" (hash lazy=true)}} - {{replace-emoji ":yemen:" (hash lazy=true)}} - {{replace-emoji ":mayotte:" (hash lazy=true)}} - {{replace-emoji ":south_africa:" (hash lazy=true)}} - {{replace-emoji ":zambia:" (hash lazy=true)}} - {{replace-emoji ":zimbabwe:" (hash lazy=true)}} - {{replace-emoji ":england:" (hash lazy=true)}} - {{replace-emoji ":scotland:" (hash lazy=true)}} - {{replace-emoji ":wales:" (hash lazy=true)}} + {{replace-emoji ":checkered_flag:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":triangular_flag_on_post:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":crossed_flags:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":black_flag:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":white_flag:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":rainbow_flag:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":transgender_flag:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pirate_flag:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ascension_island:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":andorra:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":united_arab_emirates:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":afghanistan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":antigua_barbuda:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":anguilla:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":albania:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":armenia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":angola:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":antarctica:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":argentina:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":american_samoa:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":austria:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":australia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":aruba:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":aland_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":azerbaijan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bosnia_herzegovina:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":barbados:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bangladesh:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":belgium:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":burkina_faso:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bulgaria:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bahrain:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":burundi:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":benin:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":st_barthelemy:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bermuda:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":brunei:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bolivia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":caribbean_netherlands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":brazil:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bahamas:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bhutan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":bouvet_island:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":botswana:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":belarus:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":belize:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":canada:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cocos_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":congo_kinshasa:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":central_african_republic:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":congo_brazzaville:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":switzerland:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cote_divoire:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cook_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":chile:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cameroon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cn:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":colombia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":clipperton_island:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":costa_rica:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cuba:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cape_verde:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":curacao:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":christmas_island:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cyprus:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":czech_republic:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":de:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":diego_garcia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":djibouti:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":denmark:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":dominica:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":dominican_republic:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":algeria:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ceuta_and_melilla:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ecuador:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":estonia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":egypt:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":western_sahara:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":eritrea:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":es:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ethiopia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":eu:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":finland:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fiji:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":falkland_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":micronesia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":faroe_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":fr:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":gabon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":uk:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":grenada:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":georgia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":french_guiana:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":guernsey:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ghana:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":gibraltar:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":greenland:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":gambia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":guinea:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":guadeloupe:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":equatorial_guinea:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":greece:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":south_georgia_south_sandwich_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":guatemala:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":guam:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":guinea_bissau:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":guyana:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hong_kong:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":heard_and_mc_donald_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":honduras:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":croatia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":haiti:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":hungary:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":canary_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":indonesia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ireland:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":israel:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":isle_of_man:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":india:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":british_indian_ocean_territory:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":iraq:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":iran:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":iceland:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":it:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":jersey:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":jamaica:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":jordan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":jp:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":kenya:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":kyrgyzstan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cambodia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":kiribati:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":comoros:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":st_kitts_nevis:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":north_korea:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":kr:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":kuwait:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":cayman_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":kazakhstan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":laos:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":lebanon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":st_lucia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":liechtenstein:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sri_lanka:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":liberia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":lesotho:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":lithuania:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":luxembourg:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":latvia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":libya:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":morocco:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":monaco:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":moldova:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":montenegro:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":st_martin:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":madagascar:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":marshall_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":macedonia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mali:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":myanmar:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mongolia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":macau:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":northern_mariana_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":martinique:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mauritania:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":montserrat:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":malta:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mauritius:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":maldives:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":malawi:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mexico:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":malaysia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mozambique:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":namibia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":new_caledonia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":niger:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":norfolk_island:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":nigeria:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":nicaragua:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":netherlands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":norway:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":nepal:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":nauru:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":niue:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":new_zealand:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":oman:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":panama:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":peru:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":french_polynesia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":papua_new_guinea:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":philippines:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pakistan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":poland:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":st_pierre_miquelon:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":pitcairn_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":puerto_rico:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":palestinian_territories:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":portugal:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":palau:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":paraguay:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":qatar:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":reunion:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":romania:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":serbia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ru:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":rwanda:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":saudi_arabia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":solomon_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":seychelles:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sudan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sweden:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":singapore:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":st_helena:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":slovenia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":svalbard_and_jan_mayen:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":slovakia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sierra_leone:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":san_marino:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":senegal:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":somalia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":suriname:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":south_sudan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sao_tome_principe:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":el_salvador:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":sint_maarten:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":syria:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":swaziland:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tristan_da_cunha:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":turks_caicos_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":chad:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":french_southern_territories:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":togo:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":thailand:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tajikistan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tokelau:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":timor_leste:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":turkmenistan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tunisia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tonga:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tr:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":trinidad_tobago:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tuvalu:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":taiwan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":tanzania:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":ukraine:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":uganda:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":us_outlying_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":united_nations:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":us:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":uruguay:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":uzbekistan:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":vatican_city:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":st_vincent_grenadines:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":venezuela:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":british_virgin_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":us_virgin_islands:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":vietnam:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":vanuatu:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wallis_futuna:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":samoa:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":kosovo:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":yemen:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":mayotte:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":south_africa:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":zambia:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":zimbabwe:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":england:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":scotland:" (hash lazy=true tabIndex="0")}} + {{replace-emoji ":wales:" (hash lazy=true tabIndex="0")}}
diff --git a/app/assets/javascripts/discourse/app/templates/components/emoji-picker.hbs b/app/assets/javascripts/discourse/app/templates/components/emoji-picker.hbs index d9c2156911..d35c0e5e2f 100644 --- a/app/assets/javascripts/discourse/app/templates/components/emoji-picker.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/emoji-picker.hbs @@ -37,7 +37,7 @@
{{#each this.recentEmojis as |emoji|}} - {{replace-emoji (concat ":" emoji ":") (hash lazy=true)}} + {{replace-emoji (concat ":" emoji ":") (hash lazy=true tabIndex="0" class="recent-emoji")}} {{/each}}
@@ -55,7 +55,9 @@ {{#if emojis.length}}
{{#each emojis as |emoji|}} - + + + {{/each}}
{{/if}} diff --git a/app/assets/javascripts/discourse/app/templates/components/expand-post.hbs b/app/assets/javascripts/discourse/app/templates/components/expand-post.hbs index 79b9709fb0..119ffede11 100644 --- a/app/assets/javascripts/discourse/app/templates/components/expand-post.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/expand-post.hbs @@ -1,11 +1,9 @@ {{#if this.item.truncated}} - {{#if this.expanded}} - + + {{#if this.expanded}} {{d-icon "chevron-up"}} - - {{else}} - + {{else}} {{d-icon "chevron-down"}} - - {{/if}} + {{/if}} + {{/if}} diff --git a/app/assets/javascripts/discourse/app/templates/components/group-post.hbs b/app/assets/javascripts/discourse/app/templates/components/group-post.hbs index 3a83f4b677..a442d7f077 100644 --- a/app/assets/javascripts/discourse/app/templates/components/group-post.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/group-post.hbs @@ -1,11 +1,9 @@ -
- +
+ {{avatar this.post.user imageSize="large" extraClasses="actor" ignoreTitle="true"}} - {{format-date this.post.created_at leaveAgo="true"}} - -
+
{{/if}}
+ + + {{format-date this.post.created_at leaveAgo="true"}}
diff --git a/app/assets/javascripts/discourse/app/templates/components/login-buttons.hbs b/app/assets/javascripts/discourse/app/templates/components/login-buttons.hbs index f4eec15a1c..ab36ebbfa0 100644 --- a/app/assets/javascripts/discourse/app/templates/components/login-buttons.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/login-buttons.hbs @@ -10,3 +10,4 @@ {{b.title}} {{/each}} + diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar.hbs b/app/assets/javascripts/discourse/app/templates/components/sidebar.hbs deleted file mode 100644 index 31cda7a305..0000000000 --- a/app/assets/javascripts/discourse/app/templates/components/sidebar.hbs +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/hamburger-dropdown.hbs b/app/assets/javascripts/discourse/app/templates/components/sidebar/hamburger-dropdown.hbs deleted file mode 100644 index 3167355bc9..0000000000 --- a/app/assets/javascripts/discourse/app/templates/components/sidebar/hamburger-dropdown.hbs +++ /dev/null @@ -1,12 +0,0 @@ -
- -
diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-links.hbs b/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-links.hbs deleted file mode 100644 index 41d3ef7fdb..0000000000 --- a/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-links.hbs +++ /dev/null @@ -1,30 +0,0 @@ -{{#if this.activeSectionLink}} - -{{/if}} - - diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/section-link.hbs b/app/assets/javascripts/discourse/app/templates/components/sidebar/section-link.hbs deleted file mode 100644 index bc6e2edf8b..0000000000 --- a/app/assets/javascripts/discourse/app/templates/components/sidebar/section-link.hbs +++ /dev/null @@ -1,71 +0,0 @@ - diff --git a/app/assets/javascripts/discourse/app/templates/components/time-shortcut-picker.hbs b/app/assets/javascripts/discourse/app/templates/components/time-shortcut-picker.hbs index cda6c49b87..789e07110b 100644 --- a/app/assets/javascripts/discourse/app/templates/components/time-shortcut-picker.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/time-shortcut-picker.hbs @@ -12,7 +12,7 @@
{{d-icon "calendar-alt"}} - +
{{d-icon "far-clock"}} @@ -20,8 +20,10 @@
- - + +
{{/if}} {{/if}} diff --git a/app/assets/javascripts/discourse/app/templates/components/user-card-contents.hbs b/app/assets/javascripts/discourse/app/templates/components/user-card-contents.hbs index 2a288157d5..f2614399f2 100644 --- a/app/assets/javascripts/discourse/app/templates/components/user-card-contents.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/user-card-contents.hbs @@ -36,12 +36,12 @@

{{#if this.user.profile_hidden}} - + {{if this.nameFirst this.user.name (format-username this.user.username)}} {{else}}
{{avatar @item imageSize="large" extraClasses="actor" ignoreTitle="true"}}
- {{format-date @item.created_at}} - {{#if @item.draftType}} - {{html-safe @item.draftType}} - {{else}} - - {{/if}} -
+
+ +
+ {{avatar @item imageSize="large" extraClasses="actor" ignoreTitle="true"}} +
+
+ +
@@ -20,6 +19,13 @@
{{category-link @item.category}}
+ {{#if @item.draftType}} + {{html-safe @item.draftType}} + {{else}} + + {{/if}} + {{format-date @item.created_at}} + {{#if @item.deleted_by}} {{d-icon "far-trash-alt"}} @@ -50,12 +56,12 @@
{{d-icon child.icon class="icon"}} {{#each child.items as |grandChild|}} - {{#if grandChild.removableBookmark}} - - {{else}} -
{{avatar grandChild imageSize="tiny" extraClasses="actor" ignoreTitle="true" avatarTemplatePath="acting_avatar_template"}}
- {{#if grandChild.edit_reason}} — {{grandChild.edit_reason}}{{/if}} - {{/if}} + +
+ {{avatar grandChild imageSize="tiny" extraClasses="actor" ignoreTitle="true" avatarTemplatePath="acting_avatar_template"}} +
+
+ {{#if grandChild.edit_reason}} — {{grandChild.edit_reason}}{{/if}} {{/each}}
{{/each}} diff --git a/app/assets/javascripts/discourse/app/templates/components/welcome-topic-banner.hbs b/app/assets/javascripts/discourse/app/templates/components/welcome-topic-banner.hbs index f5a577a866..2100624718 100644 --- a/app/assets/javascripts/discourse/app/templates/components/welcome-topic-banner.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/welcome-topic-banner.hbs @@ -1,9 +1,7 @@ -
-
-

{{i18n "welcome_topic_banner.title"}}

-

{{i18n "welcome_topic_banner.description"}}

-
-
- +
+
+

{{i18n "welcome_topic_banner.title"}}

+

{{i18n "welcome_topic_banner.description"}}

+
diff --git a/app/assets/javascripts/discourse/app/templates/composer.hbs b/app/assets/javascripts/discourse/app/templates/composer.hbs index e0c1f52ed1..132e37cff6 100644 --- a/app/assets/javascripts/discourse/app/templates/composer.hbs +++ b/app/assets/javascripts/discourse/app/templates/composer.hbs @@ -4,6 +4,10 @@ {{#if this.visible}} + {{#if this.showFullScreenPrompt}} + + {{/if}} + {{#if this.model.viewOpenOrFullscreen}}
@@ -41,6 +45,7 @@
+ {{#unless this.model.viewFullscreen}} {{#if this.model.canEditTitle}} {{#if this.model.creatingPrivateMessage}} @@ -77,6 +82,8 @@ }} /> {{/if}} + +
{{/if}} @@ -91,21 +98,19 @@
- {{#unless this.model.viewFullscreen}} - + - {{#if this.site.mobileView}} - - {{#if this.canEdit}} - {{d-icon "times"}} - {{else}} - {{d-icon "far-trash-alt"}} - {{/if}} - - {{else}} - {{i18n "close"}} - {{/if}} - {{/unless}} + {{#if this.site.mobileView}} + + {{#if this.canEdit}} + {{d-icon "times"}} + {{else}} + {{d-icon "far-trash-alt"}} + {{/if}} + + {{else}} + {{i18n "close"}} + {{/if}} {{#if this.site.mobileView}} {{#if this.whisperOrUnlistTopic}} diff --git a/app/assets/javascripts/discourse/app/templates/composer/custom-body.hbs b/app/assets/javascripts/discourse/app/templates/composer/custom-body.hbs deleted file mode 100644 index 1a7d7647a0..0000000000 --- a/app/assets/javascripts/discourse/app/templates/composer/custom-body.hbs +++ /dev/null @@ -1,3 +0,0 @@ -{{d-icon "times"}} -{{#if this.message.title}}

{{this.message.title}}

{{/if}} -

{{html-safe this.message.body}}

diff --git a/app/assets/javascripts/discourse/app/templates/composer/dominating-topic.hbs b/app/assets/javascripts/discourse/app/templates/composer/dominating-topic.hbs index c76aba17c8..248e6c05a4 100644 --- a/app/assets/javascripts/discourse/app/templates/composer/dominating-topic.hbs +++ b/app/assets/javascripts/discourse/app/templates/composer/dominating-topic.hbs @@ -1,4 +1,6 @@ -{{d-icon "times"}} + + {{i18n "composer.esc"}} {{d-icon "times"}} + {{html-safe this.message.body}} diff --git a/app/assets/javascripts/discourse/app/templates/composer/education.hbs b/app/assets/javascripts/discourse/app/templates/composer/education.hbs index b717e32d92..1c83813b00 100644 --- a/app/assets/javascripts/discourse/app/templates/composer/education.hbs +++ b/app/assets/javascripts/discourse/app/templates/composer/education.hbs @@ -1,2 +1,9 @@ -{{d-icon "times"}} + + {{i18n "composer.esc"}} {{d-icon "times"}} + + +{{#if this.message.title}} +

{{this.message.title}}

+{{/if}} + {{html-safe this.message.body}} diff --git a/app/assets/javascripts/discourse/app/templates/composer/get-a-room.hbs b/app/assets/javascripts/discourse/app/templates/composer/get-a-room.hbs index f3e0a5a4a3..308dbeefc9 100644 --- a/app/assets/javascripts/discourse/app/templates/composer/get-a-room.hbs +++ b/app/assets/javascripts/discourse/app/templates/composer/get-a-room.hbs @@ -1,4 +1,6 @@ -{{d-icon "times"}} + + {{i18n "composer.esc"}} {{d-icon "times"}} + {{html-safe this.message.body}} diff --git a/app/assets/javascripts/discourse/app/templates/composer/group-mentioned.hbs b/app/assets/javascripts/discourse/app/templates/composer/group-mentioned.hbs index b717e32d92..49a28605b6 100644 --- a/app/assets/javascripts/discourse/app/templates/composer/group-mentioned.hbs +++ b/app/assets/javascripts/discourse/app/templates/composer/group-mentioned.hbs @@ -1,2 +1,5 @@ -{{d-icon "times"}} + + {{i18n "composer.esc"}} {{d-icon "times"}} + + {{html-safe this.message.body}} diff --git a/app/assets/javascripts/discourse/app/templates/composer/similar-topics.hbs b/app/assets/javascripts/discourse/app/templates/composer/similar-topics.hbs index 775b160e6b..510da64e49 100644 --- a/app/assets/javascripts/discourse/app/templates/composer/similar-topics.hbs +++ b/app/assets/javascripts/discourse/app/templates/composer/similar-topics.hbs @@ -1,4 +1,7 @@ -{{d-icon "times"}} + + {{i18n "composer.esc"}} {{d-icon "times"}} + +

{{i18n "composer.similar_topics"}}

    diff --git a/app/assets/javascripts/discourse/app/templates/list/posts-count-column.hbr b/app/assets/javascripts/discourse/app/templates/list/posts-count-column.hbr index 0087b01566..f4836f416e 100644 --- a/app/assets/javascripts/discourse/app/templates/list/posts-count-column.hbr +++ b/app/assets/javascripts/discourse/app/templates/list/posts-count-column.hbr @@ -1,6 +1,6 @@ <{{view.tagName}} class='num posts-map posts {{view.likesHeat}} topic-list-data' title='{{view.title}}'> diff --git a/app/assets/javascripts/discourse/app/templates/list/topic-list-item.hbr b/app/assets/javascripts/discourse/app/templates/list/topic-list-item.hbr index da667759fa..dc1e35ac5e 100644 --- a/app/assets/javascripts/discourse/app/templates/list/topic-list-item.hbr +++ b/app/assets/javascripts/discourse/app/templates/list/topic-list-item.hbr @@ -45,8 +45,12 @@ {{#if expandPinned}} {{raw "list/topic-excerpt" topic=topic}} {{/if}} + + {{~raw-plugin-outlet name="topic-list-main-link-bottom"}} +{{~raw-plugin-outlet name="topic-list-after-main-link"}} + {{#if showPosters}} {{raw "list/posters-column" posters=topic.featuredUsers}} {{/if}} diff --git a/app/assets/javascripts/discourse/app/templates/modal/flag.hbs b/app/assets/javascripts/discourse/app/templates/modal/flag.hbs index 863c482895..a890ce311e 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/flag.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/flag.hbs @@ -18,7 +18,7 @@ {{#if this.canTakeAction}} - + {{/if}} {{#if this.showDeleteSpammer}} diff --git a/app/assets/javascripts/discourse/app/templates/preferences/notifications.hbs b/app/assets/javascripts/discourse/app/templates/preferences/notifications.hbs index 3d1f882f90..6f142e25a1 100644 --- a/app/assets/javascripts/discourse/app/templates/preferences/notifications.hbs +++ b/app/assets/javascripts/discourse/app/templates/preferences/notifications.hbs @@ -33,7 +33,7 @@ -{{#if this.siteSettings.enable_personal_messages}} +{{#if this.showMessageSettings}}
    diff --git a/app/assets/javascripts/discourse/app/templates/preferences/users.hbs b/app/assets/javascripts/discourse/app/templates/preferences/users.hbs index ebf6b46a74..5589f14d47 100644 --- a/app/assets/javascripts/discourse/app/templates/preferences/users.hbs +++ b/app/assets/javascripts/discourse/app/templates/preferences/users.hbs @@ -21,7 +21,7 @@
    {{i18n "user.muted_users_instructions"}}
    -{{#if this.siteSettings.enable_personal_messages}} +{{#if this.showMessageSettings}}
    diff --git a/app/assets/javascripts/discourse/app/templates/topic.hbs b/app/assets/javascripts/discourse/app/templates/topic.hbs index 3d49a7357c..41fa19fd1d 100644 --- a/app/assets/javascripts/discourse/app/templates/topic.hbs +++ b/app/assets/javascripts/discourse/app/templates/topic.hbs @@ -52,7 +52,7 @@ {{else}}

    {{#unless this.model.is_warning}} - {{#if this.siteSettings.enable_personal_messages}} + {{#if this.canSendPms}} {{else}} diff --git a/app/assets/javascripts/discourse/app/templates/user-card.hbs b/app/assets/javascripts/discourse/app/templates/user-card.hbs index ba2df96cac..9407edab97 100644 --- a/app/assets/javascripts/discourse/app/templates/user-card.hbs +++ b/app/assets/javascripts/discourse/app/templates/user-card.hbs @@ -2,6 +2,5 @@ {{/if}} - - + diff --git a/app/assets/javascripts/discourse/app/templates/user-selector-autocomplete.hbr b/app/assets/javascripts/discourse/app/templates/user-selector-autocomplete.hbr index 797bd64e35..4b62706363 100644 --- a/app/assets/javascripts/discourse/app/templates/user-selector-autocomplete.hbr +++ b/app/assets/javascripts/discourse/app/templates/user-selector-autocomplete.hbr @@ -5,8 +5,15 @@ {{avatar user imageSize="tiny"}} {{format-username user.username}} - {{user.name}} - {{decorate-username-selector user.username}} + {{#if user.status}} + {{emoji user.status.emoji}} + + {{user.status.description}} + + {{#if user.status.ends_at}} + {{format-age user.status.ends_at}} + {{/if}} + {{/if}} {{/each}} diff --git a/app/assets/javascripts/discourse/app/templates/user.hbs b/app/assets/javascripts/discourse/app/templates/user.hbs index c990875aaf..c3b1e4e419 100644 --- a/app/assets/javascripts/discourse/app/templates/user.hbs +++ b/app/assets/javascripts/discourse/app/templates/user.hbs @@ -59,14 +59,17 @@ {{/if}} + {{#if this.canMuteOrIgnoreUser}}
  • {{/if}} - {{#if this.currentUser.staff}} + + {{#if this.displayTopLevelAdminButton}}
  • {{d-icon "wrench"}}{{i18n "admin.user.show_admin_profile"}}
  • {{/if}} + {{#if this.canExpandProfile}} @@ -74,6 +77,12 @@ {{/if}} + + {{#if (and this.site.mobileView this.currentUser.redesigned_user_page_nav_enabled)}} +
  • + +
  • + {{/if}}

@@ -216,7 +225,7 @@ {{/if}} {{#if this.canDeleteUser}} -
+
{{/if}} @@ -224,36 +233,67 @@ {{/unless}}
-
-
- - {{#unless this.model.profile_hidden}} -
  • {{i18n 'user.summary.title'}}
  • -
  • {{i18n 'user.activity_stream'}}
  • - {{/unless}} - {{#if this.showNotificationsTab}} -
  • - - {{d-icon "comment" class="glyph"}}{{i18n 'user.notifications'}} - -
  • - {{/if}} - {{#if this.showPrivateMessages}} -
  • {{d-icon "far-envelope"}}{{i18n 'user.private_messages'}}
  • - {{/if}} - {{#if this.canInviteToForum}} -
  • {{d-icon "user-plus"}}{{i18n 'user.invited.title'}}
  • - {{/if}} - {{#if this.showBadges}} -
  • {{d-icon "certificate"}}{{i18n 'badges.title'}}
  • - {{/if}} - - {{#if this.model.can_edit}} -
  • {{d-icon "cog"}}{{i18n 'user.preferences'}}
  • - {{/if}} -
    -
    - {{outlet}} -
    + + {{#if this.currentUser.redesigned_user_page_nav_enabled}} +
    + + + {{#if (or this.site.desktopView (not this.displayUserNav))}} +
    + {{outlet}} +
    + {{/if}} +
    + {{else}} +
    +
    + + {{#unless this.model.profile_hidden}} +
  • {{i18n 'user.summary.title'}}
  • +
  • {{i18n 'user.activity_stream'}}
  • + {{/unless}} + + {{#if this.showNotificationsTab}} +
  • + + {{d-icon "comment" class="glyph"}}{{i18n 'user.notifications'}} + +
  • + {{/if}} + + {{#if this.showPrivateMessages}} +
  • {{d-icon "far-envelope"}}{{i18n 'user.private_messages'}}
  • + {{/if}} + + {{#if this.canInviteToForum}} +
  • {{d-icon "user-plus"}}{{i18n 'user.invited.title'}}
  • + {{/if}} + + {{#if this.showBadges}} +
  • {{d-icon "certificate"}}{{i18n 'badges.title'}}
  • + {{/if}} + + + + {{#if this.model.can_edit}} +
  • {{d-icon "cog"}}{{i18n 'user.preferences'}}
  • + {{/if}} +
    +
    + + {{outlet}} +
    + {{/if}}
    diff --git a/app/assets/javascripts/discourse/app/templates/user/activity.hbs b/app/assets/javascripts/discourse/app/templates/user/activity.hbs index 5709d95e79..a115f1cf06 100644 --- a/app/assets/javascripts/discourse/app/templates/user/activity.hbs +++ b/app/assets/javascripts/discourse/app/templates/user/activity.hbs @@ -1,43 +1,46 @@ - - + + + {{#if this.canDownloadPosts}} +
    + +
    + {{/if}} +{{/unless}}
    {{outlet}} diff --git a/app/assets/javascripts/discourse/app/templates/user/stream.hbs b/app/assets/javascripts/discourse/app/templates/user/stream.hbs index 90788aa4ef..a7fad6bd0f 100644 --- a/app/assets/javascripts/discourse/app/templates/user/stream.hbs +++ b/app/assets/javascripts/discourse/app/templates/user/stream.hbs @@ -1,11 +1,7 @@ {{#if this.model.stream.noContent}} - {{#if this.model.isAnotherUsersPage}} -
    {{this.model.emptyStateOthers}}
    - {{else}} - - {{/if}} + {{/if}} diff --git a/app/assets/javascripts/discourse/app/widgets/header.js b/app/assets/javascripts/discourse/app/widgets/header.js index 8fef0b8e65..0a8398f141 100644 --- a/app/assets/javascripts/discourse/app/widgets/header.js +++ b/app/assets/javascripts/discourse/app/widgets/header.js @@ -392,6 +392,15 @@ createWidget("revamped-hamburger-menu-wrapper", { ]; }, + click(event) { + if ( + event.target.closest(".sidebar-section-header-button") || + event.target.closest(".sidebar-section-link") + ) { + this.sendWidgetAction("toggleHamburger"); + } + }, + clickOutside() { this.sendWidgetAction("toggleHamburger"); }, @@ -407,14 +416,21 @@ createWidget("revamped-user-menu-wrapper", { new RenderGlimmer( this, "div.widget-component-connector", - hbs`` + hbs``, + { + closeUserMenu: this.closeUserMenu.bind(this), + } ), ]; }, - clickOutside() { + closeUserMenu() { this.sendWidgetAction("toggleUserMenu"); }, + + clickOutside() { + this.closeUserMenu(); + }, }); export default createWidget("header", { @@ -589,16 +605,21 @@ export default createWidget("header", { toggleHamburger() { if ( this.siteSettings.enable_experimental_sidebar_hamburger && - (this.attrs.sidebarEnabled || this.site.mobileView) + this.attrs.sidebarEnabled ) { this.sendWidgetAction("toggleSidebar"); } else { this.state.hamburgerVisible = !this.state.hamburgerVisible; this.toggleBodyScrolling(this.state.hamburgerVisible); - // auto focus on first link in dropdown schedule("afterRender", () => { - document.querySelector(".hamburger-panel .menu-links a")?.focus(); + if (this.siteSettings.enable_experimental_sidebar_hamburger) { + // Remove focus from hamburger toggle button + document.querySelector("#toggle-hamburger-menu").blur(); + } else { + // auto focus on first link in dropdown + document.querySelector(".hamburger-panel .menu-links a")?.focus(); + } }); } }, diff --git a/app/assets/javascripts/discourse/app/widgets/post-cooked.js b/app/assets/javascripts/discourse/app/widgets/post-cooked.js index 754312cc29..62941eaf60 100644 --- a/app/assets/javascripts/discourse/app/widgets/post-cooked.js +++ b/app/assets/javascripts/discourse/app/widgets/post-cooked.js @@ -6,6 +6,8 @@ import { iconHTML } from "discourse-common/lib/icon-library"; import { isValidLink } from "discourse/lib/click-track"; import { number } from "discourse/lib/formatter"; import { spinnerHTML } from "discourse/helpers/loading-spinner"; +import { escape } from "pretty-text/sanitizer"; +import domFromString from "discourse-common/lib/dom-from-string"; let _beforeAdoptDecorators = []; let _afterAdoptDecorators = []; @@ -31,6 +33,8 @@ function createDetachedElement(nodeName) { } export default class PostCooked { + originalQuoteContents = null; + constructor(attrs, decoratorHelper, currentUser) { this.attrs = attrs; this.expanding = false; @@ -52,13 +56,12 @@ export default class PostCooked { } init() { + this.originalQuoteContents = null; const cookedDiv = this._computeCooked(); - const $cookedDiv = $(cookedDiv); - - this._insertQuoteControls($cookedDiv); - this._showLinkCounts($cookedDiv); - this._applySearchHighlight($cookedDiv); + this._insertQuoteControls(cookedDiv); + this._showLinkCounts(cookedDiv); + this._applySearchHighlight(cookedDiv); this._decorateAndAdopt(cookedDiv); return cookedDiv; @@ -72,8 +75,7 @@ export default class PostCooked { _afterAdoptDecorators.forEach((d) => d(cooked, this.decoratorHelper)); } - _applySearchHighlight($html) { - const html = $html[0]; + _applySearchHighlight(html) { const highlight = this.attrs.highlightTerm; if (highlight && highlight.length > 2) { @@ -89,7 +91,7 @@ export default class PostCooked { } } - _showLinkCounts($html) { + _showLinkCounts(html) { const linkCounts = this.attrs.linkCounts; if (!linkCounts) { return; @@ -99,7 +101,7 @@ export default class PostCooked { // for that one (the best element is the most significant one to the // viewer) const bestElements = new Map(); - $html[0].querySelectorAll("aside.onebox").forEach((onebox) => { + html.querySelectorAll("aside.onebox").forEach((onebox) => { // look in headings first for (let i = 1; i <= 6; ++i) { const hLinks = onebox.querySelectorAll(`h${i} a[href]`); @@ -121,10 +123,8 @@ export default class PostCooked { return; } - $html.find("a[href]").each((i, e) => { - const $link = $(e); - const href = $link.attr("href"); - + html.querySelectorAll("a[href]").forEach((link) => { + const href = link.getAttribute("href"); let valid = href === lc.url; // this might be an attachment @@ -132,24 +132,29 @@ export default class PostCooked { valid = href.includes(lc.url); } - // Match server-side behaviour for internal links with query params + // match server-side behavior for internal links with query params if (lc.internal && /\?/.test(href)) { valid = href.split("?")[0] === lc.url; } // don't display badge counts on category badge & oneboxes (unless when explicitly stated) - if (valid && isValidLink($link[0])) { - const $onebox = $link.closest(".onebox"); + if (valid && isValidLink(link)) { + const onebox = link.closest(".onebox"); + if ( - $onebox.length === 0 || - !bestElements.has($onebox[0]) || - bestElements.get($onebox[0]) === $link[0] + !onebox || + !bestElements.has(onebox) || + bestElements.get(onebox) === link ) { const title = I18n.t("topic_map.clicks", { count: lc.clicks }); - $link.append( - ` ${number( - lc.clicks - )}` + + link.appendChild(document.createTextNode(" ")); + link.appendChild( + domFromString( + `${number( + lc.clicks + )}` + )[0] ); } } @@ -157,21 +162,31 @@ export default class PostCooked { }); } - _toggleQuote($aside) { + async _toggleQuote(aside) { if (this.expanding) { return; } this.expanding = true; - const blockQuote = $aside[0].querySelector("blockquote"); - $aside.data("expanded", !$aside.data("expanded")); + const blockQuote = aside.querySelector("blockquote"); - const finished = () => (this.expanding = false); + if (!blockQuote) { + return; + } + + if (aside.dataset.expanded) { + delete aside.dataset.expanded; + } else { + aside.dataset.expanded = true; + } + + const quoteId = blockQuote.id; + + if (aside.dataset.expanded) { + this._updateQuoteElements(aside, "chevron-up"); - if ($aside.data("expanded")) { - this._updateQuoteElements($aside, "chevron-up"); // Show expanded quote - $aside.data("original-contents", blockQuote.innerHTML); + this.originalQuoteContents.set(quoteId, blockQuote.innerHTML); const originalText = blockQuote.textContent.trim() || @@ -179,51 +194,45 @@ export default class PostCooked { blockQuote.innerHTML = spinnerHTML; - let topicId = this.attrs.topicId; - if ($aside.data("topic")) { - topicId = $aside.data("topic"); - } + const topicId = parseInt(aside.dataset.topic || this.attrs.topicId, 10); + const postId = parseInt(aside.dataset.post, 10); - const postId = parseInt($aside.data("post"), 10); - topicId = parseInt(topicId, 10); + try { + const result = await ajax(`/posts/by_number/${topicId}/${postId}`); - ajax(`/posts/by_number/${topicId}/${postId}`) - .then((result) => { - const post = this.decoratorHelper.getModel(); - const quotedPosts = post.quoted || {}; - quotedPosts[result.id] = result; - post.set("quoted", quotedPosts); + const post = this.decoratorHelper.getModel(); + const quotedPosts = post.quoted || {}; + quotedPosts[result.id] = result; + post.set("quoted", quotedPosts); - const div = createDetachedElement("div"); - div.classList.add("expanded-quote"); - div.dataset.postId = result.id; - div.innerHTML = result.cooked; + const div = createDetachedElement("div"); + div.classList.add("expanded-quote"); + div.dataset.postId = result.id; + div.innerHTML = result.cooked; - this._decorateAndAdopt(div); + this._decorateAndAdopt(div); - highlightHTML(div, originalText, { - matchCase: true, - }); - - blockQuote.innerHTML = ""; - blockQuote.appendChild(div); - finished(); - }) - .catch((e) => { - if ([403, 404].includes(e.jqXHR.status)) { - const icon = e.jqXHR.status === 403 ? "lock" : "far-trash-alt"; - blockQuote.innerHTML = `
    ${iconHTML( - icon - )}
    `; - } + highlightHTML(div, originalText, { + matchCase: true, }); + + blockQuote.innerHTML = ""; + blockQuote.appendChild(div); + } catch (e) { + if ([403, 404].includes(e.jqXHR.status)) { + const icon = e.jqXHR.status === 403 ? "lock" : "far-trash-alt"; + blockQuote.innerHTML = `
    ${iconHTML( + icon + )}
    `; + } + } } else { // Hide expanded quote - this._updateQuoteElements($aside, "chevron-down"); - blockQuote.innerHTML = $aside.data("original-contents"); - finished(); + this._updateQuoteElements(aside, "chevron-down"); + blockQuote.innerHTML = this.originalQuoteContents.get(blockQuote.id); } - return false; + + this.expanding = false; } _urlForPostNumber(postNumber) { @@ -232,72 +241,103 @@ export default class PostCooked { : this.attrs.topicUrl; } - _updateQuoteElements($aside, desc) { - let navLink = ""; + _updateQuoteElements(aside, desc) { const quoteTitle = I18n.t("post.follow_quote"); - let postNumber = $aside.data("post"); - let topicNumber = $aside.data("topic"); + const postNumber = aside.dataset.post; + const topicNumber = aside.dataset.topic; // If we have a post reference - if (topicNumber && topicNumber === this.attrs.topicId && postNumber) { - let icon = iconHTML("arrow-up"); + let navLink = ""; + if ( + topicNumber && + postNumber && + topicNumber === this.attrs.topicId?.toString() + ) { + const icon = iconHTML("arrow-up"); navLink = `${icon}`; } // Only add the expand/contract control if it's not a full post + const titleElement = aside.querySelector(".title"); let expandContract = ""; - const isExpanded = $aside.data("expanded") === true; - if (!$aside.data("full")) { - let icon = iconHTML(desc, { title: "post.expand_collapse" }); - const quoteId = $aside.find("blockquote").attr("id"); - expandContract = ``; - $(".title", $aside).css("cursor", "pointer"); - } - if (this.ignoredUsers && this.ignoredUsers.length > 0) { - const username = $aside.find(".title").text().trim().slice(0, -1); - if (username.length > 0 && this.ignoredUsers.includes(username)) { - $aside.find("p").remove(); - $aside.addClass("ignored-user"); + + if (!aside.dataset.full) { + const icon = iconHTML(desc, { title: "post.expand_collapse" }); + const quoteId = aside.querySelector("blockquote")?.id; + + if (quoteId) { + const isExpanded = aside.dataset.expanded === "true"; + expandContract = ``; + + if (titleElement) { + titleElement.style.cursor = "pointer"; + } } } - $(".quote-controls", $aside).html(expandContract + navLink); + + if (this.ignoredUsers?.length && titleElement) { + const username = titleElement.innerText.trim().slice(0, -1); + + if (username.length > 0 && this.ignoredUsers.includes(username)) { + aside.querySelectorAll("p").forEach((el) => el.remove()); + aside.classList.add("ignored-user"); + } + } + + const quoteControls = aside.querySelector(".quote-controls"); + if (quoteControls) { + quoteControls.innerHTML = expandContract + navLink; + } } - _insertQuoteControls($html) { - const $quotes = $html.find("aside.quote"); - if ($quotes.length === 0) { + _insertQuoteControls(html) { + const quotes = html.querySelectorAll("aside.quote"); + if (quotes.length === 0) { return; } - $quotes.each((index, e) => { - const $aside = $(e); - if ($aside.data("post")) { - const quoteId = `quote-id-${$aside.data("topic")}-${$aside.data( - "post" - )}-${index}`; - $aside.find("blockquote").attr("id", quoteId); + this.originalQuoteContents = new Map(); - this._updateQuoteElements($aside, "chevron-down"); - const $title = $(".title", $aside); + quotes.forEach((aside, index) => { + if (aside.dataset.post) { + const quoteId = `quote-id-${aside.dataset.topic}-${aside.dataset.post}-${index}`; + + const blockquote = aside.querySelector("blockquote"); + if (blockquote) { + blockquote.id = quoteId; + } + + this._updateQuoteElements(aside, "chevron-down"); + const title = aside.querySelector(".title"); + + if (!title) { + return; + } // If post/topic is not found then display username, skip controls - if (e.classList.contains("quote-post-not-found") && $title.length) { - e.querySelector(".title").innerHTML = e.dataset.username; + if (aside.classList.contains("quote-post-not-found")) { + if (aside.dataset.username) { + title.innerHTML = escape(aside.dataset.username); + } else { + title.remove(); + } + return; } // Unless it's a full quote, allow click to expand - if (!($aside.data("full") || $title.data("has-quote-controls"))) { - $title.on("click", (e2) => { - let $target = $(e2.target); - if ($target.closest("a").length) { + if (!aside.dataset.full && !title.dataset.hasQuoteControls) { + title.addEventListener("click", (e) => { + if (e.target.closest("a")) { return true; } - this._toggleQuote($aside); + + this._toggleQuote(aside); }); - $title.data("has-quote-controls", true); + + title.dataset.hasQuoteControls = true; } } }); diff --git a/app/assets/javascripts/discourse/app/widgets/post-menu.js b/app/assets/javascripts/discourse/app/widgets/post-menu.js index 7389b2b24c..6c0e520ee2 100644 --- a/app/assets/javascripts/discourse/app/widgets/post-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/post-menu.js @@ -17,8 +17,8 @@ const LIKE_ACTION = 2; const VIBRATE_DURATION = 5; const _builders = {}; -let _extraButtons = {}; export let apiExtraButtons = {}; +let _extraButtons = {}; let _buttonsToRemove = {}; export function addButton(name, builder) { @@ -26,9 +26,12 @@ export function addButton(name, builder) { } export function resetPostMenuExtraButtons() { - _buttonsToRemove = {}; - apiExtraButtons = {}; + for (const key of Object.keys(apiExtraButtons)) { + delete apiExtraButtons[key]; + } + _extraButtons = {}; + _buttonsToRemove = {}; } export function removeButton(name, callback) { @@ -147,41 +150,45 @@ function likeCount(attrs, state) { registerButton("like-count", likeCount); -registerButton("like", (attrs) => { - if (!attrs.showLike) { - return likeCount(attrs); +registerButton( + "like", + (attrs, _state, _siteSettings, _settings, currentUser) => { + if (!attrs.showLike) { + return likeCount(attrs); + } + + const className = attrs.liked + ? "toggle-like has-like fade-out" + : "toggle-like like"; + + const button = { + action: "like", + icon: attrs.liked ? "d-liked" : "d-unliked", + className, + before: "like-count", + data: { + "post-id": attrs.id, + }, + }; + + // If the user has already liked the post and doesn't have permission + // to undo that operation, then indicate via the title that they've liked it + // and disable the button. Otherwise, set the title even if the user + // is anonymous (meaning they don't currently have permission to like); + // this is important for accessibility. + if (attrs.liked && !attrs.canToggleLike) { + button.title = "post.controls.has_liked"; + } else { + button.title = attrs.liked + ? "post.controls.undo_like" + : "post.controls.like"; + } + if (currentUser && !attrs.canToggleLike) { + button.disabled = true; + } + return button; } - - const className = attrs.liked - ? "toggle-like has-like fade-out" - : "toggle-like like"; - - const button = { - action: "like", - icon: attrs.liked ? "d-liked" : "d-unliked", - className, - before: "like-count", - data: { - "post-id": attrs.id, - }, - }; - - // If the user has already liked the post and doesn't have permission - // to undo that operation, then indicate via the title that they've liked it - // and disable the button. Otherwise, set the title even if the user - // is anonymous (meaning they don't currently have permission to like); - // this is important for accessibility. - if (attrs.liked && !attrs.canToggleLike) { - button.title = "post.controls.has_liked"; - button.disabled = true; - } else { - button.title = attrs.liked - ? "post.controls.undo_like" - : "post.controls.like"; - } - - return button; -}); +); registerButton("flag-count", (attrs) => { let className = "button-count"; diff --git a/app/assets/javascripts/discourse/app/widgets/post.js b/app/assets/javascripts/discourse/app/widgets/post.js index e4354c844a..e2fa3ab3c0 100644 --- a/app/assets/javascripts/discourse/app/widgets/post.js +++ b/app/assets/javascripts/discourse/app/widgets/post.js @@ -11,7 +11,6 @@ import I18n from "I18n"; import PostCooked from "discourse/widgets/post-cooked"; import { Promise } from "rsvp"; import RawHtml from "discourse/widgets/raw-html"; -import bootbox from "bootbox"; import { dateNode } from "discourse/helpers/node"; import { h } from "virtual-dom"; import hbs from "discourse/widgets/hbs-compiler"; @@ -814,6 +813,7 @@ export function addPostClassesCallback(callback) { export default createWidget("post", { buildKey: (attrs) => `post-${attrs.id}`, + services: ["dialog"], shadowTree: true, buildAttributes(attrs) { @@ -918,7 +918,7 @@ export default createWidget("post", { const { remaining, max } = result; const threshold = Math.ceil(max * 0.1); if (remaining === threshold) { - bootbox.alert(I18n.t("post.few_likes_left")); + this.dialog.alert(I18n.t("post.few_likes_left")); kvs.set({ key: "lastWarnedLikes", value: Date.now() }); } }, diff --git a/app/assets/javascripts/discourse/app/widgets/poster-name.js b/app/assets/javascripts/discourse/app/widgets/poster-name.js index 50c1f39203..77a79fed30 100644 --- a/app/assets/javascripts/discourse/app/widgets/poster-name.js +++ b/app/assets/javascripts/discourse/app/widgets/poster-name.js @@ -42,6 +42,20 @@ export default createWidget("poster-name", { showGlyph: true, }, + didRenderWidget() { + if (this.attrs.user) { + this.attrs.user.trackStatus(); + this.attrs.user.on("status-changed", this, "scheduleRerender"); + } + }, + + willRerenderWidget() { + if (this.attrs.user) { + this.attrs.user.off("status-changed", this, "scheduleRerender"); + this.attrs.user.stopTrackingStatus(); + } + }, + // TODO: Allow extensibility posterGlyph(attrs) { if (attrs.moderator || attrs.groupModerator) { @@ -151,8 +165,12 @@ export default createWidget("poster-name", { afterNameContents(attrs) { const contents = []; - if (this.siteSettings.enable_user_status && attrs.userStatus) { - contents.push(this.attach("post-user-status", attrs.userStatus)); + if ( + this.siteSettings.enable_user_status && + attrs.user && + attrs.user.status + ) { + contents.push(this.attach("post-user-status", attrs.user.status)); } contents.push(...applyDecorators(this, "after-name", attrs, this.state)); return contents; diff --git a/app/assets/javascripts/discourse/app/widgets/render-glimmer.js b/app/assets/javascripts/discourse/app/widgets/render-glimmer.js index 3adc020614..e4db7d87ca 100644 --- a/app/assets/javascripts/discourse/app/widgets/render-glimmer.js +++ b/app/assets/javascripts/discourse/app/widgets/render-glimmer.js @@ -34,6 +34,44 @@ html(){ } ``` +You can also include function references in the `data` object, and use them as actions within the Ember component. +You will need to `bind` the function to ensure it maintains a reference to the widget, and you'll need to manually +call `this.scheduleRerender()` after making any changes to widget state (the normal widget auto-rerendering does not apply). + +Note that the @bind decorator will only work if you're using class-based Widget syntax. When using createWidget, you'll need to +call `.bind(this)` manually when passing the function to RenderGlimmer. + +For example: +``` +createWidget("my-widget", { + tagName: "div", + buildKey: () => `my-widget`, + + defaultState() { + return { counter: 0 }; + }, + + html(args, state){ + return [ + new RenderGlimmer( + this, + "div.my-wrapper-class", + hbs``, + { + counter: state.counter, + incrementCounter: this.incrementCounter.bind(this), + } + ), + ] + }, + + incrementCounter() { + this.state.counter++; + this.scheduleRerender(); + }, +}); +``` + */ export default class RenderGlimmer { @@ -70,6 +108,16 @@ export default class RenderGlimmer { } update(prev) { + if ( + prev.template.__id !== this.template.__id || + prev.tagName !== this.tagName + ) { + // Totally different component, but the widget framework guessed it was the + // same widget. Destroy old component and re-init the new one. + prev.destroy(); + return this.init(); + } + this._componentInfo = prev._componentInfo; if (prev.data !== this.data) { this._componentInfo.data = this.data; diff --git a/app/assets/javascripts/discourse/app/widgets/topic-admin-menu.js b/app/assets/javascripts/discourse/app/widgets/topic-admin-menu.js index 0a468a18e0..d019fe8046 100644 --- a/app/assets/javascripts/discourse/app/widgets/topic-admin-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/topic-admin-menu.js @@ -76,33 +76,44 @@ createWidget("topic-admin-menu-button", { showAdminMenu(e) { this.state.expanded = true; - let $button; + let button; if (e === undefined) { - $button = $(".keyboard-target-admin-menu"); + button = document.querySelector(".keyboard-target-admin-menu"); } else { - $button = $(e.target.closest("button")); + button = e.target.closest("button"); } - const position = $button.position(), - SPACING = 3, - MENU_WIDTH = 217; + const position = { top: button.offsetTop, left: button.offsetLeft }; + const spacing = 3; + const menuWidth = 212; - const rtl = $("html").hasClass("rtl"); - position.outerHeight = $button.outerHeight(); - - if (rtl) { - position.left -= MENU_WIDTH - $button.outerWidth(); - } + const rtl = document.documentElement.classList.contains("html.rtl"); + const buttonDOMRect = button.getBoundingClientRect(); + position.outerHeight = buttonDOMRect.height; if (this.attrs.openUpwards) { if (rtl) { - position.left -= $button[0].offsetWidth + SPACING; + position.left -= buttonDOMRect.width + spacing; } else { - position.left += $button[0].offsetWidth + SPACING; + position.left += buttonDOMRect.width + spacing; } } else { - position.top += $button[0].offsetHeight + SPACING; + if (rtl) { + if (buttonDOMRect.left < menuWidth) { + position.left += 0; + } else { + position.left -= menuWidth - buttonDOMRect.width; + } + } else { + const offsetRight = window.innerWidth - buttonDOMRect.right; + + if (offsetRight < menuWidth) { + position.left -= menuWidth - buttonDOMRect.width; + } + } + + position.top += buttonDOMRect.height + spacing; } this.state.position = position; @@ -323,8 +334,9 @@ export default createWidget("topic-admin-menu", { if (attrs.openUpwards) { const documentHeight = $(document).height(); - const mainHeight = $("#main").height(); - let bottom = documentHeight - top - 70 - $("#main").offset().top; + const mainHeight = $(".ember-application").height(); + let bottom = + documentHeight - top - 70 - $(".ember-application").offset().top; if (documentHeight > mainHeight) { bottom = bottom - (documentHeight - mainHeight) - outerHeight; diff --git a/app/assets/javascripts/discourse/app/widgets/user-menu.js b/app/assets/javascripts/discourse/app/widgets/user-menu.js index 3e4efc53b6..49e589e767 100644 --- a/app/assets/javascripts/discourse/app/widgets/user-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/user-menu.js @@ -156,7 +156,7 @@ createWidget("user-menu-links", { glyphs.push(this.bookmarksGlyph()); - if (this.siteSettings.enable_personal_messages || this.currentUser.staff) { + if (this.currentUser?.allowPersonalMessages) { glyphs.push(this.messagesGlyph()); } diff --git a/app/assets/javascripts/discourse/app/widgets/user-status-bubble.js b/app/assets/javascripts/discourse/app/widgets/user-status-bubble.js index d2cc0be9a8..ec814670ad 100644 --- a/app/assets/javascripts/discourse/app/widgets/user-status-bubble.js +++ b/app/assets/javascripts/discourse/app/widgets/user-status-bubble.js @@ -10,7 +10,7 @@ export default createWidget("user-status-bubble", { const until = moment .tz(attrs.ends_at, this.currentUser.timezone) .format(I18n.t("dates.long_date_without_year")); - title += `\n${I18n.t("user_status.until")} ${until}`; + title += `\n${I18n.t("until")} ${until}`; } return this.attach("emoji", { name: attrs.emoji, title }); diff --git a/app/assets/javascripts/discourse/config/optional-features.json b/app/assets/javascripts/discourse/config/optional-features.json index b5f4e8fa7b..9effd838a6 100644 --- a/app/assets/javascripts/discourse/config/optional-features.json +++ b/app/assets/javascripts/discourse/config/optional-features.json @@ -1,5 +1,4 @@ { "application-template-wrapper": false, - "default-async-observers": true, - "jquery-integration": true + "default-async-observers": true } diff --git a/app/assets/javascripts/discourse/ember-cli-build.js b/app/assets/javascripts/discourse/ember-cli-build.js index 0224c3383a..8fa1004651 100644 --- a/app/assets/javascripts/discourse/ember-cli-build.js +++ b/app/assets/javascripts/discourse/ember-cli-build.js @@ -14,6 +14,7 @@ const SILENCED_WARN_PREFIXES = [ "Setting the `jquery-integration` optional feature flag", "The Ember Classic edition has been deprecated", "Setting the `template-only-glimmer-components` optional feature flag to `false`", + "DEPRECATION: Invoking the `` component with positional arguments is deprecated", ]; module.exports = function (defaults) { @@ -29,6 +30,16 @@ module.exports = function (defaults) { } }; + // Silence warnings which go straight to console.warn (e.g. template compiler deprecations) + /* eslint-disable no-console */ + const oldConsoleWarn = console.warn.bind(console); + console.warn = (message, ...args) => { + if (!SILENCED_WARN_PREFIXES.some((prefix) => message.startsWith(prefix))) { + return oldConsoleWarn(message, ...args); + } + }; + /* eslint-enable no-console */ + const isProduction = EmberApp.env().includes("production"); const isTest = EmberApp.env().includes("test"); @@ -134,6 +145,13 @@ module.exports = function (defaults) { "/app/assets/javascripts/discourse/public/assets/scripts/module-shims.js" ); + const discoursePluginsTree = app.project + .findAddonByName("discourse-plugins") + .generatePluginsTree(); + + const terserPlugin = app.project.findAddonByName("ember-cli-terser"); + const applyTerser = (tree) => terserPlugin.postprocessTree("all", tree); + return mergeTrees([ createI18nTree(discourseRoot, vendorJs), app.toTree(), @@ -142,18 +160,20 @@ module.exports = function (defaults) { files: ["highlight-test-bundle.min.js"], destDir: "assets/highlightjs", }), - concat(mergeTrees([app.options.adminTree]), { - outputFile: `assets/admin.js`, - }), - concat(mergeTrees([app.options.wizardTree]), { - outputFile: `assets/wizard.js`, - }), - prettyTextEngine(vendorJs, "discourse-markdown"), - concat("public/assets/scripts", { - outputFile: `assets/start-discourse.js`, - headerFiles: [`start-app.js`], - inputFiles: [`discourse-boot.js`], - }), + applyTerser( + concat(mergeTrees([app.options.adminTree]), { + inputFiles: ["**/*.js"], + outputFile: `assets/admin.js`, + }) + ), + applyTerser( + concat(mergeTrees([app.options.wizardTree]), { + inputFiles: ["**/*.js"], + outputFile: `assets/wizard.js`, + }) + ), + applyTerser(prettyTextEngine(app)), generateScriptsTree(app), + applyTerser(discoursePluginsTree), ]); }; diff --git a/app/assets/javascripts/discourse/lib/bootstrap-json/index.js b/app/assets/javascripts/discourse/lib/bootstrap-json/index.js index a236d7aefe..b2b243fdc5 100644 --- a/app/assets/javascripts/discourse/lib/bootstrap-json/index.js +++ b/app/assets/javascripts/discourse/lib/bootstrap-json/index.js @@ -5,7 +5,8 @@ const fetch = require("node-fetch"); const { encode } = require("html-entities"); const cleanBaseURL = require("clean-base-url"); const path = require("path"); -const { promises: fs } = require("fs"); +const fs = require("fs"); +const fsPromises = fs.promises; const { JSDOM } = require("jsdom"); const { shouldLoadPluginTestJs } = require("discourse/lib/plugin-js"); const { Buffer } = require("node:buffer"); @@ -231,7 +232,7 @@ async function applyBootstrap(bootstrap, template, response, baseURL, preload) { async function buildFromBootstrap(proxy, baseURL, req, response, preload) { try { - const template = await fs.readFile( + const template = await fsPromises.readFile( path.join(cwd(), "dist", "index.html"), "utf8" ); @@ -239,6 +240,24 @@ async function buildFromBootstrap(proxy, baseURL, req, response, preload) { let url = new URL(`${proxy}${baseURL}bootstrap.json`); url.searchParams.append("for_url", req.url); + const forUrlSearchParams = new URL(req.url, "https://dummy-origin.invalid") + .searchParams; + + const mobileView = forUrlSearchParams.get("mobile_view"); + if (mobileView) { + url.searchParams.append("mobile_view", mobileView); + } + + const reqUrlSafeMode = forUrlSearchParams.get("safe_mode"); + if (reqUrlSafeMode) { + url.searchParams.append("safe_mode", reqUrlSafeMode); + } + + const reqUrlPreviewThemeId = forUrlSearchParams.get("preview_theme_id"); + if (reqUrlPreviewThemeId) { + url.searchParams.append("preview_theme_id", reqUrlPreviewThemeId); + } + const res = await fetch(url, { headers: req.headers }); const json = await res.json(); @@ -319,7 +338,7 @@ async function handleRequest(proxy, baseURL, req, res) { const newCSP = csp .replaceAll(proxy, `http://${originalHost}`) - .replaceAll("script-src ", `script-src ${emberCliAdditions}`); + .replaceAll("script-src ", `script-src ${emberCliAdditions} `); res.set("content-security-policy", newCSP); } @@ -360,12 +379,56 @@ module.exports = { contentFor(type, config) { if (shouldLoadPluginTestJs() && type === "test-plugin-js") { - return ` - - - `; + const scripts = []; + + const pluginInfos = this.app.project + .findAddonByName("discourse-plugins") + .pluginInfos(); + + for (const { + pluginName, + directoryName, + hasJs, + hasAdminJs, + } of pluginInfos) { + if (hasJs) { + scripts.push({ + src: `plugins/${directoryName}.js`, + name: pluginName, + }); + } + + if (fs.existsSync(`../plugins/${directoryName}_extras.js.erb`)) { + scripts.push({ + src: `plugins/${directoryName}_extras.js`, + name: pluginName, + }); + } + + if (hasAdminJs) { + scripts.push({ + src: `plugins/${directoryName}_admin.js`, + name: pluginName, + }); + } + } + + return scripts + .map( + ({ src, name }) => + `` + ) + .join("\n"); } else if (shouldLoadPluginTestJs() && type === "test-plugin-tests-js") { - return ``; + return this.app.project + .findAddonByName("discourse-plugins") + .pluginInfos() + .filter(({ hasTests }) => hasTests) + .map( + ({ directoryName, pluginName }) => + `` + ) + .join("\n"); } }, @@ -387,6 +450,16 @@ to serve API requests. For example: const rawMiddleware = express.raw({ type: () => true, limit: "100mb" }); + app.use( + "/favicon.ico", + express.static( + path.join( + __dirname, + "../../../../../../public/images/discourse-logo-sketch-small.png" + ) + ) + ); + app.use(rawMiddleware, async (req, res, next) => { try { if (this.shouldForwardRequest(req)) { diff --git a/app/assets/javascripts/discourse/lib/dialog-holder/addon/components/dialog-holder.hbs b/app/assets/javascripts/discourse/lib/dialog-holder/addon/components/dialog-holder.hbs new file mode 100644 index 0000000000..46e2cd5aaf --- /dev/null +++ b/app/assets/javascripts/discourse/lib/dialog-holder/addon/components/dialog-holder.hbs @@ -0,0 +1,33 @@ + diff --git a/app/assets/javascripts/discourse/lib/dialog-holder/addon/components/dialog-holder.js b/app/assets/javascripts/discourse/lib/dialog-holder/addon/components/dialog-holder.js new file mode 100644 index 0000000000..4a2bde4f3d --- /dev/null +++ b/app/assets/javascripts/discourse/lib/dialog-holder/addon/components/dialog-holder.js @@ -0,0 +1,16 @@ +import Component from "@glimmer/component"; +import { inject as service } from "@ember/service"; +import { action } from "@ember/object"; + +export default class DialogHolder extends Component { + @service dialog; + + @action + async handleButtonAction(btn) { + if (btn.action && typeof btn.action === "function") { + await btn.action(); + } + + this.dialog.cancel(); + } +} diff --git a/app/assets/javascripts/discourse/lib/dialog-holder/addon/services/dialog.js b/app/assets/javascripts/discourse/lib/dialog-holder/addon/services/dialog.js new file mode 100644 index 0000000000..fa072595ed --- /dev/null +++ b/app/assets/javascripts/discourse/lib/dialog-holder/addon/services/dialog.js @@ -0,0 +1,152 @@ +import Service from "@ember/service"; +import A11yDialog from "a11y-dialog"; +import { bind } from "discourse-common/utils/decorators"; + +export default Service.extend({ + message: null, + type: null, + dialogInstance: null, + + title: null, + titleElementId: null, + + confirmButtonIcon: null, + confirmButtonLabel: null, + cancelButtonLabel: null, + shouldDisplayCancel: null, + + didConfirm: null, + didCancel: null, + buttons: null, + class: null, + _confirming: false, + + dialog(params) { + const { + message, + type, + title, + + confirmButtonIcon, + confirmButtonLabel = "ok_value", + cancelButtonLabel = "cancel_value", + shouldDisplayCancel, + + didConfirm, + didCancel, + buttons, + } = params; + + const element = document.getElementById("dialog-holder"); + + this.setProperties({ + message, + type, + dialogInstance: new A11yDialog(element), + + title, + titleElementId: title !== null ? "dialog-title" : null, + + confirmButtonLabel, + confirmButtonIcon, + cancelButtonLabel, + shouldDisplayCancel, + + didConfirm, + didCancel, + buttons, + class: params.class, + }); + + this.dialogInstance.show(); + + this.dialogInstance.on("hide", () => { + if (!this._confirming && this.didCancel) { + this.didCancel(); + } + + this.reset(); + }); + }, + + alert(params) { + // support string param for easier porting of bootbox.alert + if (typeof params === "string") { + return this.dialog({ + message: params, + type: "alert", + }); + } + + return this.dialog({ + ...params, + type: "alert", + }); + }, + + confirm(params) { + return this.dialog({ + ...params, + shouldDisplayCancel: true, + buttons: null, + type: "confirm", + }); + }, + + notice(message) { + return this.dialog({ + message, + type: "notice", + }); + }, + + yesNoConfirm(params) { + return this.confirm({ + ...params, + confirmButtonLabel: "yes_value", + cancelButtonLabel: "no_value", + }); + }, + + reset() { + this.setProperties({ + message: null, + type: null, + dialogInstance: null, + + title: null, + titleElementId: null, + + confirmButtonLabel: null, + confirmButtonIcon: null, + cancelButtonLabel: null, + shouldDisplayCancel: null, + + didConfirm: null, + didCancel: null, + buttons: null, + class: null, + + _confirming: false, + }); + }, + + willDestroy() { + this.dialogInstance?.destroy(); + this.reset(); + }, + + @bind + didConfirmWrapped() { + if (this.didConfirm) { + this.didConfirm(); + } + this._confirming = true; + this.dialogInstance.hide(); + }, + + @bind + cancel() { + this.dialogInstance.hide(); + }, +}); diff --git a/app/assets/javascripts/discourse/lib/dialog-holder/app/components/dialog-holder.js b/app/assets/javascripts/discourse/lib/dialog-holder/app/components/dialog-holder.js new file mode 100644 index 0000000000..151d46784a --- /dev/null +++ b/app/assets/javascripts/discourse/lib/dialog-holder/app/components/dialog-holder.js @@ -0,0 +1 @@ +export { default } from "dialog-holder/components/dialog-holder"; diff --git a/app/assets/javascripts/discourse/lib/dialog-holder/index.js b/app/assets/javascripts/discourse/lib/dialog-holder/index.js new file mode 100644 index 0000000000..b5b31da4a4 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/dialog-holder/index.js @@ -0,0 +1,9 @@ +"use strict"; + +module.exports = { + name: require("./package").name, + + isDevelopingAddon() { + return true; + }, +}; diff --git a/app/assets/javascripts/discourse/lib/dialog-holder/package.json b/app/assets/javascripts/discourse/lib/dialog-holder/package.json new file mode 100644 index 0000000000..b82d6b7da3 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/dialog-holder/package.json @@ -0,0 +1,15 @@ +{ + "name": "dialog-holder", + "keywords": [ + "ember-addon" + ], + "dependencies": { + "a11y-dialog": "7.5.0", + "ember-auto-import": "^2.4.2", + "ember-cli-babel": "^7.26.10", + "ember-cli-htmlbars": "^6.1.0" + }, + "devDependencies": { + "webpack": "^5.73.0" + } +} diff --git a/app/assets/javascripts/discourse/lib/dialog-holder/yarn.lock b/app/assets/javascripts/discourse/lib/dialog-holder/yarn.lock new file mode 100644 index 0000000000..d81a3899f1 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/dialog-holder/yarn.lock @@ -0,0 +1,3659 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.13.tgz#6aff7b350a1e8c3e40b029e46cbe78e24a913483" + integrity sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw== + +"@babel/core@^7.12.0", "@babel/core@^7.16.7", "@babel/core@^7.3.4": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.13.tgz#9be8c44512751b05094a4d3ab05fc53a47ce00ac" + integrity sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.13" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-module-transforms" "^7.18.9" + "@babel/helpers" "^7.18.9" + "@babel/parser" "^7.18.13" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.18.13" + "@babel/types" "^7.18.13" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/generator@^7.18.13": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.13.tgz#59550cbb9ae79b8def15587bdfbaa388c4abf212" + integrity sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ== + dependencies: + "@babel/types" "^7.18.13" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb" + integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-compilation-targets@^7.12.0", "@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf" + integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg== + dependencies: + "@babel/compat-data" "^7.18.8" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.20.2" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.18.9": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.13.tgz#63e771187bd06d234f95fdf8bd5f8b6429de6298" + integrity sha512-hDvXp+QYxSRL+23mpAlSGxHMDyIGChm0/AwTfTAAK5Ufe40nCsyNdaYCGuK91phn/fVu9kqayImRDkvNAgdrsA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" + +"@babel/helper-create-regexp-features-plugin@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz#3e35f4e04acbbf25f1b3534a657610a000543d3c" + integrity sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + regexpu-core "^5.1.0" + +"@babel/helper-define-polyfill-provider@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz#bd10d0aca18e8ce012755395b05a79f45eca5073" + integrity sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg== + dependencies: + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-explode-assignable-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" + integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0" + integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== + dependencies: + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-member-expression-to-functions@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815" + integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg== + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712" + integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-optimise-call-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" + integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f" + integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w== + +"@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" + integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-wrap-function" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz#1092e002feca980fbbb0bd4d51b74a65c6a500e6" + integrity sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-skip-transparent-expression-wrappers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz#778d87b3a758d90b471e7b9918f34a9a02eb5818" + integrity sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw== + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" + integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== + +"@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helper-wrap-function@^7.18.9": + version "7.18.11" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.18.11.tgz#bff23ace436e3f6aefb61f85ffae2291c80ed1fb" + integrity sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w== + dependencies: + "@babel/helper-function-name" "^7.18.9" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.18.11" + "@babel/types" "^7.18.10" + +"@babel/helpers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9" + integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ== + dependencies: + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.18.10", "@babel/parser@^7.18.13": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.13.tgz#5b2dd21cae4a2c5145f1fbd8ca103f9313d3b7e4" + integrity sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" + integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz#a11af19aa373d68d561f08e0a57242350ed0ec50" + integrity sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/plugin-proposal-optional-chaining" "^7.18.9" + +"@babel/plugin-proposal-async-generator-functions@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz#85ea478c98b0095c3e4102bff3b67d306ed24952" + integrity sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-remap-async-to-generator" "^7.18.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.16.5", "@babel/plugin-proposal-class-properties@^7.16.7", "@babel/plugin-proposal-class-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-class-static-block@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz#8aa81d403ab72d3962fc06c26e222dacfc9b9020" + integrity sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-decorators@^7.13.5", "@babel/plugin-proposal-decorators@^7.16.7": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.10.tgz#788650d01e518a8a722eb8b3055dd9d73ecb7a35" + integrity sha512-wdGTwWF5QtpTY/gbBtQLAiCnoxfD4qMbN87NYZle1dOZ9Os8Y6zXcKrIaOU8W+TIvFUWVGG9tUgNww3CjXRVVw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/plugin-syntax-decorators" "^7.18.6" + +"@babel/plugin-proposal-dynamic-import@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94" + integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203" + integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b" + integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz#8148cbb350483bf6220af06fa6db3690e14b2e23" + integrity sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" + integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" + integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz#f9434f6beb2c8cae9dfcf97d2a5941bbbf9ad4e7" + integrity sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q== + dependencies: + "@babel/compat-data" "^7.18.8" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.18.8" + +"@babel/plugin-proposal-optional-catch-binding@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb" + integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz#e8e8fe0723f2563960e4bf5e9690933691915993" + integrity sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.16.5", "@babel/plugin-proposal-private-methods@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea" + integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-private-property-in-object@^7.16.5", "@babel/plugin-proposal-private-property-in-object@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz#a64137b232f0aca3733a67eb1a144c192389c503" + integrity sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" + integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-decorators@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.18.6.tgz#2e45af22835d0b0f8665da2bfd4463649ce5dbc1" + integrity sha512-fqyLgjcxf/1yhyZ6A+yo1u9gJ7eleFQod2lkaUsF9DQ7sbbY3Ligym3L0+I2c0WmqNKDpoD9UTb1AKP3qRMOAQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz#cd6190500a4fa2fe31990a963ffab4b63e4505e4" + integrity sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz#1c09cd25795c7c2b8a4ba9ae49394576d4133285" + integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz#19063fcf8771ec7b31d742339dac62433d0611fe" + integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-async-to-generator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz#ccda3d1ab9d5ced5265fdb13f1882d5476c71615" + integrity sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-remap-async-to-generator" "^7.18.6" + +"@babel/plugin-transform-block-scoped-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8" + integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-block-scoping@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz#f9b7e018ac3f373c81452d6ada8bd5a18928926d" + integrity sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-classes@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.9.tgz#90818efc5b9746879b869d5ce83eb2aa48bbc3da" + integrity sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz#2357a8224d402dad623caf6259b611e56aec746e" + integrity sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-destructuring@^7.18.9": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.13.tgz#9e03bc4a94475d62b7f4114938e6c5c33372cbf5" + integrity sha512-TodpQ29XekIsex2A+YJPj5ax2plkGa8YYY6mFjCohk/IG9IY42Rtuj1FuDeemfg2ipxIFLzPeA83SIBnlhSIow== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8" + integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-duplicate-keys@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e" + integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-exponentiation-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd" + integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-for-of@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1" + integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0" + integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== + dependencies: + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc" + integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-member-expression-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e" + integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-modules-amd@^7.13.0", "@babel/plugin-transform-modules-amd@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz#8c91f8c5115d2202f277549848874027d7172d21" + integrity sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz#afd243afba166cca69892e24a8fd8c9f2ca87883" + integrity sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.9.tgz#545df284a7ac6a05125e3e405e536c5853099a06" + integrity sha512-zY/VSIbbqtoRoJKo2cDTewL364jSlZGvn0LKOf9ntbfxOvjfmyrdtEEOAdswOswhZEb8UH3jDkCKHd1sPgsS0A== + dependencies: + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-module-transforms" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-validator-identifier" "^7.18.6" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9" + integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz#c89bfbc7cc6805d692f3a49bc5fc1b630007246d" + integrity sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-new-target@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8" + integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-object-super@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c" + integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + +"@babel/plugin-transform-parameters@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz#ee9f1a0ce6d78af58d0956a9378ea3427cccb48a" + integrity sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-property-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3" + integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-regenerator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz#585c66cb84d4b4bf72519a34cfce761b8676ca73" + integrity sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + regenerator-transform "^0.15.0" + +"@babel/plugin-transform-reserved-words@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a" + integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-runtime@^7.13.9": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz#37d14d1fa810a368fd635d4d1476c0154144a96f" + integrity sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.9" + babel-plugin-polyfill-corejs2 "^0.3.2" + babel-plugin-polyfill-corejs3 "^0.5.3" + babel-plugin-polyfill-regenerator "^0.4.0" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" + integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-spread@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.9.tgz#6ea7a6297740f381c540ac56caf75b05b74fb664" + integrity sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + +"@babel/plugin-transform-sticky-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc" + integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-template-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e" + integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typeof-symbol@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0" + integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typescript@^7.13.0": + version "7.18.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.12.tgz#712e9a71b9e00fde9f8c0238e0cceee86ab2f8fd" + integrity sha512-2vjjam0cum0miPkenUbQswKowuxs/NjMwIKEq0zwegRxXk12C9YOF9STXnaUptITOtOJHKHpzvvWYOjbm6tc0w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-typescript" "^7.18.6" + +"@babel/plugin-transform-unicode-escapes@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246" + integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-unicode-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca" + integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/polyfill@^7.11.5": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.12.1.tgz#1f2d6371d1261bbd961f3c5d5909150e12d0bd96" + integrity sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + +"@babel/preset-env@^7.16.5", "@babel/preset-env@^7.16.7": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.18.10.tgz#83b8dfe70d7eea1aae5a10635ab0a5fe60dfc0f4" + integrity sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA== + dependencies: + "@babel/compat-data" "^7.18.8" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-async-generator-functions" "^7.18.10" + "@babel/plugin-proposal-class-properties" "^7.18.6" + "@babel/plugin-proposal-class-static-block" "^7.18.6" + "@babel/plugin-proposal-dynamic-import" "^7.18.6" + "@babel/plugin-proposal-export-namespace-from" "^7.18.9" + "@babel/plugin-proposal-json-strings" "^7.18.6" + "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" + "@babel/plugin-proposal-numeric-separator" "^7.18.6" + "@babel/plugin-proposal-object-rest-spread" "^7.18.9" + "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" + "@babel/plugin-proposal-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-private-methods" "^7.18.6" + "@babel/plugin-proposal-private-property-in-object" "^7.18.6" + "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.18.6" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.18.6" + "@babel/plugin-transform-async-to-generator" "^7.18.6" + "@babel/plugin-transform-block-scoped-functions" "^7.18.6" + "@babel/plugin-transform-block-scoping" "^7.18.9" + "@babel/plugin-transform-classes" "^7.18.9" + "@babel/plugin-transform-computed-properties" "^7.18.9" + "@babel/plugin-transform-destructuring" "^7.18.9" + "@babel/plugin-transform-dotall-regex" "^7.18.6" + "@babel/plugin-transform-duplicate-keys" "^7.18.9" + "@babel/plugin-transform-exponentiation-operator" "^7.18.6" + "@babel/plugin-transform-for-of" "^7.18.8" + "@babel/plugin-transform-function-name" "^7.18.9" + "@babel/plugin-transform-literals" "^7.18.9" + "@babel/plugin-transform-member-expression-literals" "^7.18.6" + "@babel/plugin-transform-modules-amd" "^7.18.6" + "@babel/plugin-transform-modules-commonjs" "^7.18.6" + "@babel/plugin-transform-modules-systemjs" "^7.18.9" + "@babel/plugin-transform-modules-umd" "^7.18.6" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.18.6" + "@babel/plugin-transform-new-target" "^7.18.6" + "@babel/plugin-transform-object-super" "^7.18.6" + "@babel/plugin-transform-parameters" "^7.18.8" + "@babel/plugin-transform-property-literals" "^7.18.6" + "@babel/plugin-transform-regenerator" "^7.18.6" + "@babel/plugin-transform-reserved-words" "^7.18.6" + "@babel/plugin-transform-shorthand-properties" "^7.18.6" + "@babel/plugin-transform-spread" "^7.18.9" + "@babel/plugin-transform-sticky-regex" "^7.18.6" + "@babel/plugin-transform-template-literals" "^7.18.9" + "@babel/plugin-transform-typeof-symbol" "^7.18.9" + "@babel/plugin-transform-unicode-escapes" "^7.18.10" + "@babel/plugin-transform-unicode-regex" "^7.18.6" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.18.10" + babel-plugin-polyfill-corejs2 "^0.3.2" + babel-plugin-polyfill-corejs3 "^0.5.3" + babel-plugin-polyfill-regenerator "^0.4.0" + core-js-compat "^3.22.1" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/runtime@7.12.18": + version "7.12.18" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.18.tgz#af137bd7e7d9705a412b3caaf991fe6aaa97831b" + integrity sha512-BogPQ7ciE6SYAUPtlm9tWbgI9+2AgqSam6QivMgXgAT+fKbgppaj4ZX15MHeLC1PVF5sNk70huBu20XxWOs8Cg== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.8.4": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" + integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.18.10", "@babel/template@^7.18.6": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" + +"@babel/traverse@^7.18.11", "@babel/traverse@^7.18.13", "@babel/traverse@^7.18.9": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.13.tgz#5ab59ef51a997b3f10c4587d648b9696b6cb1a68" + integrity sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.13" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.13" + "@babel/types" "^7.18.13" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.18.10", "@babel/types@^7.18.13", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.4.4": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.13.tgz#30aeb9e514f4100f7c1cb6e5ba472b30e48f519a" + integrity sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ== + dependencies: + "@babel/helper-string-parser" "^7.18.10" + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + +"@ember-data/rfc395-data@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@ember-data/rfc395-data/-/rfc395-data-0.0.4.tgz#ecb86efdf5d7733a76ff14ea651a1b0ed1f8a843" + integrity sha512-tGRdvgC9/QMQSuSuJV45xoyhI0Pzjm7A9o/MVVA3HakXIImJbbzx/k/6dO9CUEQXIyS2y0fW6C1XaYOG7rY0FQ== + +"@ember/edition-utils@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ember/edition-utils/-/edition-utils-1.2.0.tgz#a039f542dc14c8e8299c81cd5abba95e2459cfa6" + integrity sha512-VmVq/8saCaPdesQmftPqbFtxJWrzxNGSQ+e8x8LLe3Hjm36pJ04Q8LeORGZkAeOhldoUX9seLGmSaHeXkIqoog== + +"@embroider/macros@^1.0.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@embroider/macros/-/macros-1.8.3.tgz#2f0961ab8871f6ad819630208031d705b357757e" + integrity sha512-gnIOfTL/pUkoD6oI7JyWOqXlVIUgZM+CnbH10/YNtZr2K0hij9eZQMdgjOZZVgN0rKOFw9dIREqc1ygrJHRYQA== + dependencies: + "@embroider/shared-internals" "1.8.3" + assert-never "^1.2.1" + babel-import-util "^1.1.0" + ember-cli-babel "^7.26.6" + find-up "^5.0.0" + lodash "^4.17.21" + resolve "^1.20.0" + semver "^7.3.2" + +"@embroider/shared-internals@1.8.3", "@embroider/shared-internals@^1.0.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@embroider/shared-internals/-/shared-internals-1.8.3.tgz#52d868dc80016e9fe983552c0e516f437bf9b9f9" + integrity sha512-N5Gho6Qk8z5u+mxLCcMYAoQMbN4MmH+z2jXwQHVs859bxuZTxwF6kKtsybDAASCtd2YGxEmzcc1Ja/wM28824w== + dependencies: + babel-import-util "^1.1.0" + ember-rfc176-data "^0.3.17" + fs-extra "^9.1.0" + js-string-escape "^1.0.1" + lodash "^4.17.21" + resolve-package-path "^4.0.1" + semver "^7.3.5" + typescript-memoize "^1.0.1" + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.15" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" + integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@types/eslint-scope@^3.7.3": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.4.6" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.6.tgz#7976f054c1bccfcf514bff0564c0c41df5c08207" + integrity sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" + integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== + +"@types/estree@^0.0.51": + version "0.0.51" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" + integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== + +"@types/fs-extra@^5.0.5": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.1.0.tgz#2a325ef97901504a3828718c390d34b8426a10a1" + integrity sha512-AInn5+UBFIK9FK5xc9yP5e3TQSPNNgjHByqYcj9g5elVBnDQcQL7PlO1CIRy2gWlbwK7UPYqi7vRvFA44dCmYQ== + dependencies: + "@types/node" "*" + +"@types/glob@*": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/minimatch@*", "@types/minimatch@^3.0.3", "@types/minimatch@^3.0.4": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + +"@types/node@*": + version "18.7.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.11.tgz#486e72cfccde88da24e1f23ff1b7d8bfb64e6250" + integrity sha512-KZhFpSLlmK/sdocfSAjqPETTMd0ug6HIMIAwkwUpU79olnZdQtMxpQP+G1wDzCH7na+FltSIhbaZuKdwZ8RDrw== + +"@types/rimraf@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.5.tgz#368fb04d59630b727fc05a74d2ca557f64a8ef98" + integrity sha512-YyP+VfeaqAyFmXoTh3HChxOQMyjByRMsHU7kc5KOJkSlXudhMhQIALbYV7rHh/l8d2lX3VUQzprrcAgWdRuU8g== + dependencies: + "@types/glob" "*" + "@types/node" "*" + +"@types/symlink-or-copy@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#4151a81b4052c80bc2becbae09f3a9ec010a9c7a" + integrity sha512-Lja2xYuuf2B3knEsga8ShbOdsfNOtzT73GyJmZyY7eGl2+ajOqrs8yM5ze0fsSoYwvA6bw7/Qr7OZ7PEEmYwWg== + +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== + +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== + +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== + +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== + +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== + +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" + +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +a11y-dialog@7.5.0: + version "7.5.0" + resolved "https://registry.yarnpkg.com/a11y-dialog/-/a11y-dialog-7.5.0.tgz#1540627b18e3b1e266e0dcbdb5d1e7ac52079fe1" + integrity sha512-UF7cy4lfZQtvjRV5N4xdWFba+Pb1qW6FPp0p58dLjMTJ4PwIGGekTbmqUt3etBBRo9HbTqhlNsXQhzIuXeJpng== + dependencies: + focusable-selectors "^0.3.1" + +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + +acorn@^8.5.0, acorn@^8.7.1: + version "8.8.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.8.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +amd-name-resolver@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.3.1.tgz#ffe71c683c6e7191fc4ae1bb3aaed15abea135d9" + integrity sha512-26qTEWqZQ+cxSYygZ4Cf8tsjDBLceJahhtewxtKZA3SRa4PluuqYCuheemDQD+7Mf5B7sr+zhTDWAHDh02a1Dw== + dependencies: + ensure-posix-path "^1.0.1" + object-hash "^1.3.1" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + integrity sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA== + +assert-never@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.2.1.tgz#11f0e363bf146205fb08193b5c7b90f4d1cf44fe" + integrity sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw== + +async-disk-cache@^1.2.1: + version "1.3.5" + resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.3.5.tgz#cc6206ed79bb6982b878fc52e0505e4f52b62a02" + integrity sha512-VZpqfR0R7CEOJZ/0FOTgWq70lCrZyS1rkI8PXugDUkTKyyAUgZ2zQ09gLhMkEn+wN8LYeUTPxZdXtlX/kmbXKQ== + dependencies: + debug "^2.1.3" + heimdalljs "^0.2.3" + istextorbinary "2.1.0" + mkdirp "^0.5.0" + rimraf "^2.5.3" + rsvp "^3.0.18" + username-sync "^1.0.2" + +async-disk-cache@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-2.1.0.tgz#e0f37b187ed8c41a5991518a9556d206ae2843a2" + integrity sha512-iH+boep2xivfD9wMaZWkywYIURSmsL96d6MoqrC94BnGSvXE4Quf8hnJiHGFYhw/nLeIa1XyRaf4vvcvkwAefg== + dependencies: + debug "^4.1.1" + heimdalljs "^0.2.3" + istextorbinary "^2.5.1" + mkdirp "^0.5.0" + rimraf "^3.0.0" + rsvp "^4.8.5" + username-sync "^1.0.2" + +async-promise-queue@^1.0.3: + version "1.0.5" + resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.5.tgz#cb23bce9fce903a133946a700cc85f27f09ea49d" + integrity sha512-xi0aQ1rrjPWYmqbwr18rrSKbSaXIeIwSd1J4KAgVfkq8utNbdZoht7GfvfY6swFUAMJ9obkc4WPJmtGwl+B8dw== + dependencies: + async "^2.4.1" + debug "^2.6.8" + +async@^2.4.1: + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +babel-import-util@^1.1.0, babel-import-util@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/babel-import-util/-/babel-import-util-1.2.2.tgz#1027560e143a4a68b1758e71d4fadc661614e495" + integrity sha512-8HgkHWt5WawRFukO30TuaL9EiDUOdvyKtDwLma4uBNeUSDbOO0/hiPfavrOWxSS6J6TKXfukWHZ3wiqZhJ8ONQ== + +babel-loader@^8.0.6: + version "8.2.5" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.5.tgz#d45f585e654d5a5d90f5350a779d7647c5ed512e" + integrity sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ== + dependencies: + find-cache-dir "^3.3.1" + loader-utils "^2.0.0" + make-dir "^3.1.0" + schema-utils "^2.6.5" + +babel-plugin-debug-macros@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.3.4.tgz#22961d0cb851a80654cece807a8b4b73d85c6075" + integrity sha512-wfel/vb3pXfwIDZUrkoDrn5FHmlWI96PCJ3UCDv2a86poJ3EQrnArNW5KfHSVJ9IOgxHbo748cQt7sDU+0KCEw== + dependencies: + semver "^5.3.0" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-ember-data-packages-polyfill@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-data-packages-polyfill/-/babel-plugin-ember-data-packages-polyfill-0.1.2.tgz#21154c095ddc703722b1fb8bb06c126c0b6d77dc" + integrity sha512-kTHnOwoOXfPXi00Z8yAgyD64+jdSXk3pknnS7NlqnCKAU6YDkXZ4Y7irl66kaZjZn0FBBt0P4YOZFZk85jYOww== + dependencies: + "@ember-data/rfc395-data" "^0.0.4" + +babel-plugin-ember-modules-api-polyfill@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-3.5.0.tgz#27b6087fac75661f779f32e60f94b14d0e9f6965" + integrity sha512-pJajN/DkQUnStw0Az8c6khVcMQHgzqWr61lLNtVeu0g61LRW0k9jyK7vaedrHDWGe/Qe8sxG5wpiyW9NsMqFzA== + dependencies: + ember-rfc176-data "^0.3.17" + +babel-plugin-ember-template-compilation@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-template-compilation/-/babel-plugin-ember-template-compilation-1.0.2.tgz#e0695b8ad5a8fe6b2cbdff1eadb01cf402731ad6" + integrity sha512-4HBMksmlYsWEf/C/n3uW5rkBRbUp4FNaspzdQTAHgLbfCJnkLze8R6i6sUSge48y/Wne7mx+vcImI1o6rlUwXQ== + dependencies: + babel-import-util "^1.2.0" + line-column "^1.0.2" + magic-string "^0.26.0" + string.prototype.matchall "^4.0.5" + +babel-plugin-htmlbars-inline-precompile@^5.2.1, babel-plugin-htmlbars-inline-precompile@^5.3.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-5.3.1.tgz#5ba272e2e4b6221522401f5f1d98a73b1de38787" + integrity sha512-QWjjFgSKtSRIcsBhJmEwS2laIdrA6na8HAlc/pEAhjHgQsah/gMiBFRZvbQTy//hWxR4BMwV7/Mya7q5H8uHeA== + dependencies: + babel-plugin-ember-modules-api-polyfill "^3.5.0" + line-column "^1.0.2" + magic-string "^0.25.7" + parse-static-imports "^1.1.0" + string.prototype.matchall "^4.0.5" + +babel-plugin-module-resolver@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.2.0.tgz#ddfa5e301e3b9aa12d852a9979f18b37881ff5a7" + integrity sha512-tjR0GvSndzPew/Iayf4uICWZqjBwnlMWjSx6brryfQ81F9rxBVqwDJtFCV8oOs0+vJeefK9TmdZtkIFdFe1UnA== + dependencies: + find-babel-config "^1.1.0" + glob "^7.1.2" + pkg-up "^2.0.0" + reselect "^3.0.1" + resolve "^1.4.0" + +babel-plugin-polyfill-corejs2@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz#e4c31d4c89b56f3cf85b92558954c66b54bd972d" + integrity sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q== + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-define-polyfill-provider" "^0.3.2" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz#d7e09c9a899079d71a8b670c6181af56ec19c5c7" + integrity sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.2" + core-js-compat "^3.21.0" + +babel-plugin-polyfill-regenerator@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.0.tgz#8f51809b6d5883e07e71548d75966ff7635527fe" + integrity sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.2" + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + integrity sha512-MioUE+LfjCEz65Wf7Z/Rm4XCP5k2c+TbMd2Z2JKc7U9uwjBhAfNPE48KC4GTGKhppMeYVepwDBNO/nGY6NYHBA== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +"binaryextensions@1 || 2", binaryextensions@^2.1.2: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.3.0.tgz#1d269cbf7e6243ea886aa41453c3651ccbe13c22" + integrity sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg== + +blank-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + integrity sha512-kXQ19Xhoghiyw66CUiGypnuRpWlbHAzY/+NyvqTEdTfhfQGH1/dbEMYiXju7fYKIFePpzp/y9dsu5Cu/PkmawQ== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +broccoli-babel-transpiler@^7.8.0: + version "7.8.1" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.8.1.tgz#a5dc04cf4f59de98124fc128683ab2b83e5d28c1" + integrity sha512-6IXBgfRt7HZ61g67ssBc6lBb3Smw3DPZ9dEYirgtvXWpRZ2A9M22nxy6opEwJDgDJzlu/bB7ToppW33OFkA1gA== + dependencies: + "@babel/core" "^7.12.0" + "@babel/polyfill" "^7.11.5" + broccoli-funnel "^2.0.2" + broccoli-merge-trees "^3.0.2" + broccoli-persistent-filter "^2.2.1" + clone "^2.1.2" + hash-for-dep "^1.4.7" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.9" + json-stable-stringify "^1.0.1" + rsvp "^4.8.4" + workerpool "^3.1.1" + +broccoli-debug@^0.6.4, broccoli-debug@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.5.tgz#164a5cdafd8936e525e702bf8f91f39d758e2e78" + integrity sha512-RIVjHvNar9EMCLDW/FggxFRXqpjhncM/3qq87bn/y+/zR9tqEkHvTqbyOc4QnB97NO2m6342w4wGkemkaeOuWg== + dependencies: + broccoli-plugin "^1.2.1" + fs-tree-diff "^0.5.2" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + symlink-or-copy "^1.1.8" + tree-sync "^1.2.2" + +broccoli-funnel@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-2.0.2.tgz#0edf629569bc10bd02cc525f74b9a38e71366a75" + integrity sha512-/vDTqtv7ipjEZQOVqO4vGDVAOZyuYzQ/EgGoyewfOgh1M7IQAToBKZI0oAQPgMBeFPPlIbfMuAngk+ohPBuaHQ== + dependencies: + array-equal "^1.0.0" + blank-object "^1.0.1" + broccoli-plugin "^1.3.0" + debug "^2.2.0" + fast-ordered-set "^1.0.0" + fs-tree-diff "^0.5.3" + heimdalljs "^0.2.0" + minimatch "^3.0.0" + mkdirp "^0.5.0" + path-posix "^1.0.0" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + walk-sync "^0.3.1" + +broccoli-funnel@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-3.0.8.tgz#f5b62e2763c3918026a15a3c833edc889971279b" + integrity sha512-ng4eIhPYiXqMw6SyGoxPHR3YAwEd2lr9FgBI1CyTbspl4txZovOsmzFkMkGAlu88xyvYXJqHiM2crfLa65T1BQ== + dependencies: + array-equal "^1.0.0" + broccoli-plugin "^4.0.7" + debug "^4.1.1" + fs-tree-diff "^2.0.1" + heimdalljs "^0.2.0" + minimatch "^3.0.0" + walk-sync "^2.0.2" + +broccoli-kitchen-sink-helpers@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + integrity sha512-gqYnKSJxBSjj/uJqeuRAzYVbmjWhG0mOZ8jrp6+fnUIOgLN6MvI7XxBECDHkYMIFPJ8Smf4xaI066Q2FqQDnXg== + dependencies: + glob "^5.0.10" + mkdirp "^0.5.1" + +broccoli-merge-trees@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-3.0.2.tgz#f33b451994225522b5c9bcf27d59decfd8ba537d" + integrity sha512-ZyPAwrOdlCddduFbsMyyFzJUrvW6b04pMvDiAQZrCwghlvgowJDY+EfoXn+eR1RRA5nmGHJ+B68T63VnpRiT1A== + dependencies: + broccoli-plugin "^1.3.0" + merge-trees "^2.0.0" + +broccoli-merge-trees@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-4.2.0.tgz#692d3c163ecea08c5714a9434d664e628919f47c" + integrity sha512-nTrQe5AQtCrW4enLRvbD/vTLHqyW2tz+vsLXQe4IEaUhepuMGVKJJr+I8n34Vu6fPjmPLwTjzNC8izMIDMtHPw== + dependencies: + broccoli-plugin "^4.0.2" + merge-trees "^2.0.0" + +broccoli-node-api@^1.6.0, broccoli-node-api@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/broccoli-node-api/-/broccoli-node-api-1.7.0.tgz#391aa6edecd2a42c63c111b4162956b2fa288cb6" + integrity sha512-QIqLSVJWJUVOhclmkmypJJH9u9s/aWH4+FH6Q6Ju5l+Io4dtwqdPUNmDfw40o6sxhbZHhqGujDJuHTML1wG8Yw== + +broccoli-node-info@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-2.2.0.tgz#feb01c13020792f429e01d7f7845dc5b3a7932b3" + integrity sha512-VabSGRpKIzpmC+r+tJueCE5h8k6vON7EIMMWu6d/FyPdtijwLQ7QvzShEw+m3mHoDzUaj/kiZsDYrS8X2adsBg== + +broccoli-output-wrapper@^3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/broccoli-output-wrapper/-/broccoli-output-wrapper-3.2.5.tgz#514b17801c92922a2c2f87fd145df2a25a11bc5f" + integrity sha512-bQAtwjSrF4Nu0CK0JOy5OZqw9t5U0zzv2555EA/cF8/a8SLDTIetk9UgrtMVw7qKLKdSpOZ2liZNeZZDaKgayw== + dependencies: + fs-extra "^8.1.0" + heimdalljs-logger "^0.1.10" + symlink-or-copy "^1.2.0" + +broccoli-persistent-filter@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-2.3.1.tgz#4a052e0e0868b344c3a2977e35a3d497aa9eca72" + integrity sha512-hVsmIgCDrl2NFM+3Gs4Cr2TA6UPaIZip99hN8mtkaUPgM8UeVnCbxelCvBjUBHo0oaaqP5jzqqnRVvb568Yu5g== + dependencies: + async-disk-cache "^1.2.1" + async-promise-queue "^1.0.3" + broccoli-plugin "^1.0.0" + fs-tree-diff "^2.0.0" + hash-for-dep "^1.5.0" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + mkdirp "^0.5.1" + promise-map-series "^0.2.1" + rimraf "^2.6.1" + rsvp "^4.7.0" + symlink-or-copy "^1.0.1" + sync-disk-cache "^1.3.3" + walk-sync "^1.0.0" + +broccoli-persistent-filter@^3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-3.1.3.tgz#aca815bf3e3b0247bd0a7b567fdb0d0e08c99cc2" + integrity sha512-Q+8iezprZzL9voaBsDY3rQVl7c7H5h+bvv8SpzCZXPZgfBFCbx7KFQ2c3rZR6lW5k4Kwoqt7jG+rZMUg67Gwxw== + dependencies: + async-disk-cache "^2.0.0" + async-promise-queue "^1.0.3" + broccoli-plugin "^4.0.3" + fs-tree-diff "^2.0.0" + hash-for-dep "^1.5.0" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + promise-map-series "^0.2.1" + rimraf "^3.0.0" + symlink-or-copy "^1.0.1" + sync-disk-cache "^2.0.0" + +broccoli-plugin@^1.0.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.1.tgz#a26315732fb99ed2d9fb58f12a1e14e986b4fabd" + integrity sha512-DW8XASZkmorp+q7J4EeDEZz+LoyKLAd2XZULXyD9l4m9/hAKV3vjHmB1kiUshcWAYMgTP1m2i4NnqCE/23h6AQ== + dependencies: + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.1.8" + +broccoli-plugin@^4.0.0, broccoli-plugin@^4.0.2, broccoli-plugin@^4.0.3, broccoli-plugin@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-4.0.7.tgz#dd176a85efe915ed557d913744b181abe05047db" + integrity sha512-a4zUsWtA1uns1K7p9rExYVYG99rdKeGRymW0qOCNkvDPHQxVi3yVyJHhQbM3EZwdt2E0mnhr5e0c/bPpJ7p3Wg== + dependencies: + broccoli-node-api "^1.7.0" + broccoli-output-wrapper "^3.2.5" + fs-merger "^3.2.1" + promise-map-series "^0.3.0" + quick-temp "^0.1.8" + rimraf "^3.0.2" + symlink-or-copy "^1.3.1" + +broccoli-source@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-2.1.2.tgz#e9ae834f143b607e9ec114ade66731500c38b90b" + integrity sha512-1lLayO4wfS0c0Sj50VfHJXNWf94FYY0WUhxj0R77thbs6uWI7USiOWFqQV5dRmhAJnoKaGN4WyLGQbgjgiYFwQ== + +broccoli-source@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-3.0.1.tgz#fd581b2f3877ca1338f724f6ef70acec8c7e1444" + integrity sha512-ZbGVQjivWi0k220fEeIUioN6Y68xjMy0xiLAc0LdieHI99gw+tafU8w0CggBDYVNsJMKUr006AZaM7gNEwCxEg== + dependencies: + broccoli-node-api "^1.6.0" + +browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^4.21.3: + version "4.21.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a" + integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ== + dependencies: + caniuse-lite "^1.0.30001370" + electron-to-chromium "^1.4.202" + node-releases "^2.0.6" + update-browserslist-db "^1.0.5" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +calculate-cache-key-for-tree@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-2.0.0.tgz#7ac57f149a4188eacb0a45b210689215d3fef8d6" + integrity sha512-Quw8a6y8CPmRd6eU+mwypktYCwUcf8yVFIRbNZ6tPQEckX9yd+EBVEPC/GSZZrMWH9e7Vz4pT7XhpmyApRByLQ== + dependencies: + json-stable-stringify "^1.0.1" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +can-symlink@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + integrity sha512-RbsNrFyhwkx+6psk/0fK/Q9orOUr9VMxohGd8vTa4djf4TGLfblBgUfqZChrZuW0Q+mz2eBPFLusw9Jfukzmhg== + dependencies: + tmp "0.0.28" + +caniuse-lite@^1.0.30001370: + version "1.0.30001382" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001382.tgz#4d37f0d0b6fffb826c8e5e1c0f4bf8ce592db949" + integrity sha512-2rtJwDmSZ716Pxm1wCtbPvHtbDWAreTPxXbkc5RkKglow3Ig/4GNGazDI9/BVnXbG/wnv6r3B5FEbkfg9OcTGg== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +clean-up-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clean-up-path/-/clean-up-path-1.0.0.tgz#de9e8196519912e749c9eaf67c13d64fac72a3e5" + integrity sha512-PHGlEF0Z6976qQyN6gM7kKH6EH0RdfZcc8V+QhFe36eRxV0SMH5OUBZG7Bxa9YcreNzyNbK63cGiZxdSZgosRw== + +clone@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +core-js-compat@^3.21.0, core-js-compat@^3.22.1: + version "3.24.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.24.1.tgz#d1af84a17e18dfdd401ee39da9996f9a7ba887de" + integrity sha512-XhdNAGeRnTpp8xbD+sR/HFDK9CbeeeqXT6TuofXh3urqEevzkWmLRgrVoykodsw8okqo2pu1BOmuCKrHx63zdw== + dependencies: + browserslist "^4.21.3" + semver "7.0.0" + +core-js@^2.6.5: + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== + +css-loader@^5.2.0: + version "5.2.7" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.7.tgz#9b9f111edf6fb2be5dc62525644cbc9c232064ae" + integrity sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg== + dependencies: + icss-utils "^5.1.0" + loader-utils "^2.0.0" + postcss "^8.2.15" + postcss-modules-extract-imports "^3.0.0" + postcss-modules-local-by-default "^4.0.0" + postcss-modules-scope "^3.0.0" + postcss-modules-values "^4.0.0" + postcss-value-parser "^4.1.0" + schema-utils "^3.0.0" + semver "^7.3.5" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +debug@^2.1.3, debug@^2.2.0, debug@^2.6.8: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +define-properties@^1.1.3, define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +editions@^1.1.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" + integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg== + +editions@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/editions/-/editions-2.3.1.tgz#3bc9962f1978e801312fbd0aebfed63b49bfe698" + integrity sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA== + dependencies: + errlop "^2.0.0" + semver "^6.3.0" + +electron-to-chromium@^1.4.202: + version "1.4.227" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.227.tgz#28e46e2a701fed3188db3ca7bf0a3a475e484046" + integrity sha512-I9VVajA3oswIJOUFg2PSBqrHLF5Y+ahIfjOV9+v6uYyBqFZutmPxA6fxocDUUmgwYevRWFu1VjLyVG3w45qa/g== + +ember-auto-import@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/ember-auto-import/-/ember-auto-import-2.4.2.tgz#d4d3bc6885a11cf124f606f5c37169bdf76e37ae" + integrity sha512-REh+1aJWpTkvN42a/ga41OuRpUsSW7UQfPr2wPtYx56o/xoSNhVBXejy7yV9ObrkN7gogz6fs2xZwih5cOwpYg== + dependencies: + "@babel/core" "^7.16.7" + "@babel/plugin-proposal-class-properties" "^7.16.7" + "@babel/plugin-proposal-decorators" "^7.16.7" + "@babel/preset-env" "^7.16.7" + "@embroider/macros" "^1.0.0" + "@embroider/shared-internals" "^1.0.0" + babel-loader "^8.0.6" + babel-plugin-ember-modules-api-polyfill "^3.5.0" + babel-plugin-htmlbars-inline-precompile "^5.2.1" + babel-plugin-syntax-dynamic-import "^6.18.0" + broccoli-debug "^0.6.4" + broccoli-funnel "^3.0.8" + broccoli-merge-trees "^4.2.0" + broccoli-plugin "^4.0.0" + broccoli-source "^3.0.0" + css-loader "^5.2.0" + debug "^4.3.1" + fs-extra "^10.0.0" + fs-tree-diff "^2.0.0" + handlebars "^4.3.1" + js-string-escape "^1.0.1" + lodash "^4.17.19" + mini-css-extract-plugin "^2.5.2" + parse5 "^6.0.1" + resolve "^1.20.0" + resolve-package-path "^4.0.3" + semver "^7.3.4" + style-loader "^2.0.0" + typescript-memoize "^1.0.0-alpha.3" + walk-sync "^3.0.0" + +ember-cli-babel-plugin-helpers@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-babel-plugin-helpers/-/ember-cli-babel-plugin-helpers-1.1.1.tgz#5016b80cdef37036c4282eef2d863e1d73576879" + integrity sha512-sKvOiPNHr5F/60NLd7SFzMpYPte/nnGkq/tMIfXejfKHIhaiIkYFqX8Z9UFTKWLLn+V7NOaby6niNPZUdvKCRw== + +ember-cli-babel@^7.26.10, ember-cli-babel@^7.26.6: + version "7.26.11" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.26.11.tgz#50da0fe4dcd99aada499843940fec75076249a9f" + integrity sha512-JJYeYjiz/JTn34q7F5DSOjkkZqy8qwFOOxXfE6pe9yEJqWGu4qErKxlz8I22JoVEQ/aBUO+OcKTpmctvykM9YA== + dependencies: + "@babel/core" "^7.12.0" + "@babel/helper-compilation-targets" "^7.12.0" + "@babel/plugin-proposal-class-properties" "^7.16.5" + "@babel/plugin-proposal-decorators" "^7.13.5" + "@babel/plugin-proposal-private-methods" "^7.16.5" + "@babel/plugin-proposal-private-property-in-object" "^7.16.5" + "@babel/plugin-transform-modules-amd" "^7.13.0" + "@babel/plugin-transform-runtime" "^7.13.9" + "@babel/plugin-transform-typescript" "^7.13.0" + "@babel/polyfill" "^7.11.5" + "@babel/preset-env" "^7.16.5" + "@babel/runtime" "7.12.18" + amd-name-resolver "^1.3.1" + babel-plugin-debug-macros "^0.3.4" + babel-plugin-ember-data-packages-polyfill "^0.1.2" + babel-plugin-ember-modules-api-polyfill "^3.5.0" + babel-plugin-module-resolver "^3.2.0" + broccoli-babel-transpiler "^7.8.0" + broccoli-debug "^0.6.4" + broccoli-funnel "^2.0.2" + broccoli-source "^2.1.2" + calculate-cache-key-for-tree "^2.0.0" + clone "^2.1.2" + ember-cli-babel-plugin-helpers "^1.1.1" + ember-cli-version-checker "^4.1.0" + ensure-posix-path "^1.0.2" + fixturify-project "^1.10.0" + resolve-package-path "^3.1.0" + rimraf "^3.0.1" + semver "^5.5.0" + +ember-cli-htmlbars@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-6.1.0.tgz#97150c2a6f9a981475599d74817df66f5d816c2b" + integrity sha512-kT+MA2JsNLk10HpxAjpB5HHtR0WCoxZEUwLsy/BBww5lXmsrf34QzmTw7SL6DabZVxs+YCb9RhU9KTmFygGxCg== + dependencies: + "@ember/edition-utils" "^1.2.0" + babel-plugin-ember-template-compilation "^1.0.0" + babel-plugin-htmlbars-inline-precompile "^5.3.0" + broccoli-debug "^0.6.5" + broccoli-persistent-filter "^3.1.2" + broccoli-plugin "^4.0.3" + ember-cli-version-checker "^5.1.2" + fs-tree-diff "^2.0.1" + hash-for-dep "^1.5.1" + heimdalljs-logger "^0.1.10" + js-string-escape "^1.0.1" + semver "^7.3.4" + silent-error "^1.1.1" + walk-sync "^2.2.0" + +ember-cli-version-checker@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-4.1.1.tgz#27b938228306cb0dbc4f74e95c536cdd6448e499" + integrity sha512-bzEWsTMXUGEJfxcAGWPe6kI7oHEGD3jaxUWDYPTqzqGhNkgPwXTBgoWs9zG1RaSMaOPFnloWuxRcoHi4TrYS3Q== + dependencies: + resolve-package-path "^2.0.0" + semver "^6.3.0" + silent-error "^1.1.1" + +ember-cli-version-checker@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-5.1.2.tgz#649c7b6404902e3b3d69c396e054cea964911ab0" + integrity sha512-rk7GY+FmLn/2e22HsZs0Ycrz8HQ1W3Fv+2TFOuEFW9optnDXDgkntPBIl6gact/LHsfBM5RKbM3dHsIIeLgl0Q== + dependencies: + resolve-package-path "^3.1.0" + semver "^7.3.4" + silent-error "^1.1.1" + +ember-rfc176-data@^0.3.17: + version "0.3.17" + resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.17.tgz#d4fc6c33abd6ef7b3440c107a28e04417b49860a" + integrity sha512-EVzTTKqxv9FZbEh6Ktw56YyWRAA0MijKvl7H8C06wVF+8f/cRRz3dXxa4nkwjzyVwx4rzKGuIGq77hxJAQhWWw== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +enhanced-resolve@^5.10.0: + version "5.10.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6" + integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2, ensure-posix-path@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz#3c62bdb19fa4681544289edb2b382adc029179ce" + integrity sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw== + +errlop@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/errlop/-/errlop-2.2.0.tgz#1ff383f8f917ae328bebb802d6ca69666a42d21b" + integrity sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw== + +es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.5: + version "1.20.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" + integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + regexp.prototype.flags "^1.4.3" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" + unbox-primitive "^1.0.2" + +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-ordered-set@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + integrity sha512-MxBW4URybFszOx1YlACEoK52P6lE3xiFcPaGCUZ7QQOZ6uJXKo++Se8wa31SjcZ+NC/fdAWX7UtKEfaGgHS2Vg== + dependencies: + blank-object "^1.0.1" + +find-babel-config@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.0.tgz#a9b7b317eb5b9860cda9d54740a8c8337a2283a2" + integrity sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA== + dependencies: + json5 "^0.5.1" + path-exists "^3.0.0" + +find-cache-dir@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== + dependencies: + locate-path "^2.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +fixturify-project@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/fixturify-project/-/fixturify-project-1.10.0.tgz#091c452a9bb15f09b6b9cc7cf5c0ad559f1d9aad" + integrity sha512-L1k9uiBQuN0Yr8tA9Noy2VSQ0dfg0B8qMdvT7Wb5WQKc7f3dn3bzCbSrqlb+etLW+KDV4cBC7R1OvcMg3kcxmA== + dependencies: + fixturify "^1.2.0" + tmp "^0.0.33" + +fixturify@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fixturify/-/fixturify-1.3.0.tgz#163c468093c7c4d90b70cde39fd6325f6528b25d" + integrity sha512-tL0svlOy56pIMMUQ4bU1xRe6NZbFSa/ABTWMxW2mH38lFGc9TrNAKWcMBQ7eIjo3wqSS8f2ICabFaatFyFmrVQ== + dependencies: + "@types/fs-extra" "^5.0.5" + "@types/minimatch" "^3.0.3" + "@types/rimraf" "^2.0.2" + fs-extra "^7.0.1" + matcher-collection "^2.0.0" + +focusable-selectors@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/focusable-selectors/-/focusable-selectors-0.3.1.tgz#7eacbca8dc6cc8d7f7563e5f5cc3699b91e20aaa" + integrity sha512-5JLtr0e1YJIfmnVlpLiG+av07dd0Xkf/KfswsXcei5KmLfdwOysTQsjF058ynXniujb1fvev7nql1x+CkC5ikw== + +fs-extra@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^8.0.1, fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-merger@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/fs-merger/-/fs-merger-3.2.1.tgz#a225b11ae530426138294b8fbb19e82e3d4e0b3b" + integrity sha512-AN6sX12liy0JE7C2evclwoo0aCG3PFulLjrTLsJpWh/2mM+DinhpSGqYLbHBBbIW1PLRNcFhJG8Axtz8mQW3ug== + dependencies: + broccoli-node-api "^1.7.0" + broccoli-node-info "^2.1.0" + fs-extra "^8.0.1" + fs-tree-diff "^2.0.1" + walk-sync "^2.2.0" + +fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.6: + version "0.5.9" + resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.9.tgz#a4ec6182c2f5bd80b9b83c8e23e4522e6f5fd946" + integrity sha512-872G8ax0kHh01m9n/2KDzgYwouKza0Ad9iFltBpNykvROvf2AGtoOzPJgGx125aolGPER3JuC7uZFrQ7bG1AZw== + dependencies: + heimdalljs-logger "^0.1.7" + object-assign "^4.1.0" + path-posix "^1.0.0" + symlink-or-copy "^1.1.8" + +fs-tree-diff@^2.0.0, fs-tree-diff@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-2.0.1.tgz#343e4745ab435ec39ebac5f9059ad919cd034afa" + integrity sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A== + dependencies: + "@types/symlink-or-copy" "^1.2.0" + heimdalljs-logger "^0.1.7" + object-assign "^4.1.0" + path-posix "^1.0.0" + symlink-or-copy "^1.1.8" + +fs-updater@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fs-updater/-/fs-updater-1.0.4.tgz#2329980f99ae9176e9a0e84f7637538a182ce63b" + integrity sha512-0pJX4mJF/qLsNEwTct8CdnnRdagfb+LmjRPJ8sO+nCnAZLW0cTmz4rTgU25n+RvTuWSITiLKrGVJceJPBIPlKg== + dependencies: + can-symlink "^1.0.0" + clean-up-path "^1.0.0" + heimdalljs "^0.2.5" + heimdalljs-logger "^0.1.9" + rimraf "^2.6.2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598" + integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^5.0.10: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + integrity sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA== + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.2, glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +handlebars@^4.3.1: + version "4.7.7" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-for-dep@^1.4.7, hash-for-dep@^1.5.0, hash-for-dep@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.5.1.tgz#497754b39bee2f1c4ade4521bfd2af0a7c1196e3" + integrity sha512-/dQ/A2cl7FBPI2pO0CANkvuuVi/IFS5oTyJ0PsOb6jW6WbVW1js5qJXMJTNbWHXBIPdFTWFbabjB+mE0d+gelw== + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + heimdalljs "^0.2.3" + heimdalljs-logger "^0.1.7" + path-root "^0.1.1" + resolve "^1.10.0" + resolve-package-path "^1.0.11" + +heimdalljs-logger@^0.1.10, heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: + version "0.1.10" + resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.10.tgz#90cad58aabb1590a3c7e640ddc6a4cd3a43faaf7" + integrity sha512-pO++cJbhIufVI/fmB/u2Yty3KJD0TqNPecehFae0/eps0hkZ3b4Zc/PezUMOpYuHFQbA7FxHZxa305EhmjLj4g== + dependencies: + debug "^2.2.0" + heimdalljs "^0.2.6" + +heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3, heimdalljs@^0.2.5, heimdalljs@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.6.tgz#b0eebabc412813aeb9542f9cc622cb58dbdcd9fe" + integrity sha512-o9bd30+5vLBvBtzCPwwGqpry2+n0Hi6H1+qwt6y+0kwRHGGF8TFIhJPmnuM0xO97zaKrDZMwO/V56fAnn8m/tA== + dependencies: + rsvp "~3.2.1" + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-core-module@^2.9.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" + integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +isarray@1.0.0, isarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== + dependencies: + isarray "1.0.0" + +istextorbinary@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + integrity sha512-kT1g2zxZ5Tdabtpp9VSdOzW9lb6LXImyWbzbQeTxoRtHhurC9Ej9Wckngr2+uepPL09ky/mJHmN9jeJPML5t6A== + dependencies: + binaryextensions "1 || 2" + editions "^1.1.1" + textextensions "1 || 2" + +istextorbinary@^2.5.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.6.0.tgz#60776315fb0fa3999add276c02c69557b9ca28ab" + integrity sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA== + dependencies: + binaryextensions "^2.1.2" + editions "^2.2.0" + textextensions "^2.5.0" + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-string-escape@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + integrity sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + integrity sha512-i/J297TW6xyj7sDFa7AmBPkQvLIxWr2kKPWI26tXydnZrzVAocNqn5DMNT1Mzk0vit1V5UkRM7C1KdVNp7Lmcg== + dependencies: + jsonify "~0.0.0" + +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw== + +json5@^2.1.2, json5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + integrity sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA== + +line-column@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/line-column/-/line-column-1.0.2.tgz#d25af2936b6f4849172b312e4792d1d987bc34a2" + integrity sha512-Ktrjk5noGYlHsVnYWh62FLVs4hTb8A3e+vucNZMgPeAOITdshMSgv4cCZQeRDjm7+goqmo6+liZwTXo+U3sVww== + dependencies: + isarray "^1.0.0" + isobject "^2.0.0" + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +loader-utils@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" + integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +magic-string@^0.25.7: + version "0.25.9" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" + integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== + dependencies: + sourcemap-codec "^1.4.8" + +magic-string@^0.26.0: + version "0.26.2" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.26.2.tgz#5331700e4158cd6befda738bb6b0c7b93c0d4432" + integrity sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A== + dependencies: + sourcemap-codec "^1.4.8" + +make-dir@^3.0.2, make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +matcher-collection@^1.0.0, matcher-collection@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.1.2.tgz#1076f506f10ca85897b53d14ef54f90a5c426838" + integrity sha512-YQ/teqaOIIfUHedRam08PB3NK7Mjct6BvzRnJmpGDm8uFXpNr1sbY4yuflI5JcEs6COpYA0FpRQhSDBf1tT95g== + dependencies: + minimatch "^3.0.2" + +matcher-collection@^2.0.0, matcher-collection@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-2.0.1.tgz#90be1a4cf58d6f2949864f65bb3b0f3e41303b29" + integrity sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ== + dependencies: + "@types/minimatch" "^3.0.3" + minimatch "^3.0.2" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge-trees@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-2.0.0.tgz#a560d796e566c5d9b2c40472a2967cca48d85161" + integrity sha512-5xBbmqYBalWqmhYm51XlohhkmVOua3VAUrrWh8t9iOkaLpS6ifqm/UVuUjQCeDVJ9Vx3g2l6ihfkbLSTeKsHbw== + dependencies: + fs-updater "^1.0.4" + heimdalljs "^0.2.5" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.27: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mini-css-extract-plugin@^2.5.2: + version "2.6.1" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz#9a1251d15f2035c342d99a468ab9da7a0451b71e" + integrity sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg== + dependencies: + schema-utils "^4.0.0" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.5, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mktemp@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + integrity sha512-IXnMcJ6ZyTuhRmJSjzvHSRhlVPiN9Jwc6e59V0bEJ0ba6OBeX2L0E+mRN1QseeOF4mM+F1Rit6Nh7o+rl2Yn/A== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + +neo-async@^2.6.0, neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + +object-assign@4.1.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-hash@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df" + integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA== + +object-inspect@^1.12.0, object-inspect@^1.9.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== + dependencies: + p-limit "^1.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parse-static-imports@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parse-static-imports/-/parse-static-imports-1.1.0.tgz#ae2f18f18da1a993080ae406a5219455c0bbad5d" + integrity sha512-HlxrZcISCblEV0lzXmAHheH/8qEkKgmqkdxyHTPbSqsTUV8GzqmN1L+SSti+VbNPfbBO3bYLPHDiUs2avbAdbA== + +parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-posix@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + integrity sha512-1gJ0WpNIiYcQydgg3Ed8KzvIqTsDpNwq+cjBCssvBtuTWjEqY1AW+i+OepiEMqDCzyro9B2sLAe4RBPajMYFiA== + +path-root-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + integrity sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ== + +path-root@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + integrity sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg== + dependencies: + path-root-regex "^0.1.0" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +pkg-dir@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + integrity sha512-fjAPuiws93rm7mPUu21RdBnkeZNrbfCFCwfAhPWY+rR3zG0ubpe5cEReHOw5fIbfmsxEV/g2kSxGTATY3Bpnwg== + dependencies: + find-up "^2.1.0" + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" + integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: + version "6.0.10" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" + integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^8.2.15: + version "8.4.16" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.16.tgz#33a1d675fac39941f5f445db0de4db2b6e01d43c" + integrity sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +promise-map-series@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + integrity sha512-wx9Chrutvqu1N/NHzTayZjE1BgIwt6SJykQoCOic4IZ9yUDjKyVYrpLa/4YCNsV61eRENfs29hrEquVuB13Zlw== + dependencies: + rsvp "^3.0.14" + +promise-map-series@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.3.0.tgz#41873ca3652bb7a042b387d538552da9b576f8a1" + integrity sha512-3npG2NGhTc8BWBolLLf8l/92OxMGaRLbqvIh9wjCHhDXNvk4zsxaTaCpiCunW09qWPrN2zeNSNwRLVBrQQtutA== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" + integrity sha512-YsmIFfD9j2zaFwJkzI6eMG7y0lQP7YeWzgtFgNl38pGWZBSXJooZbOWwkcRot7Vt0Fg9L23pX0tqWU3VvLDsiA== + dependencies: + mktemp "~0.4.0" + rimraf "^2.5.4" + underscore.string "~3.3.4" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +regenerate-unicode-properties@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" + integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-transform@^0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537" + integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg== + dependencies: + "@babel/runtime" "^7.8.4" + +regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + functions-have-names "^1.2.2" + +regexpu-core@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.1.0.tgz#2f8504c3fd0ebe11215783a41541e21c79942c6d" + integrity sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.0.1" + regjsgen "^0.6.0" + regjsparser "^0.8.2" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" + +regjsgen@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" + integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== + +regjsparser@^0.8.2: + version "0.8.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" + integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== + dependencies: + jsesc "~0.5.0" + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +reselect@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" + integrity sha512-b/6tFZCmRhtBMa4xGqiiRp9jh9Aqi2A687Lo265cN0/QohJQEBPiQ52f4QB6i0eF3yp3hmLL21LSGBcML2dlxA== + +resolve-package-path@^1.0.11: + version "1.2.7" + resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-1.2.7.tgz#2a7bc37ad96865e239330e3102c31322847e652e" + integrity sha512-fVEKHGeK85bGbVFuwO9o1aU0n3vqQGrezPc51JGu9UTXpFQfWq5qCeKxyaRUSvephs+06c5j5rPq/dzHGEo8+Q== + dependencies: + path-root "^0.1.1" + resolve "^1.10.0" + +resolve-package-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-2.0.0.tgz#7f258ab86ff074fff4ff8027a28f94d17d6fb1df" + integrity sha512-/CLuzodHO2wyyHTzls5Qr+EFeG6RcW4u6//gjYvUfcfyuplIX1SSccU+A5A9A78Gmezkl3NBkFAMxLbzTY9TJA== + dependencies: + path-root "^0.1.1" + resolve "^1.13.1" + +resolve-package-path@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-3.1.0.tgz#35faaa5d54a9c7dd481eb7c4b2a44410c9c763d8" + integrity sha512-2oC2EjWbMJwvSN6Z7DbDfJMnD8MYEouaLn5eIX0j8XwPsYCVIyY9bbnX88YHVkbr8XHqvZrYbxaLPibfTYKZMA== + dependencies: + path-root "^0.1.1" + resolve "^1.17.0" + +resolve-package-path@^4.0.1, resolve-package-path@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-4.0.3.tgz#31dab6897236ea6613c72b83658d88898a9040aa" + integrity sha512-SRpNAPW4kewOaNUt8VPqhJ0UMxawMwzJD8V7m1cJfdSTK9ieZwS6K7Dabsm4bmLFM96Z5Y/UznrpG5kt1im8yA== + dependencies: + path-root "^0.1.1" + +resolve@^1.10.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.20.0, resolve@^1.4.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.3, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.0, rimraf@^3.0.1, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rsvp@^3.0.14, rsvp@^3.0.18: + version "3.6.2" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== + +rsvp@^4.7.0, rsvp@^4.8.4, rsvp@^4.8.5: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + +rsvp@~3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + integrity sha512-Rf4YVNYpKjZ6ASAmibcwTNciQ5Co5Ztq6iZPEykHpkoflnD/K5ryE/rHehFsTm4NJj8nKDhbi3eKBWGogmNnkg== + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +schema-utils@^2.6.5: + version "2.7.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== + dependencies: + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" + +schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^5.3.0, semver@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +serialize-javascript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +silent-error@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.1.1.tgz#f72af5b0d73682a2ba1778b7e32cd8aa7c2d8662" + integrity sha512-n4iEKyNcg4v6/jpb3c0/iyH2G1nzUNl7Gpqtn/mHIJK9S/q/7MCfoO4rwVOoO59qPFIc0hVHvMbiOJ0NdtxKKw== + dependencies: + debug "^2.2.0" + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +sprintf-js@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + +string.prototype.matchall@^4.0.5: + version "4.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" + integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.4.1" + side-channel "^1.0.4" + +string.prototype.trimend@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" + integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +string.prototype.trimstart@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" + integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +style-loader@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-2.0.0.tgz#9669602fd4690740eaaec137799a03addbbc393c" + integrity sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0, symlink-or-copy@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.3.1.tgz#9506dd64d8e98fa21dcbf4018d1eab23e77f71fe" + integrity sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA== + +sync-disk-cache@^1.3.3: + version "1.3.4" + resolved "https://registry.yarnpkg.com/sync-disk-cache/-/sync-disk-cache-1.3.4.tgz#53a2c5a09d8f4bb53160bce182a456ad71574024" + integrity sha512-GlkGeM81GPPEKz/lH7QUTbvqLq7K/IUTuaKDSMulP9XQ42glqNJIN/RKgSOw4y8vxL1gOVvj+W7ruEO4s36eCw== + dependencies: + debug "^2.1.3" + heimdalljs "^0.2.3" + mkdirp "^0.5.0" + rimraf "^2.2.8" + username-sync "^1.0.2" + +sync-disk-cache@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sync-disk-cache/-/sync-disk-cache-2.1.0.tgz#01e879edc41c34a01fcdda5b39d47dd496e154a6" + integrity sha512-vngT2JmkSapgq0z7uIoYtB9kWOOzMihAAYq/D3Pjm/ODOGMgS4r++B+OZ09U4hWR6EaOdy9eqQ7/8ygbH3wehA== + dependencies: + debug "^4.1.1" + heimdalljs "^0.2.6" + mkdirp "^0.5.0" + rimraf "^3.0.0" + username-sync "^1.0.2" + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.1.3: + version "5.3.5" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.5.tgz#f7d82286031f915a4f8fb81af4bd35d2e3c011bc" + integrity sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.14" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + terser "^5.14.1" + +terser@^5.14.1: + version "5.15.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.0.tgz#e16967894eeba6e1091509ec83f0c60e179f2425" + integrity sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA== + dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" + commander "^2.20.0" + source-map-support "~0.5.20" + +"textextensions@1 || 2", textextensions@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.6.0.tgz#d7e4ab13fe54e32e08873be40d51b74229b00fc4" + integrity sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ== + +tmp@0.0.28: + version "0.0.28" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + integrity sha512-c2mmfiBmND6SOVxzogm1oda0OJ1HZVIk/5n26N59dDTh80MUeavpiCls4PGAdkX1PFkKokLpcf7prSjCeXLsJg== + dependencies: + os-tmpdir "~1.0.1" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +tree-sync@^1.2.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.4.0.tgz#314598d13abaf752547d9335b8f95d9a137100d6" + integrity sha512-YvYllqh3qrR5TAYZZTXdspnIhlKAYezPYw11ntmweoceu4VK+keN356phHRIIo1d+RDmLpHZrUlmxga2gc9kSQ== + dependencies: + debug "^2.2.0" + fs-tree-diff "^0.5.6" + mkdirp "^0.5.1" + quick-temp "^0.1.5" + walk-sync "^0.3.3" + +typescript-memoize@^1.0.0-alpha.3, typescript-memoize@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/typescript-memoize/-/typescript-memoize-1.1.0.tgz#4a8f512d06fc995167c703a3592219901db8bc79" + integrity sha512-LQPKVXK8QrBBkL/zclE6YgSWn0I8ew5m0Lf+XL00IwMhlotqRLlzHV+BRrljVQIc+NohUAuQP7mg4HQwrx5Xbg== + +uglify-js@^3.1.4: + version "3.17.0" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.0.tgz#55bd6e9d19ce5eef0d5ad17cd1f587d85b180a85" + integrity sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +underscore.string@~3.3.4: + version "3.3.6" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.6.tgz#ad8cf23d7423cb3b53b898476117588f4e2f9159" + integrity sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ== + dependencies: + sprintf-js "^1.1.1" + util-deprecate "^1.0.2" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +update-browserslist-db@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38" + integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +username-sync@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.3.tgz#ae41c5c8a4c8c2ecc1443a7d0742742bd7e36732" + integrity sha512-m/7/FSqjJNAzF2La448c/aEom0gJy7HY7Y509h6l0ePvEkFictAGptwWaj1msWJ38JbfEDOUoE8kqFee9EHKdA== + +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +walk-sync@^0.3.1, walk-sync@^0.3.3: + version "0.3.4" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.4.tgz#cf78486cc567d3a96b5b2237c6108017a5ffb9a4" + integrity sha512-ttGcuHA/OBnN2pcM6johpYlEms7XpO5/fyKIr48541xXedan4roO8cS1Q2S/zbbjGH/BarYDAMeS2Mi9HE5Tig== + dependencies: + ensure-posix-path "^1.0.0" + matcher-collection "^1.0.0" + +walk-sync@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-1.1.4.tgz#81049f3d8095479b49574cfa5f558d7a252b127d" + integrity sha512-nowc9thB/Jg0KW4TgxoRjLLYRPvl3DB/98S89r4ZcJqq2B0alNcKDh6pzLkBSkPMzRSMsJghJHQi79qw0YWEkA== + dependencies: + "@types/minimatch" "^3.0.3" + ensure-posix-path "^1.1.0" + matcher-collection "^1.1.1" + +walk-sync@^2.0.2, walk-sync@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-2.2.0.tgz#80786b0657fcc8c0e1c0b1a042a09eae2966387a" + integrity sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg== + dependencies: + "@types/minimatch" "^3.0.3" + ensure-posix-path "^1.1.0" + matcher-collection "^2.0.0" + minimatch "^3.0.4" + +walk-sync@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-3.0.0.tgz#67f882925021e20569a1edd560b8da31da8d171c" + integrity sha512-41TvKmDGVpm2iuH7o+DAOt06yyu/cSHpX3uzAwetzASvlNtVddgIjXIb2DfB/Wa20B1Jo86+1Dv1CraSU7hWdw== + dependencies: + "@types/minimatch" "^3.0.4" + ensure-posix-path "^1.1.0" + matcher-collection "^2.0.1" + minimatch "^3.0.4" + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.73.0: + version "5.74.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.74.0.tgz#02a5dac19a17e0bb47093f2be67c695102a55980" + integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^0.0.51" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.7.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.10.0" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.4.0" + webpack-sources "^3.2.3" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + +workerpool@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-3.1.2.tgz#b34e79243647decb174b7481ab5b351dc565c426" + integrity sha512-WJFA0dGqIK7qj7xPTqciWBH5DlJQzoPjsANvc3Y4hNB0SScT+Emjvt0jPPkDBUjBNngX1q9hHgt1Gfwytu6pug== + dependencies: + "@babel/core" "^7.3.4" + object-assign "4.1.1" + rsvp "^4.8.4" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/app/assets/javascripts/discourse/lib/pretty-text-engine.js b/app/assets/javascripts/discourse/lib/pretty-text-engine.js index f52ca30b2b..08d91f1877 100644 --- a/app/assets/javascripts/discourse/lib/pretty-text-engine.js +++ b/app/assets/javascripts/discourse/lib/pretty-text-engine.js @@ -1,21 +1,28 @@ -const babel = require("broccoli-babel-transpiler"); const mergeTrees = require("broccoli-merge-trees"); const funnel = require("broccoli-funnel"); -const path = require("path"); const concat = require("broccoli-concat"); +const WatchedDir = require("broccoli-source").WatchedDir; +const Funnel = require("broccoli-funnel"); -module.exports = function prettyTextEngine(vendorJs, engine) { - let engineTree = babel(`../pretty-text/engines/${engine}`, { - plugins: ["@babel/plugin-transform-modules-amd"], - moduleIds: true, +module.exports = function prettyTextEngine(app) { + let babelAddon = app.project.findAddonByName("ember-cli-babel"); - getModuleId(name) { - return `pretty-text/engines/${engine}/${path.basename(name)}`; + const sourceTree = new WatchedDir( + "../pretty-text/engines/discourse-markdown" + ); + const namespacedTree = new Funnel(sourceTree, { + getDestinationPath: function (relativePath) { + return `pretty-text/engines/discourse-markdown/${relativePath}`; }, }); - let markdownIt = funnel(vendorJs, { files: ["markdown-it.js"] }); + const engineTree = babelAddon.transpileTree(namespacedTree); + + let markdownIt = funnel("../node_modules/markdown-it/dist", { + files: ["markdown-it.js"], + }); return concat(mergeTrees([engineTree, markdownIt]), { - outputFile: `assets/${engine}.js`, + inputFiles: ["**/*.js"], + outputFile: `assets/markdown-it-bundle.js`, }); }; diff --git a/app/assets/javascripts/discourse/lib/scripts.js b/app/assets/javascripts/discourse/lib/scripts.js index 3c4572b113..ac73f27f4a 100644 --- a/app/assets/javascripts/discourse/lib/scripts.js +++ b/app/assets/javascripts/discourse/lib/scripts.js @@ -35,5 +35,21 @@ module.exports = function scriptsTree(app) { trees.push(transpiledWithDecodedSourcemap); } + // start-discourse.js is a combination of start-app and discourse-boot + let startDiscourseTree = funnel(`public/assets/scripts`, { + files: ["start-app.js", "discourse-boot.js"], + destDir: "scripts", + }); + startDiscourseTree = babelAddon.transpileTree( + startDiscourseTree, + babelConfig + ); + startDiscourseTree = concat(startDiscourseTree, { + outputFile: `assets/start-discourse.js`, + headerFiles: [`scripts/start-app.js`], + inputFiles: [`scripts/discourse-boot.js`], + }); + trees.push(startDiscourseTree); + return mergeTrees(trees); }; diff --git a/app/assets/javascripts/discourse/package.json b/app/assets/javascripts/discourse/package.json index 7b7b6c4289..5ba3b11d91 100644 --- a/app/assets/javascripts/discourse/package.json +++ b/app/assets/javascripts/discourse/package.json @@ -2,10 +2,10 @@ "name": "discourse", "version": "0.0.0", "private": true, - "description": "Small description for discourse-frontend goes here", + "description": "A platform for community discussion. Free, open, simple.", "repository": "", - "license": "MIT", - "author": "", + "license": "GPL-2.0-only", + "author": "Discourse", "directories": { "doc": "doc", "test": "tests" @@ -16,23 +16,27 @@ "test": "ember test" }, "dependencies": { - "@babel/core": "^7.18.5", - "@babel/standalone": "^7.18.12", + "@babel/core": "^7.19.3", + "@babel/standalone": "^7.19.3", "@discourse/itsatrap": "^2.0.10", "@ember/jquery": "^2.0.0", "@ember/optional-features": "^2.0.0", + "@ember/render-modifiers": "^2.0.4", "@ember/test-helpers": "^2.8.1", "@glimmer/component": "^1.1.2", "@glimmer/syntax": "^0.84.2", "@glimmer/tracking": "^1.1.2", - "@popperjs/core": "^2.11.5", + "@popperjs/core": "^2.11.6", "@uppy/aws-s3": "^2.2.1", "@uppy/aws-s3-multipart": "^2.4.1", "@uppy/core": "^2.3.1", "@uppy/drop-target": "^1.1.3", "@uppy/utils": "^4.1.0", "@uppy/xhr-upload": "^2.1.2", + "a11y-dialog": "7.5.2", "admin": "^1.0.0", + "discourse-plugins": "^1.0.0", + "babel-plugin-ember-template-compilation": "^1.0.2", "bootstrap": "3.4.1", "broccoli-asset-rev": "^3.0.0", "deepmerge": "^4.2.2", @@ -49,25 +53,27 @@ "ember-cli-babel": "^7.26.10", "ember-cli-dependency-checker": "^3.3.1", "ember-cli-deprecation-workflow": "^2.1.0", - "ember-cli-htmlbars": "^6.1.0", + "ember-cli-htmlbars": "^6.1.1", "ember-cli-inject-live-reload": "^2.1.0", + "ember-cli-progress-ci": "1.0.0", "ember-cli-sri": "^2.1.1", "ember-cli-terser": "^4.0.2", - "ember-exam": "^7.0.1", + "ember-exam": "^8.0.0", "ember-export-application-global": "^2.0.1", "ember-load-initializers": "^2.1.1", + "ember-modifier": "^3.2.7", + "ember-on-resize-modifier": "^1.1.0", "ember-qunit": "^5.1.5", "ember-rfc176-data": "^0.3.17", "ember-source": "~3.28.8", "ember-test-selectors": "^6.0.0", - "ember-modifier": "^3.2.7", - "@ember/render-modifiers": "^2.0.4", "eslint": "^7.32.0", "eslint-plugin-qunit": "^6.2.0", "html-entities": "^2.3.3", "js-yaml": "^4.1.0", "jsdom": "^20.0.0", "loader.js": "^4.7.0", + "markdown-it": "^13.0.1", "message-bus-client": "^4.2.0", "messageformat": "0.1.5", "node-fetch": "^2.6.6", @@ -75,12 +81,12 @@ "pretty-text": "^1.0.0", "qunit": "^2.19.1", "qunit-dom": "^2.0.0", - "sass": "^1.53.0", + "sass": "^1.55.0", "select-kit": "^1.0.0", "sinon": "^14.0.0", "tippy.js": "^6.3.7", "virtual-dom": "^2.1.1", - "webpack": "^5.73.0", + "webpack": "^5.74.0", "wizard": "^1.0.0" }, "engines": { @@ -93,12 +99,13 @@ }, "ember-addon": { "paths": [ + "lib/dialog-holder", "lib/bootstrap-json" ] }, "devDependencies": { "ember-cached-decorator-polyfill": "^0.1.4", "ember-cli-deprecation-workflow": "^2.1.0", - "ember-exam": "^7.0.1" + "ember-exam": "^8.0.0" } } diff --git a/app/assets/javascripts/discourse/public/assets/scripts/discourse-boot.js b/app/assets/javascripts/discourse/public/assets/scripts/discourse-boot.js index 7dab11a480..d9d96d27b9 100644 --- a/app/assets/javascripts/discourse/public/assets/scripts/discourse-boot.js +++ b/app/assets/javascripts/discourse/public/assets/scripts/discourse-boot.js @@ -4,15 +4,46 @@ } // TODO: Remove this and have resolver find the templates - const prefix = "discourse/templates/"; + const discoursePrefix = "discourse/templates/"; const adminPrefix = "admin/templates/"; const wizardPrefix = "wizard/templates/"; - let len = prefix.length; + const discoursePrefixLength = discoursePrefix.length; + + const pluginRegex = /^discourse\/plugins\/([^\/]+)\//; + const themeRegex = /^discourse\/theme-([^\/]+)\//; + Object.keys(requirejs.entries).forEach(function (key) { - if (key.startsWith(prefix)) { - Ember.TEMPLATES[key.slice(len)] = require(key).default; + let templateKey; + let pluginName; + let themeId; + if (key.startsWith(discoursePrefix)) { + templateKey = key.slice(discoursePrefixLength); } else if (key.startsWith(adminPrefix) || key.startsWith(wizardPrefix)) { - Ember.TEMPLATES[key] = require(key).default; + templateKey = key; + } else if ( + (pluginName = key.match(pluginRegex)?.[1]) && + key.includes("/templates/") && + require(key).default.__id // really is a template + ) { + // This logic mimics the old sprockets compilation system which used to + // output templates directly to `Ember.TEMPLATES` with this naming logic + templateKey = key.slice(`discourse/plugins/${pluginName}/`.length); + templateKey = templateKey.replace("discourse/templates/", ""); + templateKey = `javascripts/${templateKey}`; + } else if ( + (themeId = key.match(themeRegex)?.[1]) && + key.includes("/templates/") + ) { + // And likewise for themes - this mimics the old logic + templateKey = key.slice(`discourse/theme-${themeId}/`.length); + templateKey = templateKey.replace("discourse/templates/", ""); + if (!templateKey.startsWith("javascripts/")) { + templateKey = `javascripts/${templateKey}`; + } + } + + if (templateKey) { + Ember.TEMPLATES[templateKey] = require(key).default; } }); diff --git a/app/assets/javascripts/discourse/public/assets/scripts/discourse-test-listen-boot.js b/app/assets/javascripts/discourse/public/assets/scripts/discourse-test-listen-boot.js index 48a7c880f6..bc903572c7 100644 --- a/app/assets/javascripts/discourse/public/assets/scripts/discourse-test-listen-boot.js +++ b/app/assets/javascripts/discourse/public/assets/scripts/discourse-test-listen-boot.js @@ -27,4 +27,4 @@ document.body.insertAdjacentHTML( ` ); -require('discourse/tests/test-boot-ember-cli'); +require("discourse/tests/test-boot-ember-cli"); diff --git a/app/assets/javascripts/discourse/public/assets/scripts/discourse-test-load-dynamic-js.js b/app/assets/javascripts/discourse/public/assets/scripts/discourse-test-load-dynamic-js.js new file mode 100644 index 0000000000..fc0237c622 --- /dev/null +++ b/app/assets/javascripts/discourse/public/assets/scripts/discourse-test-load-dynamic-js.js @@ -0,0 +1,28 @@ +const dynamicJsTemplate = document.querySelector("#dynamic-test-js"); + +const params = new URLSearchParams(document.location.search); +const skipPlugins = params.get("qunit_skip_plugins"); + +for (const element of dynamicJsTemplate.content.childNodes) { + if (skipPlugins && element.dataset?.discoursePlugin) { + continue; + } + + if ( + element.tagName === "SCRIPT" && + element.innerHTML.includes("EmberENV.TESTS_FILE_LOADED") + ) { + // Inline script introduced by ember-cli. Incompatible with CSP and our custom plugin JS loading system + // https://github.com/ember-cli/ember-cli/blob/04a38fda2c/lib/utilities/ember-app-utils.js#L131 + // We re-implement in test-boot-ember-cli.js + continue; + } + + const clone = element.cloneNode(true); + + if (clone.tagName === "SCRIPT") { + clone.async = false; + } + + document.querySelector("discourse-dynamic-test-js").appendChild(clone); +} diff --git a/app/assets/javascripts/discourse/public/assets/scripts/discourse-test-trigger-ember-cli-boot.js b/app/assets/javascripts/discourse/public/assets/scripts/discourse-test-trigger-ember-cli-boot.js new file mode 100644 index 0000000000..65f629d8a0 --- /dev/null +++ b/app/assets/javascripts/discourse/public/assets/scripts/discourse-test-trigger-ember-cli-boot.js @@ -0,0 +1 @@ +require("discourse/tests/test-boot-ember-cli"); diff --git a/app/assets/javascripts/discourse/public/assets/scripts/module-shims.js b/app/assets/javascripts/discourse/public/assets/scripts/module-shims.js index c0071eb9fa..a8b8118e99 100644 --- a/app/assets/javascripts/discourse/public/assets/scripts/module-shims.js +++ b/app/assets/javascripts/discourse/public/assets/scripts/module-shims.js @@ -18,3 +18,16 @@ define("ember-addons/ember-computed-decorators", [ ); return decorators; }); + +// Based on https://github.com/emberjs/ember-jquery-legacy +// The addon has out-of-date dependences, but it's super simple so we can reproduce here instead: +define("ember-jquery-legacy", ["exports"], function (exports) { + exports.normalizeEvent = function (e) { + if (e instanceof Event) { + return e; + } + // __originalEvent is a private escape hatch of Ember's EventDispatcher to allow accessing `originalEvent` without + // triggering a deprecation message. + return e.__originalEvent || e.originalEvent; + }; +}); diff --git a/app/assets/javascripts/discourse/scripts/splash-screen.js b/app/assets/javascripts/discourse/scripts/splash-screen.js new file mode 100644 index 0000000000..a8a56af7ee --- /dev/null +++ b/app/assets/javascripts/discourse/scripts/splash-screen.js @@ -0,0 +1,66 @@ +// This script is inlined in `_discourse_splash.html.erb +const DELAY_TARGET = 2000; +const POLLING_INTERVAL = 50; + +const splashSvgTemplate = document.querySelector(".splash-svg-template"); +const splashTemplateClone = splashSvgTemplate.content.cloneNode(true); +const svgElement = splashTemplateClone.querySelector("svg"); + +const svgString = new XMLSerializer().serializeToString(svgElement); +const encodedSvg = btoa(svgString); + +const splashWrapper = document.querySelector("#d-splash"); +const splashImage = + splashWrapper && splashWrapper.querySelector(".preloader-image"); + +if (splashImage) { + splashImage.src = `data:image/svg+xml;base64,${encodedSvg}`; + + const connectStart = performance.timing.connectStart || 0; + const targetTime = connectStart + DELAY_TARGET; + + let splashInterval; + let discourseReady; + + const swapSplash = () => { + splashWrapper && + splashWrapper.style.setProperty("--animation-state", "running"); + svgElement && svgElement.style.setProperty("--animation-state", "running"); + + const newSvgString = new XMLSerializer().serializeToString(svgElement); + const newEncodedSvg = btoa(newSvgString); + + splashImage.src = `data:image/svg+xml;base64,${newEncodedSvg}`; + + performance.mark("discourse-splash-visible"); + + clearSplashInterval(); + }; + + const clearSplashInterval = () => { + clearInterval(splashInterval); + splashInterval = null; + }; + + (() => { + splashInterval = setInterval(() => { + if (discourseReady) { + clearSplashInterval(); + } + + if (Date.now() > targetTime) { + swapSplash(); + } + }, POLLING_INTERVAL); + })(); + + document.addEventListener( + "discourse-ready", + () => { + discourseReady = true; + splashWrapper && splashWrapper.remove(); + performance.mark("discourse-splash-removed"); + }, + { once: true } + ); +} diff --git a/app/assets/javascripts/discourse/testem.js b/app/assets/javascripts/discourse/testem.js index 67261a0fb6..1545a94f55 100644 --- a/app/assets/javascripts/discourse/testem.js +++ b/app/assets/javascripts/discourse/testem.js @@ -2,12 +2,12 @@ const TapReporter = require("testem/lib/reporters/tap_reporter"); const { shouldLoadPluginTestJs } = require("discourse/lib/plugin-js"); class Reporter { + failReports = []; + constructor() { this._tapReporter = new TapReporter(...arguments); } - failReports = []; - reportMetadata(tag, metadata) { if (tag === "summary-line") { process.stdout.write(`\n${metadata.message}\n`); @@ -44,7 +44,7 @@ module.exports = { launch_in_ci: ["Chrome"], // launch_in_dev: ["Chrome"] // Ember-CLI always launches testem in 'CI' mode tap_failed_tests_only: false, - parallel: 1, // disable parallel tests for stability + parallel: -1, browser_start_timeout: 120, browser_args: { Chrome: [ @@ -60,15 +60,16 @@ module.exports = { "--js-flags=--max_old_space_size=4096", ].filter(Boolean), Firefox: ["-headless", "--width=1440", "--height=900"], - "Headless Firefox": ["--width=1440", "--height=900"], - }, - browser_paths: { - "Headless Firefox": "/opt/firefox-evergreen/firefox", }, reporter: Reporter, }; -const target = `http://localhost:${process.env.UNICORN_PORT || "3000"}`; +if (process.env.TESTEM_FIREFOX_PATH) { + module.exports.browser_paths ||= {}; + module.exports.browser_paths["Firefox"] = process.env.TESTEM_FIREFOX_PATH; +} + +const target = `http://127.0.0.1:${process.env.UNICORN_PORT || "3000"}`; if (process.argv.includes("-t")) { // Running testem without ember cli. Probably for theme-qunit @@ -95,13 +96,7 @@ if (process.argv.includes("-t")) { } else if (shouldLoadPluginTestJs()) { // Running with ember cli, but we want to pass through plugin request to Rails module.exports.proxies = { - "/assets/discourse/tests/active-plugins.js": { - target, - }, - "/assets/admin-plugins.js": { - target, - }, - "/assets/discourse/tests/plugin-tests.js": { + "/assets/plugins/*_extra.js": { target, }, "/plugins/": { diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-badges-show-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-badges-show-test.js index 531342e2ff..2464e770b9 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/admin-badges-show-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/admin-badges-show-test.js @@ -3,8 +3,9 @@ import { exists, query, } from "discourse/tests/helpers/qunit-helpers"; -import { click, visit } from "@ember/test-helpers"; +import { click, fillIn, settled, visit } from "@ember/test-helpers"; import { test } from "qunit"; +import { set } from "@ember/object"; acceptance("Admin - Badges - Show", function (needs) { needs.user(); @@ -37,6 +38,24 @@ acceptance("Admin - Badges - Show", function (needs) { exists(".image-uploader"), "image uploader becomes visible after clicking the upload image radio button" ); + + // SQL fields + assert.false(exists("label[for=query]"), "sql input is hidden by default"); + set(this.siteSettings, "enable_badge_sql", true); + await settled(); + assert.true(exists("label[for=query]"), "sql input shows when enabled"); + + assert.false( + exists("input[name=auto_revoke]"), + "does not show sql-specific options when query is blank" + ); + + await fillIn(".ace-wrapper textarea", "SELECT 1"); + + assert.true( + exists("input[name=auto_revoke]"), + "shows sql-specific options when query is present" + ); }); test("existing badge that has an icon", async function (assert) { diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-emails-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-emails-test.js index 7d7772422e..c61bade52d 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/admin-emails-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/admin-emails-test.js @@ -51,7 +51,11 @@ acceptance("Admin - Emails", function (needs) { await fillIn(".admin-controls input", "test@example.com"); await click(".btn-primary"); - assert.ok(query(".bootbox.modal").innerText.includes("some error")); - await click(".bootbox .btn-primary"); + assert.ok(query("#dialog-holder").innerText.includes("some error")); + assert.ok( + query("#dialog-holder .dialog-body b"), + "Error message can contain html" + ); + await click(".dialog-overlay"); }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-install-theme-modal-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-install-theme-modal-test.js index 27eaf158d7..7ecab0566e 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/admin-install-theme-modal-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/admin-install-theme-modal-test.js @@ -79,6 +79,15 @@ acceptance("Admin - Themes - Install modal", function (needs) { await fillIn(urlInput, "git@github.com:discourse/discourse.git"); assert.ok(query(publicKey), "shows public key for valid github repo url"); + + await fillIn(urlInput, "git@github.com:discourse/discourse"); + assert.ok(query(publicKey), "shows public key for valid github repo url"); + + await fillIn(urlInput, "git@github.com/discourse/discourse"); + assert.notOk( + query(publicKey), + "does not shows public key for valid github repo url" + ); }); test("modal can be auto-opened with the right query params", async function (assert) { diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-site-text-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-site-text-test.js index 6770f01c01..38cfee1af7 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/admin-site-text-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/admin-site-text-test.js @@ -51,9 +51,9 @@ acceptance("Admin - Site Texts", function (needs) { // Revert the changes await click(".revert-site-text"); - assert.ok(exists(".bootbox.modal")); + assert.ok(exists("#dialog-holder .dialog-content")); - await click(".bootbox.modal .btn-primary"); + await click("#dialog-holder .btn-primary"); assert.ok(!exists(".saved")); assert.ok(!exists(".revert-site-text")); diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-user-index-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-user-index-test.js index 193c44cf0b..8e14be163d 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/admin-user-index-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/admin-user-index-test.js @@ -10,6 +10,8 @@ import I18n from "I18n"; import { SECOND_FACTOR_METHODS } from "discourse/models/user"; const { TOTP, BACKUP_CODE, SECURITY_KEY } = SECOND_FACTOR_METHODS; +let deleteAndBlock = null; + acceptance("Admin - User Index", function (needs) { needs.user(); needs.pretender((server, helper) => { @@ -97,6 +99,34 @@ acceptance("Admin - User Index", function (needs) { allowed_methods: [TOTP, BACKUP_CODE, SECURITY_KEY], }); }); + + server.get("/admin/users/5.json", () => { + return helper.response({ + id: 5, + username: "user5", + name: null, + avatar_template: "/letter_avatar_proxy/v4/letter/b/f0a364/{size}.png", + active: true, + can_be_deleted: true, + post_count: 0, + }); + }); + + server.delete("/admin/users/5.json", (request) => { + const data = helper.parsePostData(request.requestBody); + + if (data.block_email || data.block_ip || data.block_urls) { + deleteAndBlock = true; + } else { + deleteAndBlock = false; + } + + return helper.response({}); + }); + }); + + needs.hooks.beforeEach(() => { + deleteAndBlock = null; }); test("can edit username", async function (assert) { @@ -195,12 +225,13 @@ acceptance("Admin - User Index", function (needs) { test("grant admin - shows the confirmation bootbox", async function (assert) { await visit("/admin/users/3/user1"); await click(".grant-admin"); - assert.ok(exists(".bootbox")); + assert.ok(exists(".dialog-content")); assert.strictEqual( I18n.t("admin.user.grant_admin_confirm"), - query(".modal-body").textContent.trim() + query(".dialog-body").textContent.trim() ); - await click(".bootbox .btn-primary"); + + await click(".dialog-footer .btn-primary"); }); test("grant admin - redirects to the 2fa page", async function (assert) { @@ -212,4 +243,27 @@ acceptance("Admin - User Index", function (needs) { "user is redirected to the 2FA page" ); }); + + test("delete user - delete without blocking works as expected", async function (assert) { + await visit("/admin/users/5/user5"); + await click(".btn-user-delete"); + + assert.equal( + query("#dialog-title").textContent, + I18n.t("admin.user.delete_confirm_title"), + "dialog has a title" + ); + + await click(".dialog-footer .btn-primary"); + + assert.notOk(deleteAndBlock, "user does not get blocked"); + }); + + test("delete user - delete and block works as expected", async function (assert) { + await visit("/admin/users/5/user5"); + await click(".btn-user-delete"); + await click(".dialog-footer .btn-danger"); + + assert.ok(deleteAndBlock, "user does not get blocked"); + }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-users-list-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-users-list-test.js index e899cf9d3d..6e051abe6b 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/admin-users-list-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/admin-users-list-test.js @@ -3,7 +3,7 @@ import { exists, query, } from "discourse/tests/helpers/qunit-helpers"; -import { click, visit } from "@ember/test-helpers"; +import { click, fillIn, visit } from "@ember/test-helpers"; import I18n from "I18n"; import { test } from "qunit"; @@ -17,6 +17,17 @@ acceptance("Admin - Users List", function (needs) { assert.ok(!exists(".user:nth-of-type(1) .email small"), "escapes email"); }); + test("searching users with no matches", async function (assert) { + await visit("/admin/users/list/active"); + + await fillIn(".controls.username input", "doesntexist"); + + assert.equal( + query(".users-list-container").innerText, + I18n.t("search.no_results") + ); + }); + test("sorts users", async function (assert) { await visit("/admin/users/list/active"); diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-watched-words-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-watched-words-test.js index e2d6b66702..37cb1c8797 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/admin-watched-words-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/admin-watched-words-test.js @@ -58,9 +58,8 @@ acceptance("Admin - Watched Words", function (needs) { test("add words", async function (assert) { await visit("/admin/customize/watched_words/action/block"); - click(".show-words-checkbox"); - fillIn(".watched-word-form input", "poutine"); - + await click(".show-words-checkbox"); + await fillIn(".watched-word-form input", "poutine"); await click(".watched-word-form button"); let found = []; @@ -74,21 +73,20 @@ acceptance("Admin - Watched Words", function (needs) { assert.strictEqual(count(".watched-words-list .case-sensitive"), 0); }); - test("add case-sensitve words", async function (assert) { + test("add case-sensitive words", async function (assert) { await visit("/admin/customize/watched_words/action/block"); - click(".show-words-checkbox"); - fillIn(".watched-word-form input", "Discourse"); - click(".case-sensitivity-checkbox"); - + await click(".show-words-checkbox"); + await fillIn(".watched-word-form input", "Discourse"); + await click(".case-sensitivity-checkbox"); await click(".watched-word-form button"); assert .dom(".watched-words-list .watched-word") .hasText(`Discourse ${I18n.t("admin.watched_words.case_sensitive")}`); - fillIn(".watched-word-form input", "discourse"); - click(".case-sensitivity-checkbox"); + await fillIn(".watched-word-form input", "discourse"); + await click(".case-sensitivity-checkbox"); await click(".watched-word-form button"); assert diff --git a/app/assets/javascripts/discourse/tests/acceptance/bookmarks-test.js b/app/assets/javascripts/discourse/tests/acceptance/bookmarks-test.js index b2164921f8..e46c80057c 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/bookmarks-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/bookmarks-test.js @@ -303,8 +303,8 @@ acceptance("Bookmarking", function (needs) { }); test("The topic level bookmark button deletes all bookmarks if several posts on the topic are bookmarked", async function (assert) { - const yesButton = "a.btn-primary"; - const noButton = "a.btn-default"; + const yesButton = ".dialog-footer .btn-primary"; + const noButton = ".dialog-footer .btn-default"; await visit("/t/internationalization-localization/280"); await openBookmarkModal(1); @@ -336,6 +336,7 @@ acceptance("Bookmarking", function (needs) { // open the modal and accept deleting await click("#topic-footer-button-bookmark"); + // pauseTest(); await click(yesButton); assert.ok( @@ -412,7 +413,7 @@ acceptance("Bookmarking", function (needs) { "the footer button says Clear Bookmarks because there is more than one" ); await click("#topic-footer-button-bookmark"); - await click("a.btn-primary"); + await click(".dialog-footer .btn-primary"); assert.ok( !exists(".topic-post:first-child button.bookmark.bookmarked"), diff --git a/app/assets/javascripts/discourse/tests/acceptance/bootstrap-mode-notice-test.js b/app/assets/javascripts/discourse/tests/acceptance/bootstrap-mode-notice-test.js index 5f11ac4d47..9d8812ccf3 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/bootstrap-mode-notice-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/bootstrap-mode-notice-test.js @@ -1,6 +1,7 @@ import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers"; import { test } from "qunit"; -import { click, currentURL, visit } from "@ember/test-helpers"; +import { click, currentURL, settled, visit } from "@ember/test-helpers"; +import { set } from "@ember/object"; acceptance("Bootstrap Mode Notice", function (needs) { needs.user(); @@ -26,18 +27,21 @@ acceptance("Bootstrap Mode Notice", function (needs) { ); await click(".bootstrap-invite-button"); - assert.strictEqual( - currentURL(), - "/u/eviltrout/invited/pending", - "it transitions to the invite page" - ); + assert.ok(exists(".create-invite-modal"), "opens create invite modal"); - await visit("/"); await click(".bootstrap-wizard-link"); assert.strictEqual( currentURL(), "/wizard/steps/hello-world", "it transitions to the wizard page" ); + + await visit("/"); + set(this.siteSettings, "bootstrap_mode_enabled", false); + await settled(); + assert.ok( + !exists(".bootstrap-mode-notice"), + "removes the notice when bootstrap mode is disabled" + ); }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/categories-test.js b/app/assets/javascripts/discourse/tests/acceptance/categories-test.js index d0b91e934a..8f84f5ab79 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/categories-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/categories-test.js @@ -6,6 +6,10 @@ import { import { visit } from "@ember/test-helpers"; import { test } from "qunit"; +import PreloadStore from "discourse/lib/preload-store"; +import discoveryFixtures from "discourse/tests/fixtures/discovery-fixtures"; +import { cloneJSON } from "discourse-common/lib/object"; + acceptance("Categories - 'categories_only'", function (needs) { needs.settings({ desktop_category_page_style: "categories_only", @@ -99,3 +103,41 @@ acceptance( }); } ); + +acceptance("Categories - preloadStore handling", function () { + const styles = [ + "categories_only", + "categories_with_featured_topics", + "categories_and_latest_topics_created_date", + "categories_and_latest_topics", + "categories_and_top_topics", + "categories_boxes", + "categories_boxes_with_topics", + "subcategories_with_featured_topics", + ]; + + for (const style of styles) { + test(`${style} deletes data from PreloadStore to ensure it isn't left for another route`, async function (assert) { + this.siteSettings.desktop_category_page_style = style; + PreloadStore.store( + "topic_list", + cloneJSON(discoveryFixtures["/latest.json"]) + ); + PreloadStore.store( + "categories_list", + cloneJSON(discoveryFixtures["/categories.json"]) + ); + + await visit(`/categories`); + + assert.true( + PreloadStore.get("topic_list") === undefined, + `topic_list is removed from preloadStore for ${style}` + ); + assert.true( + PreloadStore.get("categories_list") === undefined, + `topic_list is removed from preloadStore for ${style}` + ); + }); + } +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/category-banner-test.js b/app/assets/javascripts/discourse/tests/acceptance/category-banner-test.js index 8e9f67798d..d6874ab1c2 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/category-banner-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/category-banner-test.js @@ -44,7 +44,7 @@ acceptance("Category Banners", function (needs) { await visit("/c/test-read-only-without-banner"); await click("#create-topic"); - assert.ok(!visible(".bootbox.modal"), "it does not pop up a modal"); + assert.ok(!visible(".dialog-body"), "it does not pop up a modal"); assert.ok( !visible(".category-read-only-banner"), "it does not show a banner" @@ -55,10 +55,10 @@ acceptance("Category Banners", function (needs) { await visit("/c/test-read-only-with-banner"); await click("#create-topic"); - assert.ok(visible(".bootbox.modal"), "it pops up a modal"); + assert.ok(visible(".dialog-body"), "it pops up a modal"); - await click(".modal-footer>.btn-primary"); - assert.ok(!visible(".bootbox.modal"), "it closes the modal"); + await click(".dialog-footer .btn-primary"); + assert.ok(!visible(".dialog-body"), "it closes the modal"); assert.ok(visible(".category-read-only-banner"), "it shows a banner"); assert.strictEqual( count(".category-read-only-banner .inner"), diff --git a/app/assets/javascripts/discourse/tests/acceptance/category-edit-test.js b/app/assets/javascripts/discourse/tests/acceptance/category-edit-test.js index eb703cd6da..5042f2c614 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/category-edit-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/category-edit-test.js @@ -164,14 +164,13 @@ acceptance("Category Edit", function (needs) { await fillIn(".email-in", "duplicate@example.com"); await click("#save-category"); - assert.ok(visible(".bootbox")); assert.strictEqual( - query(".bootbox .modal-body").innerHTML, + query(".dialog-body").textContent.trim(), "duplicate email" ); - await click(".bootbox .btn-primary"); - assert.ok(!visible(".bootbox")); + await click(".dialog-footer .btn-primary"); + assert.ok(!visible(".dialog-body")); }); test("Subcategory list settings", async function (assert) { diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-actions-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-actions-test.js index 3743d61c55..a2002935f0 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-actions-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-actions-test.js @@ -9,8 +9,6 @@ import { import { click, fillIn, visit } from "@ember/test-helpers"; import Draft from "discourse/models/draft"; import I18n from "I18n"; -import { Promise } from "rsvp"; -import { _clearSnapshots } from "select-kit/components/composer-actions"; import selectKit from "discourse/tests/helpers/select-kit-helper"; import sinon from "sinon"; import { test } from "qunit"; @@ -118,9 +116,8 @@ acceptance("Composer Actions", function (needs) { }); test("replying to post - reply_as_new_topic", async function (assert) { - sinon - .stub(Draft, "get") - .returns(Promise.resolve({ draft: "", draft_sequence: 0 })); + sinon.stub(Draft, "get").resolves({ draft: "", draft_sequence: 0 }); + const composerActions = selectKit(".composer-actions"); const categoryChooser = selectKit(".title-wrapper .category-chooser"); const categoryChooserReplyArea = selectKit(".reply-area .category-chooser"); @@ -406,13 +403,11 @@ acceptance("Composer Actions", function (needs) { }); function stubDraftResponse() { - sinon.stub(Draft, "get").returns( - Promise.resolve({ - draft: - '{"reply":"dum de dum da ba.","action":"createTopic","title":"dum da ba dum dum","categoryId":null,"archetypeId":"regular","metaData":null,"composerTime":540879,"typingTime":3400}', - draft_sequence: 0, - }) - ); + sinon.stub(Draft, "get").resolves({ + draft: + '{"reply":"dum de dum da ba.","action":"createTopic","title":"dum da ba dum dum","categoryId":null,"archetypeId":"regular","metaData":null,"composerTime":540879,"typingTime":3400}', + draft_sequence: 0, + }); } acceptance("Composer Actions With New Topic Draft", function (needs) { @@ -423,67 +418,69 @@ acceptance("Composer Actions With New Topic Draft", function (needs) { needs.site({ can_tag_topics: true, }); - needs.hooks.beforeEach(() => _clearSnapshots()); - needs.hooks.afterEach(() => _clearSnapshots()); + + needs.hooks.afterEach(() => toggleCheckDraftPopup(false)); test("shared draft", async function (assert) { + updateCurrentUser({ has_topic_draft: true }); stubDraftResponse(); - try { - toggleCheckDraftPopup(true); + toggleCheckDraftPopup(true); - const composerActions = selectKit(".composer-actions"); - const tags = selectKit(".mini-tag-chooser"); + await visit("/"); + await click("button.open-draft"); - await visit("/"); - await click("#create-topic"); + await fillIn( + "#reply-title", + "This is the new text for the title using 'quotes'" + ); + await fillIn(".d-editor-input", "This is the new text for the post"); - await fillIn( - "#reply-title", - "This is the new text for the title using 'quotes'" - ); + const tags = selectKit(".mini-tag-chooser"); + await tags.expand(); + await tags.selectRowByValue("monkey"); - await fillIn(".d-editor-input", "This is the new text for the post"); - await tags.expand(); - await tags.selectRowByValue("monkey"); - await composerActions.expand(); - await composerActions.selectRowByValue("shared_draft"); + const composerActions = selectKit(".composer-actions"); + await composerActions.expand(); + await composerActions.selectRowByValue("shared_draft"); - assert.strictEqual(tags.header().value(), "monkey", "tags are not reset"); + assert.strictEqual(tags.header().value(), "monkey", "tags are not reset"); + assert.strictEqual( + query("#reply-title").value, + "This is the new text for the title using 'quotes'" + ); - assert.strictEqual( - query("#reply-title").value, - "This is the new text for the title using 'quotes'" - ); - - assert.strictEqual( - query("#reply-control .btn-primary.create .d-button-label").innerText, - I18n.t("composer.create_shared_draft") - ); - assert.strictEqual( - count(".composer-actions svg.d-icon-far-clipboard"), - 1, - "shared draft icon is visible" - ); - - assert.strictEqual(count("#reply-control.composing-shared-draft"), 1); - await click(".modal-footer .btn.btn-default"); - } finally { - toggleCheckDraftPopup(false); - } + assert.strictEqual( + query("#reply-control .btn-primary.create .d-button-label").innerText, + I18n.t("composer.create_shared_draft") + ); + assert.strictEqual( + count(".composer-actions svg.d-icon-far-clipboard"), + 1, + "shared draft icon is visible" + ); }); test("reply_as_new_topic with new_topic draft", async function (assert) { await visit("/t/internationalization-localization/280"); await click(".create.reply"); + + stubDraftResponse(); + const composerActions = selectKit(".composer-actions"); await composerActions.expand(); - stubDraftResponse(); await composerActions.selectRowByValue("reply_as_new_topic"); + assert.strictEqual( query(".bootbox .modal-body").innerText, I18n.t("composer.composer_actions.reply_as_new_topic.confirm") ); - await click(".modal-footer .btn.btn-default"); + await click(".modal-footer .btn.btn-primary"); + + assert.ok( + query(".d-editor-input").value.startsWith( + "Continuing the discussion from" + ) + ); }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-editor-mentions-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-editor-mentions-test.js index ea6f29bc0e..6329a25769 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-editor-mentions-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-editor-mentions-test.js @@ -1,12 +1,31 @@ import { test } from "qunit"; import { click, fillIn, triggerKeyEvent, visit } from "@ember/test-helpers"; -import { acceptance, query } from "discourse/tests/helpers/qunit-helpers"; +import { + acceptance, + exists, + fakeTime, + loggedInUser, + query, +} from "discourse/tests/helpers/qunit-helpers"; import { setCaretPosition } from "discourse/lib/utilities"; acceptance("Composer - editor mentions", function (needs) { + let clock = null; + const status = { + emoji: "tooth", + description: "off to dentist", + ends_at: "2100-02-01T09:00:00.000Z", + }; + needs.user(); needs.settings({ enable_mentions: true }); + needs.hooks.afterEach(() => { + if (clock) { + clock.restore(); + } + }); + needs.pretender((server, helper) => { server.get("/u/search/users", () => { return helper.response({ @@ -16,6 +35,7 @@ acceptance("Composer - editor mentions", function (needs) { name: "Some User", avatar_template: "https://avatars.discourse.org/v3/letter/t/41988e/{size}.png", + status, }, { username: "user2", @@ -104,4 +124,37 @@ acceptance("Composer - editor mentions", function (needs) { "should replace mention correctly" ); }); + + test("shows status on search results when mentioning a user", async function (assert) { + const timezone = loggedInUser().timezone; + const now = moment(status.ends_at).add(-1, "hour").format(); + clock = fakeTime(now, timezone, true); + + await visit("/"); + await click("#create-topic"); + + // emulate typing in "abc @u" + const editor = query(".d-editor-input"); + await fillIn(".d-editor-input", "@"); + await setCaretPosition(editor, 5); + await triggerKeyEvent(".d-editor-input", "keyup", "@"); + await fillIn(".d-editor-input", "@u"); + await setCaretPosition(editor, 6); + await triggerKeyEvent(".d-editor-input", "keyup", "U"); + + assert.ok( + exists(`.autocomplete .emoji[title='${status.emoji}']`), + "status emoji is shown" + ); + assert.equal( + query(".autocomplete .status-description").textContent.trim(), + status.description, + "status description is shown" + ); + assert.equal( + query(".autocomplete .relative-date").textContent.trim(), + "1h", + "status expiration time is shown" + ); + }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-hyperlink-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-hyperlink-test.js index 274a262020..852e548dae 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-hyperlink-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-hyperlink-test.js @@ -98,5 +98,13 @@ acceptance("Composer - Hyperlink", function (needs) { query(".link-url").value.includes("http"), "replaces link url field with internal link" ); + + await triggerKeyEvent(".insert-link", "keydown", "Escape"); + + assert.strictEqual( + document.activeElement.classList.contains("d-editor-input"), + true, + "focus stays on composer after dismissing modal using Esc key" + ); }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-messages-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-messages-test.js new file mode 100644 index 0000000000..25f9cae229 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-messages-test.js @@ -0,0 +1,41 @@ +import { + acceptance, + exists, + query, +} from "discourse/tests/helpers/qunit-helpers"; +import { click, triggerKeyEvent, visit } from "@ember/test-helpers"; +import { test } from "qunit"; +import I18n from "I18n"; + +acceptance("Composer - Messages", function (needs) { + needs.user(); + needs.pretender((server, helper) => { + server.get("/composer_messages/user_not_seen_in_a_while", () => { + return helper.response({ + user_count: 1, + usernames: ["charlie"], + time_ago: "1 year ago", + }); + }); + }); + + test("Shows warning in composer if user hasn't been seen in a long time.", async function (assert) { + await visit("/u/charlie"); + await click("button.compose-pm"); + assert.ok( + !exists(".composer-popup"), + "composer warning is not shown by default" + ); + await triggerKeyEvent(".d-editor-input", "keyup", "Space"); + assert.ok(exists(".composer-popup"), "shows composer warning message"); + assert.ok( + query(".composer-popup").innerHTML.includes( + I18n.t("composer.user_not_seen_in_a_while.single", { + usernames: ['@charlie'], + time_ago: "1 year ago", + }) + ), + "warning message has correct body" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-tags-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-tags-test.js index 3ea0d2fe9e..fcea997085 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-tags-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-tags-test.js @@ -1,5 +1,6 @@ import { acceptance, + exists, query, updateCurrentUser, } from "discourse/tests/helpers/qunit-helpers"; @@ -98,4 +99,28 @@ acceptance("Composer - Tags", function (needs) { await click("#reply-control button.create"); assert.notStrictEqual(currentURL(), "/"); }); + + test("users who cannot tag PMs do not see the selector", async function (assert) { + await visit("/u/charlie"); + await click("button.compose-pm"); + + assert.notOk(exists(".composer-fields .mini-tag-chooser")); + }); +}); + +acceptance("Composer - Tags (PMs)", function (needs) { + needs.user(); + needs.pretender((server, helper) => { + server.post("/uploads/lookup-urls", () => { + return helper.response([]); + }); + }); + needs.site({ can_tag_topics: true, can_tag_pms: true }); + + test("users who can tag PMs see the selector", async function (assert) { + await visit("/u/charlie"); + await click("button.compose-pm"); + + assert.ok(exists(".composer-fields .mini-tag-chooser")); + }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js index 5c60c6086b..88c616e3fd 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js @@ -1,4 +1,11 @@ -import { click, currentURL, fillIn, settled, visit } from "@ember/test-helpers"; +import { + click, + currentURL, + fillIn, + settled, + triggerEvent, + visit, +} from "@ember/test-helpers"; import { toggleCheckDraftPopup } from "discourse/controllers/composer"; import { cloneJSON } from "discourse-common/lib/object"; import TopicFixtures from "discourse/tests/fixtures/topic"; @@ -21,8 +28,8 @@ import { import selectKit from "discourse/tests/helpers/select-kit-helper"; import I18n from "I18n"; import { test } from "qunit"; -import { Promise } from "rsvp"; import sinon from "sinon"; +import pretender, { response } from "discourse/tests/helpers/create-pretender"; acceptance("Composer", function (needs) { needs.user({ @@ -57,6 +64,67 @@ acceptance("Composer", function (needs) { }); }); + needs.hooks.afterEach(() => toggleCheckDraftPopup(false)); + + test("Composer is opened", async function (assert) { + await visit("/"); + await click("#create-topic"); + + assert.strictEqual( + document.documentElement.style.getPropertyValue("--composer-height"), + "var(--new-topic-composer-height, 400px)", + "sets --composer-height to 400px when creating topic" + ); + + await fillIn( + ".d-editor-input", + "this is the *content* of a new topic post" + ); + await click(".toggle-minimize"); + assert.strictEqual( + document.documentElement.style.getPropertyValue("--composer-height"), + "40px", + "sets --composer-height to 40px when composer is minimized to draft mode" + ); + + await click(".toggle-fullscreen"); + assert.strictEqual( + document.documentElement.style.getPropertyValue("--composer-height"), + "var(--new-topic-composer-height, 400px)", + "sets --composer-height back to 400px when composer is opened from draft mode" + ); + + await fillIn(".d-editor-input", ""); + await click(".toggle-minimize"); + assert.strictEqual( + document.documentElement.style.getPropertyValue("--composer-height"), + "", + "removes --composer-height property when composer is closed" + ); + }); + + test("Composer height adjustment", async function (assert) { + await visit("/"); + await click("#create-topic"); + await triggerEvent(document.querySelector(".grippie"), "mousedown"); + await triggerEvent(document.querySelector(".grippie"), "mousemove"); + await triggerEvent(document.querySelector(".grippie"), "mouseup"); + await visit("/"); // reload page + await click("#create-topic"); + + const expectedHeight = localStorage.getItem( + "__test_discourse_composerHeight" + ); + const actualHeight = + document.documentElement.style.getPropertyValue("--composer-height"); + + assert.strictEqual( + expectedHeight, + actualHeight, + "Updated height is persistent" + ); + }); + test("composer controls", async function (assert) { await visit("/"); assert.ok(exists("#create-topic"), "the create button is visible"); @@ -143,9 +211,9 @@ acceptance("Composer", function (needs) { await fillIn("#reply-title", "this title triggers an error"); await fillIn(".d-editor-input", "this is the *content* of a post"); await click("#reply-control button.create"); - assert.ok(exists(".bootbox.modal"), "it pops up an error message"); - await click(".bootbox.modal a.btn-primary"); - assert.ok(!exists(".bootbox.modal"), "it dismisses the error"); + assert.ok(exists(".dialog-body"), "it pops up an error message"); + await click(".dialog-footer .btn-primary"); + assert.ok(!exists(".dialog-body"), "it dismisses the error"); assert.ok(exists(".d-editor-input"), "the composer input is visible"); }); @@ -184,13 +252,14 @@ acceptance("Composer", function (needs) { await fillIn("#reply-title", "This title doesn't matter"); await fillIn(".d-editor-input", "custom message"); await click("#reply-control button.create"); + assert.strictEqual( - query(".bootbox .modal-body").innerText, + query("#dialog-holder .dialog-body").innerText, "This is a custom response" ); assert.strictEqual(currentURL(), "/", "it doesn't change routes"); - await click(".bootbox .btn-primary"); + await click(".dialog-footer .btn-primary"); assert.strictEqual( currentURL(), "/faq", @@ -278,7 +347,10 @@ acceptance("Composer", function (needs) { await fillIn(".d-editor-input", "this is the content of the first reply"); await visit("/t/this-is-a-test-topic/9"); - assert.strictEqual(currentURL(), "/t/this-is-a-test-topic/9"); + assert.ok( + currentURL().startsWith("/t/this-is-a-test-topic/9"), + "moves to second topic" + ); await click("#topic-footer-buttons .btn.create"); assert.ok( exists(".discard-draft-modal.modal"), @@ -370,34 +442,27 @@ acceptance("Composer", function (needs) { test("Editing a post stages new content", async function (assert) { await visit("/t/internationalization-localization/280"); - await click(".topic-post:nth-of-type(1) button.show-more-actions"); - await click(".topic-post:nth-of-type(1) button.edit"); + await click(".topic-post button.show-more-actions"); + await click(".topic-post button.edit"); await fillIn(".d-editor-input", "will return empty json"); await fillIn("#reply-title", "This is the new text for the title"); - // when this promise resolves, the request had already started because - // this promise will be resolved by the pretender - const promise = new Promise((resolve) => { - window.resolveLastPromise = resolve; + pretender.put("/posts/:post_id", async () => { + // at this point, request is in flight, so post is staged + assert.strictEqual(count(".topic-post.staged"), 1); + assert.ok(query(".topic-post").classList.contains("staged")); + assert.strictEqual( + query(".topic-post.staged .cooked").innerText.trim(), + "will return empty json" + ); + + return response(200, {}); }); - // click to trigger the save, but wait until the request starts - click("#reply-control button.create"); - await promise; + await click("#reply-control button.create"); - // at this point, request is in flight, so post is staged - assert.strictEqual(count(".topic-post.staged"), 1); - assert.ok(query(".topic-post:nth-of-type(1)").className.includes("staged")); - assert.strictEqual( - query(".topic-post.staged .cooked").innerText.trim(), - "will return empty json" - ); - - // finally, finish request and wait for last render - window.resolveLastPromise(); await visit("/t/internationalization-localization/280"); - assert.strictEqual(count(".topic-post.staged"), 0); }); @@ -509,6 +574,12 @@ acceptance("Composer", function (needs) { "it expands composer to full screen" ); + assert.strictEqual( + count(".composer-fullscreen-prompt"), + 1, + "the exit fullscreen prompt is visible" + ); + await click(".toggle-fullscreen"); assert.strictEqual( @@ -535,6 +606,34 @@ acceptance("Composer", function (needs) { ); }); + test("Composer fullscreen submit button", async function (assert) { + await visit("/t/this-is-a-test-topic/9"); + await click(".topic-post:nth-of-type(1) button.reply"); + + assert.strictEqual( + count("#reply-control.open"), + 1, + "it starts in open state by default" + ); + + await click(".toggle-fullscreen"); + + assert.strictEqual( + count("#reply-control button.create"), + 1, + "it shows composer submit button in fullscreen" + ); + + await fillIn(".d-editor-input", "too short"); + await click("#reply-control button.create"); + + assert.strictEqual( + count("#reply-control.open"), + 1, + "it goes back to open state if there's errors" + ); + }); + test("Composer can toggle between reply and createTopic", async function (assert) { await visit("/t/this-is-a-test-topic/9"); await click(".topic-post:nth-of-type(1) button.reply"); @@ -687,109 +786,91 @@ acceptance("Composer", function (needs) { }); test("Checks for existing draft", async function (assert) { - try { - toggleCheckDraftPopup(true); + toggleCheckDraftPopup(true); - await visit("/t/internationalization-localization/280"); + await visit("/t/internationalization-localization/280"); - await click(".topic-post:nth-of-type(1) button.show-more-actions"); - await click(".topic-post:nth-of-type(1) button.edit"); + await click(".topic-post:nth-of-type(1) button.show-more-actions"); + await click(".topic-post:nth-of-type(1) button.edit"); - assert.strictEqual( - query(".modal-body").innerText, - I18n.t("drafts.abandon.confirm") - ); + assert.strictEqual( + query(".dialog-body").innerText, + I18n.t("drafts.abandon.confirm") + ); - await click(".modal-footer .btn.btn-default"); - } finally { - toggleCheckDraftPopup(false); - } + await click(".dialog-footer .btn-resume-editing"); }); test("Can switch states without abandon popup", async function (assert) { - try { - toggleCheckDraftPopup(true); + toggleCheckDraftPopup(true); - await visit("/t/internationalization-localization/280"); + await visit("/t/internationalization-localization/280"); - const longText = "a".repeat(256); + const longText = "a".repeat(256); - sinon.stub(Draft, "get").returns( - Promise.resolve({ - draft: null, - draft_sequence: 0, - }) - ); + sinon.stub(Draft, "get").resolves({ + draft: null, + draft_sequence: 0, + }); - await click(".btn-primary.create.btn"); + await click(".btn-primary.create.btn"); - await fillIn(".d-editor-input", longText); + await fillIn(".d-editor-input", longText); - assert.ok( - exists( - '.action-title a[href="/t/internationalization-localization/280"]' - ), - "the mode should be: reply to post" - ); + assert.ok( + exists( + '.action-title a[href="/t/internationalization-localization/280"]' + ), + "the mode should be: reply to post" + ); - await click("article#post_3 button.reply"); + await click("article#post_3 button.reply"); - const composerActions = selectKit(".composer-actions"); - await composerActions.expand(); - await composerActions.selectRowByValue("reply_as_new_topic"); + const composerActions = selectKit(".composer-actions"); + await composerActions.expand(); + await composerActions.selectRowByValue("reply_as_new_topic"); - assert.ok(!exists(".modal-body"), "abandon popup shouldn't come"); + assert.ok(!exists(".modal-body"), "abandon popup shouldn't come"); - assert.ok( - query(".d-editor-input").value.includes(longText), - "entered text should still be there" - ); + assert.ok( + query(".d-editor-input").value.includes(longText), + "entered text should still be there" + ); - assert.ok( - !exists( - '.action-title a[href="/t/internationalization-localization/280"]' - ), - "mode should have changed" - ); - } finally { - toggleCheckDraftPopup(false); - } + assert.ok( + !exists( + '.action-title a[href="/t/internationalization-localization/280"]' + ), + "mode should have changed" + ); }); test("Loading draft also replaces the recipients", async function (assert) { - try { - toggleCheckDraftPopup(true); + toggleCheckDraftPopup(true); - sinon.stub(Draft, "get").returns( - Promise.resolve({ - draft: - '{"reply":"hello","action":"privateMessage","title":"hello","categoryId":null,"archetypeId":"private_message","metaData":null,"recipients":"codinghorror","composerTime":9159,"typingTime":2500}', - draft_sequence: 0, - }) - ); + sinon.stub(Draft, "get").resolves({ + draft: + '{"reply":"hello","action":"privateMessage","title":"hello","categoryId":null,"archetypeId":"private_message","metaData":null,"recipients":"codinghorror","composerTime":9159,"typingTime":2500}', + draft_sequence: 0, + }); - await visit("/u/charlie"); - await click("button.compose-pm"); - await click(".modal .btn-default"); + await visit("/u/charlie"); + await click("button.compose-pm"); + await click(".dialog-footer .btn-resume-editing"); - const privateMessageUsers = selectKit("#private-message-users"); - assert.strictEqual(privateMessageUsers.header().value(), "codinghorror"); - } finally { - toggleCheckDraftPopup(false); - } + const privateMessageUsers = selectKit("#private-message-users"); + assert.strictEqual(privateMessageUsers.header().value(), "codinghorror"); }); test("Loads tags and category from draft payload", async function (assert) { updateCurrentUser({ has_topic_draft: true }); - sinon.stub(Draft, "get").returns( - Promise.resolve({ - draft: - '{"reply":"Hey there","action":"createTopic","title":"Draft topic","categoryId":2,"tags":["fun", "times"],"archetypeId":"regular","metaData":null,"composerTime":25269,"typingTime":8100}', - draft_sequence: 0, - draft_key: NEW_TOPIC_KEY, - }) - ); + sinon.stub(Draft, "get").resolves({ + draft: + '{"reply":"Hey there","action":"createTopic","title":"Draft topic","categoryId":2,"tags":["fun", "times"],"archetypeId":"regular","metaData":null,"composerTime":25269,"typingTime":8100}', + draft_sequence: 0, + draft_key: NEW_TOPIC_KEY, + }); await visit("/latest"); assert.strictEqual( diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-uploads-uppy-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-uploads-uppy-test.js index c966f796d4..0ff8883870 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-uploads-uppy-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-uploads-uppy-test.js @@ -6,8 +6,7 @@ import { query, } from "discourse/tests/helpers/qunit-helpers"; import { withPluginApi } from "discourse/lib/plugin-api"; -import bootbox from "bootbox"; -import { authorizedExtensions } from "discourse/lib/uploads"; +import { authorizedExtensions, dialog } from "discourse/lib/uploads"; import { click, fillIn, settled, visit } from "@ember/test-helpers"; import I18n from "I18n"; import { skip, test } from "qunit"; @@ -125,15 +124,16 @@ acceptance("Uppy Composer Attachment - Upload Placeholder", function (needs) { const image2 = createFile("avatar2.png"); const done = assert.async(); appEvents.on("composer:uploads-aborted", async () => { + await settled(); assert.strictEqual( - query(".bootbox .modal-body").innerHTML, + query(".dialog-body").textContent.trim(), I18n.t("post.errors.too_many_dragged_and_dropped_files", { count: 2, }), "it should warn about too many files added" ); - await click(".modal-footer .btn-primary"); + await click(".dialog-footer .btn-primary"); done(); }); @@ -149,8 +149,9 @@ acceptance("Uppy Composer Attachment - Upload Placeholder", function (needs) { const done = assert.async(); appEvents.on("composer:uploads-aborted", async () => { + await settled(); assert.strictEqual( - query(".bootbox .modal-body").innerHTML, + query(".dialog-body").textContent.trim(), I18n.t("post.errors.upload_not_authorized", { authorized_extensions: authorizedExtensions( false, @@ -160,7 +161,7 @@ acceptance("Uppy Composer Attachment - Upload Placeholder", function (needs) { "it should warn about unauthorized extensions" ); - await click(".modal-footer .btn-primary"); + await click(".dialog-footer .btn-primary"); done(); }); @@ -438,14 +439,14 @@ acceptance("Uppy Composer Attachment - Upload Error", function (needs) { appEvents.on("composer:upload-error", async () => { sinon.assert.calledOnce(stub); + await settled(); assert.strictEqual( - query(".bootbox .modal-body").innerHTML, + query(".dialog-body").textContent.trim(), "There was an error uploading the file, the gif was way too cool.", "it should show the error message from the server" ); - await click(".modal-footer .btn-primary"); - + await click(".dialog-footer .btn-primary"); done(); }); @@ -465,7 +466,7 @@ acceptance("Uppy Composer Attachment - Upload Handler", function (needs) { api.addComposerUploadHandler(["png"], (files) => { const file = files[0]; const isNativeFile = file instanceof File ? "WAS" : "WAS NOT"; - bootbox.alert( + dialog.alert( `This is an upload handler test for ${file.name}. The file ${isNativeFile} a native file object.` ); }); @@ -480,12 +481,13 @@ acceptance("Uppy Composer Attachment - Upload Handler", function (needs) { const done = assert.async(); appEvents.on("composer:uploads-aborted", async () => { + await settled(); assert.strictEqual( - query(".bootbox .modal-body").innerHTML, + query(".dialog-body").textContent.trim(), "This is an upload handler test for handler-test.png. The file WAS a native file object.", - "it should show the bootbox triggered by the upload handler" + "it should show the dialog triggered by the upload handler" ); - await click(".modal-footer .btn"); + await click(".dialog-footer .btn-primary"); done(); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/do-not-disturb-test.js b/app/assets/javascripts/discourse/tests/acceptance/do-not-disturb-test.js index eb1f7e3bfb..e96f21f77d 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/do-not-disturb-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/do-not-disturb-test.js @@ -100,3 +100,124 @@ acceptance("Do not disturb", function (needs) { ); }); }); + +acceptance("Do not disturb - new user menu", function (needs) { + needs.user({ redesigned_user_menu_enabled: true }); + needs.pretender((server, helper) => { + server.post("/do-not-disturb.json", () => { + const now = new Date(); + now.setHours(now.getHours() + 1); + return helper.response({ ends_at: now }); + }); + server.delete("/do-not-disturb.json", () => + helper.response({ success: true }) + ); + }); + + test("when turned off, it is turned on from modal", async function (assert) { + updateCurrentUser({ do_not_disturb_until: null }); + + await visit("/"); + await click(".header-dropdown-toggle.current-user"); + await click("#user-menu-button-profile"); + await click("#quick-access-profile .do-not-disturb .btn"); + + assert.ok(exists(".do-not-disturb-modal"), "modal to choose time appears"); + + let tiles = queryAll(".do-not-disturb-tile"); + assert.ok(tiles.length === 4, "There are 4 duration choices"); + + await click(tiles[0]); + + assert.ok(query(".do-not-disturb-modal.hidden"), "modal is hidden"); + + assert.ok( + exists(".header-dropdown-toggle .do-not-disturb-background .d-icon-moon"), + "moon icon is present in header" + ); + }); + + test("Can be invoked via keyboard", async function (assert) { + updateCurrentUser({ do_not_disturb_until: null }); + + await visit("/"); + await click(".header-dropdown-toggle.current-user"); + await click("#user-menu-button-profile"); + await click("#quick-access-profile .do-not-disturb .btn"); + + assert.ok(exists(".do-not-disturb-modal"), "DND modal is displayed"); + + assert.strictEqual( + count(".do-not-disturb-tile"), + 4, + "There are 4 duration choices" + ); + + await triggerKeyEvent( + ".do-not-disturb-tile:nth-child(1)", + "keydown", + "Enter" + ); + + assert.ok( + query(".do-not-disturb-modal.hidden"), + "DND modal is hidden after making a choice" + ); + + assert.ok( + exists(".header-dropdown-toggle .do-not-disturb-background .d-icon-moon"), + "moon icon is shown in header avatar" + ); + }); + + test("when turned on, it can be turned off", async function (assert) { + const now = new Date(); + now.setHours(now.getHours() + 1); + updateCurrentUser({ do_not_disturb_until: now }); + + await visit("/"); + + assert.ok( + exists(".do-not-disturb-background"), + "The active moon icon is shown" + ); + + await click(".header-dropdown-toggle.current-user"); + await click("#user-menu-button-profile"); + assert.strictEqual( + query(".do-not-disturb .relative-date").textContent.trim(), + "1h", + "the Do Not Disturb button shows how much time is left for DND mode" + ); + assert.ok( + exists(".do-not-disturb .d-icon-toggle-on"), + "the Do Not Disturb button has the toggle-on icon" + ); + + await click("#quick-access-profile .do-not-disturb .btn"); + + assert.notOk( + exists(".do-not-disturb-background"), + "The active moon icons are removed" + ); + assert.notOk( + exists(".do-not-disturb .relative-date"), + "the text showing how much time is left for DND mode is gone" + ); + assert.ok( + exists(".do-not-disturb .d-icon-toggle-off"), + "the Do Not Disturb button has the toggle-off icon" + ); + }); + + test("user menu gets closed when the DnD modal is opened", async function (assert) { + this.siteSettings.enable_user_status = true; + + await visit("/"); + await click(".header-dropdown-toggle.current-user"); + await click("#user-menu-button-profile"); + await click("#quick-access-profile .do-not-disturb .btn"); + + assert.notOk(exists(".user-menu")); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/emoji-picker-test.js b/app/assets/javascripts/discourse/tests/acceptance/emoji-picker-test.js index 5faac2f7dc..6245f6cfa8 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/emoji-picker-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/emoji-picker-test.js @@ -5,7 +5,7 @@ import { query, queryAll, } from "discourse/tests/helpers/qunit-helpers"; -import { click, fillIn, visit } from "@ember/test-helpers"; +import { click, fillIn, triggerKeyEvent, visit } from "@ember/test-helpers"; import { test } from "qunit"; acceptance("EmojiPicker", function (needs) { @@ -179,4 +179,99 @@ acceptance("EmojiPicker", function (needs) { "it stores diversity scale" ); }); + + test("emoji can be selected with keyboard", async function (assert) { + const searchInput = ".emoji-picker-search-container input"; + await visit("/t/internationalization-localization/280"); + await click("#topic-footer-buttons .btn.create"); + await click(".emoji.btn"); + + let emojis = document.querySelectorAll( + ".emoji-picker-emoji-area img.emoji" + ); + + assert.strictEqual( + document.activeElement, + document.querySelector(searchInput), + "search input is focused by default" + ); + + await triggerKeyEvent(searchInput, "keydown", "ArrowDown"); + assert.strictEqual( + document.activeElement, + emojis[0], + "ArrowDown from search focuses on the first emoji result" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowRight"); + assert.strictEqual( + document.activeElement, + emojis[1], + "ArrowRight from first emoji focuses on the second emoji" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowLeft"); + assert.strictEqual( + document.activeElement, + emojis[0], + "ArrowLeft from second emoji focuses on the first emoji" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowRight"); + await triggerKeyEvent(document.activeElement, "keydown", "Enter"); + assert.strictEqual( + document.querySelector(".d-editor-input").value, + ":smiley:", + "Pressing enter inserts the emoji markup in the composer" + ); + + await click("#topic-footer-buttons .btn.create"); + await click(".emoji.btn"); + await triggerKeyEvent(searchInput, "keydown", "ArrowDown"); + emojis = document.querySelectorAll(".emoji-picker-emoji-area img.emoji"); + + assert.strictEqual( + document.activeElement, + document.querySelector(".emoji-picker-emoji-area .emoji.recent-emoji"), + "ArrowDown focuses on the first emoji result (recent emoji)" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowDown"); + assert.strictEqual( + document.activeElement, + document.querySelector(".emojis-container .emoji[title='grinning']"), + "ArrowDown again focuses on the first emoji result in a section" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowRight"); + await triggerKeyEvent(document.activeElement, "keydown", "ArrowRight"); + await triggerKeyEvent(document.activeElement, "keydown", "ArrowRight"); + + assert.strictEqual( + document.activeElement, + emojis[4], + "ArrowRight moves focus to next right element" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowUp"); + + assert.strictEqual( + document.activeElement, + document.querySelector(searchInput), + "ArrowUp from first row items moves focus to input" + ); + }); + + test("emoji picker can be dismissed with escape key", async function (assert) { + await visit("/t/internationalization-localization/280"); + await click("#topic-footer-buttons .btn.create"); + await click("button.emoji.btn"); + await triggerKeyEvent(document.activeElement, "keydown", "Escape"); + assert.notOk(exists(".emoji-picker")); + assert.strictEqual( + document.activeElement, + document.querySelector("textarea"), + "escaping from emoji picker focuses back on input" + ); + }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/group-manage-email-settings-test.js b/app/assets/javascripts/discourse/tests/acceptance/group-manage-email-settings-test.js index cff0acf17b..9fb6577981 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/group-manage-email-settings-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/group-manage-email-settings-test.js @@ -126,12 +126,12 @@ acceptance( await click("#enable_smtp"); assert.strictEqual( - query(".modal-body").innerText, + query(".dialog-body").innerText.trim(), I18n.t("groups.manage.email.smtp_disable_confirm"), "shows a confirm dialogue warning SMTP settings will be wiped" ); - await click(".modal-footer .btn.btn-primary"); + await click(".dialog-footer .btn-primary"); }); test("enabling IMAP, testing, and saving", async function (assert) { @@ -202,11 +202,11 @@ acceptance( await click("#enable_imap"); assert.strictEqual( - query(".modal-body").innerText, + query(".dialog-body").innerText.trim(), I18n.t("groups.manage.email.imap_disable_confirm"), "shows a confirm dialogue warning IMAP settings will be wiped" ); - await click(".modal-footer .btn.btn-primary"); + await click(".dialog-footer .btn-primary"); }); } ); @@ -362,11 +362,11 @@ acceptance( await click(".test-smtp-settings"); assert.strictEqual( - query(".modal-body").innerText, + query(".dialog-body").innerText.trim(), "There was an issue with the SMTP credentials provided, check the username and password and try again.", "shows a dialogue with the error message from the server" ); - await click(".modal-footer .btn.btn-primary"); + await click(".dialog-footer .btn-primary"); }); } ); diff --git a/app/assets/javascripts/discourse/tests/acceptance/group-test.js b/app/assets/javascripts/discourse/tests/acceptance/group-test.js index 194fdab4b2..445e403350 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/group-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/group-test.js @@ -275,14 +275,21 @@ acceptance("Group - Authenticated", function (needs) { await click(".group-details-button button.btn-danger"); assert.strictEqual( - query(".bootbox .modal-body").innerHTML, + query(".dialog-body").textContent.trim(), I18n.t("admin.groups.delete_with_messages_confirm", { count: 2, }), "it should warn about orphan messages" ); - await click(".modal-footer .btn-default"); + await click(".dialog-footer .btn-default"); + + await visit("/g/discourse/activity/posts"); + + assert.ok( + ".user-stream-item a.avatar-link[href='/u/awesomerobot']", + "avatar link contains href (is tabbable)" + ); }); test("Moderator Viewing Group", async function (assert) { diff --git a/app/assets/javascripts/discourse/tests/acceptance/login-with-email-test.js b/app/assets/javascripts/discourse/tests/acceptance/login-with-email-test.js index ee9718f0fa..15f83901d2 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/login-with-email-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/login-with-email-test.js @@ -6,6 +6,10 @@ import { import { click, fillIn, visit } from "@ember/test-helpers"; import I18n from "I18n"; import { test } from "qunit"; +import DiscourseURL from "discourse/lib/url"; +import sinon from "sinon"; + +const TOKEN = "sometoken"; acceptance("Login with email", function (needs) { needs.settings({ @@ -18,6 +22,20 @@ acceptance("Login with email", function (needs) { server.post("/u/email-login", () => helper.response({ success: "OK", user_found: userFound }) ); + + server.get(`/session/email-login/${TOKEN}.json`, () => + helper.response({ + token: TOKEN, + can_login: true, + token_email: "blah@example.com", + }) + ); + + server.post(`/session/email-login/${TOKEN}`, () => + helper.response({ + success: true, + }) + ); }); test("with email button", async function (assert) { @@ -83,4 +101,21 @@ acceptance("Login with email", function (needs) { userFound = false; }); + + test("finish login UI", async function (assert) { + await visit(`/session/email-login/${TOKEN}`); + sinon.stub(DiscourseURL, "redirectTo"); + await click(".email-login .btn-primary"); + assert.true(DiscourseURL.redirectTo.calledWith("/"), "redirects to home"); + }); + + test("finish login UI - safe mode", async function (assert) { + await visit(`/session/email-login/${TOKEN}?safe_mode=no_themes,no_plugins`); + sinon.stub(DiscourseURL, "redirectTo"); + await click(".email-login .btn-primary"); + assert.true( + DiscourseURL.redirectTo.calledWith("/?safe_mode=no_themes%2Cno_plugins"), + "redirects to home with safe mode" + ); + }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/mobile-pan-test.js b/app/assets/javascripts/discourse/tests/acceptance/mobile-pan-test.js index 8ef7a1b70d..6fc8ea63c2 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/mobile-pan-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/mobile-pan-test.js @@ -7,15 +7,6 @@ import { import { click, triggerEvent, visit } from "@ember/test-helpers"; async function triggerSwipeStart(touchTarget) { - // some tests are shown in a zoom viewport. - // boundingClientRect is affected by the zoom and need to be multiplied by the zoom effect. - // EG: if the element has a zoom of 50%, this DOUBLES the x and y positions and offsets. - // The numbers you get from getBoundingClientRect are seen as twice as large... however, the - // touch input still deals with the base inputs, not doubled. This allows us to convert for those environments. - let zoom = parseFloat( - window.getComputedStyle(document.querySelector("#ember-testing")).zoom || 1 - ); - // Other tests are shown in a transformed viewport, and this is a multiple for the offsets let scale = parseFloat( window @@ -26,13 +17,11 @@ async function triggerSwipeStart(touchTarget) { const touchStart = { touchTarget, x: - zoom * - (touchTarget.getBoundingClientRect().x + - (scale * touchTarget.offsetWidth) / 2), + touchTarget.getBoundingClientRect().x + + (scale * touchTarget.offsetWidth) / 2, y: - zoom * - (touchTarget.getBoundingClientRect().y + - (scale * touchTarget.offsetHeight) / 2), + touchTarget.getBoundingClientRect().y + + (scale * touchTarget.offsetHeight) / 2, }; const touch = new Touch({ identifier: "test", diff --git a/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-multi-template-test.js b/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-multi-template-test.js index 8caa688682..2c1ced058a 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-multi-template-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-multi-template-test.js @@ -3,7 +3,6 @@ import { count, query, } from "discourse/tests/helpers/qunit-helpers"; -import { clearCache } from "discourse/lib/plugin-connectors"; import { hbs } from "ember-cli-htmlbars"; import { test } from "qunit"; import { visit } from "@ember/test-helpers"; @@ -14,7 +13,6 @@ const GOODBYE = acceptance("Plugin Outlet - Multi Template", function (needs) { needs.hooks.beforeEach(() => { - clearCache(); // eslint-disable-next-line no-undef Ember.TEMPLATES[HELLO] = hbs`Hello`; // eslint-disable-next-line no-undef @@ -26,7 +24,6 @@ acceptance("Plugin Outlet - Multi Template", function (needs) { delete Ember.TEMPLATES[HELLO]; // eslint-disable-next-line no-undef delete Ember.TEMPLATES[GOODBYE]; - clearCache(); }); test("Renders a template into the outlet", async function (assert) { diff --git a/app/assets/javascripts/discourse/tests/acceptance/preferences-test.js b/app/assets/javascripts/discourse/tests/acceptance/preferences-test.js index e8bc847fec..27f91bf1e3 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/preferences-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/preferences-test.js @@ -233,7 +233,7 @@ acceptance("User Preferences", function (needs) { await click(".new-security-key"); assert.ok(exists("#security-key-name"), "shows security key name input"); - fillIn("#security-key-name", ""); + await fillIn("#security-key-name", ""); // The following tests can only run when Webauthn is enabled. This is not // always the case, for example on a browser running on a non-standard port @@ -474,63 +474,6 @@ acceptance("User Preferences when badges are disabled", function (needs) { }); }); -acceptance( - "User can select a topic to feature on profile if site setting in enabled", - function (needs) { - needs.user(); - needs.settings({ allow_featured_topic_on_user_profiles: true }); - needs.pretender((server, helper) => { - server.put("/u/eviltrout/feature-topic", () => { - return helper.response({ - success: true, - }); - }); - }); - - test("setting featured topic on profile", async function (assert) { - await visit("/u/eviltrout/preferences/profile"); - - assert.ok( - !exists(".featured-topic-link"), - "no featured topic link to present" - ); - assert.ok( - !exists(".clear-feature-topic-on-profile-btn"), - "clear button not present" - ); - - const selectTopicBtn = query( - ".feature-topic-on-profile-btn:nth-of-type(1)" - ); - assert.ok(exists(selectTopicBtn), "feature topic button is present"); - - await click(selectTopicBtn); - - assert.ok( - exists(".feature-topic-on-profile"), - "topic picker modal is open" - ); - - const topicRadioBtn = query( - 'input[name="choose_topic_id"]:nth-of-type(1)' - ); - assert.ok(exists(topicRadioBtn), "Topic options are prefilled"); - await click(topicRadioBtn); - - await click(".save-featured-topic-on-profile"); - - assert.ok( - exists(".featured-topic-link"), - "link to featured topic is present" - ); - assert.ok( - exists(".clear-feature-topic-on-profile-btn"), - "clear button is present" - ); - }); - } -); - acceptance("Custom User Fields", function (needs) { needs.user(); needs.site({ diff --git a/app/assets/javascripts/discourse/tests/acceptance/redirect-to-top-test.js b/app/assets/javascripts/discourse/tests/acceptance/redirect-to-top-test.js index 8774ebf8e4..ac40d43db0 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/redirect-to-top-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/redirect-to-top-test.js @@ -8,9 +8,6 @@ import { test } from "qunit"; acceptance("Redirect to Top", function (needs) { needs.pretender((server, helper) => { - server.get("/top.json?period=weekly", () => { - return helper.response(DiscoveryFixtures["/latest.json"]); - }); server.get("/top/monthly.json", () => { return helper.response(DiscoveryFixtures["/latest.json"]); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/review-test.js b/app/assets/javascripts/discourse/tests/acceptance/review-test.js index d6659ffa3c..3272b8bd15 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/review-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/review-test.js @@ -2,8 +2,10 @@ import { acceptance, count, exists, + loggedInUser, publishToMessageBus, query, + updateCurrentUser, visible, } from "discourse/tests/helpers/qunit-helpers"; import { click, fillIn, visit } from "@ember/test-helpers"; @@ -210,7 +212,8 @@ acceptance("Review", function (needs) { ); }); - test("Reviewables can become stale", async function (assert) { + test("Reviewables can become stale when redesigned_user_menu_enabled is false", async function (assert) { + updateCurrentUser({ redesigned_user_menu_enabled: false }); await visit("/review"); const reviewable = query(`[data-reviewable-id="1234"]`); @@ -238,4 +241,34 @@ acceptance("Review", function (needs) { assert.strictEqual(count(".stale-help"), 0); }); + + test("Reviewables can become stale when redesigned_user_menu_enabled is true", async function (assert) { + updateCurrentUser({ redesigned_user_menu_enabled: true }); + await visit("/review"); + + const reviewable = query(`[data-reviewable-id="1234"]`); + assert.notOk(reviewable.className.includes("reviewable-stale")); + assert.strictEqual( + count(`[data-reviewable-id="1234"] .status .pending`), + 1 + ); + assert.ok(!exists(".stale-help")); + + await publishToMessageBus(`/reviewable_counts/${loggedInUser().id}`, { + review_count: 1, + updates: { + 1234: { last_performing_username: "foo", status: 1 }, + }, + }); + + assert.ok(reviewable.className.includes("reviewable-stale")); + assert.strictEqual(count("[data-reviewable-id=1234] .status .approved"), 1); + assert.strictEqual(count(".stale-help"), 1); + assert.ok(query(".stale-help").innerText.includes("foo")); + + await visit("/"); + await visit("/review"); // reload review + + assert.strictEqual(count(".stale-help"), 0); + }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/share-topic-test.js b/app/assets/javascripts/discourse/tests/acceptance/share-topic-test.js index be66565f7a..47847c6c67 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/share-topic-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/share-topic-test.js @@ -139,3 +139,24 @@ acceptance("Share url with badges disabled - desktop", function (needs) { ); }); }); + +acceptance("With username in share links disabled - desktop", function (needs) { + needs.user(); + needs.settings({ allow_username_in_share_links: false }); + + needs.pretender((server, helper) => { + server.get("/c/feature/find_by_slug.json", () => + helper.response(200, CategoryFixtures["/c/1/show.json"]) + ); + }); + + test("topic footer button - username in share links disabled - desktop", async function (assert) { + await visit("/t/internationalization-localization/280"); + await click("#topic-footer-button-share-and-invite"); + + assert.notOk( + query("input.invite-link").value.includes("?u=eviltrout"), + "it doesn't add the username param when username in share links are disabled" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-categories-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-categories-section-test.js new file mode 100644 index 0000000000..ef1a442676 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-categories-section-test.js @@ -0,0 +1,74 @@ +import { test } from "qunit"; +import { visit } from "@ember/test-helpers"; +import { + acceptance, + exists, + queryAll, +} from "discourse/tests/helpers/qunit-helpers"; +import Site from "discourse/models/site"; + +acceptance("Sidebar - Anonymous Categories Section", function (needs) { + needs.settings({ + enable_experimental_sidebar_hamburger: true, + enable_sidebar: true, + }); + + test("category section links", async function (assert) { + await visit("/"); + + const categories = queryAll( + ".sidebar-section-categories .sidebar-section-link-wrapper" + ); + assert.strictEqual(categories.length, 6); + assert.strictEqual(categories[0].textContent.trim(), "bug"); + assert.strictEqual(categories[1].textContent.trim(), "dev"); + assert.strictEqual(categories[2].textContent.trim(), "feature"); + assert.strictEqual(categories[3].textContent.trim(), "support"); + assert.strictEqual(categories[4].textContent.trim(), "ux"); + + assert.ok( + exists("a.sidebar-section-link-all-categories"), + "all categories link is visible" + ); + }); + + test("category section links in sidebar when default_sidebar_categories site setting has been configured", async function (assert) { + this.siteSettings.default_sidebar_categories = "3|13|1"; + await visit("/"); + + const categories = queryAll( + ".sidebar-section-categories .sidebar-section-link-wrapper" + ); + + assert.strictEqual(categories.length, 4); + assert.strictEqual(categories[0].textContent.trim(), "blog"); + assert.strictEqual(categories[1].textContent.trim(), "bug"); + assert.strictEqual(categories[2].textContent.trim(), "meta"); + + assert.ok( + exists("a.sidebar-section-link-all-categories"), + "all categories link is visible" + ); + }); + + test("default uncategorized category section links is not shown when allow_uncategorized_topics is disabled", async function (assert) { + this.siteSettings.allow_uncategorized_topics = false; + this.siteSettings.fixed_category_positions = true; + const site = Site.current(); + + const firstCategory = Site.current().categories.find((category) => { + return !category.parent_category_id; + }); + + site.set("uncategorized_category_id", firstCategory.id); + + await visit("/"); + + assert.notOk( + exists( + `.sidebar-section-categories .sidebar-section-link-${firstCategory.slug}` + ), + "category section link is not shown in sidebar after being marked as uncategorized" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-community-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-community-section-test.js new file mode 100644 index 0000000000..c01d2357d9 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-community-section-test.js @@ -0,0 +1,110 @@ +import I18n from "I18n"; + +import { test } from "qunit"; + +import { + acceptance, + exists, + query, + queryAll, +} from "discourse/tests/helpers/qunit-helpers"; +import { click, visit } from "@ember/test-helpers"; + +acceptance("Sidebar - Anonymous user - Community Section", function (needs) { + needs.settings({ + enable_experimental_sidebar_hamburger: true, + enable_sidebar: true, + }); + + test("display short site description site setting when it is set", async function (assert) { + this.siteSettings.short_site_description = + "This is a short description about the site"; + + await visit("/"); + + assert.strictEqual( + query( + ".sidebar-section-community .sidebar-section-message" + ).textContent.trim(), + this.siteSettings.short_site_description, + "displays the short site description under the community section" + ); + + const sectionLinks = queryAll( + ".sidebar-section-community .sidebar-section-link" + ); + + assert.strictEqual( + sectionLinks[0].textContent.trim(), + I18n.t("sidebar.sections.community.links.about.content"), + "displays the about section link first" + ); + }); + + test("everything, users, about and FAQ section links are shown by default ", async function (assert) { + await visit("/"); + + const sectionLinks = queryAll( + ".sidebar-section-community .sidebar-section-link" + ); + + assert.strictEqual( + sectionLinks[0].textContent.trim(), + I18n.t("sidebar.sections.community.links.everything.content"), + "displays the everything section link first" + ); + + assert.strictEqual( + sectionLinks[1].textContent.trim(), + I18n.t("sidebar.sections.community.links.users.content"), + "displays the users section link second" + ); + + assert.strictEqual( + sectionLinks[2].textContent.trim(), + I18n.t("sidebar.sections.community.links.about.content"), + "displays the about section link third" + ); + + assert.strictEqual( + sectionLinks[3].textContent.trim(), + I18n.t("sidebar.sections.community.links.faq.content"), + "displays the FAQ section link last" + ); + }); + + test("users section link is not shown when hide_user_profiles_from_public site setting is enabled", async function (assert) { + this.siteSettings.hide_user_profiles_from_public = true; + + await visit("/"); + + assert.notOk( + exists(".sidebar-section-community .sidebar-section-link-users"), + "users section link is not shown in sidebar" + ); + }); + + test("groups and badges section links are shown in more...", async function (assert) { + await visit("/"); + + await click( + ".sidebar-section-community .sidebar-more-section-links-details-summary" + ); + + const sectionLinks = queryAll( + ".sidebar-more-section-links-details-content-main .sidebar-section-link" + ); + + assert.strictEqual( + sectionLinks[0].textContent.trim(), + I18n.t("sidebar.sections.community.links.groups.content"), + "displays the groups section link first" + ); + + assert.strictEqual( + sectionLinks[1].textContent.trim(), + I18n.t("sidebar.sections.community.links.badges.content"), + "displays the badges section link second" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-tags-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-tags-section-test.js new file mode 100644 index 0000000000..dc2ba51e56 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-tags-section-test.js @@ -0,0 +1,89 @@ +import { test } from "qunit"; +import { visit } from "@ember/test-helpers"; +import { + acceptance, + exists, + queryAll, +} from "discourse/tests/helpers/qunit-helpers"; + +acceptance("Sidebar - Anonymous Tags Section", function (needs) { + needs.settings({ + enable_experimental_sidebar_hamburger: true, + enable_sidebar: true, + suppress_uncategorized_badge: false, + tagging_enabled: true, + }); + + needs.site({ + top_tags: ["design", "development", "fun"], + }); + + test("tag section links", async function (assert) { + await visit("/"); + + const categories = queryAll( + ".sidebar-section-tags .sidebar-section-link-wrapper" + ); + assert.strictEqual(categories.length, 4); + assert.strictEqual(categories[0].textContent.trim(), "design"); + assert.strictEqual(categories[1].textContent.trim(), "development"); + assert.strictEqual(categories[2].textContent.trim(), "fun"); + + assert.ok( + exists("a.sidebar-section-link-all-tags"), + "all tags link is visible" + ); + }); +}); + +acceptance("Sidebar - Anonymous Tags Section - default tags", function (needs) { + needs.settings({ + enable_experimental_sidebar_hamburger: true, + enable_sidebar: true, + suppress_uncategorized_badge: false, + tagging_enabled: true, + }); + + needs.site({ + top_tags: ["design", "development", "fun"], + anonymous_default_sidebar_tags: ["random", "meta"], + }); + + test("tag section links", async function (assert) { + await visit("/"); + + const categories = queryAll( + ".sidebar-section-tags .sidebar-section-link-wrapper" + ); + assert.strictEqual(categories.length, 3); + assert.strictEqual(categories[0].textContent.trim(), "random"); + assert.strictEqual(categories[1].textContent.trim(), "meta"); + + assert.ok( + exists("a.sidebar-section-link-all-tags"), + "all tags link is visible" + ); + }); +}); + +acceptance( + "Sidebar - Anonymous Tags Section - Tagging disabled", + function (needs) { + needs.settings({ + enable_experimental_sidebar_hamburger: true, + enable_sidebar: true, + suppress_uncategorized_badge: false, + tagging_enabled: false, + }); + + needs.site({ + top_tags: ["design", "development", "fun"], + }); + + test("tag section links", async function (assert) { + await visit("/"); + + assert.ok(!exists(".sidebar-section-tags"), "section is not visible"); + }); + } +); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-user-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-user-test.js new file mode 100644 index 0000000000..d350dd1aaa --- /dev/null +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-anonymous-user-test.js @@ -0,0 +1,65 @@ +import { test } from "qunit"; + +import { click, visit } from "@ember/test-helpers"; + +import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers"; + +acceptance("Sidebar - Anonymous User", function (needs) { + needs.settings({ + enable_experimental_sidebar_hamburger: true, + enable_sidebar: true, + }); + + test("sidebar is displayed", async function (assert) { + await visit("/"); + + assert.ok( + document.body.classList.contains("has-sidebar-page"), + "adds sidebar utility class to body" + ); + + assert.ok( + exists(".sidebar-container"), + "sidebar exists for anonymous user" + ); + + assert.ok( + exists(".header-sidebar-toggle"), + "toggle button for anonymous user" + ); + }); + + test("sidebar hamburger panel dropdown when sidebar has been disabled", async function (assert) { + this.siteSettings.enable_sidebar = false; + + await visit("/"); + await click(".hamburger-dropdown"); + + assert.ok( + exists(".sidebar-hamburger-dropdown .sidebar-sections-anonymous"), + "sidebar hamburger panel dropdown renders anonymous sidebar sections" + ); + }); +}); + +acceptance("Sidebar - Anonymous User - Login Required", function (needs) { + needs.settings({ + enable_experimental_sidebar_hamburger: true, + enable_sidebar: true, + login_required: true, + }); + + test("sidebar and toggle button is hidden", async function (assert) { + await visit("/"); + + assert.ok( + !exists(".sidebar-container"), + "sidebar is hidden for anonymous user" + ); + + assert.ok( + !exists(".header-sidebar-toggle"), + "toggle button is hidden for anonymous user" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-mobile-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-mobile-test.js index 74970e2510..64bfe6c65e 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-mobile-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-mobile-test.js @@ -18,7 +18,10 @@ acceptance("Sidebar - Mobile - User with sidebar enabled", function (needs) { test("hidden by default", async function (assert) { await visit("/"); - assert.ok(!exists(".sidebar-container"), "sidebar is not displayed"); + assert.ok( + !exists(".sidebar-hamburger-dropdown"), + "sidebar is not displayed" + ); }); test("clicking outside sidebar collapses it", async function (assert) { @@ -26,50 +29,33 @@ acceptance("Sidebar - Mobile - User with sidebar enabled", function (needs) { await click(".hamburger-dropdown"); - assert.ok(exists(".sidebar-container"), "sidebar is displayed"); + assert.ok(exists(".sidebar-hamburger-dropdown"), "sidebar is displayed"); await click("#main-outlet"); - assert.ok(!exists(".sidebar-container"), "sidebar is collapsed"); + assert.ok(!exists(".sidebar-hamburger-dropdown"), "sidebar is collapsed"); }); test("clicking on a link or button in sidebar collapses it", async function (assert) { await visit("/"); await click(".hamburger-dropdown"); - await click(".sidebar-section-link-tracked"); + await click(".sidebar-section-community .sidebar-section-header-button"); assert.ok( - !exists(".sidebar-container"), + !exists(".sidebar-hamburger-dropdown"), "sidebar is collapsed when a button in sidebar is clicked" ); await click(".hamburger-dropdown"); - await click(".sidebar-section-header-link"); + await click(".sidebar-section-community .sidebar-section-link-everything"); assert.ok( - !exists(".sidebar-container"), + !exists(".sidebar-hamburger-dropdown"), "sidebar is collapsed when a link in sidebar is clicked" ); }); - test("collapsing sidebar sections does not collapse sidebar", async function (assert) { - await visit("/"); - - await click(".hamburger-dropdown"); - await click(".sidebar-section-header-caret"); - - assert.ok( - !exists(".sidebar-section-community .sidebar-section-content"), - "topics section is collapsed" - ); - - assert.ok( - exists(".sidebar-container"), - "sidebar is not collapsed when clicking on caret to collapse a section in sidebar" - ); - }); - test("button to toggle between mobile and desktop view", async function (assert) { await visit("/"); await click(".hamburger-dropdown"); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js index 70c371c139..e83b1a05e4 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js @@ -1,6 +1,5 @@ import { test } from "qunit"; import I18n from "I18n"; - import { click, visit } from "@ember/test-helpers"; import { acceptance, @@ -9,7 +8,6 @@ import { queryAll, } from "discourse/tests/helpers/qunit-helpers"; import { withPluginApi } from "discourse/lib/plugin-api"; -import { resetSidebarSection } from "discourse/lib/sidebar/custom-sections"; import { bind } from "discourse-common/utils/decorators"; acceptance("Sidebar - Plugin API", function (needs) { @@ -21,7 +19,6 @@ acceptance("Sidebar - Plugin API", function (needs) { }); needs.hooks.afterEach(() => { - resetSidebarSection(); linkDestroy = undefined; sectionDestroy = undefined; }); @@ -37,14 +34,6 @@ acceptance("Sidebar - Plugin API", function (needs) { return "test-chat-channels"; } - get route() { - return "discovery.latest"; - } - - get title() { - return "chat channels title"; - } - get text() { return "chat channels text"; } @@ -208,16 +197,9 @@ acceptance("Sidebar - Plugin API", function (needs) { await visit("/"); - assert.strictEqual( - query(".sidebar-section-test-chat-channels .sidebar-section-header-link") - .title, - "chat channels title", - "displays header with correct title attribute" - ); - assert.strictEqual( query( - ".sidebar-section-test-chat-channels .sidebar-section-header-link" + ".sidebar-section-test-chat-channels .sidebar-section-header-text" ).textContent.trim(), "chat channels text", "displays header with correct text" @@ -273,31 +255,31 @@ acceptance("Sidebar - Plugin API", function (needs) { ); assert.strictEqual( - links[0].children.item(0).style.color, + links[0].children[0].style.color, "rgb(255, 0, 0)", "has correct prefix color" ); assert.strictEqual( - $(links[0].children.item(0).children.item(0)).hasClass("d-icon-hashtag"), + links[0].children[0].children[0].classList.contains("d-icon-hashtag"), true, "displays prefix icon" ); assert.strictEqual( - $(links[0].children.item(0).children.item(1)).hasClass("d-icon-lock"), + links[0].children[0].children[1].classList.contains("d-icon-lock"), true, "displays prefix icon badge" ); assert.strictEqual( - $(links[0].children.item(2).children.item(0)).hasClass("d-icon-circle"), + links[0].children[2].children[0].classList.contains("d-icon-circle"), true, "displays suffix icon" ); assert.strictEqual( - $(links[1].children[1])[0].textContent.trim(), + links[1].children[1].textContent.trim(), "dev channel text", "displays second link with correct text" ); @@ -309,19 +291,19 @@ acceptance("Sidebar - Plugin API", function (needs) { ); assert.strictEqual( - links[1].children.item(0).style.color, + links[1].children[0].style.color, "", "has no color style when value is invalid" ); assert.strictEqual( - $(links[1].children)[0].textContent.trim(), + links[1].children[0].textContent.trim(), "test text", "displays prefix text" ); assert.strictEqual( - $(links[2].children[1])[0].textContent.trim(), + links[2].children[1].textContent.trim(), "fun channel text", "displays third link with correct text" ); @@ -333,7 +315,7 @@ acceptance("Sidebar - Plugin API", function (needs) { ); assert.strictEqual( - $(links[2].children.item(0).children).attr("src"), + links[2].children[0].children[0].getAttribute("src"), "/test.png", "uses correct prefix image url" ); @@ -367,14 +349,6 @@ acceptance("Sidebar - Plugin API", function (needs) { return "test-chat-channels"; } - get route() { - return "discovery.latest"; - } - - get title() { - return "chat channels title"; - } - get text() { return "chat channels text"; } @@ -404,7 +378,7 @@ acceptance("Sidebar - Plugin API", function (needs) { assert.strictEqual( query( - ".sidebar-section-test-chat-channels .sidebar-section-header-link" + ".sidebar-section-test-chat-channels .sidebar-section-header-text" ).textContent.trim(), "chat channels text", "displays header with correct text" @@ -500,22 +474,22 @@ acceptance("Sidebar - Plugin API", function (needs) { await visit("/"); - const customlatestSectionLink = query( + const customLatestSectionLink = query( ".sidebar-section-community .sidebar-section-link-latest" ); assert.ok( - customlatestSectionLink, + customLatestSectionLink, "adds custom latest section link to community section" ); assert.ok( - customlatestSectionLink.href.endsWith("/latest"), + customLatestSectionLink.href.endsWith("/latest"), "sets the right href attribute for the custom latest section link" ); assert.strictEqual( - customlatestSectionLink.textContent.trim(), + customLatestSectionLink.textContent.trim(), I18n.t("filters.latest.title"), "displays the right text for custom latest section link" ); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-categories-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js similarity index 79% rename from app/assets/javascripts/discourse/tests/acceptance/sidebar-categories-section-test.js rename to app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js index 7abc849dbb..8737c9eb9e 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-categories-section-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js @@ -7,6 +7,7 @@ import { exists, publishToMessageBus, query, + queryAll, updateCurrentUser, } from "discourse/tests/helpers/qunit-helpers"; @@ -16,10 +17,10 @@ import categoryFixture from "discourse/tests/fixtures/category-fixtures"; import { cloneJSON } from "discourse-common/lib/object"; acceptance( - "Sidebar - Categories Section - suppress_uncategorized_badge enabled", + "Sidebar - Logged on user - Categories Section - allow_uncategorized_topics disabled", function (needs) { needs.settings({ - suppress_uncategorized_badge: true, + allow_uncategorized_topics: false, enable_experimental_sidebar_hamburger: true, enable_sidebar: true, }); @@ -41,7 +42,9 @@ acceptance( await visit("/"); assert.strictEqual( - count(".sidebar-section-categories .sidebar-section-link"), + count( + ".sidebar-section-categories .sidebar-section-link:not(.sidebar-section-link-all-categories)" + ), 1, "there should only be one section link under the section" ); @@ -54,10 +57,10 @@ acceptance( } ); -acceptance("Sidebar - Categories Section", function (needs) { +acceptance("Sidebar - Logged on user - Categories Section", function (needs) { needs.user({ sidebar_category_ids: [], - sidebar_tag_names: [], + sidebar_tags: [], }); needs.settings({ @@ -84,18 +87,22 @@ acceptance("Sidebar - Categories Section", function (needs) { const categories = Site.current().categories; const category1 = categories[0]; const category2 = categories[1]; - updateCurrentUser({ sidebar_category_ids: [category1.id, category2.id] }); - return { category1, category2 }; + const category3 = categories[5]; + + updateCurrentUser({ + sidebar_category_ids: [category1.id, category2.id, category3.id], + }); + + return { category1, category2, category3 }; }; test("clicking on section header link", async function (assert) { await visit("/t/280"); - await click(".sidebar-section-categories .sidebar-section-header-link"); + await click(".sidebar-section-categories .sidebar-section-header"); - assert.strictEqual( - currentURL(), - "/categories", - "it should transition to the categories page" + assert.notOk( + exists(".sidebar-section-categories .sidebar-section-content"), + "hides the content of the section" ); }); @@ -144,34 +151,55 @@ acceptance("Sidebar - Categories Section", function (needs) { ); }); - test("category section links uses the bullet style even when category_style site setting has been configured", async function (assert) { - this.siteSettings.category_style = "box"; - const { category1 } = setupUserSidebarCategories(); + test("category section links are sorted by category name alphabetically", async function (assert) { + const { category1, category2, category3 } = setupUserSidebarCategories(); + + category3.set("name", "aBC"); + category2.set("name", "abc"); + category1.set("name", "efg"); await visit("/"); - assert.ok( - exists( - `.sidebar-section-categories .sidebar-section-link-${category1.slug} .badge-wrapper.bullet` - ), - "category badge uses the bullet style" + const categorySectionLinks = queryAll( + ".sidebar-section-categories .sidebar-section-link:not(.sidebar-section-link-all-categories)" + ); + + const categoryNames = [...categorySectionLinks].map((categorySectionLink) => + categorySectionLink.textContent.trim() + ); + + assert.deepEqual( + categoryNames, + ["abc", "aBC", "efg"], + "category section links are displayed in the right order" ); }); test("category section links", async function (assert) { - const { category1, category2 } = setupUserSidebarCategories(); + const { category1, category2, category3 } = setupUserSidebarCategories(); await visit("/"); assert.strictEqual( - count(".sidebar-section-categories .sidebar-section-link"), - 2, - "there should only be two section link under the section" + count( + ".sidebar-section-categories .sidebar-section-link:not(.sidebar-section-link-all-categories)" + ), + 3, + "there should only be 3 section link under the section" ); assert.ok( - exists(`.sidebar-section-link-${category1.slug} .badge-category`), - "category1 section link is rendered with category badge" + exists( + `.sidebar-section-link-${category1.slug} .prefix-icon.d-icon-square-full` + ), + "category1 section link is rendered with right prefix icon" + ); + + assert.ok( + exists( + `.sidebar-section-link-${category1.slug} .sidebar-section-link-prefix[style="color: #${category1.color}"]` + ), + "category1 section link is rendered with right prefix icon color" ); assert.strictEqual( @@ -217,6 +245,32 @@ acceptance("Sidebar - Categories Section", function (needs) { exists(`.sidebar-section-link-${category2.slug}.active`), "the category2 section link is marked as active" ); + + assert.ok( + exists( + `.sidebar-section-link-${category3.slug} .sidebar-section-link-prefix .prefix-badge.d-icon-lock` + ), + "category3 section link is rendered with lock prefix badge icon as it is read restricted" + ); + }); + + test("category section link have the right title", async function (assert) { + const categories = Site.current().categories; + + // Category with link HTML tag in description + const category = categories.find((c) => c.id === 28); + + updateCurrentUser({ + sidebar_category_ids: [category.id], + }); + + await visit("/"); + + assert.strictEqual( + query(`.sidebar-section-link-${category.slug}`).title, + category.description_text, + "category description without HTML entity is used as the link's title" + ); }); test("visiting category discovery new route", async function (assert) { diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-community-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-community-section-test.js similarity index 85% rename from app/assets/javascripts/discourse/tests/acceptance/sidebar-community-section-test.js rename to app/assets/javascripts/discourse/tests/acceptance/sidebar-user-community-section-test.js index 5dbcee7748..f034d089f4 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-community-section-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-community-section-test.js @@ -1,5 +1,5 @@ import I18n from "I18n"; -import { test } from "qunit"; +import { skip, test } from "qunit"; import { click, currentRouteName, @@ -21,7 +21,7 @@ import { withPluginApi } from "discourse/lib/plugin-api"; import Site from "discourse/models/site"; import { NotificationLevels } from "discourse/lib/notification-levels"; -acceptance("Sidebar - Community Section", function (needs) { +acceptance("Sidebar - Logged on user - Community Section", function (needs) { needs.user({ tracked_tags: ["tag1"], watched_tags: ["tag2"], @@ -67,8 +67,8 @@ acceptance("Sidebar - Community Section", function (needs) { ); }); - test("clicking on section caret button", async function (assert) { - await visit("/"); + test("clicking on section header link", async function (assert) { + await visit("/t/280"); assert.ok( exists(".sidebar-section-community .sidebar-section-content"), @@ -76,19 +76,19 @@ acceptance("Sidebar - Community Section", function (needs) { ); assert.strictEqual( - query(".sidebar-section-community .sidebar-section-header-caret").title, + query(".sidebar-section-community .sidebar-section-header").title, I18n.t("sidebar.toggle_section"), "caret has the right title" ); - await click(".sidebar-section-community .sidebar-section-header-caret"); + await click(".sidebar-section-community .sidebar-section-header"); - assert.ok( - !exists(".sidebar-section-community .sidebar-section-content"), - "hides content section" + assert.notOk( + exists(".sidebar-section-community .sidebar-section-content"), + "hides the content of the section" ); - await click(".sidebar-section-community .sidebar-section-header-caret"); + await click(".sidebar-section-community .sidebar-section-header"); assert.ok( exists(".sidebar-section-community .sidebar-section-content"), @@ -96,31 +96,8 @@ acceptance("Sidebar - Community Section", function (needs) { ); }); - test("clicking on section header link", async function (assert) { - await visit("/t/280"); - await click(".sidebar-section-community .sidebar-section-header-link"); - - assert.strictEqual( - currentURL(), - "/latest", - "it should transition to the homepage" - ); - - assert.strictEqual( - count(".sidebar-section-community .sidebar-section-link.active"), - 1, - "only one link is marked as active" - ); - - assert.ok( - exists( - ".sidebar-section-community .sidebar-section-link-everything.active" - ), - "the everything link is marked as active" - ); - }); - - test("clicking on more... link", async function (assert) { + // TODO(tgxworld): Flaky probably due to assertions running before event listener callbacks have completed. + skip("clicking on more... link", async function (assert) { await visit("/"); await click( @@ -252,6 +229,52 @@ acceptance("Sidebar - Community Section", function (needs) { ); }); + test("users section link is not shown when enable_user_directory site setting is disabled", async function (assert) { + this.siteSettings.enable_user_directory = false; + + await visit("/"); + + await click( + ".sidebar-section-community .sidebar-more-section-links-details-summary" + ); + + assert.notOk( + exists(".sidebar-section-community .sidebar-section-link-users"), + "users section link is not displayed in sidebar" + ); + }); + + test("clicking on badges link", async function (assert) { + await visit("/"); + + await click( + ".sidebar-section-community .sidebar-more-section-links-details-summary" + ); + + await click(".sidebar-section-community .sidebar-section-link-badges"); + + assert.strictEqual( + currentURL(), + "/badges", + "it should transition to the badges url" + ); + }); + + test("badges section link is not shown when badges has been disabled", async function (assert) { + this.siteSettings.enable_badges = false; + + await visit("/"); + + await click( + ".sidebar-section-community .sidebar-more-section-links-details-summary" + ); + + assert.notOk( + exists(".sidebar-section-community .sidebar-section-link-badges"), + "badges section link is not shown in sidebar" + ); + }); + test("clicking on groups link", async function (assert) { await visit("/t/280"); @@ -299,6 +322,21 @@ acceptance("Sidebar - Community Section", function (needs) { ); }); + test("groups section link is not shown when enable_group_directory site setting has been disabled", async function (assert) { + this.siteSettings.enable_group_directory = false; + + await visit("/"); + + await click( + ".sidebar-section-community .sidebar-more-section-links-details-summary" + ); + + assert.notOk( + exists(".sidebar-section-community .sidebar-section-link-groups"), + "groups section link is not shown in sidebar" + ); + }); + test("navigating to about from sidebar", async function (assert) { await visit("/"); @@ -672,6 +710,86 @@ acceptance("Sidebar - Community Section", function (needs) { ); }); + test("review link is not shown when user cannot review", async function (assert) { + updateCurrentUser({ can_review: false }); + + await visit("/"); + + assert.notOk( + exists(".sidebar-section-community .sidebar-section-link-review"), + "review link is not shown" + ); + + await click( + ".sidebar-section-community .sidebar-more-section-links-details-summary" + ); + + assert.notOk( + exists(".sidebar-section-community .sidebar-section-link-review"), + "review link is not shown" + ); + }); + + test("review link when user can review", async function (assert) { + updateCurrentUser({ + can_review: true, + reviewable_count: 0, + }); + + await visit("/reivew"); + + assert.notOk( + exists(".sidebar-section-community .sidebar-section-link-review.active"), + "review link is shown as active when visiting the review route even if there are no pending reviewables" + ); + + await visit("/"); + + assert.notOk( + exists(".sidebar-section-community .sidebar-section-link-review"), + "review link is not shown as part of the main section links" + ); + + await click( + ".sidebar-section-community .sidebar-more-section-links-details-summary" + ); + + assert.ok( + exists( + ".sidebar-section-community .sidebar-more-section-links-details-content .sidebar-section-link-review" + ), + "review link is displayed in the more drawer" + ); + + await publishToMessageBus("/reviewable_counts", { + reviewable_count: 34, + }); + + assert.ok( + exists(".sidebar-section-community .sidebar-section-link-review"), + "review link is shown as part of the main section links" + ); + + assert.strictEqual( + query( + ".sidebar-section-community .sidebar-section-link-review .sidebar-section-link-content-badge" + ).textContent.trim(), + "34 pending", + "displays the pending reviewable count" + ); + + await click( + ".sidebar-section-community .sidebar-more-section-links-details-summary" + ); + + assert.notOk( + exists( + ".sidebar-section-community .sidebar-more-section-links-details-content .sidebar-section-link-review" + ), + "review link is not displayed in the more drawer" + ); + }); + test("new and unread count for tracked link", async function (assert) { const categories = Site.current().categories; diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-messages-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-messages-section-test.js similarity index 96% rename from app/assets/javascripts/discourse/tests/acceptance/sidebar-messages-section-test.js rename to app/assets/javascripts/discourse/tests/acceptance/sidebar-user-messages-section-test.js index 801f6746ec..c42ba0d83e 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-messages-section-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-messages-section-test.js @@ -12,14 +12,14 @@ import { import { NotificationLevels } from "discourse/lib/notification-levels"; acceptance( - "Sidebar - Messages Section - enable_personal_messages disabled", + "Sidebar - Logged on user - Messages Section - user not in personal_message_enabled_groups", function (needs) { - needs.user(); + needs.user({ moderator: false, admin: false }); needs.settings({ enable_experimental_sidebar_hamburger: true, enable_sidebar: true, - enable_personal_messages: false, + personal_message_enabled_groups: "13", // trust_level_3 auto group ID; }); test("clicking on section header button", async function (assert) { @@ -34,7 +34,7 @@ acceptance( ); acceptance( - "Sidebar - Messages Section - enable_personal_messages enabled", + "Sidebar - Logged on user - Messages Section - user in personal_message_enabled_groups", function (needs) { needs.user(); @@ -82,12 +82,11 @@ acceptance( test("clicking on section header link", async function (assert) { await visit("/"); - await click(".sidebar-section-messages .sidebar-section-header-link"); + await click(".sidebar-section-messages .sidebar-section-header"); - assert.strictEqual( - currentURL(), - `/u/eviltrout/messages`, - "it should transition to the user's messages" + assert.notOk( + exists(".sidebar-section-messages .sidebar-section-content"), + "hides the content of the section" ); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-tags-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-tags-section-test.js similarity index 78% rename from app/assets/javascripts/discourse/tests/acceptance/sidebar-tags-section-test.js rename to app/assets/javascripts/discourse/tests/acceptance/sidebar-user-tags-section-test.js index 4d370ea55a..29f082fdc7 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-tags-section-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-tags-section-test.js @@ -7,31 +7,35 @@ import { exists, publishToMessageBus, query, + queryAll, updateCurrentUser, } from "discourse/tests/helpers/qunit-helpers"; import discoveryFixture from "discourse/tests/fixtures/discovery-fixtures"; import { cloneJSON } from "discourse-common/lib/object"; -acceptance("Sidebar - Tags section - tagging disabled", function (needs) { - needs.settings({ - tagging_enabled: false, - enable_experimental_sidebar_hamburger: true, - enable_sidebar: true, - }); +acceptance( + "Sidebar - Logged on user - Tags section - tagging disabled", + function (needs) { + needs.settings({ + tagging_enabled: false, + enable_experimental_sidebar_hamburger: true, + enable_sidebar: true, + }); - needs.user(); + needs.user(); - test("tags section is not shown", async function (assert) { - await visit("/"); + test("tags section is not shown", async function (assert) { + await visit("/"); - assert.ok( - !exists(".sidebar-section-tags"), - "does not display the tags section" - ); - }); -}); + assert.ok( + !exists(".sidebar-section-tags"), + "does not display the tags section" + ); + }); + } +); -acceptance("Sidebar - Tags section", function (needs) { +acceptance("Sidebar - Logged on user - Tags section", function (needs) { needs.settings({ tagging_enabled: true, enable_experimental_sidebar_hamburger: true, @@ -42,7 +46,18 @@ acceptance("Sidebar - Tags section", function (needs) { tracked_tags: ["tag1"], watched_tags: ["tag2", "tag3"], watching_first_post_tags: [], - sidebar_tag_names: ["tag1", "tag2", "tag3"], + sidebar_tags: [ + { name: "tag2", pm_only: false }, + { name: "tag1", pm_only: false }, + { + name: "tag4", + pm_only: true, + }, + { + name: "tag3", + pm_only: false, + }, + ], }); needs.pretender((server, helper) => { @@ -52,6 +67,20 @@ acceptance("Sidebar - Tags section", function (needs) { }); }); + server.get("/topics/private-messages-tags/:username/:tagId", () => { + const topics = [ + { id: 1, posters: [] }, + { id: 2, posters: [] }, + { id: 3, posters: [] }, + ]; + + return helper.response({ + topic_list: { + topics, + }, + }); + }); + ["latest", "top", "new", "unread"].forEach((type) => { server.get(`/tag/:tagId/l/${type}.json`, () => { return helper.response( @@ -61,17 +90,6 @@ acceptance("Sidebar - Tags section", function (needs) { }); }); - test("clicking on section header link", async function (assert) { - await visit("/"); - await click(".sidebar-section-tags .sidebar-section-header-link"); - - assert.strictEqual( - currentURL(), - "/tags", - "it should transition to the tags page" - ); - }); - test("clicking on section header button", async function (assert) { await visit("/"); await click(".sidebar-section-tags .sidebar-section-header-button"); @@ -85,7 +103,7 @@ acceptance("Sidebar - Tags section", function (needs) { test("section content when user has not added any tags", async function (assert) { updateCurrentUser({ - sidebar_tag_names: [], + sidebar_tags: [], }); await visit("/"); @@ -101,13 +119,33 @@ acceptance("Sidebar - Tags section", function (needs) { ); }); + test("tag section links are sorted alphabetically by tag's name", async function (assert) { + await visit("/"); + + const tagSectionLinks = queryAll( + ".sidebar-section-tags .sidebar-section-link:not(.sidebar-section-link-all-tags)" + ); + + const tagNames = [...tagSectionLinks].map((tagSectionLink) => + tagSectionLink.textContent.trim() + ); + + assert.deepEqual( + tagNames, + ["tag1", "tag2", "tag3", "tag4"], + "tag section links are displayed in the right order" + ); + }); + test("tag section links for user", async function (assert) { await visit("/"); assert.strictEqual( - count(".sidebar-section-tags .sidebar-section-link"), - 3, - "3 section links under the section" + count( + ".sidebar-section-tags .sidebar-section-link:not(.sidebar-section-link-all-tags)" + ), + 4, + "4 section links under the section" ); assert.strictEqual( @@ -167,6 +205,29 @@ acceptance("Sidebar - Tags section", function (needs) { ); }); + test("private message tag section links for user", async function (assert) { + await visit("/"); + + await click(".sidebar-section-link-tag4"); + + assert.strictEqual( + currentURL(), + "/u/eviltrout/messages/tags/tag4", + "it should transition to user's private message tag4 tag page" + ); + + assert.strictEqual( + count(".sidebar-section-tags .sidebar-section-link.active"), + 1, + "only one link is marked as active" + ); + + assert.ok( + exists(`.sidebar-section-link-tag4.active`), + "the tag4 section link is marked as active" + ); + }); + test("visiting tag discovery top route", async function (assert) { await visit(`/tag/tag1/l/top`); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-test.js similarity index 84% rename from app/assets/javascripts/discourse/tests/acceptance/sidebar-test.js rename to app/assets/javascripts/discourse/tests/acceptance/sidebar-user-test.js index f75d4b2248..5f5aa93fca 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-test.js @@ -1,25 +1,10 @@ import I18n from "I18n"; - import { test } from "qunit"; import { click, visit } from "@ember/test-helpers"; import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers"; -acceptance("Sidebar - Anon User", function () { - // Don't show sidebar for anon user until we know what we want to display - test("sidebar is not displayed", async function (assert) { - await visit("/"); - - assert.ok( - !document.body.classList.contains("has-sidebar-page"), - "does not add sidebar utility class to body" - ); - - assert.ok(!exists(".sidebar-container")); - }); -}); - acceptance( - "Sidebar - Experimental sidebar and hamburger setting disabled", + "Sidebar - Logged on user - Experimental sidebar and hamburger setting disabled", function (needs) { needs.user(); @@ -27,7 +12,7 @@ acceptance( enable_experimental_sidebar_hamburger: false, }); - test("clicking header hamburger icon displays old hamburger drodown", async function (assert) { + test("clicking header hamburger icon displays old hamburger dropdown", async function (assert) { await visit("/"); await click(".hamburger-dropdown"); @@ -37,7 +22,7 @@ acceptance( ); acceptance( - "Sidebar - Experimental sidebar and hamburger setting enabled - Sidebar disabled", + "Sidebar - Logged on user - Experimental sidebar and hamburger setting enabled - Sidebar disabled", function (needs) { needs.user(); @@ -115,13 +100,6 @@ acceptance( exists(".sidebar-container"), "does not display the sidebar on wizard route" ); - - await click(".hamburger-dropdown"); - - assert.ok( - exists(".sidebar-hamburger-dropdown"), - "navigation around the site can still be done via the sidebar hamburger" - ); }); test("showing and hiding sidebar", async function (assert) { diff --git a/app/assets/javascripts/discourse/tests/acceptance/tags-test.js b/app/assets/javascripts/discourse/tests/acceptance/tags-test.js index 73ef18d357..cfeb1b2944 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/tags-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/tags-test.js @@ -502,7 +502,6 @@ acceptance("Tag info", function (needs) { await visit("/tags/c/feature/2/planters"); await click(".nav-item_latest a[href]"); - // await pauseTest(); assert.strictEqual(currentURL(), "/tags/c/feature/2/planters/l/latest"); await click(".nav-item_top a[href]"); diff --git a/app/assets/javascripts/discourse/tests/acceptance/topic-discovery-test.js b/app/assets/javascripts/discourse/tests/acceptance/topic-discovery-test.js index ebc2c46f8f..5106f49861 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/topic-discovery-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/topic-discovery-test.js @@ -201,15 +201,11 @@ acceptance("Topic Discovery | Footer", function (needs) { }); needs.pretender((server, helper) => { - server.get("/c/dev/7/l/latest.json", () => { + server.get("/c/dev/7/l/latest.json", (request) => { const json = cloneJSON(discoveryFixtures["/c/dev/7/l/latest.json"]); - json.topic_list.more_topics_url = "/c/dev/7/l/latest.json?page=2"; - return helper.response(json); - }); - - server.get("/c/dev/7/l/latest.json?page=2", () => { - const json = cloneJSON(discoveryFixtures["/c/dev/7/l/latest.json"]); - json.topic_list.more_topics_url = null; + if (!request.queryParams.page) { + json.topic_list.more_topics_url = "/c/dev/7/l/latest.json?page=2"; + } return helper.response(json); }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/topic-discovery-tracked-test.js b/app/assets/javascripts/discourse/tests/acceptance/topic-discovery-tracked-test.js index f60f66ac0b..5fbb9f3be8 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/topic-discovery-tracked-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/topic-discovery-tracked-test.js @@ -69,6 +69,13 @@ acceptance("Topic Discovery Tracked", function (needs) { "the categories nav item is displayed when tracked filter is not present" ); + await visit("/categories"); + + assert.ok( + exists("#navigation-bar li.categories"), + "the categories nav item is displayed on categories route when tracked filter is not present" + ); + await visit("/?f=tracked"); assert.ok( diff --git a/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js b/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js index ab4755bd4a..ad6f4a6082 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js @@ -247,22 +247,18 @@ acceptance("Topic - Edit timer", function (needs) { test("schedule publish to category - last custom date and time", async function (assert) { updateCurrentUser({ moderator: true }); - await visit("/t/internationalization-localization"); - await click(".toggle-admin-menu"); - await click(".admin-topic-timer-update button"); - - await click("#tap_tile_custom"); - await click(".modal-close"); await click(".toggle-admin-menu"); await click(".admin-topic-timer-update button"); - assert.notOk( exists("#tap_tile_last_custom"), - "it does not show last custom if the custom date and time was not filled and valid" + "it does not show last custom if the custom date and time was not filled before" ); + await click(".modal-close"); + await click(".toggle-admin-menu"); + await click(".admin-topic-timer-update button"); await click("#tap_tile_custom"); await fillIn(".tap-tile-date-input .date-picker", "2100-11-24"); await fillIn("#custom-time", "10:30"); diff --git a/app/assets/javascripts/discourse/tests/acceptance/topic-user-status-test.js b/app/assets/javascripts/discourse/tests/acceptance/topic-user-status-test.js new file mode 100644 index 0000000000..c8960b64fb --- /dev/null +++ b/app/assets/javascripts/discourse/tests/acceptance/topic-user-status-test.js @@ -0,0 +1,127 @@ +import { + acceptance, + exists, + publishToMessageBus, + query, + queryAll, +} from "discourse/tests/helpers/qunit-helpers"; +import { visit } from "@ember/test-helpers"; +import { test } from "qunit"; +import TopicFixtures from "discourse/tests/fixtures/topic"; +import { cloneJSON } from "discourse-common/lib/object"; + +acceptance("Topic - User Status", function (needs) { + const status = { emoji: "tooth", description: "off to dentist" }; + + needs.user(); + needs.pretender((server, helper) => { + server.get("/t/299/1.json", () => { + const response = cloneJSON(TopicFixtures["/t/299/1.json"]); + response.post_stream.posts.forEach((post) => { + post.user_status = status; + }); + + return helper.response(200, response); + }); + }); + + test("shows user status next to avatar on posts", async function (assert) { + this.siteSettings.enable_user_status = true; + await visit("/t/-/299/1"); + + assert.equal( + queryAll(".topic-post .user-status-message").length, + 3, + "all posts has user status" + ); + }); +}); + +acceptance("Topic - User Status - live updates", function (needs) { + const userId = 1; + const status = { emoji: "tooth", description: "off to dentist" }; + + needs.user(); + needs.pretender((server, helper) => { + server.get("/t/299/1.json", () => { + const response = cloneJSON(TopicFixtures["/t/299/1.json"]); + response.post_stream.posts.forEach((post) => { + post.user_id = userId; + post.user_status = { emoji: "tooth", description: "off to dentist" }; + }); + + return helper.response(200, response); + }); + }); + + test("updating status", async function (assert) { + this.siteSettings.enable_user_status = true; + + await visit("/t/-/299/1"); + assert.equal( + queryAll(".topic-post .user-status-message").length, + 3, + "all posts has user status" + ); + assert.ok( + query(".topic-post .user-status-message .emoji").src.includes( + status.emoji + ), + "status emoji is correct" + ); + + const newStatus = { emoji: "surfing_man", description: "surfing" }; + await publishToMessageBus(`/user-status`, { [userId]: newStatus }); + + assert.equal( + queryAll(".topic-post .user-status-message").length, + 3, + "all posts has user status" + ); + assert.ok( + query(".topic-post .user-status-message .emoji").src.includes( + newStatus.emoji + ), + "status emoji is correct" + ); + }); + + test("removing status and setting again", async function (assert) { + this.siteSettings.enable_user_status = true; + + await visit("/t/-/299/1"); + assert.equal( + queryAll(".topic-post .user-status-message").length, + 3, + "all posts has user status" + ); + assert.ok( + query(".topic-post .user-status-message .emoji").src.includes( + status.emoji + ), + "status emoji is correct" + ); + + await publishToMessageBus(`/user-status`, { [userId]: null }); + + assert.notOk( + exists(".topic-post .user-status-message"), + "status on all posts has disappeared" + ); + + const newStatus = { emoji: "surfing_man", description: "surfing" }; + await publishToMessageBus(`/user-status`, { [userId]: newStatus }); + + assert.equal( + queryAll(".topic-post .user-status-message").length, + 3, + "all posts have user status" + ); + assert.ok( + query(".topic-post .user-status-message .emoji").src.includes( + newStatus.emoji + ), + "status emoji is correct" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-activity-all-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-activity-all-test.js index 701b9852e4..f0e6f9732a 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-activity-all-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-activity-all-test.js @@ -1,9 +1,11 @@ -import { acceptance, exists, query } from "../helpers/qunit-helpers"; +import { acceptance, query } from "../helpers/qunit-helpers"; import { test } from "qunit"; import { visit } from "@ember/test-helpers"; import I18n from "I18n"; acceptance("User Activity / All - empty state", function (needs) { + const currentUser = "eviltrout"; + const anotherUser = "charlie"; needs.user(); needs.pretender((server, helper) => { @@ -14,17 +16,19 @@ acceptance("User Activity / All - empty state", function (needs) { }); }); - test("When looking at own activity it renders the empty state panel", async function (assert) { - await visit("/u/eviltrout/activity"); - assert.ok(exists("div.empty-state")); - }); - - test("When looking at another user activity it renders the 'No activity' message", async function (assert) { - await visit("/u/charlie/activity"); - assert.ok(exists("div.alert-info")); - assert.strictEqual( - query("div.alert-info").innerText.trim(), - I18n.t("user_activity.no_activity_others") + test("When looking at own activity page", async function (assert) { + await visit(`/u/${currentUser}/activity`); + assert.equal( + query("div.empty-state span.empty-state-title").innerText, + I18n.t("user_activity.no_activity_title") ); }); + + test("When looking at another user's activity page", async function (assert) { + await visit(`/u/${anotherUser}/activity`); + assert.equal( + query("div.empty-state span.empty-state-title").innerText, + I18n.t("user_activity.no_activity_title") + ); // the same title as when looking at own page + }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-activity-likes-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-activity-likes-test.js index fea8c445be..56559f9bd0 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-activity-likes-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-activity-likes-test.js @@ -1,9 +1,11 @@ -import { acceptance, exists, query } from "../helpers/qunit-helpers"; +import { acceptance, query } from "../helpers/qunit-helpers"; import { test } from "qunit"; import { visit } from "@ember/test-helpers"; import I18n from "I18n"; acceptance("User Activity / Likes - empty state", function (needs) { + const currentUser = "eviltrout"; + const anotherUser = "charlie"; needs.user(); needs.pretender((server, helper) => { @@ -14,17 +16,19 @@ acceptance("User Activity / Likes - empty state", function (needs) { }); }); - test("When looking at own activity it renders the empty state panel", async function (assert) { - await visit("/u/eviltrout/activity/likes-given"); - assert.ok(exists("div.empty-state")); + test("When looking at own likes page", async function (assert) { + await visit(`/u/${currentUser}/activity/likes-given`); + assert.equal( + query("div.empty-state span.empty-state-title").innerText, + I18n.t("user_activity.no_likes_title") + ); }); - test("When looking at another user activity it renders the 'No activity' message", async function (assert) { - await visit("/u/charlie/activity/likes-given"); - assert.ok(exists("div.alert-info")); - assert.strictEqual( - query("div.alert-info").innerText.trim(), - I18n.t("user_activity.no_likes_others") + test("When looking at another user's likes page", async function (assert) { + await visit(`/u/${anotherUser}/activity/likes-given`); + assert.equal( + query("div.empty-state span.empty-state-title").innerText, + I18n.t("user_activity.no_likes_title_others", { username: anotherUser }) ); }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-activity-replies-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-activity-replies-test.js index b0b7690a98..431c0d2871 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-activity-replies-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-activity-replies-test.js @@ -1,9 +1,12 @@ -import { acceptance, exists, query } from "../helpers/qunit-helpers"; +import { acceptance, query } from "../helpers/qunit-helpers"; import { test } from "qunit"; -import { visit } from "@ember/test-helpers"; +import { click, visit } from "@ember/test-helpers"; import I18n from "I18n"; acceptance("User Activity / Replies - empty state", function (needs) { + const currentUser = "eviltrout"; + const anotherUser = "charlie"; + needs.user(); needs.pretender((server, helper) => { @@ -14,17 +17,55 @@ acceptance("User Activity / Replies - empty state", function (needs) { }); }); - test("When looking at own activity it renders the empty state panel", async function (assert) { - await visit("/u/eviltrout/activity/replies"); - assert.ok(exists("div.empty-state")); + test("When looking at own replies page", async function (assert) { + await visit(`/u/${currentUser}/activity/replies`); + assert.equal( + query("div.empty-state span.empty-state-title").innerText, + I18n.t("user_activity.no_replies_title") + ); }); - test("When looking at another user activity it renders the 'No activity' message", async function (assert) { - await visit("/u/charlie/activity/replies"); - assert.ok(exists("div.alert-info")); - assert.strictEqual( - query("div.alert-info").innerText.trim(), - I18n.t("user_activity.no_replies_others") + test("When looking at another user's replies page", async function (assert) { + await visit(`/u/${anotherUser}/activity/replies`); + assert.equal( + query("div.empty-state span.empty-state-title").innerText, + I18n.t("user_activity.no_replies_title_others", { username: anotherUser }) + ); + }); +}); + +acceptance("User Activity / Replies - Download All", function (needs) { + const currentUser = "eviltrout"; + const anotherUser = "charlie"; + needs.user(); + needs.pretender((server, helper) => { + server.post("/export_csv/export_entity.json", () => { + return helper.response({}); + }); + }); + + test("Can see and trigger download for own data replies", async function (assert) { + await visit(`/u/${currentUser}/activity`); + + assert.ok(query(".user-additional-controls .btn"), "button exists"); + + await click(".user-additional-controls .btn"); + await click("#dialog-holder .btn-primary"); + + assert.equal( + query(".dialog-body").innerText.trim(), + I18n.t("user.download_archive.success") + ); + + await click("#dialog-holder .btn-primary"); + }); + + test("Cannot see 'Download All' button for another user", async function (assert) { + await visit(`/u/${anotherUser}/activity`); + + assert.notOk( + query(".user-additional-controls .btn"), + "download button is not present" ); }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-drafts-stream-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-drafts-stream-test.js index 2ea3fb5b54..fef99da02c 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-drafts-stream-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-drafts-stream-test.js @@ -18,9 +18,9 @@ acceptance("User Drafts", function (needs) { assert.strictEqual(count(".user-stream-item"), 3, "has drafts"); await click(".user-stream-item:first-child .remove-draft"); - assert.ok(visible(".bootbox")); + assert.ok(visible(".dialog-body")); - await click(".bootbox .btn-primary"); + await click(".dialog-footer .btn-primary"); assert.strictEqual( count(".user-stream-item"), 2, @@ -62,5 +62,12 @@ acceptance("User Drafts", function (needs) { ), "shows the excerpt" ); + + assert.ok( + query(".user-stream-item:nth-child(2) a.avatar-link").href.endsWith( + "/u/eviltrout" + ), + "has correct avatar link" + ); }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-menu-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-menu-test.js index e0d125177f..da24b409fd 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-menu-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-menu-test.js @@ -1,4 +1,4 @@ -import { click, visit } from "@ember/test-helpers"; +import { click, currentURL, visit } from "@ember/test-helpers"; import { acceptance, exists, @@ -6,6 +6,7 @@ import { publishToMessageBus, query, queryAll, + updateCurrentUser, } from "discourse/tests/helpers/qunit-helpers"; import { test } from "qunit"; import { cloneJSON } from "discourse-common/lib/object"; @@ -13,13 +14,25 @@ import { withPluginApi } from "discourse/lib/plugin-api"; import { NOTIFICATION_TYPES } from "discourse/tests/fixtures/concerns/notification-types"; import UserMenuFixtures from "discourse/tests/fixtures/user-menu"; import TopicFixtures from "discourse/tests/fixtures/topic"; +import { Promise } from "rsvp"; +import { later } from "@ember/runloop"; import I18n from "I18n"; acceptance("User menu", function (needs) { needs.user({ redesigned_user_menu_enabled: true, unread_high_priority_notifications: 73, + trust_level: 3, + grouped_unread_notifications: { + [NOTIFICATION_TYPES.replied]: 2, + }, }); + + needs.settings({ + allow_anonymous_posting: true, + anonymous_posting_min_trust_level: 3, + }); + let requestHeaders = {}; needs.pretender((server, helper) => { @@ -38,9 +51,54 @@ acceptance("User menu", function (needs) { requestHeaders = {}; }); + test("notifications panel has a11y attributes", async function (assert) { + await visit("/"); + await click(".d-header-icons .current-user"); + const panel = query("#quick-access-all-notifications"); + assert.strictEqual(panel.getAttribute("tabindex"), "-1"); + assert.strictEqual( + panel.querySelector("ul").getAttribute("aria-labelledby"), + "user-menu-button-all-notifications" + ); + }); + + test("mentions notifications panel has a11y attributes", async function (assert) { + await visit("/"); + await click(".d-header-icons .current-user"); + await click("#user-menu-button-mentions"); + const panel = query("#quick-access-mentions"); + assert.strictEqual(panel.getAttribute("tabindex"), "-1"); + assert.strictEqual( + panel.querySelector("ul").getAttribute("aria-labelledby"), + "user-menu-button-mentions" + ); + }); + + test("profile panel has a11y attributes", async function (assert) { + await visit("/"); + await click(".d-header-icons .current-user"); + await click("#user-menu-button-profile"); + const panel = query("#quick-access-profile"); + assert.strictEqual(panel.getAttribute("tabindex"), "-1"); + assert.strictEqual( + panel.querySelector("ul").getAttribute("aria-labelledby"), + "user-menu-button-profile" + ); + }); + test("clicking on an unread notification", async function (assert) { await visit("/"); await click(".d-header-icons .current-user"); + + let repliesBadgeNotification = query( + "#user-menu-button-replies .badge-notification" + ); + assert.strictEqual( + repliesBadgeNotification.textContent.trim(), + "2", + "badge shows the right count" + ); + await click(".user-menu ul li.replied a"); assert.strictEqual( @@ -48,6 +106,132 @@ acceptance("User menu", function (needs) { 123, // id is from the fixtures in fixtures/notification-fixtures.js "the Discourse-Clear-Notifications request header is set to the notification id in the next ajax request" ); + + await click(".d-header-icons .current-user"); + repliesBadgeNotification = query( + "#user-menu-button-replies .badge-notification" + ); + assert.strictEqual( + repliesBadgeNotification.textContent.trim(), + "1", + "badge shows count reduced by one" + ); + }); + + test("clicking on user menu items", async function (assert) { + await visit("/"); + await click(".d-header-icons .current-user"); + await click("#user-menu-button-review-queue"); + await click("#quick-access-review-queue li.reviewable.pending a"); + + assert.strictEqual( + currentURL(), + "/review/17", + "clicking on an item results in navigation to the item's page" + ); + assert.notOk( + exists(".user-menu"), + "clicking on an item closes the menu after navigating" + ); + + await click(".d-header-icons .current-user"); + await click("#user-menu-button-review-queue"); + await click("#quick-access-review-queue li.reviewable.pending a"); + + assert.strictEqual( + currentURL(), + "/review/17", + "clicking on the same item again keeps on the same page" + ); + assert.notOk( + exists(".user-menu"), + "clicking on the same item again closes the menu" + ); + + await click(".d-header-icons .current-user"); + await click("#user-menu-button-review-queue"); + // this may not be ideal because it actually attempts to open a new tab + // which gets blocked by the browser, but otherwise it seems harmless and + // doesn't cause the test to fail. if it causes problems for you, feel free + // to remove the ctrl+click tests. + await click("#quick-access-review-queue li.reviewable.reviewed a", { + ctrlKey: true, + }); + assert.strictEqual( + currentURL(), + "/review/17", + "ctrl-clicking on an item doesn't navigate to a new page" + ); + assert.ok( + exists(".user-menu"), + "ctrl-clicking on an item doesn't close the menu" + ); + }); + + test("tabs have title attributes", async function (assert) { + withPluginApi("0.1", (api) => { + api.registerUserMenuTab((UserMenuTab) => { + return class extends UserMenuTab { + get id() { + return "tiny-tab-1"; + } + + get count() { + return this.currentUser.get("unread_high_priority_notifications"); + } + + get icon() { + return "wrench"; + } + + get panelComponent() { + return "d-button"; + } + + get title() { + return `Custom title: ${this.count}`; + } + }; + }); + }); + + const expectedTitles = { + "user-menu-button-all-notifications": I18n.t( + "user_menu.tabs.all_notifications" + ), + "user-menu-button-replies": I18n.t("user_menu.tabs.replies_with_unread", { + count: 2, + }), + "user-menu-button-mentions": I18n.t("user_menu.tabs.mentions"), + "user-menu-button-likes": I18n.t("user_menu.tabs.likes"), + "user-menu-button-watching": I18n.t("user_menu.tabs.watching"), + "user-menu-button-messages": I18n.t("user_menu.tabs.messages"), + "user-menu-button-bookmarks": I18n.t("user_menu.tabs.bookmarks"), + "user-menu-button-tiny-tab-1": "Custom title: 73", + "user-menu-button-review-queue": I18n.t("user_menu.tabs.review_queue"), + "user-menu-button-other-notifications": I18n.t( + "user_menu.tabs.other_notifications" + ), + "user-menu-button-profile": I18n.t("user_menu.tabs.profile"), + }; + await visit("/"); + await click(".d-header-icons .current-user"); + for (const [key, title] of Object.entries(expectedTitles)) { + assert.strictEqual( + query(`#${key}`).title, + title, + `${key} tab has the right title` + ); + } + + await publishToMessageBus(`/notification/${loggedInUser().id}`, { + unread_high_priority_notifications: 22, + }); + assert.strictEqual( + query("#user-menu-button-tiny-tab-1").title, + "Custom title: 22", + "tabs titles can update dynamically" + ); }); test("tabs added via the plugin API", async function (assert) { @@ -97,11 +281,13 @@ acceptance("User menu", function (needs) { "user-menu-button-replies": "1", "user-menu-button-mentions": "2", "user-menu-button-likes": "3", - "user-menu-button-messages": "4", - "user-menu-button-bookmarks": "5", - "user-menu-button-custom-tab-1": "6", - "user-menu-button-custom-tab-2": "7", - "user-menu-button-review-queue": "8", + "user-menu-button-watching": "4", + "user-menu-button-messages": "5", + "user-menu-button-bookmarks": "6", + "user-menu-button-custom-tab-1": "7", + "user-menu-button-custom-tab-2": "8", + "user-menu-button-review-queue": "9", + "user-menu-button-other-notifications": "10", }; await visit("/"); @@ -128,7 +314,7 @@ acceptance("User menu", function (needs) { ); assert.strictEqual( query(".tabs-list.bottom-tabs .btn").dataset.tabNumber, - "9", + "11", "bottom tab has the correct data-tab-number" ); @@ -178,15 +364,408 @@ acceptance("User menu", function (needs) { "the tab's content is now displayed in the panel" ); }); + + test("notifications tab applies model transformations registered by plugins", async function (assert) { + withPluginApi("0.1", (api) => { + api.registerModelTransformer("notification", (notifications) => { + notifications.forEach((notification, index) => { + if (notification.fancy_title) { + notification.fancy_title = `pluginNotificationTransformer ${index} ${notification.fancy_title}`; + } + }); + }); + }); + + await visit("/"); + await click(".d-header-icons .current-user"); + + const notifications = queryAll( + "#quick-access-all-notifications ul li.notification" + ); + assert.strictEqual( + notifications[0].textContent.replace(/\s+/g, " ").trim(), + "velesin pluginNotificationTransformer 0 edited topic 443" + ); + assert.strictEqual( + notifications[1].textContent.replace(/\s+/g, " ").trim(), + "velesin pluginNotificationTransformer 1 some title" + ); + }); + + test("bookmarks tab applies model transformations registered by plugins", async function (assert) { + withPluginApi("0.1", (api) => { + api.registerModelTransformer("bookmark", (bookmarks) => { + bookmarks.forEach((bookmark) => { + if (bookmark.title) { + bookmark.title = `pluginBookmarkTransformer ${bookmark.title}`; + } + }); + }); + }); + + await visit("/"); + await click(".d-header-icons .current-user"); + await click("#user-menu-button-bookmarks"); + + const bookmarks = queryAll("#quick-access-bookmarks ul li.bookmark"); + assert.strictEqual( + bookmarks[0].textContent.replace(/\s+/g, " ").trim(), + "osama pluginBookmarkTransformer Test poll topic hello world" + ); + }); + + test("messages tab applies model transformations registered by plugins", async function (assert) { + withPluginApi("0.1", (api) => { + api.registerModelTransformer("topic", (topics) => { + topics.forEach((topic) => { + topic.fancy_title = `pluginTransformer#1 ${topic.fancy_title}`; + }); + }); + api.registerModelTransformer("topic", async (topics) => { + // sleep 1 ms + await new Promise((resolve) => later(resolve, 1)); + topics.forEach((topic) => { + topic.fancy_title = `pluginTransformer#2 ${topic.fancy_title}`; + }); + }); + }); + + await visit("/"); + await click(".d-header-icons .current-user"); + await click("#user-menu-button-messages"); + + const messages = queryAll("#quick-access-messages ul li.message"); + assert.strictEqual( + messages[0].textContent.replace(/\s+/g, " ").trim(), + "mixtape pluginTransformer#2 pluginTransformer#1 BUG: Can not render emoji properly" + ); + }); + + test("the profile tab", async function (assert) { + updateCurrentUser({ draft_count: 13 }); + await visit("/"); + await click(".d-header-icons .current-user"); + await click("#user-menu-button-profile"); + + const summaryLink = query("#quick-access-profile ul li.summary a"); + assert.ok( + summaryLink.href.endsWith("/u/eviltrout/summary"), + "has a link to the summary page of the user" + ); + assert.strictEqual( + summaryLink.textContent.trim(), + I18n.t("user.summary.title"), + "summary link has the right label" + ); + assert.ok( + summaryLink.querySelector(".d-icon-user"), + "summary link has the right icon" + ); + + const activityLink = query("#quick-access-profile ul li.activity a"); + assert.ok( + activityLink.href.endsWith("/u/eviltrout/activity"), + "has a link to the activity page of the user" + ); + assert.strictEqual( + activityLink.textContent.trim(), + I18n.t("user.activity_stream"), + "activity link has the right label" + ); + assert.ok( + activityLink.querySelector(".d-icon-stream"), + "activity link has the right icon" + ); + + const invitesLink = query("#quick-access-profile ul li.invites a"); + assert.ok( + invitesLink.href.endsWith("/u/eviltrout/invited"), + "has a link to the invites page of the user" + ); + assert.strictEqual( + invitesLink.textContent.trim(), + I18n.t("user.invited.title"), + "invites link has the right label" + ); + assert.ok( + invitesLink.querySelector(".d-icon-user-plus"), + "invites link has the right icon" + ); + + await click("header.d-header"); // close the menu + updateCurrentUser({ can_invite_to_forum: false }); + await click(".d-header-icons .current-user"); + await click("#user-menu-button-profile"); + + assert.notOk( + exists("#quick-access-profile ul li.invites"), + "invites link not shown when the user can't invite" + ); + + const dratsLink = query("#quick-access-profile ul li.drafts a"); + assert.ok( + dratsLink.href.endsWith("/u/eviltrout/activity/drafts"), + "has a link to the drafts page of the user" + ); + assert.strictEqual( + dratsLink.textContent.trim(), + I18n.t("drafts.label_with_count", { count: 13 }), + "drafts link has the right label with count of the user's drafts" + ); + assert.ok( + dratsLink.querySelector(".d-icon-pencil-alt"), + "drafts link has the right icon" + ); + + const preferencesLink = query("#quick-access-profile ul li.preferences a"); + assert.ok( + preferencesLink.href.endsWith("/u/eviltrout/preferences"), + "has a link to the preferences page of the user" + ); + assert.strictEqual( + preferencesLink.textContent.trim(), + I18n.t("user.preferences"), + "preferences link has the right label" + ); + assert.ok( + preferencesLink.querySelector(".d-icon-cog"), + "preferences link has the right icon" + ); + + let doNotDisturbButton = query( + "#quick-access-profile ul li.do-not-disturb .btn" + ); + assert.strictEqual( + doNotDisturbButton.textContent + .replaceAll(/\s+/g, " ") + .replaceAll(/\u200B/g, "") + .trim(), + I18n.t("do_not_disturb.label"), + "Do Not Disturb button has the right label" + ); + assert.ok( + doNotDisturbButton.querySelector(".d-icon-toggle-off"), + "Do Not Disturb button has the right icon" + ); + + await click("header.d-header"); // close the menu + const date = new Date(); + date.setHours(date.getHours() + 2); + updateCurrentUser({ do_not_disturb_until: date.toISOString() }); + await click(".d-header-icons .current-user"); + await click("#user-menu-button-profile"); + + doNotDisturbButton = query( + "#quick-access-profile ul li.do-not-disturb .btn" + ); + assert.strictEqual( + doNotDisturbButton.textContent + .replaceAll(/\s+/g, " ") + .replaceAll(/\u200B/g, "") + .trim(), + `${I18n.t("do_not_disturb.label")} 2h`, + "Do Not Disturb button has the right label when Do Not Disturb is enabled" + ); + assert.ok( + doNotDisturbButton.querySelector(".d-icon-toggle-on"), + "Do Not Disturb button has the right icon when Do Not Disturb is enabled" + ); + + let toggleAnonButton = query( + "#quick-access-profile ul li.enable-anonymous .btn" + ); + assert.strictEqual( + toggleAnonButton.textContent + .replaceAll(/\s+/g, " ") + .replaceAll(/\u200B/g, "") + .trim(), + I18n.t("switch_to_anon"), + "toggle anonymous button has the right label when the user isn't anonymous" + ); + assert.ok( + toggleAnonButton.querySelector(".d-icon-user-secret"), + "toggle anonymous button has the right icon when the user isn't anonymous" + ); + + await click("header.d-header"); // close the menu + updateCurrentUser({ is_anonymous: true }); + await click(".d-header-icons .current-user"); + await click("#user-menu-button-profile"); + + toggleAnonButton = query( + "#quick-access-profile ul li.disable-anonymous .btn" + ); + assert.strictEqual( + toggleAnonButton.textContent + .replaceAll(/\s+/g, " ") + .replaceAll(/\u200B/g, "") + .trim(), + I18n.t("switch_from_anon"), + "toggle anonymous button has the right label when the user is anonymous" + ); + assert.ok( + toggleAnonButton.querySelector(".d-icon-ban"), + "toggle anonymous button has the right icon when the user is anonymous" + ); + + await click("header.d-header"); // close the menu + updateCurrentUser({ is_anonymous: false, trust_level: 2 }); + await click(".d-header-icons .current-user"); + await click("#user-menu-button-profile"); + + assert.notOk( + exists("#quick-access-profile ul li.enable-anonymous"), + "toggle anon button isn't shown when the user can't use it" + ); + assert.notOk( + exists("#quick-access-profile ul li.disable-anonymous"), + "toggle anon button isn't shown when the user can't use it" + ); + + await click("header.d-header"); // close the menu + updateCurrentUser({ is_anonymous: true, trust_level: 2 }); + this.siteSettings.allow_anonymous_posting = false; + this.siteSettings.anonymous_posting_min_trust_level = 3; + await click(".d-header-icons .current-user"); + await click("#user-menu-button-profile"); + + assert.ok( + exists("#quick-access-profile ul li.disable-anonymous"), + "toggle anon button is always shown if the user is anonymous" + ); + + await click("header.d-header"); // close the menu + updateCurrentUser({ is_anonymous: false, trust_level: 4 }); + this.siteSettings.allow_anonymous_posting = false; + this.siteSettings.anonymous_posting_min_trust_level = 3; + await click(".d-header-icons .current-user"); + await click("#user-menu-button-profile"); + + assert.notOk( + exists("#quick-access-profile ul li.enable-anonymous"), + "toggle anon button is not shown if the allow_anonymous_posting setting is false" + ); + + await click("header.d-header"); // close the menu + updateCurrentUser({ is_anonymous: false, trust_level: 2 }); + this.siteSettings.allow_anonymous_posting = true; + this.siteSettings.anonymous_posting_min_trust_level = 3; + await click(".d-header-icons .current-user"); + await click("#user-menu-button-profile"); + + assert.notOk( + exists("#quick-access-profile ul li.enable-anonymous"), + "toggle anon button is not shown if the user doesn't have a high enough trust level" + ); + + const logoutButton = query("#quick-access-profile ul li.logout .btn"); + assert.strictEqual( + logoutButton.textContent + .replaceAll(/\s+/g, " ") + .replaceAll(/\u200B/g, "") + .trim(), + I18n.t("user.log_out"), + "logout button has the right label" + ); + assert.ok( + logoutButton.querySelector(".d-icon-sign-out-alt"), + "logout button has the right icon" + ); + }); + + test("the active tab can be clicked again to navigate to a page", async function (assert) { + withPluginApi("0.1", (api) => { + api.registerUserMenuTab((UserMenuTab) => { + return class extends UserMenuTab { + get id() { + return "custom-tab-1"; + } + + get icon() { + return "wrench"; + } + + get panelComponent() { + return "d-button"; + } + + get linkWhenActive() { + return "/u/eviltrout/preferences"; + } + }; + }); + + api.registerUserMenuTab((UserMenuTab) => { + return class extends UserMenuTab { + get id() { + return "custom-tab-2"; + } + + get icon() { + return "plus"; + } + + get panelComponent() { + return "d-button"; + } + }; + }); + }); + await visit("/"); + await click(".d-header-icons .current-user"); + await click("#user-menu-button-all-notifications"); + assert.strictEqual( + currentURL(), + "/u/eviltrout/notifications", + "clicking on active tab navigates to the page it links to" + ); + assert.notOk(exists(".user-menu"), "user menu is closed after navigating"); + + const tabs = [ + ["#user-menu-button-custom-tab-1", "/u/eviltrout/preferences/account"], + ["#user-menu-button-replies", "/u/eviltrout/notifications/responses"], + ["#user-menu-button-messages", "/u/eviltrout/messages"], + ["#user-menu-button-mentions", "/u/eviltrout/notifications/mentions"], + ["#user-menu-button-bookmarks", "/u/eviltrout/activity/bookmarks"], + ["#user-menu-button-likes", "/u/eviltrout/notifications/likes-received"], + ["#user-menu-button-custom-tab-2", null], + ["#user-menu-button-review-queue", "/review"], + ["#user-menu-button-profile", "/u/eviltrout/summary"], + ]; + for (const [id, expectedLink] of tabs) { + await click(".d-header-icons .current-user"); + await click(id); + await click(id); + if (expectedLink) { + assert.strictEqual( + currentURL(), + expectedLink, + `clicking on the ${id} tab navigates to ${expectedLink}` + ); + assert.notOk( + exists(".user-menu"), + "user menu is closed after navigating" + ); + } else { + assert.ok( + exists(".user-menu"), + "user menu remains open if tab doesn't link to anywhere" + ); + } + await click("#site-logo"); + } + }); }); acceptance("User menu - Dismiss button", function (needs) { needs.user({ redesigned_user_menu_enabled: true, unread_high_priority_notifications: 10, - grouped_unread_high_priority_notifications: { + grouped_unread_notifications: { [NOTIFICATION_TYPES.bookmark_reminder]: 103, [NOTIFICATION_TYPES.private_message]: 89, + [NOTIFICATION_TYPES.votes_released]: 1, + [NOTIFICATION_TYPES.code_review_commit_approved]: 3, }, }); @@ -372,4 +951,29 @@ acceptance("User menu - Dismiss button", function (needs) { "mark-read request is sent without a confirmation modal" ); }); + + test("doesn't show confirmation modal for the other notifications list", async function (assert) { + await visit("/"); + await click(".d-header-icons .current-user"); + + await click("#user-menu-button-other-notifications"); + let othersBadgeNotification = query( + "#user-menu-button-other-notifications .badge-notification" + ); + assert.strictEqual( + othersBadgeNotification.textContent.trim(), + "4", + "badge shows the right count" + ); + + await click(".user-menu .notifications-dismiss"); + + assert.ok( + !exists("#user-menu-button-other-notifications .badge-notification") + ); + assert.ok( + markRead, + "mark-read request is sent without a confirmation modal" + ); + }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-account-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-account-test.js new file mode 100644 index 0000000000..67ddd63241 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-account-test.js @@ -0,0 +1,38 @@ +import { acceptance, query } from "discourse/tests/helpers/qunit-helpers"; +import { click, visit } from "@ember/test-helpers"; +import { test } from "qunit"; +import DiscourseURL from "discourse/lib/url"; +import I18n from "I18n"; +import sinon from "sinon"; + +acceptance("User Profile - Account - Self Delete", function (needs) { + needs.user({ + username: "charlie", + }); + + needs.pretender((server, helper) => { + server.delete("/u/charlie.json", () => helper.response({ success: true })); + }); + + test("Delete dialog", async function (assert) { + sinon.stub(DiscourseURL, "redirectAbsolute"); + + await visit("/u/charlie/preferences/account"); + await click(".delete-account .btn-danger"); + + await click(".dialog-footer .btn-danger"); + + assert.strictEqual( + query(".dialog-body").textContent.trim(), + I18n.t("user.deleted_yourself"), + "confirmation dialog is shown" + ); + + await click(".dialog-footer .btn-primary"); + + assert.ok( + DiscourseURL.redirectAbsolute.calledWith("/"), + "redirects to home after deleting" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-interface-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-interface-test.js index 50cf773d12..7c36de796d 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-interface-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-interface-test.js @@ -11,6 +11,7 @@ import Session from "discourse/models/session"; import Site from "discourse/models/site"; import selectKit from "discourse/tests/helpers/select-kit-helper"; import { test } from "qunit"; +import userFixtures from "discourse/tests/fixtures/user-fixtures"; acceptance("User Preferences - Interface", function (needs) { needs.user(); @@ -147,6 +148,14 @@ acceptance( success: "OK", }); }); + server.get("/color-scheme-stylesheet/3.json", () => { + return helper.response({ + new_href: "3.css", + }); + }); + server.get("/u/charlie.json", () => { + return helper.response(userFixtures["/u/charlie.json"]); + }); }); test("show option to disable dark mode", async function (assert) { @@ -310,5 +319,37 @@ acceptance( "resets dark scheme dropdown" ); }); + + test("preview the color scheme only in current user's profile", async function (assert) { + let site = Site.current(); + + site.set("default_dark_color_scheme", { id: 1, name: "Dark" }); + site.set("user_color_schemes", [ + { id: 2, name: "Cool Breeze" }, + { id: 3, name: "Dark Night", is_dark: true }, + ]); + + await visit("/u/eviltrout/preferences/interface"); + + await selectKit(".light-color-scheme .combobox").expand(); + await selectKit(".light-color-scheme .combobox").selectRowByValue(3); + + assert.ok( + document.querySelector("link#cs-preview-light").href.endsWith("/3.css"), + "correct stylesheet loaded" + ); + + document.querySelector("link#cs-preview-light").remove(); + + await visit("/u/charlie/preferences/interface"); + + await selectKit(".light-color-scheme .combobox").expand(); + await selectKit(".light-color-scheme .combobox").selectRowByValue(3); + + assert.notOk( + document.querySelector("link#cs-preview-light"), + "stylesheet not loaded" + ); + }); } ); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-profile-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-profile-test.js index 3abd43494c..1bf8cfa1f4 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-profile-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-profile-test.js @@ -1,9 +1,69 @@ -import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers"; -import { visit } from "@ember/test-helpers"; +import { + acceptance, + exists, + query, +} from "discourse/tests/helpers/qunit-helpers"; +import { click, visit } from "@ember/test-helpers"; import { test } from "qunit"; +acceptance("User - Preferences - Profile - Featured topic", function (needs) { + needs.user(); + + needs.settings({ allow_featured_topic_on_user_profiles: true }); + + needs.pretender((server, helper) => { + server.put("/u/eviltrout/feature-topic", () => + helper.response({ success: true }) + ); + }); + + test("setting featured topic on profile", async function (assert) { + await visit("/u/eviltrout/preferences/profile"); + + assert.ok( + !exists(".featured-topic-link"), + "no featured topic link to present" + ); + assert.ok( + !exists(".clear-feature-topic-on-profile-btn"), + "clear button not present" + ); + + await click(".feature-topic-on-profile-btn"); + + assert.ok( + exists(".feature-topic-on-profile"), + "topic picker modal is open" + ); + + await click(query('input[name="choose_topic_id"]')); + await click(".save-featured-topic-on-profile"); + + assert.ok( + exists(".featured-topic-link"), + "link to featured topic is present" + ); + assert.ok( + exists(".clear-feature-topic-on-profile-btn"), + "clear button is present" + ); + }); + + test("focused item after closing feature topic modal", async function (assert) { + await visit("/u/eviltrout/preferences/profile"); + await click(".feature-topic-on-profile-btn"); + await click(".modal-close"); + + assert.equal( + document.activeElement, + query(".feature-topic-on-profile-btn"), + "it keeps focus on the feature topic button" + ); + }); +}); + acceptance( - "User profile preferences without default calendar set", + "User - Preferences - Profile - No default calendar set", function (needs) { needs.user({ default_calendar: "none_selected" }); @@ -19,7 +79,7 @@ acceptance( ); acceptance( - "User profile preferences with default calendar set", + "User - Preferences - Profile - Default calendar set", function (needs) { needs.user({ default_calendar: "google" }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-sidebar-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-sidebar-test.js index 6a2d3d429e..5e48f669bd 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-sidebar-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-sidebar-test.js @@ -12,7 +12,7 @@ import selectKit from "discourse/tests/helpers/select-kit-helper"; acceptance("User Preferences - Sidebar", function (needs) { needs.user({ sidebar_category_ids: [], - sidebar_tag_names: [], + sidebar_tags: [], }); needs.settings({ @@ -39,7 +39,14 @@ acceptance("User Preferences - Sidebar", function (needs) { // This request format will cause an error return helper.response(400, {}); } else { - return helper.response({ user: {} }); + return helper.response({ + user: { + sidebar_tags: [ + { name: "monkey", pm_only: false }, + { name: "gazelle", pm_only: false }, + ], + }, + }); } }); }); @@ -77,9 +84,9 @@ acceptance("User Preferences - Sidebar", function (needs) { "contains the right request body to update user's sidebar category links" ); - assert.ok(exists(".modal-body"), "error message is displayed"); + assert.ok(exists(".dialog-body"), "error message is displayed"); - await click(".modal .d-button-label"); + await click(".dialog-footer .btn-primary"); assert.ok( !exists(".sidebar-section-categories .sidebar-section-link-howto"), @@ -121,7 +128,7 @@ acceptance("User Preferences - Sidebar", function (needs) { }); test("user encountering error when adding tags to sidebar", async function (assert) { - updateCurrentUser({ sidebar_tag_names: ["monkey"] }); + updateCurrentUser({ sidebar_tags: [{ name: "monkey", pm_only: false }] }); await visit("/"); @@ -145,9 +152,9 @@ acceptance("User Preferences - Sidebar", function (needs) { "contains the right request body to update user's sidebar tag links" ); - assert.ok(exists(".modal-body"), "error message is displayed"); + assert.ok(exists(".dialog-body"), "error message is displayed"); - await click(".modal .d-button-label"); + await click(".dialog-footer .btn-primary"); assert.ok( !exists(".sidebar-section-tags .sidebar-section-link-gazelle"), diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-profile-summary-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-profile-summary-test.js index 7734a0b504..169cb95748 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-profile-summary-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-profile-summary-test.js @@ -3,12 +3,14 @@ import { exists, query, } from "discourse/tests/helpers/qunit-helpers"; -import { visit } from "@ember/test-helpers"; +import { click, visit } from "@ember/test-helpers"; import { test } from "qunit"; import I18n from "I18n"; import userFixtures from "discourse/tests/fixtures/user-fixtures"; import { cloneJSON } from "discourse-common/lib/object"; +let deleteAndBlock = null; + acceptance("User Profile - Summary", function (needs) { needs.user(); needs.pretender((server, helper) => { @@ -113,3 +115,58 @@ acceptance("User Profile - Summary - Stats", function (needs) { ); }); }); + +acceptance("User Profile - Summary - Admin", function (needs) { + needs.user({ + username: "eviltrout", + }); + + needs.pretender((server, helper) => { + server.get("/admin/users/5.json", () => { + return helper.response({ + id: 5, + username: "charlie", + name: null, + avatar_template: "/letter_avatar_proxy/v4/letter/b/f0a364/{size}.png", + active: true, + }); + }); + server.delete("/admin/users/5.json", (request) => { + const data = helper.parsePostData(request.requestBody); + + if (data.block_email || data.block_ip || data.block_urls) { + deleteAndBlock = true; + } else { + deleteAndBlock = false; + } + + return helper.response({}); + }); + }); + + needs.hooks.beforeEach(() => { + deleteAndBlock = null; + }); + + test("Delete only action", async function (assert) { + await visit("/u/charlie/summary"); + await click(".btn-delete-user"); + await click(".dialog-footer .btn-primary"); + + assert.notOk(deleteAndBlock, "first button does not block user"); + }); + + test("Delete and block", async function (assert) { + await visit("/u/charlie/summary"); + await click(".btn-delete-user"); + + assert.equal( + query("#dialog-title").textContent, + I18n.t("admin.user.delete_confirm_title"), + "dialog has a title" + ); + + await click(".dialog-footer .btn-danger"); + assert.ok(deleteAndBlock, "second button also block user"); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-status-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-status-test.js index 3da4866d61..ccef190ca1 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-status-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-status-test.js @@ -80,8 +80,9 @@ acceptance("User Status", function (needs) { await click(".menu-links-row .user-preferences-link"); assert.equal( - query("div.quick-access-panel li.user-status span.d-button-label") - .innerText, + query( + "div.quick-access-panel li.user-status span.d-button-label" + ).textContent.trim(), userStatus, "shows user status description on the menu" ); @@ -177,8 +178,9 @@ acceptance("User Status", function (needs) { await click(".header-dropdown-toggle.current-user"); await click(".menu-links-row .user-preferences-link"); assert.equal( - query("div.quick-access-panel li.user-status span.d-button-label") - .innerText, + query( + "div.quick-access-panel li.user-status span.d-button-label" + ).textContent.trim(), userStatus, "shows user status description on the menu" ); @@ -205,8 +207,9 @@ acceptance("User Status", function (needs) { await click(".header-dropdown-toggle.current-user"); await click(".menu-links-row .user-preferences-link"); assert.equal( - query("div.quick-access-panel li.user-status span.d-button-label") - .innerText, + query( + "div.quick-access-panel li.user-status span.d-button-label" + ).textContent.trim(), updatedStatus, "shows user status description on the menu" ); @@ -243,8 +246,9 @@ acceptance("User Status", function (needs) { await click(".menu-links-row .user-preferences-link"); assert.equal( - query("div.quick-access-panel li.user-status span.relative-date") - .innerText, + query( + "div.quick-access-panel li.user-status span.relative-date" + ).textContent.trim(), "1h", "shows user status timer on the menu" ); @@ -340,3 +344,94 @@ acceptance("User Status", function (needs) { ); }); }); + +acceptance("User Status - new user menu", function (needs) { + const userStatus = "off to dentist"; + const userStatusEmoji = "tooth"; + const userId = 1; + const userTimezone = "UTC"; + + needs.user({ + id: userId, + timezone: userTimezone, + redesigned_user_menu_enabled: true, + }); + + needs.pretender((server, helper) => { + server.put("/user-status.json", () => { + publishToMessageBus(`/user-status/${userId}`, { + description: userStatus, + emoji: userStatusEmoji, + }); + return helper.response({ success: true }); + }); + server.delete("/user-status.json", () => { + publishToMessageBus(`/user-status/${userId}`, null); + return helper.response({ success: true }); + }); + }); + + test("doesn't show the user status button on the menu by default", async function (assert) { + this.siteSettings.enable_user_status = false; + + await visit("/"); + await click(".header-dropdown-toggle.current-user"); + await click("#user-menu-button-profile"); + + assert.notOk(exists("li.set-user-status")); + }); + + test("shows the user status button on the menu when enabled in settings", async function (assert) { + this.siteSettings.enable_user_status = true; + + await visit("/"); + await click(".header-dropdown-toggle.current-user"); + await click("#user-menu-button-profile"); + + assert.ok(exists("li.set-user-status .btn"), "shows the button"); + assert.ok( + exists("li.set-user-status svg.d-icon-plus-circle"), + "shows the icon on the button" + ); + }); + + test("shows user status on the button", async function (assert) { + this.siteSettings.enable_user_status = true; + updateCurrentUser({ + status: { description: userStatus, emoji: userStatusEmoji }, + }); + + await visit("/"); + await click(".header-dropdown-toggle.current-user"); + await click("#user-menu-button-profile"); + + assert.equal( + query("li.set-user-status .item-label").textContent.trim(), + userStatus, + "shows user status description on the menu" + ); + + assert.equal( + query("li.set-user-status .emoji").alt, + `${userStatusEmoji}`, + "shows user status emoji on the menu" + ); + + assert.equal( + query(".header-dropdown-toggle .user-status-background img.emoji").alt, + `:${userStatusEmoji}:`, + "shows user status emoji on the user avatar in the header" + ); + }); + + test("user menu gets closed when the user status modal is opened", async function (assert) { + this.siteSettings.enable_user_status = true; + + await visit("/"); + await click(".header-dropdown-toggle.current-user"); + await click("#user-menu-button-profile"); + await click(".set-user-status button"); + + assert.notOk(exists(".user-menu")); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-test.js index 54711f0aff..e54642d5fe 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-test.js @@ -1,3 +1,4 @@ +import I18n from "I18n"; import EmberObject from "@ember/object"; import User from "discourse/models/user"; import selectKit from "discourse/tests/helpers/select-kit-helper"; @@ -6,10 +7,12 @@ import userFixtures from "discourse/tests/fixtures/user-fixtures"; import { acceptance, exists, + publishToMessageBus, query, queryAll, updateCurrentUser, } from "discourse/tests/helpers/qunit-helpers"; +import * as logout from "discourse/lib/logout"; import { click, currentRouteName, visit } from "@ember/test-helpers"; import { cloneJSON } from "discourse-common/lib/object"; import { test } from "qunit"; @@ -305,3 +308,27 @@ acceptance( }); } ); + +acceptance("User - Logout", function (needs) { + needs.user({ username: "eviltrout" }); + + test("Dialog works", async function (assert) { + sinon.stub(logout, "default"); + await visit("/u/eviltrout"); + await publishToMessageBus("/logout"); + + assert.ok(exists(".dialog-body")); + assert.ok( + !exists(".dialog-footer .btn-default"), + "no cancel button present" + ); + assert.strictEqual( + query(".dialog-footer .btn-primary").innerText, + I18n.t("home"), + "primary dialog button is present" + ); + + await click(".dialog-overlay"); + assert.ok(logout.default.called, "logout helper was called"); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/welcome-topic-banner-test.js b/app/assets/javascripts/discourse/tests/acceptance/welcome-topic-banner-test.js index 2e7ee79a01..273b85ecf0 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/welcome-topic-banner-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/welcome-topic-banner-test.js @@ -8,9 +8,9 @@ acceptance("Welcome Topic Banner", function (needs) { test("Navigation", async function (assert) { await visit("/"); - assert.ok(exists(".welcome-topic-banner"), "has the welcome topic banner"); + assert.ok(exists(".welcome-cta"), "has the welcome topic banner"); assert.ok( - exists("button.welcome-topic-cta"), + exists("button.welcome-cta__button"), "has the welcome topic edit button" ); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/wizard-test.js b/app/assets/javascripts/discourse/tests/acceptance/wizard-test.js index 51395f65cb..f3dbdb5e97 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/wizard-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/wizard-test.js @@ -14,6 +14,10 @@ acceptance("Wizard", function (needs) { test("Wizard starts", async function (assert) { await visit("/wizard"); assert.ok(exists(".wizard-container")); + assert.notOk( + exists(".d-header-wrap"), + "header is not rendered on wizard pages" + ); assert.strictEqual(currentRouteName(), "wizard.step"); }); @@ -58,6 +62,15 @@ acceptance("Wizard", function (needs) { "shows finish on an intermediate step" ); + await click(".wizard-container__button.finish"); + assert.strictEqual( + currentURL(), + "/latest", + "it should transition to the homepage" + ); + + await visit("/wizard/steps/styling"); + await click(".wizard-container__button.next"); assert.ok( exists(".wizard-container__text-input#company_name"), diff --git a/app/assets/javascripts/discourse/tests/active-plugins.js.erb b/app/assets/javascripts/discourse/tests/active-plugins.js.erb deleted file mode 100644 index 6b2958541e..0000000000 --- a/app/assets/javascripts/discourse/tests/active-plugins.js.erb +++ /dev/null @@ -1,11 +0,0 @@ -<% - DiscoursePluginRegistry.javascripts.each { |js| require_asset(js) } - DiscoursePluginRegistry.handlebars.each { |hb| require_asset(hb) } - DiscoursePluginRegistry.each_globbed_asset do |f| - if File.directory?(f) - depend_on(f) - else - require_asset(f) - end - end -%> diff --git a/app/assets/javascripts/discourse/tests/addons/truth-helpers/integration/helpers/includes-test.js b/app/assets/javascripts/discourse/tests/addons/truth-helpers/integration/helpers/includes-test.js new file mode 100644 index 0000000000..adf2000528 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/addons/truth-helpers/integration/helpers/includes-test.js @@ -0,0 +1,43 @@ +import { assert, module, test } from "qunit"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { render } from "@ember/test-helpers"; +import { hbs } from "ember-cli-htmlbars"; +import { exists } from "discourse/tests/helpers/qunit-helpers"; + +module("Addons | truth-helpers | Integration | includes", function (hooks) { + setupRenderingTest(hooks); + + test("when using an array", async function () { + this.foo = [1]; + this.bar = 1; + await render( + hbs`{{#if (includes foo bar)}}{{/if}}` + ); + + assert.ok(exists(".test"), "it returns true when element is found"); + + this.bar = 2; + await render( + hbs`{{#if (includes foo bar)}}{{/if}}` + ); + + assert.notOk(exists(".test"), "it returns false when element is not found"); + }); + + test("when using a string", async function () { + this.foo = "foo"; + this.bar = "f"; + await render( + hbs`{{#if (includes foo bar)}}{{/if}}` + ); + + assert.ok(exists(".test"), "it returns true when element is found"); + + this.bar = "b"; + await render( + hbs`{{#if (includes foo bar)}}{{/if}}` + ); + + assert.notOk(exists(".test"), "it returns false when element is not found"); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/core-tests.js b/app/assets/javascripts/discourse/tests/core-tests.js deleted file mode 100644 index 1890b65888..0000000000 --- a/app/assets/javascripts/discourse/tests/core-tests.js +++ /dev/null @@ -1,3 +0,0 @@ -//= require_tree ./acceptance -//= require_tree ./integration -//= require_tree ./unit diff --git a/app/assets/javascripts/discourse/tests/fixtures/drafts.js b/app/assets/javascripts/discourse/tests/fixtures/drafts.js index bfb3d3acea..96c0061fd9 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/drafts.js +++ b/app/assets/javascripts/discourse/tests/fixtures/drafts.js @@ -26,7 +26,7 @@ export default { draft_key: "topic_280", sequence: 0, draft_username: "eviltrout", - avatar_template: "/letter_avatar_proxy/v2/letter/p/a87d85/{size}.png", + avatar_template: "/user_avatar/localhost/eviltrout/{size}/2_1.png", data: '{"reply":"The last reply to this topic was 6 months ago. Your reply will bump the topic to the top of its list.","action":"reply","categoryId":8,"archetypeId":"regular","metaData":null,"composerTime":139499,"typingTime":6100}', topic_id: 280, username: "zogstrip", diff --git a/app/assets/javascripts/discourse/tests/fixtures/notification-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/notification-fixtures.js index a3ff25c5d8..4097c2de19 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/notification-fixtures.js +++ b/app/assets/javascripts/discourse/tests/fixtures/notification-fixtures.js @@ -10,6 +10,7 @@ export default { post_number: 1, topic_id: 130, slug: "lorem-ipsum-dolor-sit-amet", + fancy_title: "edited topic 443", data: { topic_title: "edited topic 443", display_username: "velesin", @@ -26,6 +27,7 @@ export default { post_number: 1, topic_id: 1234, slug: "a-slug", + fancy_title: "some title", data: { topic_title: "some title", display_username: "velesin" }, }, { diff --git a/app/assets/javascripts/discourse/tests/fixtures/session-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/session-fixtures.js index 08a365ecaa..d99b6ab825 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/session-fixtures.js +++ b/app/assets/javascripts/discourse/tests/fixtures/session-fixtures.js @@ -33,7 +33,21 @@ export default { timezone: "Australia/Brisbane", skip_new_user_tips: false, can_review: true, - ignored_users: [] + ignored_users: [], + groups: [ + { + id: 10, + automatic: true, + name: "trust_level_0", + display_name: "trust_level_0", + }, + { + id: 11, + automatic: true, + name: "trust_level_1", + display_name: "trust_level_1", + } + ] }, }, }; diff --git a/app/assets/javascripts/discourse/tests/fixtures/site-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/site-fixtures.js index 784178a11d..9c7475e196 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/site-fixtures.js +++ b/app/assets/javascripts/discourse/tests/fixtures/site-fixtures.js @@ -61,7 +61,7 @@ export default { { id: 3, name: "meta", - color: "aaa", + color: "aaaaaa", text_color: "FFFFFF", slug: "meta", topic_count: 122, diff --git a/app/assets/javascripts/discourse/tests/fixtures/topic.js b/app/assets/javascripts/discourse/tests/fixtures/topic.js index 5a5d220be2..fa37c17c5c 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/topic.js +++ b/app/assets/javascripts/discourse/tests/fixtures/topic.js @@ -5799,6 +5799,7 @@ export default { avatar_template: "/images/avatar.png", }, }, + tags: ["foo", "baz"], }, "/t/2481/1.json": { post_stream: { diff --git a/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js index 4ed74958a7..471f7c47fc 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js +++ b/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js @@ -2499,6 +2499,7 @@ export default { last_posted_at: null, last_seen_at: null, created_at: "2019-03-06T19:06:20.340Z", + can_delete_account: true, can_edit: true, can_edit_username: true, can_edit_email: true, diff --git a/app/assets/javascripts/discourse/tests/fixtures/user-menu.js b/app/assets/javascripts/discourse/tests/fixtures/user-menu.js index a96893ea66..a645cce16a 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/user-menu.js +++ b/app/assets/javascripts/discourse/tests/fixtures/user-menu.js @@ -136,52 +136,6 @@ export default { primary_group_id: null, }, ], - fancy_title: "BUG: Can not render emoji properly :confused:", - slug: "bug-can-not-render-emoji-properly", - posts_count: 1, - reply_count: 0, - highest_post_number: 2, - image_url: null, - created_at: "2019-07-26T01:29:24.008Z", - last_posted_at: "2019-07-26T01:29:24.177Z", - bumped: true, - bumped_at: "2019-07-26T01:29:24.177Z", - unseen: false, - last_read_post_number: 2, - unread_posts: 0, - pinned: false, - unpinned: null, - visible: true, - closed: false, - archived: false, - notification_level: 3, - bookmarked: false, - bookmarks: [], - liked: false, - views: 5, - like_count: 0, - has_summary: false, - archetype: "private_message", - last_poster_username: "mixtape", - category_id: null, - pinned_globally: false, - featured_link: null, - posters: [ - { - extras: "latest single", - description: "Original Poster, Most Recent Poster", - user_id: 13, - primary_group_id: null, - }, - ], - participants: [ - { - extras: "latest", - description: null, - user_id: 13, - primary_group_id: null, - }, - ], } ], } diff --git a/app/assets/javascripts/discourse/tests/helpers/component-test.js b/app/assets/javascripts/discourse/tests/helpers/component-test.js index c23b4f1542..4e79dd558a 100644 --- a/app/assets/javascripts/discourse/tests/helpers/component-test.js +++ b/app/assets/javascripts/discourse/tests/helpers/component-test.js @@ -7,7 +7,6 @@ import { autoLoadModules } from "discourse/initializers/auto-load-modules"; import QUnit, { test } from "qunit"; import { setupRenderingTest as emberSetupRenderingTest } from "ember-qunit"; import { currentSettings } from "discourse/tests/helpers/site-settings"; -import { testCleanup } from "discourse/tests/helpers/qunit-helpers"; import { injectServiceIntoService } from "discourse/pre-initializers/inject-discourse-objects"; export function setupRenderingTest(hooks) { @@ -16,11 +15,7 @@ export function setupRenderingTest(hooks) { hooks.beforeEach(function () { if (!hooks.usingDiscourseModule) { this.siteSettings = currentSettings(); - - if (!this.registry) { - this.registry = this.owner.__registry__; - } - + this.registry ||= this.owner.__registry__; this.container = this.owner; } @@ -30,6 +25,23 @@ export function setupRenderingTest(hooks) { const currentUser = User.create({ username: "eviltrout", timezone: "Australia/Brisbane", + name: "Robin Ward", + admin: false, + moderator: false, + groups: [ + { + id: 10, + automatic: true, + name: "trust_level_0", + display_name: "trust_level_0", + }, + { + id: 11, + automatic: true, + name: "trust_level_1", + display_name: "trust_level_1", + }, + ], }); this.currentUser = currentUser; this.owner.unregister("service:current-user"); @@ -60,12 +72,6 @@ export function setupRenderingTest(hooks) { $.fn.autocomplete = function () {}; }); - - if (!hooks.usingDiscourseModule) { - hooks.afterEach(function () { - testCleanup(this.container); - }); - } } export default function (name, hooks, opts) { diff --git a/app/assets/javascripts/discourse/tests/helpers/create-pretender.js b/app/assets/javascripts/discourse/tests/helpers/create-pretender.js index 40317640ee..faddd058ad 100644 --- a/app/assets/javascripts/discourse/tests/helpers/create-pretender.js +++ b/app/assets/javascripts/discourse/tests/helpers/create-pretender.js @@ -1,7 +1,6 @@ import Pretender from "pretender"; import User from "discourse/models/user"; import getURL from "discourse-common/lib/get-url"; -import { Promise } from "rsvp"; export function parsePostData(query) { const result = {}; @@ -506,14 +505,11 @@ export function applyDefaultHandlers(pretender) { pretender.put("/posts/:post_id", async (request) => { const data = parsePostData(request.requestBody); + if (data.post.raw === "this will 409") { return response(409, { errors: ["edit conflict"] }); - } else if (data.post.raw === "will return empty json") { - window.resolveLastPromise(); - return new Promise((resolve) => { - window.resolveLastPromise = resolve; - }).then(() => response(200, {})); } + data.post.id = request.params.post_id; data.post.version = 2; return response(200, data.post); @@ -674,6 +670,12 @@ export function applyDefaultHandlers(pretender) { }, ]; + if (request.queryParams.filter) { + store = store.filter((user) => + user.username.includes(request.queryParams.filter) + ); + } + const showEmails = request.queryParams.show_emails; if (showEmails === "false") { diff --git a/app/assets/javascripts/discourse/tests/helpers/notification-items-helper.js b/app/assets/javascripts/discourse/tests/helpers/notification-types-helper.js similarity index 85% rename from app/assets/javascripts/discourse/tests/helpers/notification-items-helper.js rename to app/assets/javascripts/discourse/tests/helpers/notification-types-helper.js index 4f05a666cb..5c9c10481e 100644 --- a/app/assets/javascripts/discourse/tests/helpers/notification-items-helper.js +++ b/app/assets/javascripts/discourse/tests/helpers/notification-types-helper.js @@ -1,4 +1,4 @@ -import { getRenderDirector } from "discourse/lib/notification-item"; +import { getRenderDirector } from "discourse/lib/notification-types-manager"; import sessionFixtures from "discourse/tests/fixtures/session-fixtures"; import User from "discourse/models/user"; import Site from "discourse/models/site"; diff --git a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js index 35660ee8c4..4de353d143 100644 --- a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js +++ b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js @@ -15,7 +15,6 @@ import { getApplication, getContext, settled } from "@ember/test-helpers"; import { getOwner } from "discourse-common/lib/get-owner"; import { run } from "@ember/runloop"; import { setupApplicationTest } from "ember-qunit"; -import { Promise } from "rsvp"; import Site from "discourse/models/site"; import User from "discourse/models/user"; import { _clearSnapshots } from "select-kit/components/composer-actions"; @@ -73,8 +72,10 @@ import { clearTagsHtmlCallbacks } from "discourse/lib/render-tags"; import { clearToolbarCallbacks } from "discourse/components/d-editor"; import { clearExtraHeaderIcons } from "discourse/widgets/header"; import { resetSidebarSection } from "discourse/lib/sidebar/custom-sections"; -import { resetNotificationTypeRenderers } from "discourse/lib/notification-item"; +import { resetNotificationTypeRenderers } from "discourse/lib/notification-types-manager"; import { resetUserMenuTabs } from "discourse/lib/user-menu/tab"; +import { reset as resetLinkLookup } from "discourse/lib/link-lookup"; +import { resetModelTransformers } from "discourse/lib/model-transformers"; export function currentUser() { return User.create(sessionFixtures["/session/current.json"].current_user); @@ -159,7 +160,6 @@ export function testCleanup(container, app) { }); } - localStorage.clear(); User.resetCurrent(); resetExtraClasses(); clearOutletCache(); @@ -206,6 +206,8 @@ export function testCleanup(container, app) { resetNotificationTypeRenderers(); clearExtraHeaderIcons(); resetUserMenuTabs(); + resetLinkLookup(); + resetModelTransformers(); } export function discourseModule(name, options) { @@ -223,8 +225,6 @@ export function discourseModule(name, options) { this.siteSettings = currentSettings(); }); - hooks.afterEach(() => testCleanup(this.container)); - this.getController = function (controllerName, properties) { let controller = this.container.lookup(`controller:${controllerName}`); controller.application = {}; @@ -252,7 +252,6 @@ export function discourseModule(name, options) { }, afterEach() { options?.afterEach?.call(this); - testCleanup(this.container); }, }); } @@ -452,15 +451,11 @@ QUnit.assert.containsInstance = function (collection, klass, message) { }; export async function selectDate(selector, date) { - return new Promise((resolve) => { - const elem = document.querySelector(selector); - elem.value = date; - const evt = new Event("input", { bubbles: true, cancelable: false }); - elem.dispatchEvent(evt); - elem.blur(); - - resolve(); - }); + const elem = document.querySelector(selector); + elem.value = date; + const evt = new Event("input", { bubbles: true, cancelable: false }); + elem.dispatchEvent(evt); + elem.blur(); } export function queryAll(selector, context) { @@ -495,10 +490,12 @@ export function exists(selector) { export async function publishToMessageBus(channelPath, ...args) { args = cloneJSON(args); - MessageBus.callbacks - .filterBy("channel", channelPath) - .forEach((c) => c.func(...args)); + const promises = MessageBus.callbacks + .filterBy("channel", channelPath) + .map((callback) => callback.func(...args)); + + await Promise.allSettled(promises); await settled(); } diff --git a/app/assets/javascripts/discourse/tests/helpers/reviewable-items-helper.js b/app/assets/javascripts/discourse/tests/helpers/reviewable-types-helper.js similarity index 85% rename from app/assets/javascripts/discourse/tests/helpers/reviewable-items-helper.js rename to app/assets/javascripts/discourse/tests/helpers/reviewable-types-helper.js index 4a0c30f1ce..5a0b2fc528 100644 --- a/app/assets/javascripts/discourse/tests/helpers/reviewable-items-helper.js +++ b/app/assets/javascripts/discourse/tests/helpers/reviewable-types-helper.js @@ -1,4 +1,4 @@ -import { getRenderDirector } from "discourse/lib/reviewable-item"; +import { getRenderDirector } from "discourse/lib/reviewable-types-manager"; import sessionFixtures from "discourse/tests/fixtures/session-fixtures"; import User from "discourse/models/user"; import Site from "discourse/models/site"; diff --git a/app/assets/javascripts/discourse/tests/helpers/site-settings.js b/app/assets/javascripts/discourse/tests/helpers/site-settings.js index 6201942429..7909b030a2 100644 --- a/app/assets/javascripts/discourse/tests/helpers/site-settings.js +++ b/app/assets/javascripts/discourse/tests/helpers/site-settings.js @@ -13,6 +13,7 @@ const ORIGINAL_SETTINGS = { post_menu: "like|share|flag|edit|bookmark|delete|admin|reply", post_menu_hidden_items: "flag|bookmark|edit|delete|admin", share_links: "twitter|facebook|email", + allow_username_in_share_links: true, category_colors: "BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|27AA5B|B3B5B4|E45735", enable_mobile_theme: true, @@ -94,10 +95,12 @@ const ORIGINAL_SETTINGS = { desktop_category_page_style: "categories_and_latest_topics", enable_mentions: true, enable_personal_messages: true, + personal_message_enabled_groups: "11", // TL1 group unicode_usernames: false, - secure_media: false, + secure_uploads: false, external_emoji_url: "", remove_muted_tags_from_latest: "always", + enable_group_directory: true, }; let siteSettings = Object.assign({}, ORIGINAL_SETTINGS); diff --git a/app/assets/javascripts/discourse/tests/helpers/widget-test.js b/app/assets/javascripts/discourse/tests/helpers/widget-test.js deleted file mode 100644 index 93f16c38a3..0000000000 --- a/app/assets/javascripts/discourse/tests/helpers/widget-test.js +++ /dev/null @@ -1,30 +0,0 @@ -import { addPretenderCallback } from "discourse/tests/helpers/qunit-helpers"; -import componentTest from "discourse/tests/helpers/component-test"; -import { moduleForComponent } from "ember-qunit"; -import { warn } from "@ember/debug"; -import deprecated from "discourse-common/lib/deprecated"; - -export function moduleForWidget(name, options = {}) { - warn( - "moduleForWidget will not work in the Ember CLI environment. Please upgrade your tests.", - { id: "module-for-widget" } - ); - return; - - let fullName = `widget:${name}`; - addPretenderCallback(fullName, options.pretend); - - moduleForComponent( - name, - fullName, - Object.assign( - { integration: true }, - { beforeEach: options.beforeEach, afterEach: options.afterEach } - ) - ); -} - -export function widgetTest(name, opts) { - deprecated("Use `componentTest` instead of `widgetTest`"); - return componentTest(name, opts); -} diff --git a/app/assets/javascripts/discourse/tests/index.html b/app/assets/javascripts/discourse/tests/index.html index e8c2e10b16..3277f0b1cc 100644 --- a/app/assets/javascripts/discourse/tests/index.html +++ b/app/assets/javascripts/discourse/tests/index.html @@ -47,18 +47,25 @@ - + - {{content-for "test-plugin-js"}} - - - {{content-for "test-plugin-tests-js"}} - - - {{content-for "body-footer"}} {{content-for "test-body-footer"}} + + + + + + + + diff --git a/app/assets/javascripts/discourse/tests/integration/components/d-document-test.js b/app/assets/javascripts/discourse/tests/integration/components/d-document-test.js new file mode 100644 index 0000000000..361c55b570 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/d-document-test.js @@ -0,0 +1,77 @@ +import { module, test } from "qunit"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { render } from "@ember/test-helpers"; +import { hbs } from "ember-cli-htmlbars"; + +function getTitleCount() { + const match = document.title.match(/^\((\d+)\)\s/); + if (match) { + return parseInt(match[1], 10); + } else { + return null; + } +} + +function triggerTitleUpdate(appEvents) { + appEvents.trigger("notifications:changed", { forced: true }); +} + +module("Integration | Component | d-document", function (hooks) { + setupRenderingTest(hooks); + + test("when experimental user menu is enabled", async function (assert) { + const titleBefore = document.title; + try { + this.currentUser.redesigned_user_menu_enabled = true; + this.currentUser.title_count_mode = "notifications"; + await render(hbs``); + assert.strictEqual( + getTitleCount(), + null, + "title doesn't have a count initially" + ); + + this.currentUser.unread_high_priority_notifications = 1; + this.currentUser.unread_notifications = 2; + this.currentUser.all_unread_notifications_count = 4; + this.currentUser.unseen_reviewable_count = 8; + triggerTitleUpdate(this.currentUser.appEvents); + + assert.strictEqual( + getTitleCount(), + 12, + "count in the title is the sum of all_unread_notifications_count and unseen_reviewable_count" + ); + } finally { + document.title = titleBefore; + } + }); + + test("when experimental user menu is disabled", async function (assert) { + const titleBefore = document.title; + try { + this.currentUser.redesigned_user_menu_enabled = false; + this.currentUser.title_count_mode = "notifications"; + await render(hbs``); + assert.strictEqual( + getTitleCount(), + null, + "title doesn't have a count initially" + ); + + this.currentUser.unread_high_priority_notifications = 1; + this.currentUser.unread_notifications = 2; + this.currentUser.all_unread_notifications_count = 4; + this.currentUser.unseen_reviewable_count = 8; + triggerTitleUpdate(this.currentUser.appEvents); + + assert.strictEqual( + getTitleCount(), + 3, + "count in the title is the sum of unread_notifications and unread_high_priority_notifications" + ); + } finally { + document.title = titleBefore; + } + }); +}); diff --git a/app/assets/javascripts/discourse/tests/integration/components/d-editor-test.js b/app/assets/javascripts/discourse/tests/integration/components/d-editor-test.js index 3720f70b7f..3a6fbdbf8f 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/d-editor-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/d-editor-test.js @@ -6,6 +6,7 @@ import { exists, paste, query, + queryAll, } from "discourse/tests/helpers/qunit-helpers"; import { getTextareaSelection, @@ -705,6 +706,18 @@ third line` ); }); + test("toolbar buttons tabindex", async function (assert) { + await render(hbs``); + const buttons = queryAll(".d-editor-button-bar .btn"); + + assert.strictEqual( + buttons[0].getAttribute("tabindex"), + "0", + "it makes the first button focusable" + ); + assert.strictEqual(buttons[1].getAttribute("tabindex"), "-1"); + }); + testCase("replace-text event by default", async function (assert) { this.set("value", "red green blue"); diff --git a/app/assets/javascripts/discourse/tests/integration/components/d-popover-test.js b/app/assets/javascripts/discourse/tests/integration/components/d-popover-test.js index a53a9b49d5..804a24bdcf 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/d-popover-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/d-popover-test.js @@ -3,14 +3,36 @@ import { setupRenderingTest } from "discourse/tests/helpers/component-test"; import { click, render, triggerKeyEvent } from "@ember/test-helpers"; import { exists, query } from "discourse/tests/helpers/qunit-helpers"; import { hbs } from "ember-cli-htmlbars"; -import { showPopover } from "discourse/lib/d-popover"; +import { + hidePopover, + isPopoverShown, + showPopover, +} from "discourse/lib/d-popover"; module("Integration | Component | d-popover", function (hooks) { setupRenderingTest(hooks); test("show/hide popover from lib", async function (assert) { + let showCallCount = 0; + let hideCallCount = 0; + this.set("onButtonClick", (_, event) => { - showPopover(event, { content: "test", trigger: "click", duration: 0 }); + if (isPopoverShown(event)) { + hidePopover(event); + hideCallCount++; + } else { + // Note: we need to override the default `trigger` and `hideOnClick` + // settings in order to completely control showing / hiding the tip + // via showPopover / hidePopover. Otherwise tippy's event listeners + // will compete with those created in this test (on DButton). + showPopover(event, { + content: "test", + duration: 0, + trigger: "manual", + hideOnClick: false, + }); + showCallCount++; + } }); await render(hbs` @@ -30,7 +52,11 @@ module("Integration | Component | d-popover", function (hooks) { ); await click(".btn"); + assert.notOk(document.querySelector("div[data-tippy-root]")); + + assert.strictEqual(showCallCount, 1, "showPopover was invoked once"); + assert.strictEqual(hideCallCount, 1, "hidePopover was invoked once"); }); test("show/hide popover from component", async function (assert) { diff --git a/app/assets/javascripts/discourse/tests/integration/components/date-time-input-range-test.js b/app/assets/javascripts/discourse/tests/integration/components/date-time-input-range-test.js index b08a59bb2d..d668975eed 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/date-time-input-range-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/date-time-input-range-test.js @@ -21,7 +21,8 @@ function toTimeInput() { return query(".to.d-date-time-input .d-time-input .combo-box-header"); } -const DEFAULT_DATE_TIME = moment("2019-01-29 14:45"); +const DEFAULT_DATE_TIME_STRING = "2019-01-29 14:45"; +const DEFAULT_DATE_TIME = moment(DEFAULT_DATE_TIME_STRING); module("Integration | Component | date-time-input-range", function (hooks) { setupRenderingTest(hooks); @@ -56,7 +57,10 @@ module("Integration | Component | date-time-input-range", function (hooks) { test("timezone support", async function (assert) { this.setProperties({ - state: { from: moment.tz(DEFAULT_DATE_TIME, "Europe/Paris"), to: null }, + state: { + from: moment.tz(DEFAULT_DATE_TIME_STRING, "Europe/Paris"), + to: null, + }, }); await render( @@ -64,7 +68,7 @@ module("Integration | Component | date-time-input-range", function (hooks) { ); assert.strictEqual(fromDateInput().value, "2019-01-29"); - assert.strictEqual(fromTimeInput().dataset.name, "15:45"); + assert.strictEqual(fromTimeInput().dataset.name, "14:45"); assert.strictEqual(toDateInput().value, ""); assert.strictEqual(toTimeInput().dataset.name, "--:--"); diff --git a/app/assets/javascripts/discourse/tests/integration/components/dialog-holder-test.js b/app/assets/javascripts/discourse/tests/integration/components/dialog-holder-test.js new file mode 100644 index 0000000000..c83889e20f --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/dialog-holder-test.js @@ -0,0 +1,367 @@ +import I18n from "I18n"; +import { module, test } from "qunit"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { click, render, settled, triggerKeyEvent } from "@ember/test-helpers"; +import { hbs } from "ember-cli-htmlbars"; +import { query } from "discourse/tests/helpers/qunit-helpers"; + +module("Integration | Component | dialog-holder", function (hooks) { + setupRenderingTest(hooks); + + hooks.beforeEach(function () { + this.dialog = this.container.lookup("service:dialog"); + }); + + test("basics", async function (assert) { + await render(hbs``); + assert.ok(query("#dialog-holder"), "element is in DOM"); + assert.strictEqual( + query("#dialog-holder").innerText.trim(), + "", + "dialog is empty by default" + ); + + this.dialog.alert({ + message: "This is an error", + }); + await settled(); + + assert.ok( + query(".dialog-overlay").offsetWidth > 0, + true, + "overlay is visible" + ); + assert.strictEqual( + query(".dialog-body").innerText.trim(), + "This is an error", + "dialog has error message" + ); + + // dismiss by clicking on overlay + await click(".dialog-overlay"); + + assert.ok(query("#dialog-holder"), "element is still in DOM"); + assert.strictEqual( + query(".dialog-overlay").offsetWidth, + 0, + "overlay is not visible" + ); + assert.strictEqual( + query("#dialog-holder").innerText.trim(), + "", + "dialog is empty" + ); + }); + + test("basics - dismiss using Esc", async function (assert) { + let cancelCallbackCalled = false; + await render(hbs``); + assert.ok(query("#dialog-holder"), "element is in DOM"); + assert.strictEqual( + query("#dialog-holder").innerText.trim(), + "", + "dialog is empty by default" + ); + + this.dialog.alert({ + message: "This is an error", + didCancel: () => { + cancelCallbackCalled = true; + }, + }); + await settled(); + + assert.ok( + query(".dialog-overlay").offsetWidth > 0, + true, + "overlay is visible" + ); + assert.strictEqual( + query(".dialog-body").innerText.trim(), + "This is an error", + "dialog has error message" + ); + + // dismiss by pressing Esc + await triggerKeyEvent(document, "keydown", "Escape"); + + assert.ok(cancelCallbackCalled, "cancel callback called"); + assert.ok(query("#dialog-holder"), "element is still in DOM"); + + assert.strictEqual( + query(".dialog-overlay").offsetWidth, + 0, + "overlay is not visible" + ); + + assert.strictEqual( + query("#dialog-holder").innerText.trim(), + "", + "dialog is empty" + ); + }); + + test("alert with title", async function (assert) { + await render(hbs``); + + this.dialog.alert({ + message: "This is a note.", + title: "And this is a title", + }); + + await settled(); + + assert.strictEqual( + query("#dialog-title").innerText.trim(), + "And this is a title", + "dialog has title" + ); + + assert.ok( + query("#dialog-holder[aria-labelledby='dialog-title']"), + "aria-labelledby is correctly set" + ); + + assert.ok(query(".dialog-close"), "close button present"); + assert.ok(query("#dialog-holder"), "element is still in DOM"); + assert.strictEqual( + query(".dialog-body").innerText.trim(), + "This is a note.", + "dialog message is shown" + ); + + await click(".dialog-close"); + + assert.ok(query("#dialog-holder"), "element is still in DOM"); + assert.strictEqual( + query(".dialog-overlay").offsetWidth, + 0, + "overlay is not visible" + ); + assert.strictEqual( + query("#dialog-holder").innerText.trim(), + "", + "dialog is empty" + ); + }); + + test("alert with a string parameter", async function (assert) { + await render(hbs``); + + this.dialog.alert("An alert message"); + await settled(); + + assert.strictEqual( + query(".dialog-body").innerText.trim(), + "An alert message", + "dialog message is shown" + ); + }); + + test("confirm", async function (assert) { + let confirmCallbackCalled = false; + let cancelCallbackCalled = false; + await render(hbs``); + + this.dialog.confirm({ + message: "A confirm message", + didConfirm: () => { + confirmCallbackCalled = true; + }, + didCancel: () => { + cancelCallbackCalled = true; + }, + }); + await settled(); + + assert.strictEqual( + query(".dialog-body").innerText.trim(), + "A confirm message", + "dialog message is shown" + ); + + assert.strictEqual( + query(".dialog-footer .btn-primary").innerText.trim(), + I18n.t("ok_value"), + "dialog primary button says Ok" + ); + + assert.strictEqual( + query(".dialog-footer .btn-default").innerText.trim(), + I18n.t("cancel_value"), + "dialog second button is present and says No" + ); + + await click(".dialog-footer .btn-primary"); + + assert.ok(confirmCallbackCalled, "confirm callback called"); + assert.notOk(cancelCallbackCalled, "cancel callback NOT called"); + + assert.strictEqual( + query("#dialog-holder").innerText.trim(), + "", + "dialog is empty" + ); + }); + + test("cancel callback", async function (assert) { + let confirmCallbackCalled = false; + let cancelCallbackCalled = false; + + await render(hbs``); + + this.dialog.confirm({ + message: "A confirm message", + didConfirm: () => { + confirmCallbackCalled = true; + }, + didCancel: () => { + cancelCallbackCalled = true; + }, + }); + await settled(); + + assert.strictEqual( + query(".dialog-body").innerText.trim(), + "A confirm message", + "dialog message is shown" + ); + + await click(".dialog-footer .btn-default"); + assert.notOk(confirmCallbackCalled, "confirm callback NOT called"); + assert.ok(cancelCallbackCalled, "cancel callback called"); + + assert.strictEqual( + query("#dialog-holder").innerText.trim(), + "", + "dialog has been dismissed" + ); + }); + + test("yes/no confirm", async function (assert) { + await render(hbs``); + + this.dialog.yesNoConfirm({ message: "A yes/no confirm message" }); + await settled(); + + assert.strictEqual( + query(".dialog-body").innerText.trim(), + "A yes/no confirm message", + "dialog message is shown" + ); + + assert.strictEqual( + query(".dialog-footer .btn-primary").innerText.trim(), + I18n.t("yes_value"), + "dialog primary button says Yes" + ); + + assert.strictEqual( + query(".dialog-footer .btn-default").innerText.trim(), + I18n.t("no_value"), + "dialog second button is present and says No" + ); + }); + + test("alert with custom buttons", async function (assert) { + let customCallbackTriggered = false; + await render(hbs``); + + this.dialog.alert({ + message: "An alert with custom buttons", + buttons: [ + { + icon: "cog", + label: "Danger ahead", + class: "btn-danger", + action: () => { + return new Promise((resolve) => { + customCallbackTriggered = true; + return resolve(); + }); + }, + }, + ], + }); + await settled(); + + assert.strictEqual( + query(".dialog-body").innerText.trim(), + "An alert with custom buttons", + "dialog message is shown" + ); + + assert.strictEqual( + query(".dialog-footer .btn-danger").innerText.trim(), + "Danger ahead", + "dialog custom button is present" + ); + + assert.notOk( + query(".dialog-footer .btn-primary"), + "default confirm button is not present" + ); + assert.notOk( + query(".dialog-footer .btn-default"), + "default cancel button is not present" + ); + + await click(".dialog-footer .btn-danger"); + assert.ok(customCallbackTriggered, "custom action was triggered"); + + assert.strictEqual( + query("#dialog-holder").innerText.trim(), + "", + "dialog has been dismissed" + ); + }); + + test("alert with custom classes", async function (assert) { + await render(hbs``); + + this.dialog.alert({ + message: "An alert with custom classes", + class: "dialog-special dialog-super", + }); + await settled(); + + assert.strictEqual( + query(".dialog-body").innerText.trim(), + "An alert with custom classes", + "dialog message is shown" + ); + + assert.ok( + query("#dialog-holder.dialog-special.dialog-super"), + "additional classes are present" + ); + + await click(".dialog-footer .btn-primary"); + + assert.notOk( + query("#dialog-holder.dialog-special"), + "additional class removed on dismissal" + ); + + assert.notOk( + query("#dialog-holder.dialog-super"), + "additional class removed on dismissal" + ); + }); + + test("notice", async function (assert) { + await render(hbs``); + + this.dialog.notice("Noted!"); + await settled(); + + assert.strictEqual( + query(".dialog-body").innerText.trim(), + "Noted!", + "message is shown" + ); + + assert.notOk(query(".dialog-footer"), "no footer"); + assert.notOk(query(".dialog-header"), "no header"); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/integration/components/highlighted-code-test.js b/app/assets/javascripts/discourse/tests/integration/components/highlighted-code-test.js index 112bb8c79b..4e15f8517d 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/highlighted-code-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/highlighted-code-test.js @@ -17,7 +17,7 @@ module("Integration | Component | highlighted-code", function (hooks) { await render(hbs``); assert.strictEqual( - query("code.ruby.hljs .hljs-function .hljs-keyword").innerText.trim(), + query("code.language-ruby.hljs .hljs-keyword").innerText.trim(), "def" ); }); diff --git a/app/assets/javascripts/discourse/tests/integration/components/select-kit/email-group-user-chooser-test.js b/app/assets/javascripts/discourse/tests/integration/components/select-kit/email-group-user-chooser-test.js index 127b6c8d57..386d5f1efc 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/select-kit/email-group-user-chooser-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/select-kit/email-group-user-chooser-test.js @@ -1,9 +1,10 @@ import { module, test } from "qunit"; import { setupRenderingTest } from "discourse/tests/helpers/component-test"; -import { render } from "@ember/test-helpers"; +import { fillIn, render } from "@ember/test-helpers"; import { hbs } from "ember-cli-htmlbars"; import selectKit from "discourse/tests/helpers/select-kit-helper"; -import { paste, query } from "discourse/tests/helpers/qunit-helpers"; +import { exists, paste, query } from "discourse/tests/helpers/qunit-helpers"; +import pretender, { response } from "../../../helpers/create-pretender"; module( "Integration | Component | select-kit/email-group-user-chooser", @@ -22,5 +23,62 @@ module( assert.equal(this.subject.header().value(), "foo,bar"); }); + + test("doesn't show user status by default", async function (assert) { + pretender.get("/u/search/users", () => + response({ + users: [ + { + username: "test-user", + status: { + description: "off to dentist", + emoji: "tooth", + }, + }, + ], + }) + ); + + await render(hbs``); + await this.subject.expand(); + await fillIn(".filter-input", "test-user"); + + assert.notOk(exists(".user-status-message")); + }); + + test("shows user status if enabled", async function (assert) { + const status = { + description: "off to dentist", + emoji: "tooth", + }; + pretender.get("/u/search/users", () => + response({ + users: [ + { + username: "test-user", + status, + }, + ], + }) + ); + + await render(hbs``); + await this.subject.expand(); + await fillIn(".filter-input", "test-user"); + + assert.ok(exists(".user-status-message"), "user status is rendered"); + assert.equal( + query(".user-status-message .emoji").alt, + status.emoji, + "status emoji is correct" + ); + assert.equal( + query( + ".user-status-message .user-status-message-description" + ).innerText.trim(), + status.description, + "status description is correct" + ); + }); } ); diff --git a/app/assets/javascripts/discourse/tests/integration/components/select-kit/mini-tag-chooser-test.js b/app/assets/javascripts/discourse/tests/integration/components/select-kit/mini-tag-chooser-test.js index c41aa7686a..92a50d0e57 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/select-kit/mini-tag-chooser-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/select-kit/mini-tag-chooser-test.js @@ -125,5 +125,26 @@ module( "it forces the max length of the tag" ); }); + + test("values in hiddenFromPreview will not display in preview", async function (assert) { + this.set("value", ["foo", "bar"]); + this.set("hiddenValues", ["foo"]); + + await render( + hbs`` + ); + assert.strictEqual( + query(".formatted-selection").textContent.trim(), + "bar" + ); + + await this.subject.expand(); + assert.deepEqual( + [...queryAll(".selected-content .selected-choice")].map((el) => + el.textContent.trim() + ), + ["bar"] + ); + }); } ); diff --git a/app/assets/javascripts/discourse/tests/integration/components/sidebar/section-link-test.js b/app/assets/javascripts/discourse/tests/integration/components/sidebar/section-link-test.js new file mode 100644 index 0000000000..1267cff396 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/sidebar/section-link-test.js @@ -0,0 +1,35 @@ +import { module, test } from "qunit"; + +import { hbs } from "ember-cli-htmlbars"; +import { render } from "@ember/test-helpers"; + +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { query } from "discourse/tests/helpers/qunit-helpers"; + +module("Integration | Component | sidebar | section-link", function (hooks) { + setupRenderingTest(hooks); + + test("default class attribute for link", async function (assert) { + const template = hbs``; + + await render(template); + + assert.strictEqual( + query("a").className, + "sidebar-section-link sidebar-section-link-test sidebar-row ember-view", + "has the right class attribute for the link" + ); + }); + + test("custom class attribute for link", async function (assert) { + const template = hbs``; + + await render(template); + + assert.strictEqual( + query("a").className, + "sidebar-section-link sidebar-section-link-test sidebar-row 123 abc ember-view", + "has the right class attribute for the link" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/integration/components/site-header-test.js b/app/assets/javascripts/discourse/tests/integration/components/site-header-test.js index 26e767d981..07f7d52da4 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/site-header-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/site-header-test.js @@ -1,6 +1,12 @@ import { module, test } from "qunit"; import { setupRenderingTest } from "discourse/tests/helpers/component-test"; -import { click, render, settled, waitUntil } from "@ember/test-helpers"; +import { + click, + render, + settled, + triggerKeyEvent, + waitUntil, +} from "@ember/test-helpers"; import { count, exists, query } from "discourse/tests/helpers/qunit-helpers"; import pretender, { response } from "discourse/tests/helpers/create-pretender"; import { hbs } from "ember-cli-htmlbars"; @@ -135,4 +141,51 @@ module("Integration | Component | site-header", function (hooks) { await waitUntil(() => getProperty() === "60px", { timeout: 100 }); assert.strictEqual(getProperty(), "60px"); }); + + test("arrow up/down keys move focus between the tabs", async function (assert) { + this.currentUser.set("redesigned_user_menu_enabled", true); + await render(hbs``); + await click(".header-dropdown-toggle.current-user"); + let activeTab = query(".menu-tabs-container .btn.active"); + assert.strictEqual(activeTab.id, "user-menu-button-all-notifications"); + + await triggerKeyEvent(document, "keydown", "ArrowDown"); + let focusedTab = document.activeElement; + assert.strictEqual( + focusedTab.id, + "user-menu-button-replies", + "pressing the down arrow key moves focus to the next tab towards the bottom" + ); + + await triggerKeyEvent(document, "keydown", "ArrowDown"); + await triggerKeyEvent(document, "keydown", "ArrowDown"); + await triggerKeyEvent(document, "keydown", "ArrowDown"); + await triggerKeyEvent(document, "keydown", "ArrowDown"); + await triggerKeyEvent(document, "keydown", "ArrowDown"); + await triggerKeyEvent(document, "keydown", "ArrowDown"); + await triggerKeyEvent(document, "keydown", "ArrowDown"); + + focusedTab = document.activeElement; + assert.strictEqual( + focusedTab.id, + "user-menu-button-profile", + "the down arrow key can move the focus to the bottom tabs" + ); + + await triggerKeyEvent(document, "keydown", "ArrowDown"); + focusedTab = document.activeElement; + assert.strictEqual( + focusedTab.id, + "user-menu-button-all-notifications", + "the focus moves back to the top after reaching the bottom" + ); + + await triggerKeyEvent(document, "keydown", "ArrowUp"); + focusedTab = document.activeElement; + assert.strictEqual( + focusedTab.id, + "user-menu-button-profile", + "the up arrow key moves the focus in the opposite direction" + ); + }); }); diff --git a/app/assets/javascripts/discourse/tests/integration/components/time-shortcut-picker-test.js b/app/assets/javascripts/discourse/tests/integration/components/time-shortcut-picker-test.js index d47c98c971..d1ecae1de2 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/time-shortcut-picker-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/time-shortcut-picker-test.js @@ -116,11 +116,18 @@ module("Integration | Component | time-shortcut-picker", function (hooks) { ); }); - test("defaults to 08:00 for custom time", async function (assert) { + test("default custom date time is in one hour from now", async function (assert) { + this.clock = fakeTime( + "2100-12-11T17:00:00", + this.currentUser.timezone, + true + ); + await render(hbs``); await click("#tap_tile_custom"); - assert.strictEqual(query("#custom-time").value, "08:00"); + assert.strictEqual(query("#custom-date > input").value, "2100-12-11"); + assert.strictEqual(query("#custom-time").value, "18:00"); }); test("shows 'Next Monday' instead of 'Monday' on Sundays", async function (assert) { diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-menu/bookmark-item-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-menu/bookmark-item-test.js deleted file mode 100644 index 8a6d98c2df..0000000000 --- a/app/assets/javascripts/discourse/tests/integration/components/user-menu/bookmark-item-test.js +++ /dev/null @@ -1,84 +0,0 @@ -import { module, test } from "qunit"; -import { setupRenderingTest } from "discourse/tests/helpers/component-test"; -import { query } from "discourse/tests/helpers/qunit-helpers"; -import { render } from "@ember/test-helpers"; -import { deepMerge } from "discourse-common/lib/object"; -import { hbs } from "ember-cli-htmlbars"; - -function getBookmark(overrides = {}) { - return deepMerge( - { - id: 6, - created_at: "2022-08-05T06:09:39.559Z", - updated_at: "2022-08-05T06:11:27.246Z", - name: "", - reminder_at: "2022-08-05T06:10:42.223Z", - reminder_at_ics_start: "20220805T061042Z", - reminder_at_ics_end: "20220805T071042Z", - pinned: false, - title: "Test poll topic hello world", - fancy_title: "Test poll topic hello world", - excerpt: "poll", - bookmarkable_id: 1009, - bookmarkable_type: "Post", - bookmarkable_url: "http://localhost:4200/t/this-bookmarkable-url/227/1", - tags: [], - tags_descriptions: {}, - truncated: true, - topic_id: 227, - linked_post_number: 1, - deleted: false, - hidden: false, - category_id: 1, - closed: false, - archived: false, - archetype: "regular", - highest_post_number: 45, - last_read_post_number: 31, - bumped_at: "2022-04-21T15:14:37.359Z", - slug: "test-poll-topic-hello-world", - user: { - id: 1, - username: "somebody", - name: "Mr. Somebody", - avatar_template: "/letter_avatar_proxy/v4/letter/o/f05b48/{size}.png", - }, - }, - overrides - ); -} - -module("Integration | Component | user-menu | bookmark-item", function (hooks) { - setupRenderingTest(hooks); - - const template = hbs``; - - test("uses bookmarkable_url for the href", async function (assert) { - this.set("bookmark", getBookmark()); - await render(template); - assert.ok( - query("li.bookmark a").href.endsWith("/t/this-bookmarkable-url/227/1") - ); - }); - - test("item label is the bookmarked post author", async function (assert) { - this.set( - "bookmark", - getBookmark({ user: { username: "bookmarkPostAuthor" } }) - ); - await render(template); - assert.strictEqual( - query("li.bookmark .item-label").textContent.trim(), - "bookmarkPostAuthor" - ); - }); - - test("item description is the bookmark title", async function (assert) { - this.set("bookmark", getBookmark({ title: "Custom bookmark title" })); - await render(template); - assert.strictEqual( - query("li.bookmark .item-description").textContent.trim(), - "Custom bookmark title" - ); - }); -}); diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-menu/bookmarks-list-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-menu/bookmarks-list-test.js index cecb3ed696..f66752630f 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/user-menu/bookmarks-list-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/user-menu/bookmarks-list-test.js @@ -42,7 +42,7 @@ module( }); test("dismiss button", async function (assert) { - this.currentUser.set("grouped_unread_high_priority_notifications", { + this.currentUser.set("grouped_unread_notifications", { [NOTIFICATION_TYPES.bookmark_reminder]: 72, }); await render(template); @@ -57,7 +57,7 @@ module( "dismiss button has a title" ); - this.currentUser.set("grouped_unread_high_priority_notifications", {}); + this.currentUser.set("grouped_unread_notifications", {}); await settled(); assert.notOk( diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-menu/menu-item-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-menu/menu-item-test.js new file mode 100644 index 0000000000..ddb768905d --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/user-menu/menu-item-test.js @@ -0,0 +1,615 @@ +import { module, test } from "qunit"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { exists, query } from "discourse/tests/helpers/qunit-helpers"; +import { render, settled } from "@ember/test-helpers"; +import { cloneJSON, deepMerge } from "discourse-common/lib/object"; +import { NOTIFICATION_TYPES } from "discourse/tests/fixtures/concerns/notification-types"; +import Notification from "discourse/models/notification"; +import UserMenuReviewable from "discourse/models/user-menu-reviewable"; +import { hbs } from "ember-cli-htmlbars"; +import { withPluginApi } from "discourse/lib/plugin-api"; +import UserMenuNotificationItem from "discourse/lib/user-menu/notification-item"; +import UserMenuMessageItem from "discourse/lib/user-menu/message-item"; +import UserMenuBookmarkItem from "discourse/lib/user-menu/bookmark-item"; +import UserMenuReviewableItem from "discourse/lib/user-menu/reviewable-item"; +import PrivateMessagesFixture from "discourse/tests/fixtures/private-messages-fixtures"; +import I18n from "I18n"; + +function getNotification(currentUser, siteSettings, site, overrides = {}) { + const notification = Notification.create( + deepMerge( + { + id: 11, + user_id: 1, + notification_type: NOTIFICATION_TYPES.mentioned, + read: false, + high_priority: false, + created_at: "2022-07-01T06:00:32.173Z", + post_number: 113, + topic_id: 449, + fancy_title: "This is fancy title <a>!", + slug: "this-is-fancy-title", + data: { + topic_title: "this is title before it becomes fancy !", + display_username: "osama", + original_post_id: 1, + original_post_type: 1, + original_username: "velesin", + }, + }, + overrides + ) + ); + return new UserMenuNotificationItem({ + notification, + currentUser, + siteSettings, + site, + }); +} + +module( + "Integration | Component | user-menu | menu-item | with notification items", + function (hooks) { + setupRenderingTest(hooks); + + const template = hbs``; + + test("pushes `read` to the classList if the notification is read and `unread` if it isn't", async function (assert) { + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site) + ); + this.item.notification.read = false; + await render(template); + assert.notOk(exists("li.read")); + assert.ok(exists("li.unread")); + + this.item.notification.read = true; + await settled(); + + assert.ok( + exists("li.read"), + "the item re-renders when the read property is updated" + ); + assert.notOk( + exists("li.unread"), + "the item re-renders when the read property is updated" + ); + }); + + test("pushes the notification type name to the classList", async function (assert) { + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site) + ); + await render(template); + let item = query("li"); + assert.ok(item.classList.contains("mentioned")); + + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site, { + notification_type: NOTIFICATION_TYPES.private_message, + }) + ); + await settled(); + + assert.ok( + exists("li.private-message"), + "replaces underscores in type name with dashes" + ); + }); + + test("pushes is-warning to the classList if the notification originates from a warning PM", async function (assert) { + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site, { + is_warning: true, + }) + ); + await render(template); + assert.ok(exists("li.is-warning")); + }); + + test("doesn't push is-warning to the classList if the notification doesn't originate from a warning PM", async function (assert) { + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site) + ); + await render(template); + assert.ok(!exists("li.is-warning")); + assert.ok(exists("li")); + }); + + test("the item's href links to the topic that the notification originates from", async function (assert) { + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site) + ); + await render(template); + const link = query("li a"); + assert.ok(link.href.endsWith("/t/this-is-fancy-title/449/113")); + }); + + test("the item's href links to the group messages if the notification is for a group messages", async function (assert) { + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site, { + topic_id: null, + post_number: null, + slug: null, + data: { + group_id: 33, + group_name: "grouperss", + username: "ossaama", + }, + }) + ); + await render(template); + const link = query("li a"); + assert.ok(link.href.endsWith("/u/ossaama/messages/grouperss")); + }); + + test("the item's link has a title for accessibility", async function (assert) { + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site) + ); + await render(template); + const link = query("li a"); + assert.strictEqual(link.title, I18n.t("notifications.titles.mentioned")); + }); + + test("has elements for label and description", async function (assert) { + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site) + ); + await render(template); + const label = query("li a .item-label"); + const description = query("li a .item-description"); + + assert.strictEqual( + label.textContent.trim(), + "osama", + "the label's content is the username by default" + ); + + assert.strictEqual( + description.textContent.trim(), + "This is fancy title !", + "the description defaults to the fancy_title" + ); + }); + + test("the description falls back to topic_title from data if fancy_title is absent", async function (assert) { + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site, { + fancy_title: null, + }) + ); + await render(template); + const description = query("li a .item-description"); + + assert.strictEqual( + description.textContent.trim(), + "this is title before it becomes fancy !", + "topic_title from data is rendered safely" + ); + }); + + test("fancy_title is emoji-unescaped", async function (assert) { + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site, { + fancy_title: "title with emoji :phone:", + }) + ); + await render(template); + assert.ok( + exists("li a .item-description img.emoji"), + "emojis are unescaped when fancy_title is used for description" + ); + }); + + test("topic_title from data is emoji-unescaped safely", async function (assert) { + this.set( + "item", + getNotification(this.currentUser, this.siteSettings, this.site, { + fancy_title: null, + data: { + topic_title: "unsafe title with unescaped emoji :phone:", + }, + }) + ); + await render(template); + const description = query("li a .item-description"); + + assert.strictEqual( + description.textContent.trim(), + "unsafe title with unescaped emoji", + "topic_title is rendered safely" + ); + assert.ok( + exists(".item-description img.emoji"), + "emoji is rendered correctly" + ); + }); + + test("various aspects can be customized according to the notification's render director", async function (assert) { + withPluginApi("0.1", (api) => { + api.registerNotificationTypeRenderer( + "linked", + (NotificationTypeBase) => { + return class extends NotificationTypeBase { + get classNames() { + return ["additional", "classes"]; + } + + get linkHref() { + return "/somewhere/awesome"; + } + + get linkTitle() { + return "hello world this is unsafe '\""; + } + + get icon() { + return "wrench"; + } + + get label() { + return "notification label 666 "; + } + + get description() { + return "notification description 123 + HTML + end + + def self.fingerprint + if Rails.env.development? + calculate_fingerprint + else + @fingerprint ||= calculate_fingerprint + end + end + + private + + def self.load_js + File.read("#{Rails.root}/app/assets/javascripts/discourse/dist/assets/splash-screen.js").sub("//# sourceMappingURL=splash-screen.map\n", "") + rescue Errno::ENOENT + Rails.logger.error("Unable to load splash screen JS") if Rails.env.production? + "console.log('Unable to load splash screen JS')" + end + + def self.raw_js + if Rails.env.development? + load_js + else + @loaded_js ||= load_js + end + end + + def self.calculate_fingerprint + "sha256-#{Digest::SHA256.base64digest(raw_js)}" + end +end diff --git a/app/jobs/regular/export_user_archive.rb b/app/jobs/regular/export_user_archive.rb index 3e76285f9d..256b8a3d4d 100644 --- a/app/jobs/regular/export_user_archive.rb +++ b/app/jobs/regular/export_user_archive.rb @@ -361,7 +361,7 @@ module Jobs yield [ rev.id, - Reviewable.statuses[rev.status], + rev.status, rev.category_id, rev.topic_id, rev.payload['raw'], diff --git a/app/jobs/regular/notify_reviewable.rb b/app/jobs/regular/notify_reviewable.rb index 8d0c4f7c27..7709ca8ca3 100644 --- a/app/jobs/regular/notify_reviewable.rb +++ b/app/jobs/regular/notify_reviewable.rb @@ -31,35 +31,37 @@ class Jobs::NotifyReviewable < ::Jobs::Base counts[r.reviewable_by_group_id] += 1 if r.reviewable_by_group_id end - redesigned_menu_enabled_user_ids = User.redesigned_user_menu_enabled_user_ids - - new_menu_admins = User.real.admins.where(id: redesigned_menu_enabled_user_ids) - notify_users(new_menu_admins, all_updates[:admins]) - - legacy_menu_admins = User.real.admins.where("id NOT IN (?)", @contacted).pluck(:id) - notify_legacy( - legacy_menu_admins, - count: counts[:admins], - updates: all_updates[:admins], - ) + if SiteSetting.enable_experimental_sidebar_hamburger + notify_users( + User.real.admins, + all_updates[:admins] + ) + else + notify_legacy( + User.real.admins.pluck(:id), + count: counts[:admins], + updates: all_updates[:admins], + ) + end if reviewable.reviewable_by_moderator? - new_menu_mods = User - .real - .moderators - .where("id IN (?)", redesigned_menu_enabled_user_ids - @contacted.to_a) - notify_users(new_menu_mods, all_updates[:moderators]) - - legacy_menu_mods = User.real.moderators.where("id NOT IN (?)", @contacted).pluck(:id) - notify_legacy( - legacy_menu_mods, - count: counts[:moderators], - updates: all_updates[:moderators], - ) + if SiteSetting.enable_experimental_sidebar_hamburger + notify_users( + User.real.moderators.where("id NOT IN (?)", @contacted), + all_updates[:moderators] + ) + else + notify_legacy( + User.real.moderators.where("id NOT IN (?)", @contacted).pluck(:id), + count: counts[:moderators], + updates: all_updates[:moderators], + ) + end end if SiteSetting.enable_category_group_moderation? && (group = reviewable.reviewable_by_group) users = group.users.includes(:group_users).where("users.id NOT IN (?)", @contacted) + users.find_each do |user| count = 0 updates = {} @@ -67,12 +69,14 @@ class Jobs::NotifyReviewable < ::Jobs::Base updates.merge!(all_updates[gu.group_id]) count += counts[gu.group_id] end - if redesigned_menu_enabled_user_ids.include?(user.id) + + if SiteSetting.enable_experimental_sidebar_hamburger notify_user(user, updates) else notify_legacy([user.id], count: count, updates: updates) end end + @contacted += users.pluck(:id) end end diff --git a/app/jobs/regular/publish_group_membership_updates.rb b/app/jobs/regular/publish_group_membership_updates.rb index a9bc5dc93e..6b93e87a0b 100644 --- a/app/jobs/regular/publish_group_membership_updates.rb +++ b/app/jobs/regular/publish_group_membership_updates.rb @@ -3,12 +3,13 @@ module Jobs class PublishGroupMembershipUpdates < ::Jobs::Base def execute(args) - raise Discourse::InvalidParameters.new(:type) if !%w[add remove].include?(args[:type]) + available_types = [Group::AUTO_GROUPS_ADD, Group::AUTO_GROUPS_REMOVE] + raise Discourse::InvalidParameters.new(:type) if !available_types.include?(args[:type]) group = Group.find_by(id: args[:group_id]) return if !group - added_members = args[:type] == 'add' + added_members = args[:type] == Group::AUTO_GROUPS_ADD User.human_users.where(id: args[:user_ids]).each do |user| if added_members diff --git a/app/jobs/regular/pull_hotlinked_images.rb b/app/jobs/regular/pull_hotlinked_images.rb index f29874e05a..7c1accdb89 100644 --- a/app/jobs/regular/pull_hotlinked_images.rb +++ b/app/jobs/regular/pull_hotlinked_images.rb @@ -86,7 +86,8 @@ module Jobs max_file_size: @max_size, retain_on_max_file_size_exceeded: true, tmp_file_name: "discourse-hotlinked", - follow_redirect: true + follow_redirect: true, + read_timeout: 15 ) rescue => e if SiteSetting.verbose_upload_logging @@ -107,9 +108,9 @@ module Jobs class UploadCreateError < StandardError; end def attempt_download(src, user_id) - # secure-media-uploads endpoint prevents anonymous downloads, so we + # secure-uploads endpoint prevents anonymous downloads, so we # need the presigned S3 URL here - src = Upload.signed_url_from_secure_media_url(src) if Upload.secure_media_url?(src) + src = Upload.signed_url_from_secure_uploads_url(src) if Upload.secure_uploads_url?(src) hotlinked = download(src) raise ImageBrokenError if !hotlinked @@ -146,7 +147,7 @@ module Jobs ].compact.map { |s| normalize_src(s) } if Discourse.store.has_been_uploaded?(src) || normalize_src(src).start_with?(*local_bases) || src =~ /\A\/[^\/]/i - return false if !(src =~ /\/uploads\// || Upload.secure_media_url?(src)) + return false if !(src =~ /\/uploads\// || Upload.secure_uploads_url?(src)) # Someone could hotlink a file from a different site on the same CDN, # so check whether we have it in this database diff --git a/app/jobs/regular/sync_acls_for_uploads.rb b/app/jobs/regular/sync_acls_for_uploads.rb index 73837ff7e7..237795cb5b 100644 --- a/app/jobs/regular/sync_acls_for_uploads.rb +++ b/app/jobs/regular/sync_acls_for_uploads.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Jobs - # Sometimes we need to update a _lot_ of ACLs on S3 (such as when secure media + # Sometimes we need to update a _lot_ of ACLs on S3 (such as when secure uploads # is enabled), and since it takes ~1s per upload to update the ACL, this is # best spread out over many jobs instead of having to do the whole thing serially. class SyncAclsForUploads < ::Jobs::Base diff --git a/app/jobs/regular/update_hotlinked_raw.rb b/app/jobs/regular/update_hotlinked_raw.rb index b938a1ffaa..1fb425839b 100644 --- a/app/jobs/regular/update_hotlinked_raw.rb +++ b/app/jobs/regular/update_hotlinked_raw.rb @@ -11,6 +11,7 @@ module Jobs post = Post.find_by(id: @post_id) return if post.nil? return if post.cook_method == Post.cook_methods[:raw_html] + return if post.topic.nil? hotlinked_map = post.post_hotlinked_media.preload(:upload).map { |r| [r.url, r] }.to_h diff --git a/app/jobs/scheduled/auto_queue_handler.rb b/app/jobs/scheduled/auto_queue_handler.rb index dfc87b77f1..6bf75924c9 100644 --- a/app/jobs/scheduled/auto_queue_handler.rb +++ b/app/jobs/scheduled/auto_queue_handler.rb @@ -11,7 +11,7 @@ module Jobs return unless SiteSetting.auto_handle_queued_age.to_i > 0 Reviewable - .where(status: Reviewable.statuses[:pending]) + .pending .where('created_at < ?', SiteSetting.auto_handle_queued_age.to_i.days.ago) .each do |reviewable| diff --git a/app/jobs/scheduled/pending_queued_posts_reminder.rb b/app/jobs/scheduled/pending_queued_posts_reminder.rb index 0bc78cb69e..22b84fc701 100644 --- a/app/jobs/scheduled/pending_queued_posts_reminder.rb +++ b/app/jobs/scheduled/pending_queued_posts_reminder.rb @@ -27,7 +27,7 @@ module Jobs end def should_notify_ids - ReviewableQueuedPost.where(status: Reviewable.statuses[:pending]).where( + ReviewableQueuedPost.pending.where( 'created_at < ?', SiteSetting.notify_about_queued_posts_after.to_f.hours.ago ).pluck(:id) end diff --git a/app/jobs/scheduled/periodical_updates.rb b/app/jobs/scheduled/periodical_updates.rb index 5c5da8bac6..01649de062 100644 --- a/app/jobs/scheduled/periodical_updates.rb +++ b/app/jobs/scheduled/periodical_updates.rb @@ -48,6 +48,8 @@ module Jobs Category.auto_bump_topic! + Upload.backfill_dominant_colors!(25) + nil end diff --git a/app/jobs/scheduled/reviewable_priorities.rb b/app/jobs/scheduled/reviewable_priorities.rb index da4d9c8148..b9c5e4c8b5 100644 --- a/app/jobs/scheduled/reviewable_priorities.rb +++ b/app/jobs/scheduled/reviewable_priorities.rb @@ -15,11 +15,7 @@ class Jobs::ReviewablePriorities < ::Jobs::Scheduled def execute(args) min_priority_threshold = SiteSetting.reviewable_low_priority_threshold - reviewable_count = Reviewable.where( - "score > ? AND status = ?", - min_priority_threshold, - Reviewable.statuses[:approved] - ).count + reviewable_count = Reviewable.approved.where("score > ?", min_priority_threshold).count return if reviewable_count < self.class.min_reviewables res = DB.query_single(<<~SQL, target_count: self.class.target_count, min_priority: min_priority_threshold) diff --git a/app/models/category_featured_topic.rb b/app/models/category_featured_topic.rb index 2e454effca..0e4a53ef55 100644 --- a/app/models/category_featured_topic.rb +++ b/app/models/category_featured_topic.rb @@ -60,24 +60,19 @@ class CategoryFeaturedTopic < ActiveRecord::Base # Add topics, even if they're in secured categories or invisible query = TopicQuery.new(Discourse.system_user, query_opts) - results = query.list_category_topic_ids(c).uniq + results = query.list_category_topic_ids(c) # Add some topics that are visible to everyone: anon_query = TopicQuery.new(nil, query_opts.merge(except_topic_ids: [c.topic_id] + results)) - results += anon_query.list_category_topic_ids(c).uniq + results += anon_query.list_category_topic_ids(c) + results.uniq! return if results == existing CategoryFeaturedTopic.transaction do CategoryFeaturedTopic.where(category_id: c.id).delete_all - if results - results.each_with_index do |topic_id, idx| - begin - c.category_featured_topics.create(topic_id: topic_id, rank: idx) - rescue PG::UniqueViolation - # If another process features this topic, just ignore it - end - end + results.each_with_index do |topic_id, idx| + c.category_featured_topics.create(topic_id: topic_id, rank: idx) end end end diff --git a/app/models/category_list.rb b/app/models/category_list.rb index 2ed506273a..743a4cc446 100644 --- a/app/models/category_list.rb +++ b/app/models/category_list.rb @@ -64,17 +64,18 @@ class CategoryList @all_topics = Topic.where(id: category_featured_topics.map(&:topic_id)).includes(:shared_draft, :category) + @all_topics = @all_topics.joins(:tags).where(tags: { name: @options[:tag] }) if @options[:tag].present? + if @guardian.authenticated? @all_topics = @all_topics .joins("LEFT JOIN topic_users tu ON topics.id = tu.topic_id AND tu.user_id = #{@guardian.user.id.to_i}") .where('COALESCE(tu.notification_level,1) > :muted', muted: TopicUser.notification_levels[:muted]) end - @all_topics = TopicQuery.remove_muted_tags(@all_topics, @guardian.user) - @all_topics = @all_topics.includes(:last_poster) if @options[:include_topics] + @all_topics = TopicQuery.remove_muted_tags(@all_topics, @guardian.user).includes(:last_poster) @all_topics.each do |t| # hint for the serializer - t.include_last_poster = true if @options[:include_topics] + t.include_last_poster = true t.dismissed = dismissed_topic?(t) @topics_by_id[t.id] = t end diff --git a/app/models/concerns/roleable.rb b/app/models/concerns/roleable.rb index 4a9a6be3dd..6dc571f229 100644 --- a/app/models/concerns/roleable.rb +++ b/app/models/concerns/roleable.rb @@ -80,7 +80,7 @@ module Roleable private def auto_approve_user - if reviewable = ReviewableUser.find_by(target: self, status: Reviewable.statuses[:pending]) + if reviewable = ReviewableUser.pending.find_by(target: self) reviewable.perform(Discourse.system_user, :approve_user, send_email: false) else ReviewableUser.set_approved_fields!(self, Discourse.system_user) diff --git a/app/models/emoji.rb b/app/models/emoji.rb index c940f31796..2333a913f4 100644 --- a/app/models/emoji.rb +++ b/app/models/emoji.rb @@ -94,6 +94,7 @@ class Emoji e.name = name e.tonable = Emoji.tonable_emojis.include?(name) e.url = Emoji.url_for(filename) + e.group = groups[name] || DEFAULT_GROUP end end @@ -122,6 +123,24 @@ class Emoji site_emoji_cache.clear end + def self.groups_file + @groups_file ||= "#{Rails.root}/lib/emoji/groups.json" + end + + def self.groups + @groups ||= begin + groups = {} + + File.open(groups_file, "r:UTF-8") { |f| JSON.parse(f.read) }.each do |group| + group["icons"].each do |icon| + groups[icon["name"]] = group["name"] + end + end + + groups + end + end + def self.db_file @db_file ||= "#{Rails.root}/lib/emoji/db.json" end diff --git a/app/models/group.rb b/app/models/group.rb index 1228288ca5..aa6fdc0220 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -103,6 +103,9 @@ class Group < ActiveRecord::Base AUTO_GROUP_IDS = Hash[*AUTO_GROUPS.to_a.flatten.reverse] STAFF_GROUPS = [:admins, :moderators, :staff] + AUTO_GROUPS_ADD = "add" + AUTO_GROUPS_REMOVE = "remove" + IMAP_SETTING_ATTRIBUTES = [ "imap_server", "imap_port", @@ -493,7 +496,7 @@ class Group < ActiveRecord::Base if removed_user_ids.present? Jobs.enqueue( :publish_group_membership_updates, - user_ids: removed_user_ids, group_id: group.id, type: :remove + user_ids: removed_user_ids, group_id: group.id, type: AUTO_GROUPS_REMOVE ) end @@ -526,7 +529,7 @@ class Group < ActiveRecord::Base if added_user_ids.present? Jobs.enqueue( :publish_group_membership_updates, - user_ids: added_user_ids, group_id: group.id, type: :add + user_ids: added_user_ids, group_id: group.id, type: AUTO_GROUPS_ADD ) end diff --git a/app/models/group_user.rb b/app/models/group_user.rb index babfaade4e..5e6b3f7dcb 100644 --- a/app/models/group_user.rb +++ b/app/models/group_user.rb @@ -8,7 +8,7 @@ class GroupUser < ActiveRecord::Base after_destroy :grant_other_available_title after_save :set_primary_group - after_destroy :remove_primary_group, :recalculate_trust_level + after_destroy :remove_primary_and_flair_group, :recalculate_trust_level before_create :set_notification_level after_save :grant_trust_level @@ -84,10 +84,14 @@ class GroupUser < ActiveRecord::Base user.update!(primary_group: group) if group.primary_group end - def remove_primary_group - return if user.primary_group_id != group_id + def remove_primary_and_flair_group return if self.destroyed_by_association&.active_record == User # User is being destroyed, so don't try to update - user.update_attribute(:primary_group_id, nil) + + updates = {} + updates[:primary_group_id] = nil if user.primary_group_id == group_id + updates[:flair_group_id] = nil if user.flair_group_id == group_id + + user.update(updates) if updates.present? end def grant_other_available_title @@ -116,7 +120,7 @@ class GroupUser < ActiveRecord::Base return if group.grant_trust_level.nil? return if self.destroyed_by_association&.active_record == User # User is being destroyed, so don't try to recalculate - Promotion.recalculate(user) + Promotion.recalculate(user, use_previous_trust_level: true) end def set_category_notifications diff --git a/app/models/notification.rb b/app/models/notification.rb index 70bf554775..fc4e8ffe69 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -18,6 +18,12 @@ class Notification < ActiveRecord::Base scope :unread_type, ->(user, type, limit = 20) do where(user_id: user.id, read: false, notification_type: type).visible.includes(:topic).limit(limit) end + scope :prioritized, ->(limit = nil) do + order("notifications.high_priority AND NOT notifications.read DESC") + .order("NOT notifications.read DESC") + .order("notifications.created_at DESC") + .limit(limit || 30) + end attr_accessor :skip_send_email @@ -214,6 +220,30 @@ class Notification < ActiveRecord::Base Post.find_by(topic_id: topic_id, post_number: post_number) end + def self.prioritized_list(user, count: 30, types: []) + return [] if !user&.user_option + + notifications = user.notifications + .includes(:topic) + .visible + .prioritized(count) + + if types.present? + notifications = notifications.where(notification_type: types) + elsif user.user_option.like_notification_frequency == UserOption.like_notification_frequency_type[:never] + [ + Notification.types[:liked], + Notification.types[:liked_consolidated] + ].each do |notification_type| + notifications = notifications.where( + 'notification_type <> ?', notification_type + ) + end + end + notifications.to_a + end + + # TODO(osama): deprecate this method when redesigned_user_menu_enabled is removed def self.recent_report(user, count = nil, types = []) return unless user && user.user_option diff --git a/app/models/post.rb b/app/models/post.rb index 3352856160..5f493c4585 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -309,7 +309,7 @@ class Post < ActiveRecord::Base options[:user_id] = post_user.id if post_user options[:omit_nofollow] = true if omit_nofollow? - if self.with_secure_media? + if self.with_secure_uploads? each_upload_url do |url| uri = URI.parse(url) if FileHelper.is_supported_media?(File.basename(uri.path)) @@ -517,8 +517,8 @@ class Post < ActiveRecord::Base ReviewableFlaggedPost.pending.find_by(target: self) end - def with_secure_media? - return false if !SiteSetting.secure_media? + def with_secure_uploads? + return false if !SiteSetting.secure_uploads? SiteSetting.login_required? || \ (topic.present? && (topic.private_message? || topic.category&.read_restricted)) end @@ -971,7 +971,7 @@ class Post < ActiveRecord::Base UploadReference.where(target: self).delete_all UploadReference.insert_all(upload_references) if upload_references.size > 0 - if SiteSetting.secure_media? + if SiteSetting.secure_uploads? Upload.where( id: upload_ids, access_control_post_id: nil ).where( @@ -1033,7 +1033,7 @@ class Post < ActiveRecord::Base next if Rails.configuration.multisite && src.exclude?(current_db) src = "#{SiteSetting.force_https ? "https" : "http"}:#{src}" if src.start_with?("//") - next unless Discourse.store.has_been_uploaded?(src) || Upload.secure_media_url?(src) || (include_local_upload && src =~ /\A\/[^\/]/i) + next unless Discourse.store.has_been_uploaded?(src) || Upload.secure_uploads_url?(src) || (include_local_upload && src =~ /\A\/[^\/]/i) path = begin URI(UrlHelper.unencode(GlobalSetting.cdn_url ? src.sub(GlobalSetting.cdn_url, "") : src))&.path @@ -1209,6 +1209,7 @@ end # action_code :string # locked_by_id :integer # image_upload_id :bigint +# outbound_message_id :string # # Indexes # diff --git a/app/models/reviewable.rb b/app/models/reviewable.rb index b1b5f518f4..0f544519ea 100644 --- a/app/models/reviewable.rb +++ b/app/models/reviewable.rb @@ -31,6 +31,25 @@ class Reviewable < ActiveRecord::Base has_many :reviewable_histories has_many :reviewable_scores, -> { order(created_at: :desc) } + enum :status, { + pending: 0, + approved: 1, + rejected: 2, + ignored: 3, + deleted: 4 + } + enum :priority, { + low: 0, + medium: 5, + high: 10 + }, scopes: false, suffix: true + enum :sensitivity, { + disabled: 0, + low: 9, + medium: 6, + high: 3 + }, scopes: false, suffix: true + after_create do log_history(:created, created_by) end @@ -48,47 +67,12 @@ class Reviewable < ActiveRecord::Base {} end - # The gaps are in case we want more precision in the future - def self.priorities - @priorities ||= Enum.new( - low: 0, - medium: 5, - high: 10 - ) - end - - # The gaps are in case we want more precision in the future - def self.sensitivity - @sensitivity ||= Enum.new( - disabled: 0, - low: 9, - medium: 6, - high: 3 - ) - end - - def self.statuses - @statuses ||= Enum.new( - pending: 0, - approved: 1, - rejected: 2, - ignored: 3, - deleted: 4 - ) - end - # This number comes from looking at forums in the wild and what numbers work. # As the site accumulates real data it'll be based on the site activity instead. def self.typical_sensitivity 12.5 end - # Generate `pending?`, `rejected?`, etc helper methods - statuses.each do |name, id| - define_method("#{name}?") { status == id } - singleton_class.define_method(name) { where(status: id) } - end - def self.default_visible where("score >= ?", min_score_for_priority) end @@ -211,7 +195,7 @@ class Reviewable < ActiveRecord::Base rs = reviewable_scores.new( user: user, - status: ReviewableScore.statuses[:pending], + status: :pending, reviewable_score_type: reviewable_score_type, score: sub_total, user_accuracy_bonus: user_accuracy_bonus, @@ -232,7 +216,7 @@ class Reviewable < ActiveRecord::Base def self.set_priorities(values) values.each do |k, v| - id = Reviewable.priorities[k] + id = priorities[k] PluginStore.set('reviewables', "priority_#{id}", v) unless id.nil? end end @@ -240,9 +224,9 @@ class Reviewable < ActiveRecord::Base def self.sensitivity_score_value(sensitivity, scale) return Float::MAX if sensitivity == 0 - ratio = sensitivity / Reviewable.sensitivity[:low].to_f + ratio = sensitivity / sensitivities[:low].to_f high = ( - PluginStore.get('reviewables', "priority_#{Reviewable.priorities[:high]}") || + PluginStore.get('reviewables', "priority_#{priorities[:high]}") || typical_sensitivity ).to_f @@ -271,7 +255,7 @@ class Reviewable < ActiveRecord::Base def self.min_score_for_priority(priority = nil) priority ||= SiteSetting.reviewable_default_visibility - id = Reviewable.priorities[priority.to_sym] + id = priorities[priority] return 0.0 if id.nil? PluginStore.get('reviewables', "priority_#{id}").to_f end @@ -282,7 +266,7 @@ class Reviewable < ActiveRecord::Base def log_history(reviewable_history_type, performed_by, edited: nil) reviewable_histories.create!( - reviewable_history_type: ReviewableHistory.types[reviewable_history_type], + reviewable_history_type: reviewable_history_type, status: status, created_by: performed_by, edited: edited @@ -386,9 +370,7 @@ class Reviewable < ActiveRecord::Base end def transition_to(status_symbol, performed_by) - was_pending = pending? - - self.status = Reviewable.statuses[status_symbol] + self.status = status_symbol save! log_history(:transitioned, performed_by) @@ -402,7 +384,7 @@ class Reviewable < ActiveRecord::Base ) end - was_pending + status_previously_changed?(from: "pending") end def post_options @@ -503,13 +485,13 @@ class Reviewable < ActiveRecord::Base SELECT reviewable_id FROM reviewable_histories WHERE reviewable_history_type = #{ReviewableHistory.types[:transitioned]} AND - status <> #{Reviewable.statuses[:pending]} AND created_by_id = #{reviewed_by_id} + status <> #{statuses[:pending]} AND created_by_id = #{reviewed_by_id} ) AS rh ON rh.reviewable_id = reviewables.id SQL ) end - min_score = Reviewable.min_score_for_priority(priority) + min_score = min_score_for_priority(priority) if min_score > 0 && status == :pending result = result.where("reviewables.score >= ? OR reviewables.force_review", min_score) @@ -678,8 +660,8 @@ class Reviewable < ActiveRecord::Base DB.query( sql, topic_id: topic_id, - pending: Reviewable.statuses[:pending], - approved: Reviewable.statuses[:approved] + pending: self.class.statuses[:pending], + approved: self.class.statuses[:approved] ) self.score = result[0].score @@ -776,7 +758,7 @@ end # # id :bigint not null, primary key # type :string not null -# status :integer default(0), not null +# status :integer default("pending"), not null # created_by_id :integer not null # reviewable_by_moderator :boolean default(FALSE), not null # reviewable_by_group_id :integer diff --git a/app/models/reviewable_flagged_post.rb b/app/models/reviewable_flagged_post.rb index debfa19c34..d79f1daf1c 100644 --- a/app/models/reviewable_flagged_post.rb +++ b/app/models/reviewable_flagged_post.rb @@ -13,7 +13,7 @@ class ReviewableFlaggedPost < Reviewable def self.counts_for(posts) result = {} - counts = DB.query(<<~SQL, pending: Reviewable.statuses[:pending]) + counts = DB.query(<<~SQL, pending: statuses[:pending]) SELECT r.target_id AS post_id, rs.reviewable_score_type, count(*) as total @@ -336,7 +336,7 @@ end # # id :bigint not null, primary key # type :string not null -# status :integer default(0), not null +# status :integer default("pending"), not null # created_by_id :integer not null # reviewable_by_moderator :boolean default(FALSE), not null # reviewable_by_group_id :integer diff --git a/app/models/reviewable_history.rb b/app/models/reviewable_history.rb index 98b6636500..c01d41a935 100644 --- a/app/models/reviewable_history.rb +++ b/app/models/reviewable_history.rb @@ -4,16 +4,22 @@ class ReviewableHistory < ActiveRecord::Base belongs_to :reviewable belongs_to :created_by, class_name: 'User' - def self.types - @types ||= Enum.new( - created: 0, - transitioned: 1, - edited: 2, - claimed: 3, - unclaimed: 4 - ) - end + enum status: { + pending: 0, + approved: 1, + rejected: 2, + ignored: 3, + deleted: 4 + } + alias_attribute :type, :reviewable_history_type + enum type: { + created: 0, + transitioned: 1, + edited: 2, + claimed: 3, + unclaimed: 4 + } end # == Schema Information diff --git a/app/models/reviewable_post.rb b/app/models/reviewable_post.rb index a8c24b1878..983a96c054 100644 --- a/app/models/reviewable_post.rb +++ b/app/models/reviewable_post.rb @@ -8,7 +8,7 @@ class ReviewablePost < Reviewable def self.queue_for_review_if_possible(post, created_or_edited_by) return unless SiteSetting.review_every_post return if post.post_type != Post.types[:regular] || post.topic.private_message? - return if Reviewable.where(target: post, status: Reviewable.statuses[:pending]).exists? + return if Reviewable.pending.where(target: post).exists? return if created_or_edited_by.bot? || created_or_edited_by.staff? || created_or_edited_by.has_trust_level?(TrustLevel[4]) system_user = Discourse.system_user @@ -116,7 +116,7 @@ end # # id :bigint not null, primary key # type :string not null -# status :integer default(0), not null +# status :integer default("pending"), not null # created_by_id :integer not null # reviewable_by_moderator :boolean default(FALSE), not null # reviewable_by_group_id :integer diff --git a/app/models/reviewable_queued_post.rb b/app/models/reviewable_queued_post.rb index ccfcea6671..50a453c734 100644 --- a/app/models/reviewable_queued_post.rb +++ b/app/models/reviewable_queued_post.rb @@ -174,7 +174,7 @@ class ReviewableQueuedPost < Reviewable def status_changed_from_or_to_pending? saved_change_to_id?(from: nil) && pending? || - saved_change_to_status?(from: self.class.statuses[:pending]) + saved_change_to_status?(from: "pending") end end @@ -184,7 +184,7 @@ end # # id :bigint not null, primary key # type :string not null -# status :integer default(0), not null +# status :integer default("pending"), not null # created_by_id :integer not null # reviewable_by_moderator :boolean default(FALSE), not null # reviewable_by_group_id :integer diff --git a/app/models/reviewable_score.rb b/app/models/reviewable_score.rb index 34080a944d..2d650b4131 100644 --- a/app/models/reviewable_score.rb +++ b/app/models/reviewable_score.rb @@ -6,6 +6,13 @@ class ReviewableScore < ActiveRecord::Base belongs_to :reviewed_by, class_name: 'User' belongs_to :meta_topic, class_name: 'Topic' + enum status: { + pending: 0, + agreed: 1, + disagreed: 2, + ignored: 3 + } + # To keep things simple the types correspond to `PostActionType` for backwards # compatibility, but we can add extra reasons for scores. def self.types @@ -29,15 +36,6 @@ class ReviewableScore < ActiveRecord::Base end end - def self.statuses - @statuses ||= Enum.new( - pending: 0, - agreed: 1, - disagreed: 2, - ignored: 3 - ) - end - def self.score_transitions { approved: statuses[:agreed], @@ -46,12 +44,6 @@ class ReviewableScore < ActiveRecord::Base } end - # Generate `pending?`, `rejected?`, etc helper methods - statuses.each do |name, id| - define_method("#{name}?") { status == id } - singleton_class.define_method(name) { where(status: id) } - end - def score_type Reviewable::Collection::Item.new(reviewable_score_type) end diff --git a/app/models/reviewable_sensitivity_setting.rb b/app/models/reviewable_sensitivity_setting.rb index 4207d14260..c6fa405c3d 100644 --- a/app/models/reviewable_sensitivity_setting.rb +++ b/app/models/reviewable_sensitivity_setting.rb @@ -7,7 +7,7 @@ class ReviewableSensitivitySetting < EnumSiteSetting end def self.values - Reviewable.sensitivity.map do |p| + Reviewable.sensitivities.map do |p| { name: I18n.t("reviewables.sensitivity.#{p[0]}"), value: p[1] } end end diff --git a/app/models/reviewable_user.rb b/app/models/reviewable_user.rb index 2fbe915c80..c885c8718c 100644 --- a/app/models/reviewable_user.rb +++ b/app/models/reviewable_user.rb @@ -69,8 +69,8 @@ class ReviewableUser < Reviewable end destroyer.destroy(target, delete_args) - rescue UserDestroyer::PostsExistError - # If a user has posts, we won't delete them to preserve their content. + rescue UserDestroyer::PostsExistError, Discourse::InvalidAccess + # If a user has posts or user is an admin, we won't delete them to preserve their content. # However the reviewable record will be "rejected" and they will remain # unapproved in the database. A staff member can still approve them # via the admin. @@ -105,7 +105,7 @@ end # # id :bigint not null, primary key # type :string not null -# status :integer default(0), not null +# status :integer default("pending"), not null # created_by_id :integer not null # reviewable_by_moderator :boolean default(FALSE), not null # reviewable_by_group_id :integer diff --git a/app/models/site.rb b/app/models/site.rb index 8a23bf1e04..b76a0fa2a0 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -203,10 +203,24 @@ class Site MessageBus.publish(SITE_JSON_CHANNEL, '') end - def self.show_welcome_topic_banner?(guardian) - return false unless guardian.is_admin? - return false unless guardian.user.id == User.first_login_admin_id + def self.welcome_topic_banner_cache_key(user_id) + "show_welcome_topic_banner:#{user_id}" + end - Post.find_by("topic_id = :topic_id AND post_number = 1 AND version = 1 AND created_at > :created_at", topic_id: SiteSetting.welcome_topic_id, created_at: 1.month.ago).present? + def self.show_welcome_topic_banner?(guardian) + return false if !guardian.is_admin? + user_id = guardian.user.id + + show_welcome_topic_banner = Discourse.cache.read(welcome_topic_banner_cache_key(user_id)) + return show_welcome_topic_banner unless show_welcome_topic_banner.nil? + + show_welcome_topic_banner = if (user_id == User.first_login_admin_id) + Post.find_by("topic_id = :topic_id AND post_number = 1 AND version = 1 AND created_at > :created_at", topic_id: SiteSetting.welcome_topic_id, created_at: 1.month.ago).present? + else + false + end + + Discourse.cache.write(welcome_topic_banner_cache_key(user_id), show_welcome_topic_banner) + show_welcome_topic_banner end end diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb index b074d95af4..fc73aa76dc 100644 --- a/app/models/site_setting.rb +++ b/app/models/site_setting.rb @@ -193,6 +193,7 @@ class SiteSetting < ActiveRecord::Base def self.whispers_allowed_group_ids if SiteSetting.enable_whispers && SiteSetting.whispers_allowed_groups.present? + # TODO (martin) Change to whispers_allowed_groups_map SiteSetting.whispers_allowed_groups.split("|").map(&:to_i) else [] diff --git a/app/models/theme.rb b/app/models/theme.rb index 4727426a15..fa98138643 100644 --- a/app/models/theme.rb +++ b/app/models/theme.rb @@ -6,7 +6,7 @@ require 'json_schemer' class Theme < ActiveRecord::Base include GlobalPath - BASE_COMPILER_VERSION = 59 + BASE_COMPILER_VERSION = 63 attr_accessor :child_components @@ -157,8 +157,11 @@ class Theme < ActiveRecord::Base get_set_cache "compiler_version" do dependencies = [ BASE_COMPILER_VERSION, - Ember::VERSION, + EmberCli.ember_version, GlobalSetting.cdn_url, + GlobalSetting.s3_cdn_url, + GlobalSetting.s3_endpoint, + GlobalSetting.s3_bucket, Discourse.current_hostname ] Digest::SHA1.hexdigest(dependencies.join) diff --git a/app/models/theme_field.rb b/app/models/theme_field.rb index a48b5f9218..a0b80685f6 100644 --- a/app/models/theme_field.rb +++ b/app/models/theme_field.rb @@ -92,7 +92,7 @@ class ThemeField < ActiveRecord::Base if is_raw js_compiler.append_raw_template(name, hbs_template) else - js_compiler.append_ember_template(name, hbs_template) + js_compiler.append_ember_template("discourse/templates/#{name}", hbs_template) end rescue ThemeJavascriptCompiler::CompileError => ex errors << ex.message @@ -164,7 +164,7 @@ class ThemeField < ActiveRecord::Base when "js.es6", "js" js_compiler.append_module(content, filename, include_variables: true) when "hbs" - js_compiler.append_ember_template(filename.sub("discourse/templates/", ""), content) + js_compiler.append_ember_template(filename, content) when "hbr", "raw.hbs" js_compiler.append_raw_template(filename.sub("discourse/templates/", ""), content) else diff --git a/app/models/topic.rb b/app/models/topic.rb index 54af4242de..50eda089fd 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -976,7 +976,6 @@ class Topic < ActiveRecord::Base topic_user.destroy if user.id == removed_by&.id - removed_by = Discourse.system_user add_small_action(removed_by, "user_left", user.username) else add_small_action(removed_by, "removed_user", user.username) diff --git a/app/models/topic_converter.rb b/app/models/topic_converter.rb index 2164575310..47c8b4a3c7 100644 --- a/app/models/topic_converter.rb +++ b/app/models/topic_converter.rb @@ -63,7 +63,9 @@ class TopicConverter private def posters - @posters ||= @topic.posts.distinct.pluck(:user_id) + @posters ||= @topic.posts + .where.not(post_type: [Post.types[:small_action], Post.types[:whisper]]) + .distinct.pluck(:user_id) end def increment_users_post_count diff --git a/app/models/topic_list.rb b/app/models/topic_list.rb index 192687d177..d13c2ab3ec 100644 --- a/app/models/topic_list.rb +++ b/app/models/topic_list.rb @@ -76,17 +76,7 @@ class TopicList end def preload_key - if @category - if @opts[:no_subcategories] - "topic_list_#{@category.url.sub(/^\//, '')}/none/l/#{@filter}" - else - "topic_list_#{@category.url.sub(/^\//, '')}/l/#{@filter}" - end - elsif @tags && @tags.first.present? - "topic_list_tag/#{@tags.first.name}/l/#{@filter}" - else - "topic_list_#{@filter}" - end + "topic_list" end # Lazy initialization diff --git a/app/models/upload.rb b/app/models/upload.rb index 11fb98d0e1..7bd583f2a6 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -10,6 +10,7 @@ class Upload < ActiveRecord::Base SEEDED_ID_THRESHOLD = 0 URL_REGEX ||= /(\/original\/\dX[\/\.\w]*\/(\h+)[\.\w]*)/ MAX_IDENTIFY_SECONDS = 5 + DOMINANT_COLOR_COMMAND_TIMEOUT_SECONDS = 5 belongs_to :user belongs_to :access_control_post, class_name: 'Post' @@ -36,6 +37,7 @@ class Upload < ActiveRecord::Base validates_presence_of :filesize validates_presence_of :original_filename + validates :dominant_color, length: { is: 6 }, allow_blank: true, allow_nil: true validates_with UploadValidator @@ -184,7 +186,7 @@ class Upload < ActiveRecord::Base "upload://#{short_url_basename}" end - def uploaded_before_secure_media_enabled? + def uploaded_before_secure_uploads_enabled? original_sha1.blank? end @@ -202,14 +204,14 @@ class Upload < ActiveRecord::Base end def self.consider_for_reuse(upload, post) - return upload if !SiteSetting.secure_media? || upload.blank? || post.blank? - return nil if !upload.matching_access_control_post?(post) || upload.uploaded_before_secure_media_enabled? + return upload if !SiteSetting.secure_uploads? || upload.blank? || post.blank? + return nil if !upload.matching_access_control_post?(post) || upload.uploaded_before_secure_uploads_enabled? upload end - def self.secure_media_url?(url) + def self.secure_uploads_url?(url) # we do not want to exclude topic links that for whatever reason - # have secure-media-uploads in the URL e.g. /t/secure-media-uploads-are-cool/223452 + # have secure-uploads in the URL e.g. /t/secure-uploads-are-cool/223452 route = UrlHelper.rails_route_from_url(url) return false if route.blank? route[:action] == "show_secure" && route[:controller] == "uploads" && FileHelper.is_supported_media?(url) @@ -217,14 +219,14 @@ class Upload < ActiveRecord::Base false end - def self.signed_url_from_secure_media_url(url) + def self.signed_url_from_secure_uploads_url(url) route = UrlHelper.rails_route_from_url(url) url = Rails.application.routes.url_for(route.merge(only_path: true)) secure_upload_s3_path = url[url.index(route[:path])..-1] Discourse.store.signed_url_for_path(secure_upload_s3_path) end - def self.secure_media_url_from_upload_url(url) + def self.secure_uploads_url_from_upload_url(url) return url if !url.include?(SiteSetting.Upload.absolute_base_url) uri = URI.parse(url) Rails.application.routes.url_for( @@ -316,6 +318,76 @@ class Upload < ActiveRecord::Base get_dimension(:thumbnail_height) end + def dominant_color(calculate_if_missing: false) + val = read_attribute(:dominant_color) + if val.nil? && calculate_if_missing + calculate_dominant_color! + read_attribute(:dominant_color) + else + val + end + end + + def calculate_dominant_color!(local_path = nil) + color = nil + + if !FileHelper.is_supported_image?("image.#{extension}") || extension == "svg" + color = "" + end + + if color.nil? + local_path ||= + if local? + Discourse.store.path_for(self) + else + Discourse.store.download(self)&.path + end + + if local_path.nil? + # Download failed. Could be too large to download, or file could be missing in s3 + color = "" + end + + color ||= begin + data = Discourse::Utils.execute_command( + "nice", + "-n", + "10", + "convert", + local_path, + "-resize", + "1x1", + "-define", + "histogram:unique-colors=true", + "-format", + "%c", + "histogram:info:", + timeout: DOMINANT_COLOR_COMMAND_TIMEOUT_SECONDS + ) + + # Output format: + # 1: (110.873,116.226,93.8821) #6F745E srgb(43.4798%,45.5789%,36.8165%) + + color = data[/#([0-9A-F]{6})/, 1] + + raise "Calculated dominant color but unable to parse output:\n#{data}" if color.nil? + + color + rescue Discourse::Utils::CommandError => e + # Timeout or unable to parse image + # This can happen due to bad user input - ignore and save + # an empty string to prevent re-evaluation + "" + end + end + + if persisted? + self.update_column(:dominant_color, color) + else + self.dominant_color = color + end + end + def target_image_quality(local_path, test_quality) @file_quality ||= Discourse::Utils.execute_command("identify", "-format", "%Q", local_path, timeout: MAX_IDENTIFY_SECONDS).to_i rescue 0 @@ -522,6 +594,12 @@ class Upload < ActiveRecord::Base Upload.where(sha1: sha1s.uniq).pluck(:id) end + def self.backfill_dominant_colors!(count) + Upload.where(dominant_color: nil).order("id desc").first(count).each do |upload| + upload.calculate_dominant_color! + end + end + private def short_url_basename @@ -553,10 +631,11 @@ end # secure :boolean default(FALSE), not null # access_control_post_id :bigint # original_sha1 :string -# verification_status :integer default(1), not null # animated :boolean +# verification_status :integer default(1), not null # security_last_changed_at :datetime # security_last_changed_reason :string +# dominant_color :text # # Indexes # @@ -564,6 +643,7 @@ end # index_uploads_on_access_control_post_id (access_control_post_id) # index_uploads_on_etag (etag) # index_uploads_on_extension (lower((extension)::text)) +# index_uploads_on_id (id) WHERE (dominant_color IS NULL) # index_uploads_on_id_and_url (id,url) # index_uploads_on_original_sha1 (original_sha1) # index_uploads_on_sha1 (sha1) UNIQUE diff --git a/app/models/user.rb b/app/models/user.rb index 2811029705..0fbc35849e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -109,7 +109,7 @@ class User < ActiveRecord::Base has_many :sidebar_section_links, dependent: :delete_all has_many :category_sidebar_section_links, -> { where(linkable_type: "Category") }, class_name: 'SidebarSectionLink' - has_many :sidebar_tags, through: :sidebar_section_links, source: :linkable, source_type: "Tag" + has_many :custom_sidebar_tags, through: :sidebar_section_links, source: :linkable, source_type: "Tag" delegate :last_sent_email_address, to: :email_logs @@ -412,6 +412,14 @@ class User < ActiveRecord::Base find_by(username_lower: normalize_username(username)) end + def in_any_groups?(group_ids) + group_ids.include?(Group::AUTO_GROUPS[:everyone]) || (group_ids & belonging_to_group_ids).any? + end + + def belonging_to_group_ids + @belonging_to_group_ids ||= group_users.pluck(:group_id) + end + def group_granted_trust_level GroupUser .where(user_id: id) @@ -495,6 +503,7 @@ class User < ActiveRecord::Base @user_fields_cache = nil @ignored_user_ids = nil @muted_user_ids = nil + @belonging_to_group_ids = nil super end @@ -538,15 +547,14 @@ class User < ActiveRecord::Base DB.query_single(sql, user_id: id, high_priority: high_priority)[0].to_i end - MAX_UNREAD_HIGH_PRI_BACKLOG = 200 - def grouped_unread_high_priority_notifications - results = DB.query(<<~SQL, user_id: self.id, limit: MAX_UNREAD_HIGH_PRI_BACKLOG) + MAX_UNREAD_BACKLOG = 400 + def grouped_unread_notifications + results = DB.query(<<~SQL, user_id: self.id, limit: MAX_UNREAD_BACKLOG) SELECT X.notification_type AS type, COUNT(*) FROM ( SELECT n.notification_type FROM notifications n LEFT JOIN topics t ON t.id = n.topic_id WHERE t.deleted_at IS NULL - AND n.high_priority AND n.user_id = :user_id AND NOT n.read LIMIT :limit @@ -643,6 +651,9 @@ class User < ActiveRecord::Base end def saw_notification_id(notification_id) + Discourse.deprecate(<<~TEXT, since: "2.9", drop_from: "3.0") + User#saw_notification_id is deprecated. Please use User#bump_last_seen_notification! instead. + TEXT if seen_notification_id.to_i < notification_id.to_i update_columns(seen_notification_id: notification_id.to_i) true @@ -651,6 +662,19 @@ class User < ActiveRecord::Base end end + def bump_last_seen_notification! + query = self.notifications.visible + if seen_notification_id + query = query.where("notifications.id > ?", seen_notification_id) + end + if max_notification_id = query.maximum(:id) + update!(seen_notification_id: max_notification_id) + true + else + false + end + end + def bump_last_seen_reviewable! query = Reviewable.unseen_list_for(self, preload: false) @@ -730,7 +754,7 @@ class User < ActiveRecord::Base if self.redesigned_user_menu_enabled? payload[:all_unread_notifications_count] = all_unread_notifications_count - payload[:grouped_unread_high_priority_notifications] = grouped_unread_high_priority_notifications + payload[:grouped_unread_notifications] = grouped_unread_notifications end MessageBus.publish("/notification/#{id}", payload, user_ids: [id]) @@ -1381,7 +1405,7 @@ class User < ActiveRecord::Base def number_of_rejected_posts ReviewableQueuedPost - .where(status: Reviewable.statuses[:rejected]) + .rejected .where(created_by_id: self.id) .count end @@ -1447,6 +1471,8 @@ class User < ActiveRecord::Base GroupActionLogger.new(Discourse.system_user, group).log_add_user_to_group(self) end end + + @belonging_to_group_ids = nil end def email @@ -1640,24 +1666,27 @@ class User < ActiveRecord::Base user_status && !user_status.expired? end - REDESIGN_USER_MENU_REDIS_KEY_PREFIX = "redesigned_user_menu_for_user_" - - def self.redesigned_user_menu_enabled_user_ids - Discourse.redis.scan_each(match: "#{REDESIGN_USER_MENU_REDIS_KEY_PREFIX}*").map do |key| - key.sub(REDESIGN_USER_MENU_REDIS_KEY_PREFIX, "").to_i - end - end - def redesigned_user_menu_enabled? - Discourse.redis.get("#{REDESIGN_USER_MENU_REDIS_KEY_PREFIX}#{self.id}") == "1" + SiteSetting.enable_experimental_sidebar_hamburger end - def enable_redesigned_user_menu - Discourse.redis.setex("#{REDESIGN_USER_MENU_REDIS_KEY_PREFIX}#{self.id}", 6.months, "1") + def sidebar_categories_ids + categories_ids = category_sidebar_section_links.pluck(:linkable_id) + + if categories_ids.blank? && SiteSetting.default_sidebar_categories.present? + return SiteSetting.default_sidebar_categories.split("|").map(&:to_i) & guardian.allowed_category_ids + end + + categories_ids end - def disable_redesigned_user_menu - Discourse.redis.del("#{REDESIGN_USER_MENU_REDIS_KEY_PREFIX}#{self.id}") + def sidebar_tags + return custom_sidebar_tags if custom_sidebar_tags.present? + if SiteSetting.default_sidebar_tags.present? + tag_names = SiteSetting.default_sidebar_tags.split("|") - DiscourseTagging.hidden_tag_names(guardian) + return Tag.where(name: tag_names) + end + Tag.none end protected diff --git a/app/models/user_bookmark_list.rb b/app/models/user_bookmark_list.rb index bb6db58bec..a55a72a814 100644 --- a/app/models/user_bookmark_list.rb +++ b/app/models/user_bookmark_list.rb @@ -5,7 +5,7 @@ class UserBookmarkList PER_PAGE = 20 - attr_reader :bookmarks, :per_page + attr_reader :bookmarks, :per_page, :has_more attr_accessor :more_bookmarks_url, :bookmark_serializer_opts def initialize(user:, guardian:, params:) @@ -21,7 +21,9 @@ class UserBookmarkList end def load(&blk) - @bookmarks = BookmarkQuery.new(user: @user, guardian: @guardian, params: @params).list_all(&blk) + query = BookmarkQuery.new(user: @user, guardian: @guardian, params: @params) + @bookmarks = query.list_all(&blk) + @has_more = (@params[:page].to_i + 1) * @params[:per_page] < query.count @bookmarks end diff --git a/app/serializers/concerns/user_sidebar_tags_mixin.rb b/app/serializers/concerns/user_sidebar_tags_mixin.rb new file mode 100644 index 0000000000..f9ec79fbee --- /dev/null +++ b/app/serializers/concerns/user_sidebar_tags_mixin.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module UserSidebarTagsMixin + def self.included(base) + base.has_many :sidebar_tags, serializer: Sidebar::TagSerializer, embed: :objects + end + + def include_sidebar_tags? + SiteSetting.enable_experimental_sidebar_hamburger && SiteSetting.tagging_enabled + end +end diff --git a/app/serializers/current_user_serializer.rb b/app/serializers/current_user_serializer.rb index a922e4fcaa..0d37b055b4 100644 --- a/app/serializers/current_user_serializer.rb +++ b/app/serializers/current_user_serializer.rb @@ -2,6 +2,7 @@ class CurrentUserSerializer < BasicUserSerializer include UserTagNotificationsMixin + include UserSidebarTagsMixin attributes :name, :unread_notifications, @@ -57,6 +58,7 @@ class CurrentUserSerializer < BasicUserSerializer :can_create_group, :link_posting_access, :external_id, + :associated_account_ids, :top_category_ids, :hide_profile_and_presence, :groups, @@ -75,16 +77,17 @@ class CurrentUserSerializer < BasicUserSerializer :pending_posts_count, :status, :sidebar_category_ids, - :sidebar_tag_names, :likes_notifications_disabled, - :grouped_unread_high_priority_notifications, - :redesigned_user_menu_enabled + :grouped_unread_notifications, + :redesigned_user_menu_enabled, + :redesigned_user_page_nav_enabled delegate :user_stat, to: :object, private: true delegate :any_posts, :draft_count, :pending_posts_count, :read_faq?, to: :user_stat def groups owned_group_ids = GroupUser.where(user_id: id, owner: true).pluck(:group_id).to_set + object.visible_groups.pluck(:id, :name, :has_messages).map do |id, name, has_messages| group = { id: id, name: name, has_messages: has_messages } group[:owner] = true if owned_group_ids.include?(id) @@ -291,6 +294,20 @@ class CurrentUserSerializer < BasicUserSerializer SiteSetting.enable_discourse_connect end + def associated_account_ids + values = {} + + object.user_associated_accounts.map do |user_associated_account| + values[user_associated_account.provider_name] = user_associated_account.provider_uid + end + + values + end + + def include_associated_account_ids? + SiteSetting.include_associated_account_ids + end + def second_factor_enabled object.totp_enabled? || object.security_keys_enabled? end @@ -308,21 +325,13 @@ class CurrentUserSerializer < BasicUserSerializer end def sidebar_category_ids - object.category_sidebar_section_links.pluck(:linkable_id) + object.sidebar_categories_ids end def include_sidebar_category_ids? SiteSetting.enable_experimental_sidebar_hamburger end - def sidebar_tag_names - object.sidebar_tags.pluck(:name) - end - - def include_sidebar_tag_names? - include_sidebar_category_ids? && SiteSetting.tagging_enabled - end - def include_status? SiteSetting.enable_user_status && object.has_status? end @@ -332,10 +341,7 @@ class CurrentUserSerializer < BasicUserSerializer end def redesigned_user_menu_enabled - if defined?(@redesigned_user_menu_enabled) - return @redesigned_user_menu_enabled - end - @redesigned_user_menu_enabled = object.redesigned_user_menu_enabled? + object.redesigned_user_menu_enabled? end def likes_notifications_disabled @@ -346,11 +352,19 @@ class CurrentUserSerializer < BasicUserSerializer redesigned_user_menu_enabled end - def include_grouped_unread_high_priority_notifications? + def include_grouped_unread_notifications? redesigned_user_menu_enabled end def include_unseen_reviewable_count? redesigned_user_menu_enabled end + + def redesigned_user_page_nav_enabled + if SiteSetting.enable_new_user_profile_nav_groups.present? + object.in_any_groups?(SiteSetting.enable_new_user_profile_nav_groups_map) + else + false + end + end end diff --git a/app/serializers/post_revision_serializer.rb b/app/serializers/post_revision_serializer.rb index 1791c38304..de4430fafc 100644 --- a/app/serializers/post_revision_serializer.rb +++ b/app/serializers/post_revision_serializer.rb @@ -208,6 +208,7 @@ class PostRevisionSerializer < ApplicationSerializer # Retrieve any `tracked_topic_fields` PostRevisor.tracked_topic_fields.each_key do |field| + next if field == :tags # Special handling below if topic.respond_to?(field) latest_modifications[field.to_s] = [topic.public_send(field)] end diff --git a/app/serializers/queued_post_serializer.rb b/app/serializers/queued_post_serializer.rb index a0e51ab133..f9dc0dcdef 100644 --- a/app/serializers/queued_post_serializer.rb +++ b/app/serializers/queued_post_serializer.rb @@ -2,7 +2,6 @@ # Deprecated, should be removed once users have sufficient opportunity to do so class QueuedPostSerializer < ApplicationSerializer - attributes( :id, :queue, @@ -33,11 +32,11 @@ class QueuedPostSerializer < ApplicationSerializer end def approved_by_id - who_did(:approved) + post_history.approved.last&.created_by_id end def rejected_by_id - who_did(:rejected) + post_history.rejected.last&.created_by_id end def raw @@ -56,17 +55,12 @@ class QueuedPostSerializer < ApplicationSerializer created_by && created_by.trust_level == TrustLevel[0] end -protected + private - def who_did(status) + def post_history object. reviewable_histories. - where( - reviewable_history_type: ReviewableHistory.types[:transitioned], - status: Reviewable.statuses[status] - ). + transitioned. order(:created_at) - .last&.created_by_id end - end diff --git a/app/serializers/reviewable_history_serializer.rb b/app/serializers/reviewable_history_serializer.rb index 16733219ce..d4ae2e7838 100644 --- a/app/serializers/reviewable_history_serializer.rb +++ b/app/serializers/reviewable_history_serializer.rb @@ -1,8 +1,10 @@ # frozen_string_literal: true class ReviewableHistorySerializer < ApplicationSerializer + attributes :id, :created_at + + attribute :reviewable_history_type_for_database, key: :reviewable_history_type + attribute :status_for_database, key: :status - attributes :id, :reviewable_history_type, :status, :created_at has_one :created_by, serializer: BasicUserSerializer, root: 'users' - end diff --git a/app/serializers/reviewable_score_serializer.rb b/app/serializers/reviewable_score_serializer.rb index 549bd4536a..6a0eac38d0 100644 --- a/app/serializers/reviewable_score_serializer.rb +++ b/app/serializers/reviewable_score_serializer.rb @@ -15,7 +15,10 @@ class ReviewableScoreSerializer < ApplicationSerializer contains_media: 'review_media_unless_trust_level', } - attributes :id, :score, :agree_stats, :status, :reason, :created_at, :reviewed_at + attributes :id, :score, :agree_stats, :reason, :created_at, :reviewed_at + + attribute :status_for_database, key: :status + has_one :user, serializer: BasicUserSerializer, root: 'users' has_one :score_type, serializer: ReviewableScoreTypeSerializer has_one :reviewable_conversation, serializer: ReviewableConversationSerializer diff --git a/app/serializers/reviewable_serializer.rb b/app/serializers/reviewable_serializer.rb index 5dafa06a0b..2260a4f9db 100644 --- a/app/serializers/reviewable_serializer.rb +++ b/app/serializers/reviewable_serializer.rb @@ -6,7 +6,6 @@ class ReviewableSerializer < ApplicationSerializer attributes( :id, - :status, :type, :topic_id, :topic_url, @@ -20,6 +19,8 @@ class ReviewableSerializer < ApplicationSerializer :target_created_by_trust_level ) + attribute :status_for_database, key: :status + has_one :created_by, serializer: UserWithCustomFieldsSerializer, root: 'users' has_one :target_created_by, serializer: UserWithCustomFieldsSerializer, root: 'users' has_one :topic, serializer: ListableTopicSerializer diff --git a/app/serializers/sidebar/tag_serializer.rb b/app/serializers/sidebar/tag_serializer.rb new file mode 100644 index 0000000000..3e576cd247 --- /dev/null +++ b/app/serializers/sidebar/tag_serializer.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Sidebar + class TagSerializer < ::ApplicationSerializer + attributes :name, :pm_only + + def pm_only + object.topic_count == 0 && object.pm_topic_count > 0 + end + end +end diff --git a/app/serializers/site_serializer.rb b/app/serializers/site_serializer.rb index aa68f845f0..fa396d1a62 100644 --- a/app/serializers/site_serializer.rb +++ b/app/serializers/site_serializer.rb @@ -35,7 +35,8 @@ class SiteSerializer < ApplicationSerializer :categories, :markdown_additional_options, :displayed_about_plugin_stat_groups, - :show_welcome_topic_banner + :show_welcome_topic_banner, + :anonymous_default_sidebar_tags ) has_many :archetypes, embed: :objects, serializer: ArchetypeSerializer @@ -218,6 +219,14 @@ class SiteSerializer < ApplicationSerializer Site.show_welcome_topic_banner?(scope) end + def anonymous_default_sidebar_tags + User.new.sidebar_tags.pluck(:name) + end + + def include_anonymous_default_sidebar_tags? + SiteSetting.default_sidebar_tags.present? + end + private def ordered_flags(flags) diff --git a/app/serializers/topic_view_serializer.rb b/app/serializers/topic_view_serializer.rb index 1207a9a515..57bd35aaf4 100644 --- a/app/serializers/topic_view_serializer.rb +++ b/app/serializers/topic_view_serializer.rb @@ -290,7 +290,7 @@ class TopicViewSerializer < ApplicationSerializer SiteSetting.enable_page_publishing? && scope.is_staff? && object.published_page.present? && - !SiteSetting.secure_media + !SiteSetting.secure_uploads end def thumbnails diff --git a/app/serializers/upload_serializer.rb b/app/serializers/upload_serializer.rb index 43b89526f9..7626c0e1e2 100644 --- a/app/serializers/upload_serializer.rb +++ b/app/serializers/upload_serializer.rb @@ -13,9 +13,10 @@ class UploadSerializer < ApplicationSerializer :short_url, :short_path, :retain_hours, - :human_filesize + :human_filesize, + :dominant_color def url - object.for_site_setting ? object.url : UrlHelper.cook_url(object.url, secure: SiteSetting.secure_media? && object.secure) + object.for_site_setting ? object.url : UrlHelper.cook_url(object.url, secure: SiteSetting.secure_uploads? && object.secure) end end diff --git a/app/serializers/user_bookmark_list_serializer.rb b/app/serializers/user_bookmark_list_serializer.rb index b9f74ef4b0..cefdd95114 100644 --- a/app/serializers/user_bookmark_list_serializer.rb +++ b/app/serializers/user_bookmark_list_serializer.rb @@ -15,6 +15,6 @@ class UserBookmarkListSerializer < ApplicationSerializer end def include_more_bookmarks_url? - @include_more_bookmarks_url ||= object.bookmarks.size == object.per_page + @include_more_bookmarks_url ||= object.has_more end end diff --git a/app/serializers/user_card_serializer.rb b/app/serializers/user_card_serializer.rb index 3170936174..a109e9ebbf 100644 --- a/app/serializers/user_card_serializer.rb +++ b/app/serializers/user_card_serializer.rb @@ -16,7 +16,11 @@ class UserCardSerializer < BasicUserSerializer attributes(*attrs) attrs.each do |attr| define_method "include_#{attr}?" do - can_edit + if defined?(super) + super() && can_edit + else + can_edit + end end end end diff --git a/app/serializers/user_post_topic_bookmark_base_serializer.rb b/app/serializers/user_post_topic_bookmark_base_serializer.rb index b91002a4b1..ca5d50e684 100644 --- a/app/serializers/user_post_topic_bookmark_base_serializer.rb +++ b/app/serializers/user_post_topic_bookmark_base_serializer.rb @@ -15,7 +15,6 @@ class UserPostTopicBookmarkBaseSerializer < UserBookmarkBaseSerializer :archived, :archetype, :highest_post_number, - :last_read_post_number, :bumped_at, :slug @@ -51,10 +50,6 @@ class UserPostTopicBookmarkBaseSerializer < UserBookmarkBaseSerializer scope.is_whisperer? ? topic.highest_staff_post_number : topic.highest_post_number end - def last_read_post_number - topic_user&.last_read_post_number - end - def bumped_at topic.bumped_at end @@ -62,10 +57,4 @@ class UserPostTopicBookmarkBaseSerializer < UserBookmarkBaseSerializer def slug topic.slug end - - private - - def topic_user - @topic_user ||= topic.topic_users.find { |tu| tu.user_id == scope.user.id } - end end diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index 7c0a97378c..0e9f975032 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -2,6 +2,7 @@ class UserSerializer < UserCardSerializer include UserTagNotificationsMixin + include UserSidebarTagsMixin attributes :bio_raw, :bio_cooked, @@ -62,7 +63,8 @@ class UserSerializer < UserCardSerializer :user_api_keys, :user_auth_tokens, :user_notification_schedule, - :use_logo_small_as_avatar + :use_logo_small_as_avatar, + :sidebar_tags untrusted_attributes :bio_raw, :bio_cooked, diff --git a/app/serializers/user_topic_bookmark_serializer.rb b/app/serializers/user_topic_bookmark_serializer.rb index b4ef6762d2..477c744f1e 100644 --- a/app/serializers/user_topic_bookmark_serializer.rb +++ b/app/serializers/user_topic_bookmark_serializer.rb @@ -1,7 +1,9 @@ # frozen_string_literal: true class UserTopicBookmarkSerializer < UserPostTopicBookmarkBaseSerializer - # it does not matter what the linked post number is for topic bookmarks, + attributes :last_read_post_number + + # NOTE: It does not matter what the linked post number is for topic bookmarks, # on the client we always take the user to the last unread post in the # topic when the bookmark URL is clicked def linked_post_number @@ -9,7 +11,7 @@ class UserTopicBookmarkSerializer < UserPostTopicBookmarkBaseSerializer end def first_post - @first_post ||= topic.posts.find { |post| post.post_number == 1 } + @first_post ||= topic.first_post end def deleted @@ -25,28 +27,7 @@ class UserTopicBookmarkSerializer < UserPostTopicBookmarkBaseSerializer end def cooked - @cooked ||= \ - if last_read_post_number.present? - for_topic_cooked_post - else - first_post.cooked - end - end - - def for_topic_cooked_post - post_number = [last_read_post_number + 1, highest_post_number].min - sorted_regular_posts = topic.posts.sort_by(&:post_number).select do |post| - post.post_type == Post.types[:regular] - end - first_unread_post = sorted_regular_posts.find do |post| - post.post_number >= post_number - end - - # if first_unread_cooked is blank this likely means that the last - # read post was either deleted or is a small action post. - # in this case we should just get the last regular post and - # use that for the cooked value so we have something to show - (first_unread_post || sorted_regular_posts.last).cooked + first_post.cooked end def bookmarkable_user @@ -63,9 +44,17 @@ class UserTopicBookmarkSerializer < UserPostTopicBookmarkBaseSerializer end end + def last_read_post_number + topic_user&.last_read_post_number + end + private def topic object.bookmarkable end + + def topic_user + topic.user_data + end end diff --git a/app/serializers/wizard_field_serializer.rb b/app/serializers/wizard_field_serializer.rb index b6b5cf3b2a..12c3db2060 100644 --- a/app/serializers/wizard_field_serializer.rb +++ b/app/serializers/wizard_field_serializer.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class WizardFieldSerializer < ApplicationSerializer - attributes :id, :type, :required, :value, :label, :placeholder, :description, :extra_description, :icon, :show_in_sidebar + attributes :id, :type, :required, :value, :label, :placeholder, :description, :extra_description, :icon, :disabled, :show_in_sidebar has_many :choices, serializer: WizardFieldChoiceSerializer, embed: :objects def id @@ -75,6 +75,14 @@ class WizardFieldSerializer < ApplicationSerializer object.icon.present? end + def disabled + object.disabled + end + + def include_disabled? + object.disabled + end + def show_in_sidebar object.show_in_sidebar end diff --git a/app/services/base_bookmarkable.rb b/app/services/base_bookmarkable.rb index dacc02c07e..6976eece62 100644 --- a/app/services/base_bookmarkable.rb +++ b/app/services/base_bookmarkable.rb @@ -39,6 +39,15 @@ class BaseBookmarkable preload_associations.present? end + ## + # + # Implementations can define their own preloading logic here + # @param [Array] bookmarks_of_type The list of bookmarks to preload data for. Already filtered to be of the correct class. + # @param [Guardian] guardian An instance of Guardian for the current_user + def self.perform_custom_preload!(bookmarks_of_type, guardian) + nil + end + ## # This is where the main query to filter the bookmarks by the provided bookmarkable # type should occur. This should join on additional tables that are required later diff --git a/app/services/group_message.rb b/app/services/group_message.rb index 4ffac25e12..1f24289434 100644 --- a/app/services/group_message.rb +++ b/app/services/group_message.rb @@ -27,23 +27,23 @@ class GroupMessage end def create - unless sent_recently? - post = PostCreator.create( - Discourse.system_user, - target_group_names: [@group_name], - archetype: Archetype.private_message, - subtype: TopicSubtype.system_message, - title: I18n.t("system_messages.#{@message_type}.subject_template", message_params), - raw: I18n.t("system_messages.#{@message_type}.text_body_template", message_params) - ) - remember_message_sent - post - else - false - end + return false if sent_recently? + + post = PostCreator.create( + Discourse.system_user, + target_group_names: [@group_name], + archetype: Archetype.private_message, + subtype: TopicSubtype.system_message, + title: I18n.t("system_messages.#{@message_type}.subject_template", message_params), + raw: I18n.t("system_messages.#{@message_type}.text_body_template", message_params) + ) + remember_message_sent + post end - def delete_previous!(match_raw: true) + def delete_previous!(respect_sent_recently: true, match_raw: true) + return false if respect_sent_recently && sent_recently? + posts = Post .joins(topic: { topic_allowed_groups: :group }) .where(topic: { diff --git a/app/services/post_alerter.rb b/app/services/post_alerter.rb index 53942b31d5..83ae94e17a 100644 --- a/app/services/post_alerter.rb +++ b/app/services/post_alerter.rb @@ -110,6 +110,8 @@ class PostAlerter def after_save_post(post, new_record = false) notified = [post.user, post.last_editor].uniq + DiscourseEvent.trigger(:post_alerter_before_mentions, post, new_record, notified) + # mentions (users/groups) mentioned_groups, mentioned_users, mentioned_here = extract_mentions(post) @@ -139,6 +141,8 @@ class PostAlerter end end + DiscourseEvent.trigger(:post_alerter_before_replies, post, new_record, notified) + # replies reply_to_user = post.reply_notification_target @@ -146,31 +150,42 @@ class PostAlerter notified += notify_non_pm_users(reply_to_user, :replied, post) end + DiscourseEvent.trigger(:post_alerter_before_quotes, post, new_record, notified) + # quotes quoted_users = extract_quoted_users(post) notified += notify_non_pm_users(quoted_users - notified, :quoted, post) + DiscourseEvent.trigger(:post_alerter_before_linked, post, new_record, notified) + # linked linked_users = extract_linked_users(post) notified += notify_non_pm_users(linked_users - notified, :linked, post) - # private messages + DiscourseEvent.trigger(:post_alerter_before_post, post, new_record, notified) + if new_record if post.topic.private_message? - notify_pm_users(post, reply_to_user, quoted_users, notified) + # private messages + notified += notify_pm_users(post, reply_to_user, quoted_users, notified) elsif notify_about_reply?(post) - notify_post_users(post, notified, new_record: new_record) + # posts + notified += notify_post_users(post, notified, new_record: new_record) end end sync_group_mentions(post, mentioned_groups) + DiscourseEvent.trigger(:post_alerter_before_first_post, post, new_record, notified) + if new_record && post.post_number == 1 topic = post.topic if topic.present? watchers = category_watchers(topic) + tag_watchers(topic) + group_watchers(topic) - notify_first_post_watchers(post, watchers) + # Notify only users who can see the topic + watchers &= topic.all_allowed_users.pluck(:id) if post.topic.private_message? + notified += notify_first_post_watchers(post, watchers, notified) end end @@ -197,20 +212,23 @@ class PostAlerter .pluck(:user_id) end - def notify_first_post_watchers(post, user_ids) - return if user_ids.blank? + def notify_first_post_watchers(post, user_ids, notified = nil) + return [] if user_ids.blank? user_ids.uniq! warn_if_not_sidekiq - # Don't notify the OP - user_ids -= [post.user_id] + # Don't notify the OP and last editor + user_ids -= [post.user_id, post.last_editor_id] users = User.where(id: user_ids).includes(:do_not_disturb_timings) + users = users.where.not(id: notified.map(&:id)) if notified.present? DiscourseEvent.trigger(:before_create_notifications_for_users, users, post) each_user_in_batches(users) do |user| create_notification(user, Notification.types[:watching_first_post], post) end + + users end def sync_group_mentions(post, mentioned_groups) @@ -618,7 +636,7 @@ class PostAlerter end def notify_pm_users(post, reply_to_user, quoted_users, notified) - return unless post.topic + return [] unless post.topic warn_if_not_sidekiq @@ -747,7 +765,7 @@ class PostAlerter end def notify_post_users(post, notified, group_ids: nil, include_topic_watchers: true, include_category_watchers: true, include_tag_watchers: true, new_record: false) - return unless post.topic + return [] unless post.topic warn_if_not_sidekiq @@ -843,6 +861,8 @@ class PostAlerter opts[:display_username] = post.last_editor.username if notification_type == Notification.types[:edited] create_notification(user, notification_type, post, opts) end + + notify end def warn_if_not_sidekiq diff --git a/app/services/post_bookmarkable.rb b/app/services/post_bookmarkable.rb index 5690d30db6..09373f6e99 100644 --- a/app/services/post_bookmarkable.rb +++ b/app/services/post_bookmarkable.rb @@ -12,7 +12,7 @@ class PostBookmarkable < BaseBookmarkable end def self.preload_associations - [{ topic: [:topic_users, :tags] }, :user] + [{ topic: [:tags] }, :user] end def self.list_query(user, guardian) diff --git a/app/services/registered_bookmarkable.rb b/app/services/registered_bookmarkable.rb index ce3cb1a490..fc40dee521 100644 --- a/app/services/registered_bookmarkable.rb +++ b/app/services/registered_bookmarkable.rb @@ -55,18 +55,25 @@ class RegisteredBookmarkable # # [{ topic: [:topic_users, :tags] }, :user] # + # For more advanced preloading, bookmarkable classes can implement `perform_custom_preload!` + # # @param [Array] bookmarks The array of bookmarks after initial listing and filtering, note this is # array _not_ an ActiveRecord::Relation. # @return [void] - def perform_preload(bookmarks) - return if !bookmarkable_klass.has_preloads? + def perform_preload(bookmarks, guardian) + bookmarks_of_type = Bookmark.select_type(bookmarks, bookmarkable_klass.model.to_s) + return if bookmarks_of_type.empty? - ActiveRecord::Associations::Preloader - .new( - records: Bookmark.select_type(bookmarks, bookmarkable_klass.model.to_s), - associations: [bookmarkable: bookmarkable_klass.preload_associations] - ) - .call + if bookmarkable_klass.has_preloads? + ActiveRecord::Associations::Preloader + .new( + records: bookmarks_of_type, + associations: [bookmarkable: bookmarkable_klass.preload_associations] + ) + .call + end + + bookmarkable_klass.perform_custom_preload!(bookmarks_of_type, guardian) end def can_send_reminder?(bookmark) diff --git a/app/services/spam_rule/flag_sockpuppets.rb b/app/services/spam_rule/flag_sockpuppets.rb index 00f74e881b..c51d67f402 100644 --- a/app/services/spam_rule/flag_sockpuppets.rb +++ b/app/services/spam_rule/flag_sockpuppets.rb @@ -47,8 +47,7 @@ class SpamRule::FlagSockpuppets private def flag_post(post, message) - can_trust_user = ReviewableFlaggedPost.where(status: Reviewable.statuses[:rejected], target_created_by: post.user).exists? - return if can_trust_user + return if ReviewableFlaggedPost.rejected.exists?(target_created_by: post.user) PostActionCreator.create(Discourse.system_user, post, :spam, message: message) end diff --git a/app/services/staff_action_logger.rb b/app/services/staff_action_logger.rb index f5c3386f15..a4203452bb 100644 --- a/app/services/staff_action_logger.rb +++ b/app/services/staff_action_logger.rb @@ -100,7 +100,8 @@ class StaffActionLogger UserHistory.create!(params(opts).merge( action: UserHistory.actions[:change_trust_level], target_user_id: user.id, - details: "old trust level: #{old_trust_level}\nnew trust level: #{new_trust_level}" + previous_value: old_trust_level, + new_value: new_trust_level, )) end diff --git a/app/services/topic_bookmarkable.rb b/app/services/topic_bookmarkable.rb index 45ce54adfd..5a5276f64a 100644 --- a/app/services/topic_bookmarkable.rb +++ b/app/services/topic_bookmarkable.rb @@ -12,7 +12,16 @@ class TopicBookmarkable < BaseBookmarkable end def self.preload_associations - [:topic_users, :tags, { posts: :user }] + [:tags, { first_post: :user }] + end + + def self.perform_custom_preload!(topic_bookmarks, guardian) + topics = topic_bookmarks.map(&:bookmarkable) + topic_user_lookup = TopicUser.lookup_for(guardian.user, topics) + + topics.each do |topic| + topic.user_data = topic_user_lookup[topic.id] + end end def self.list_query(user, guardian) diff --git a/app/views/common/_discourse_splash.html.erb b/app/views/common/_discourse_splash.html.erb index 3ce1009a69..4ce41e78e8 100644 --- a/app/views/common/_discourse_splash.html.erb +++ b/app/views/common/_discourse_splash.html.erb @@ -246,71 +246,6 @@ - + <%= SplashScreenHelper.inline_splash_screen_script %>
    <%- end %> diff --git a/app/views/finish_installation/index.html.erb b/app/views/finish_installation/index.html.erb index 65bc54618e..de7ffeb009 100644 --- a/app/views/finish_installation/index.html.erb +++ b/app/views/finish_installation/index.html.erb @@ -1,19 +1,18 @@ -

    <%= t 'finish_installation.congratulations' %>

    +
    +
    +

    <%= t 'finish_installation.congratulations' %>

    +

    <%= t 'finish_installation.register.help' %>

    -
    - <%= image_tag "/images/wizard/tada.svg", class: "tada" %> -
    - -
    - <%= t 'finish_installation.register.help' %> -
    - -
    - <%= link_to(finish_installation_register_path, class: 'wizard-container__button primary') do %> - - - - - <%= t 'finish_installation.register.button' %> - <% end %> + <%= link_to(finish_installation_register_path, class: 'wizard-container__button primary') do %> + + + + <%= t 'finish_installation.register.button' %> + <% end %> + +
    + +
    + <%= image_tag "/images/wizard/tada.svg", class: "tada" %> +
    diff --git a/app/views/layouts/_noscript_header.html.erb b/app/views/layouts/_noscript_header.html.erb index 5085644f17..61095d320b 100644 --- a/app/views/layouts/_noscript_header.html.erb +++ b/app/views/layouts/_noscript_header.html.erb @@ -1,5 +1,5 @@
    "> -

    <%=SiteSetting.title%>

    + <%=SiteSetting.title%>
    diff --git a/app/views/qunit/theme.html.erb b/app/views/qunit/theme.html.erb index c5e1071b5f..f2db3572fb 100644 --- a/app/views/qunit/theme.html.erb +++ b/app/views/qunit/theme.html.erb @@ -8,8 +8,9 @@ <%= preload_script "vendor" %> <%= preload_script "discourse" %> <%= preload_script "admin" %> - <%= preload_script "discourse/tests/active-plugins" %> - <%= preload_script "admin-plugins" %> + <%- Discourse.find_plugin_js_assets(include_disabled: true).each do |file| %> + <%= preload_script file %> + <%- end %> <%= preload_script "test-support" %> <%= preload_script "test-helpers" %> <%= theme_translations_lookup %> diff --git a/app/views/safe_mode/index.html.erb b/app/views/safe_mode/index.html.erb index 0405a07946..c6ee82531f 100644 --- a/app/views/safe_mode/index.html.erb +++ b/app/views/safe_mode/index.html.erb @@ -6,14 +6,14 @@

    diff --git a/app/views/users/admin_login.html.erb b/app/views/users/admin_login.html.erb index 95a74a123f..82e061bdfd 100644 --- a/app/views/users/admin_login.html.erb +++ b/app/views/users/admin_login.html.erb @@ -5,6 +5,11 @@ <%=form_tag(u_admin_login_path, method: :put) do %> <%= label_tag(:email, t('admin_login.email_input')) %> <%= text_field_tag(:email, nil, autofocus: true) %>

    + +
    <%= submit_tag t('admin_login.submit_button'), class: "btn btn-primary" %> <% end %> <% end %> diff --git a/bin/ember-cli b/bin/ember-cli index 55f771aa28..d1c480085c 100755 --- a/bin/ember-cli +++ b/bin/ember-cli @@ -7,7 +7,7 @@ RAILS_ROOT = File.expand_path("../../", Pathname.new(__FILE__).realpath) PORT = ENV["UNICORN_PORT"] ||= "3000" HOSTNAME = ENV["DISCOURSE_HOSTNAME"] ||= "127.0.0.1" YARN_DIR = File.join(RAILS_ROOT, "app/assets/javascripts/discourse") -CUSTOM_ARGS = ["--try", "--test", "--unicorn", "-u", "--forward-host"] +CUSTOM_ARGS = ["--try", "--test", "--build", "--unicorn", "-u", "--forward-host"] PROXY = if ARGV.include?("--try") "https://try.discourse.org" @@ -15,9 +15,17 @@ PROXY = "http://#{HOSTNAME}:#{PORT}" end +def process_running?(pid) + !!Process.kill(0, pid) +rescue Errno::ESRCH + false +end + command = if ARGV.include?("--test") "test" + elsif ARGV.include?("--build") + "build" else "server" end @@ -43,7 +51,7 @@ end args = ["-s", "--cwd", YARN_DIR, "run", "ember", command] + (ARGV - CUSTOM_ARGS) -if !args.include?("test") && !args.include?("--proxy") +if !args.include?("test") && !args.include?("build") && !args.include?("--proxy") args << "--proxy" args << PROXY end @@ -58,11 +66,13 @@ end if ARGV.include?("-u") || ARGV.include?("--unicorn") unicorn_env = { "DISCOURSE_PORT" => ENV["DISCOURSE_PORT"] || "4200" } unicorn_pid = spawn(unicorn_env, __dir__ + "/unicorn") + ember_cli_pid = nil Thread.new do require 'open3' Open3.popen2e(yarn_env, "yarn", *args.to_a.flatten) do |i, oe, t| - puts "Ember CLI running on PID: #{t.pid}" + ember_cli_pid = t.pid + puts "Ember CLI running on PID: #{ember_cli_pid}" oe.each do |line| if line.include?("\e[32m200\e") || line.include?("\e[36m304\e[0m") || line.include?("POST /message-bus") # skip 200s and 304s and message bus @@ -71,6 +81,10 @@ if ARGV.include?("-u") || ARGV.include?("--unicorn") end end end + if process_running?(unicorn_pid) + puts "[bin/ember-cli] ember-cli process stopped. Terminating unicorn." + Process.kill("TERM", unicorn_pid) + end end trap("SIGINT") do @@ -79,6 +93,11 @@ if ARGV.include?("-u") || ARGV.include?("--unicorn") end Process.wait(unicorn_pid) + + if ember_cli_pid && process_running?(ember_cli_pid) + puts "[bin/ember-cli] unicorn process stopped. Terminating ember-cli." + Process.kill("TERM", ember_cli_pid) + end else exec(yarn_env, "yarn", *args.to_a.flatten) end diff --git a/bin/rake b/bin/rake index 61c75ed85a..b699951a80 100755 --- a/bin/rake +++ b/bin/rake @@ -2,7 +2,7 @@ # frozen_string_literal: true if ENV['RAILS_ENV'] == 'test' && ENV['LOAD_PLUGINS'].nil? - if ARGV.include?('db:migrate') + if ARGV.include?('db:migrate') || ARGV.include?('parallel:migrate') STDERR.puts "You are attempting to run migrations in your test environment and are not loading plugins, setting LOAD_PLUGINS to 1" ENV['LOAD_PLUGINS'] = '1' end diff --git a/bin/system_rspec b/bin/system_rspec new file mode 100755 index 0000000000..3f9e0f2adf --- /dev/null +++ b/bin/system_rspec @@ -0,0 +1,7 @@ +#!/bin/bash + +if [[ -z "$@" ]]; then + bin/rspec spec/system +elif [[ -n "$@" ]]; then + bin/rspec "$@" +fi diff --git a/bin/turbo_rspec b/bin/turbo_rspec index 66464bc67b..7d4c427816 100755 --- a/bin/turbo_rspec +++ b/bin/turbo_rspec @@ -59,10 +59,18 @@ formatters.each do |formatter| end end +# We do not want to include system specs by default, they are super +# slow and require a selenium server to be running. +default_spec_dirs = Dir.entries("#{Rails.root}/spec").reject do |entry| + !File.directory?("spec/#{entry}") || ["..", ".", "system"].include?(entry) +end.map { |entry| "spec/#{entry}" } +files = ARGV.empty? ? default_spec_dirs : ARGV + +puts "Running turbo_rspec using files in #{files}" success = TurboTests::Runner.run( formatters: formatters, - files: ARGV.empty? ? ["spec"] : ARGV, + files: files, verbose: verbose, fail_fast: fail_fast ) diff --git a/bin/unicorn b/bin/unicorn index 6f6e169313..2d076feff4 100755 --- a/bin/unicorn +++ b/bin/unicorn @@ -107,6 +107,10 @@ if dev_mode restart = true end + Signal.trap("TERM") do + Process.kill('TERM', pid) + end + while !done sleep 1 done = Process.waitpid(pid, Process::WNOHANG) diff --git a/config/discourse_defaults.conf b/config/discourse_defaults.conf index 23e1669a83..1007417f87 100644 --- a/config/discourse_defaults.conf +++ b/config/discourse_defaults.conf @@ -95,6 +95,12 @@ smtp_openssl_verify_mode = # force implicit TLS as per RFC 8314 3.3 smtp_force_tls = false +# number of seconds to wait while attempting to open a SMTP connection +smtp_open_timeout = 5 + +# Number of seconds to wait until timing-out a SMTP read(2) call +smtp_read_timeout = 5 + # load MiniProfiler in production, to be used by developers load_mini_profiler = true diff --git a/config/environments/production.rb b/config/environments/production.rb index 5f05f6e9b3..6b73c82e9d 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -32,7 +32,9 @@ Discourse::Application.configure do user_name: GlobalSetting.smtp_user_name, password: GlobalSetting.smtp_password, authentication: GlobalSetting.smtp_authentication, - enable_starttls_auto: GlobalSetting.smtp_enable_start_tls + enable_starttls_auto: GlobalSetting.smtp_enable_start_tls, + open_timeout: GlobalSetting.smtp_open_timeout, + read_timeout: GlobalSetting.smtp_read_timeout } settings[:openssl_verify_mode] = GlobalSetting.smtp_openssl_verify_mode if GlobalSetting.smtp_openssl_verify_mode diff --git a/config/initializers/006-mini_profiler.rb b/config/initializers/006-mini_profiler.rb index a9f4fad518..9642894352 100644 --- a/config/initializers/006-mini_profiler.rb +++ b/config/initializers/006-mini_profiler.rb @@ -45,10 +45,12 @@ if defined?(Rack::MiniProfiler) && defined?(Rack::MiniProfiler::Config) /^\/site_customizations/, /^\/uploads/, /^\/secure-media-uploads/, + /^\/secure-uploads/, /^\/javascripts\//, /^\/images\//, /^\/stylesheets\//, - /^\/favicon\/proxied/ + /^\/favicon\/proxied/, + /^\/theme-javascripts/ ] # we DO NOT WANT mini-profiler loading on anything but real desktops and laptops diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 504a14de96..84bc719d32 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -31,7 +31,6 @@ Rails.application.config.assets.precompile += %w{ browser-detect.js browser-update.js break_string.js - pretty-text-bundle.js markdown-it-bundle.js service-worker.js google-tag-manager.js @@ -47,13 +46,11 @@ Rails.application.config.assets.precompile += %w{ confirm-new-email/bootstrap.js onpopstate-handler.js embed-application.js - discourse/tests/active-plugins.js - admin-plugins.js scripts/discourse-test-listen-boot scripts/discourse-boot } -Rails.application.config.assets.precompile += EmberCli::ASSETS.map { |name| name.sub('.js', '.map') } +Rails.application.config.assets.precompile += EmberCli.assets.map { |name| name.sub('.js', '.map') } # Precompile all available locales unless GlobalSetting.try(:omit_base_locales) diff --git a/config/locales/client.ar.yml b/config/locales/client.ar.yml index d59b17f93d..7348ebaa1e 100644 --- a/config/locales/client.ar.yml +++ b/config/locales/client.ar.yml @@ -254,7 +254,6 @@ ar: forwarded: "أعاد توجيه الرسالة الإلكترونية أعلاه" topic_admin_menu: "إجراءات الموضوع" skip_to_main_content: "تخطي إلى المحتوى الرئيسي" - wizard_required: "مرحبًا بك في Discourse! لنبدأ من معالج الإعداد ✨" emails_are_disabled: "أوقف أحد المسؤولين البريد الصادر بشكلٍ عام. ولن يتم إرسال إشعارات عبر البريد الإلكتروني أيًا كان نوعها." software_update_prompt: message: "لقد حدَّثنا هذا الموقع، يُرجى التحديث ، أو قد تواجه سلوكًا غير متوقَّع." @@ -267,6 +266,7 @@ ar: many: "أنت في وضع تمهيد التشغيل لتسهيل إطلاق موقعك الجديد. سيتم منح جميع المستخدمين الجُدد مستوى الثقة 1 وتفعيل الرسائل الإلكترونية التلخيصية لهم. وسيتم إيقاف هذا الوضع تلقائيًا عند انضمام %{count} مستخدمًا." other: "أنت في وضع تمهيد التشغيل لتسهيل إطلاق موقعك الجديد. سيتم منح جميع المستخدمين الجُدد مستوى الثقة 1 وتفعيل الرسائل الإلكترونية التلخيصية لهم. وسيتم إيقاف هذا الوضع تلقائيًا عند انضمام %{count} مستخدم." bootstrap_mode_disabled: "سيتم إيقاف وضع تمهيد التشغيل خلال 24 ساعة." + bootstrap_invite_button_title: "إرسال الدعوات" themes: default_description: "افتراضي" s3: @@ -299,6 +299,8 @@ ar: not_implemented: "عذرًا، لم يتم تنفيذ هذه الميزة بعد." no_value: "لا" yes_value: "نعم" + ok_value: "حسنًا" + cancel_value: "إلغاء" submit: "إرسال" generic_error: "عذرًا، حدث خطأ." generic_error_with_reason: "حدث خطأ: %{error}" @@ -2638,6 +2640,13 @@ ar: not_logged_in_user: "صفحة المستخدم مع ملخص عن نشاطه الحالي وتفضيلاته" current_user: "الانتقال إلى صفحة المستخدم" view_all: "عرض الكل %{tab}" + user_menu: + tabs: + replies: "الردود" + mentions: "الإشارات" + likes: "الاعجابات" + bookmarks: "الإشارات المرجعية" + profile: "الملف الشخصي" topics: new_messages_marker: "آخر زيارة" bulk: @@ -3425,14 +3434,6 @@ ar: few: "هل تريد بالتأكيد حذف %{count} منشورات؟" many: "هل تريد بالتأكيد حذف %{count} منشورًا؟" other: "هل تريد بالتأكيد حذف %{count} منشور؟" - merge: - confirm: - zero: "هل تريد بالتأكيد دمج %{count} منشور؟" - one: "هل تريد بالتأكيد دمج هذا المنشور؟" - two: "هل تريد بالتأكيد دمج هذين المنشورين (%{count})؟" - few: "هل تريد بالتأكيد دمج %{count} منشورات؟" - many: "هل تريد بالتأكيد دمج %{count} منشورًا؟" - other: "هل تريد بالتأكيد دمج %{count} منشور؟" revisions: controls: first: "أول مراجعة" @@ -4065,7 +4066,6 @@ ar: google: "تقويم جوجل" ics: "ICS" tagging: - all_tags: "كل الوسوم" other_tags: "وسوم أخرى" selector_all_tags: "كل الوسوم" selector_no_tags: "لا توجد وسوم" @@ -4254,14 +4254,11 @@ ar: unsupported_file_picked: "لقد اخترت ملفًا غير مدعوم. أنواع الملفات المدعومة - %{types}." user_activity: no_activity_title: "لا يوجد نشاط." - no_activity_others: "لا يوجد نشاط." no_replies_title: "لم ترد على أي مواضيع حتى الآن" - no_replies_others: "لا توجد ردود." no_drafts_title: "لم تبدأ أي مسودات" no_drafts_body: "لست مستعدًا للنشر؟ سنقوم تلقائيًا بحفظ مسودة جديدة وإدراجها هنا كلما بدأت في إنشاء موضوع أو رد أو رسالة شخصية. حدد زر الإلغاء لتجاهل المُسَوَّدَة أو حفظها للمتابعة لاحقًا." no_likes_title: "لم بالإعجاب بأي مواضيع حتى الآن" no_likes_body: "هناك طريقة رائعة للتقدّم والبدء في المساهمة هي البَدْء في قراءة المحادثات التي جرت بالفعل، واختيار %{heartIcon} على المشاركات التي تريدها." - no_likes_others: "لا توجد منشورات سجَّلت إعجابك بها." no_topics_title: "لم تنشئ أي مواضيع حتى الآن" no_read_topics_title: "لم تقرأ أي مواضيع حتى الآن" no_read_topics_body: "بمجرد البَدْء في قراءة المناقشات، سترى قائمة هنا. لبدء القراءة، ابحث عن الموضوعات التي تهمك في أعلى أو فئات أو البحث عن طريق الكلمة الرئيسية %{searchIcon}" @@ -4289,7 +4286,10 @@ ar: many: "%{count} جديدًا" other: "%{count} جديدة" more: "المزيد..." + all_categories: "كل الفئات" sections: + about: + header_link_text: "نبذة" messages: header_link_text: "الرسائل" links: @@ -4301,19 +4301,24 @@ ar: unread_with_count: "غير المقروءة (%{count})" archive: "الأرشيف" tags: - header_link_title: "كل الوسوم" header_link_text: "الوسوم" categories: - header_link_title: "كل الفئات" header_link_text: "الفئات" community: - header_link_title: "الصفحة الرئيسية" header_link_text: "المجتمع" header_action_title: "إنشاء موضوع جديد" links: + about: + content: "نبذة" + admin: + content: "مسؤول" + badges: + content: "الشارات" everything: content: "كل شىء" title: "جميع الموضوعات" + faq: + content: "الأسئلة الشائعة" tracked: content: "المتتبَّعة" title: "جميع المواضيع المُتَعَقبة" @@ -5548,7 +5553,6 @@ ar: few: "يتعذَّر حذف جميع المنشورات لأن المستخدم لديه أكثر من %{count} منشورات. (delete_all_posts_max)" many: "يتعذَّر حذف جميع المنشورات لأن المستخدم لديه أكثر من %{count} منشورًا. (delete_all_posts_max)" other: "يتعذَّر حذف جميع المنشورات لأن المستخدم لديه أكثر من %{count} منشور. (delete_all_posts_max)" - delete_confirm: "يُفضَّل عامةً إخفاء هوية المستخدمين بدلًا من حذفهم لتجنُّب إزالة المحتوى من المناقشات الحالية.

    هل تريد بالتأكيد حذف هذا المستخدم؟ هذا الإجراء دائم!" delete_and_block: "حذف هذا البريد الإلكتروني وعنوان IP وحظرهما" delete_dont_block: "الحذف فقط" deleting_user: "جارٍ حذف المستخدم..." @@ -5683,7 +5687,6 @@ ar: recommended: "نوصيك بتخصيص النص التالي ليلائم احتياجاتك:" show_overriden: "إظهار النصوص المخصَّصة فقط" locale: "اللغة:" - fallback_locale_warning: "أنت تجري تعديلًا على لغة بناءً على %{fallback}. لن يتمكن المستخدمون الذين اختاروا%{fallback} كلغة لواجهتهم من رؤية تغييراتك." more_than_50_results: "هناك أكثر من 50 نتيجة. يُرجى تحسين البحث." settings: show_overriden: "إظهار النصوص المخصَّصة فقط" diff --git a/config/locales/client.be.yml b/config/locales/client.be.yml index b420f8a993..875f64ca22 100644 --- a/config/locales/client.be.yml +++ b/config/locales/client.be.yml @@ -76,6 +76,7 @@ be: topic_html: 'Тэма: %{topicTitle}' close: "схаваць" emails_are_disabled: "Адпраўка паведамленняў па электроннай пошце было глабальна адключана адміністратарам. Ні адно апавяшчэнне па электроннай пошце не будзе даслана." + bootstrap_invite_button_title: "Адправіць запрашэнні" s3: regions: ap_northeast_1: "Азія (Токіа)" @@ -91,6 +92,8 @@ be: not_implemented: "Гэты функцыянал яшчэ не рэалізаваны, прабачце!" no_value: "Не" yes_value: "Так" + ok_value: "Добра" + cancel_value: "адмяніць" submit: "Адправіць" generic_error: "Выбачайце, здарылася памылка." generic_error_with_reason: "Паўстала памылка: %{error}" @@ -905,6 +908,13 @@ be: go_back: "вярнуцца назад" not_logged_in_user: "старонка карыстальніка з вынікам бягучай дзейнасці і наладамі" current_user: "перайсці да Вашай старонкі карыстальніка" + user_menu: + tabs: + replies: "Адказы" + mentions: "згадкі" + likes: "сімпатыі" + bookmarks: "закладкі" + profile: "Профіль" topics: new_messages_marker: "апошні візыт" bulk: @@ -1335,13 +1345,12 @@ be: member: "член" regular: "рэгулярны" leader: "лідэр" - user_activity: - no_activity_others: "Няма актыўнасці." - no_replies_others: "Няма адказаў." - no_likes_others: "Не спадабалася паведамленні." sidebar: more: "Яшчэ ..." + all_categories: "Усе катэгорыі" sections: + about: + header_link_text: "Аб тэме" messages: header_link_text: "Паведамленні" links: @@ -1353,12 +1362,18 @@ be: tags: header_link_text: "тэгі" categories: - header_link_title: "усе катэгорыі" header_link_text: "катэгорыі" community: - header_link_title: "дома" header_link_text: "супольнасць" links: + about: + content: "Аб тэме" + admin: + content: "адміністратар" + badges: + content: "значкі" + faq: + content: "Пытанні і адказы" groups: content: "Групы" title: "Усе групы" diff --git a/config/locales/client.bg.yml b/config/locales/client.bg.yml index ac9d33238b..dfd8828f01 100644 --- a/config/locales/client.bg.yml +++ b/config/locales/client.bg.yml @@ -159,12 +159,12 @@ bg: forwarded: "препрати горния имейл" topic_admin_menu: "действия по темата" skip_to_main_content: "Прескачане към основното съдържание" - wizard_required: "Добре дошли във вашия нов Discourse! Нека започнем с съветника за настройка ✨" emails_are_disabled: "Всички изходящи имейли са изцяло забранени от администратора. Няма да бъдат изпращани никакви имейл известия." software_update_prompt: message: "Актуализирахме този сайт, моля, презаредете, или може да изпитате неочаквано поведение." dismiss: "Отмени" bootstrap_mode_disabled: "Режимът на стартиране ще бъде изключен в следващите 24 часа. " + bootstrap_invite_button_title: "Изпрати поканите" themes: default_description: "По подразбиране" s3: @@ -197,6 +197,8 @@ bg: not_implemented: "Тази функционалност все още не е добавена." no_value: "Не" yes_value: "Да" + ok_value: "Ок" + cancel_value: "Прекрати" submit: "Изпрати" generic_error: "Съжаляваме, възникна грешка." generic_error_with_reason: "Грешка: %{error}" @@ -2053,6 +2055,13 @@ bg: go_back: "Назад " not_logged_in_user: "Потребителска страница с история на текущата дейност и предпочитания" current_user: "Отиди към потребителската страница " + user_menu: + tabs: + replies: "Отговори" + mentions: "Споменавания" + likes: "Дадени харесвания" + bookmarks: "Отметки" + profile: "Профил" topics: new_messages_marker: "последно посещение" bulk: @@ -2917,7 +2926,6 @@ bg: download_calendar: download: "Изтегли" tagging: - all_tags: "Всички тагове" other_tags: "Други тагове" selector_all_tags: "всички тагове" selector_no_tags: "няма тагове" @@ -2990,7 +2998,10 @@ bg: one: "%{count} нов" other: "%{count} нови" more: "Още..." + all_categories: "Всички категории" sections: + about: + header_link_text: "Относно" messages: header_link_text: "Съобщения" links: @@ -3002,15 +3013,20 @@ bg: unread_with_count: "Непрочетен (%{count})" archive: "Архив" tags: - header_link_title: "всички тагове" header_link_text: "Тагове" categories: - header_link_title: "всички категории" header_link_text: "Категории" community: - header_link_title: "начало" header_link_text: "Общност " links: + about: + content: "Относно" + admin: + content: "Администратор" + badges: + content: "Значки" + faq: + content: "FAQ" tracked: content: "Следени" groups: diff --git a/config/locales/client.bs_BA.yml b/config/locales/client.bs_BA.yml index 140922aa4d..8e46e299a1 100644 --- a/config/locales/client.bs_BA.yml +++ b/config/locales/client.bs_BA.yml @@ -42,6 +42,7 @@ bs_BA: long_date_without_year_with_linebreak: "D MMM
    LT" long_date_with_year_with_linebreak: "D MMM, 'YY
    LT" wrap_ago: "%{date} prije" + wrap_on: "na %{date}" tiny: half_a_minute: "< 1m" less_than_x_seconds: @@ -177,11 +178,11 @@ bs_BA: disabled: "maknuo banner %{when}. Banner se više neće prikazivati na vrhu svake stranice." forwarded: "gornji email proslijeđen" topic_admin_menu: "akcije u vezi teme" - wizard_required: "Dobrodošli na vaš novi Discourse! Odpočnimo sa čarobnjakom za postavke ✨" emails_are_disabled: "Sve odlazeće email poruke su globalno onemogućene od strane administratora. Ni jedna notifikacija bilo koje vrste neće biti poslana." software_update_prompt: dismiss: "Odpusti" bootstrap_mode_disabled: "Bootstrap način rada će biti isključen u toku 24 sata." + bootstrap_invite_button_title: "Pošalji Pozivnice" themes: default_description: "Uobičajen" s3: @@ -211,6 +212,8 @@ bs_BA: not_implemented: "Nažalost ta funkcionalnost nije još implementirana!" no_value: "Ne" yes_value: "Da" + ok_value: "OK" + cancel_value: "Odustani" submit: "Potvrdi" generic_error: "Uff, došlo je do greške." generic_error_with_reason: "Došlo je do greške: %{error}" @@ -1941,6 +1944,13 @@ bs_BA: go_back: "go back" not_logged_in_user: "user page with summary of current activity and preferences" current_user: "go to your user page" + user_menu: + tabs: + replies: "Odgovori" + mentions: "Spomenuto" + likes: "Lajkovi" + bookmarks: "Zabilješke" + profile: "Profil" topics: new_messages_marker: "zadnja posjeta" bulk: @@ -2442,11 +2452,6 @@ bs_BA: one: "Jeste li sigurni da želite izbrisati taj post?" few: "Jeste li sigurni da želite izbrisati one postove %{count}?" other: "Jeste li sigurni da želite izbrisati one postove %{count}?" - merge: - confirm: - one: "Jeste li sigurni da želite spojiti te postove?" - few: "Jeste li sigurni da želite spojiti te postove %{count}?" - other: "Jeste li sigurni da želite spojiti te postove %{count}?" revisions: controls: first: "First revision" @@ -2938,7 +2943,6 @@ bs_BA: download_calendar: download: "Skinuti" tagging: - all_tags: "Sve oznake" other_tags: "Druge oznake" selector_all_tags: "sve oznake" selector_no_tags: "bez oznaka" @@ -3066,8 +3070,6 @@ bs_BA: member: "član" regular: "pokretač" leader: "vođa" - user_activity: - no_replies_others: "Nema odgovora." sidebar: unread_count: one: "%{count} nepročitana" @@ -3078,7 +3080,10 @@ bs_BA: few: "%{count} nova" other: "%{count} novih" more: "Više..." + all_categories: "Sve kategorije" sections: + about: + header_link_text: "O nama" messages: header_link_text: "Poruke" links: @@ -3090,15 +3095,20 @@ bs_BA: unread_with_count: "Nepročitano (%{count})" archive: "Arhiva" tags: - header_link_title: "sve oznake" header_link_text: "Oznake" categories: - header_link_title: "Sve kategorije" header_link_text: "Kategorije" community: - header_link_title: "naslovnica" header_link_text: "Zajednica" links: + about: + content: "O nama" + admin: + content: "Admin" + badges: + content: "Bedž" + faq: + content: "Česta pitanja" tracked: content: "Praćeno" groups: diff --git a/config/locales/client.ca.yml b/config/locales/client.ca.yml index aa6cad74fe..c7c06a26b0 100644 --- a/config/locales/client.ca.yml +++ b/config/locales/client.ca.yml @@ -162,12 +162,12 @@ ca: forwarded: "el missatge de dalt s'ha reenviat" topic_admin_menu: "accions del tema" skip_to_main_content: "Vés al contingut principal" - wizard_required: "Us donem la benvinguda al vostre nou Discourse! Comencem amb l'assistent de configuració ✨" emails_are_disabled: "Tots els correus sortints han estat globalment inhabilitats per un administrador. No s'enviarà cap notificació de cap mena per correu electrònic." software_update_prompt: message: "Hem actualitzat aquest lloc, si us plau actualitzeu, o podeu experimentar un comportament inesperat." dismiss: "Descarta-ho" bootstrap_mode_disabled: "El mode d'arrencada serà desactivat d'aquí a 24 hores." + bootstrap_invite_button_title: "Envia invitacions" themes: default_description: "Per defecte" s3: @@ -200,6 +200,8 @@ ca: not_implemented: "Ho sentim! Aquesta funcionalitat encara no s'ha implementat." no_value: "No" yes_value: "Sí" + ok_value: "D'acord" + cancel_value: "Cancel·la" submit: "Envia" generic_error: "Ho sentim, s'ha produït un error." generic_error_with_reason: "Hi ha hagut un error: %{error}" @@ -1860,6 +1862,13 @@ ca: go_back: "vés enrere" not_logged_in_user: "pàgina d'usuari amb resum de l'activitat actual i preferències " current_user: "vés a la meva pàgina d'usuari" + user_menu: + tabs: + replies: "Respostes" + mentions: "Mencions" + likes: "'M'agrada'" + bookmarks: "Preferits" + profile: "Perfil" topics: new_messages_marker: "darrera visita" bulk: @@ -2338,10 +2347,6 @@ ca: confirm: one: "Esteu segur que voleu suprimir aquesta publicació?" other: "Esteu segur que voleu suprimir aquestes %{count} publicacions?" - merge: - confirm: - one: "Esteu segur que voleu combinar aquesta publicació?" - other: "Esteu segur que voleu combinar aquests %{count}missatges?" revisions: controls: first: "Primera revisió" @@ -2789,7 +2794,6 @@ ca: download_calendar: download: "Descarrega" tagging: - all_tags: "Totes les etiquetes" other_tags: "Altres etiquetes" selector_all_tags: "totes les etiquetes" selector_no_tags: "sense etiquetes" @@ -2886,10 +2890,6 @@ ca: member: "membre" regular: "habitual" leader: "líder" - user_activity: - no_activity_others: "No hi ha activitat." - no_replies_others: "No hi ha respostes." - no_likes_others: "Publicacions sense 'm'agrada'." sidebar: unread_count: one: "%{count} no llegit" @@ -2898,7 +2898,10 @@ ca: one: "%{count} nou" other: "%{count} nous" more: "Més..." + all_categories: "Totes les categories" sections: + about: + header_link_text: "Quant a" messages: header_link_text: "Missatges" links: @@ -2910,15 +2913,20 @@ ca: unread_with_count: "No llegit (%{count})" archive: "Arxiva" tags: - header_link_title: "totes les etiquetes" header_link_text: "Etiquetes" categories: - header_link_title: "totes les categories" header_link_text: "Categories" community: - header_link_title: "pàgina principal" header_link_text: "Comunitat" links: + about: + content: "Quant a" + admin: + content: "Administració" + badges: + content: "Insígnies" + faq: + content: "PMF" tracked: content: "Seguit" groups: @@ -3896,7 +3904,6 @@ ca: cant_delete_all_too_many_posts: one: "No es poden suprimir totes les publicacions perquè l'usuari té més d'%{count} publicació. (delete_all_posts_max)" other: "No es poden suprimir totes les publicacions perquè l'usuari té més de %{count} publicacions. (delete_all_posts_max)" - delete_confirm: "En general, és preferible fer anònims els usuaris en lloc de suprimir-los, per a evitar que s'esborrin els continguts de les discussions existents.

    Esteu SEGUR que voleu suprimir aquest usuari? Això és permanent!" delete_and_block: "Suprimeix i bloca aquest correu electrònic i aquesta adreça IP" delete_dont_block: "Només suprimeix" deleting_user: "Suprimint l'usuari..." diff --git a/config/locales/client.cs.yml b/config/locales/client.cs.yml index 4a9cb90e77..53c62c66db 100644 --- a/config/locales/client.cs.yml +++ b/config/locales/client.cs.yml @@ -200,7 +200,6 @@ cs: forwarded: "přeposlat výše uvedený e-mail" topic_admin_menu: "Akce tématu." skip_to_main_content: "Přeskočit na hlavní obsah" - wizard_required: "Vítejte ve vašem novém Discourse! Začněte s nastavením pomocí průvodce ✨" emails_are_disabled: "Všechny odchozí emaily byly administrátorem vypnuty. Žádné odchozí emaily nebudou odeslány." emails_are_disabled_non_staff: "Odchozí e-maily byly zakázány pro uživatele, kteří nejsou personál." software_update_prompt: @@ -212,6 +211,7 @@ cs: many: "Aby se váš web jednodušeji rozjel, nachází se v režimu bootstrap. Všichni noví uživatelé začínají s důveryhodností 1 a mají povolené denní odesílání souhrnných emailů. Tento režim se automaticky vypne, jakmile se zaregistruje alespoň %{count} uživatelů." other: "Aby se váš web jednodušeji rozjel, nachází se v režimu bootstrap. Všichni noví uživatelé začínají s důveryhodností 1 a mají povolené denní odesílání souhrnných emailů. Tento režim se automaticky vypne, jakmile se zaregistruje alespoň %{count} uživatelů." bootstrap_mode_disabled: "Režim bootstrap bude deaktivován v následujících 24 hodinách." + bootstrap_invite_button_title: "Poslat pozvánky" themes: default_description: "Výchozí" broken_theme_alert: "Váš web nemusí fungovat, protože motiv/komponenta obsahuje chyby." @@ -247,6 +247,8 @@ cs: not_implemented: "Tato funkce ještě nebyla naprogramována, omlouváme se." no_value: "Ne" yes_value: "Ano" + ok_value: "OK" + cancel_value: "Zrušit" submit: "Odeslat" generic_error: "Bohužel nastala chyba." generic_error_with_reason: "Nastala chyba: %{error}" @@ -1840,6 +1842,13 @@ cs: go_back: "jít zpět" not_logged_in_user: "stránka uživatele s přehledem o aktuální činnosti a nastavení" current_user: "jít na vaši uživatelskou stránku" + user_menu: + tabs: + replies: "Odpovědi" + mentions: "Zmínění" + likes: "Nová 'líbí se'" + bookmarks: "Záložky" + profile: "Profil" topics: new_messages_marker: "poslední návštěva" bulk: @@ -2326,12 +2335,6 @@ cs: few: "Jsi si jistý, že chceš smazat tyto všechny %{count} příspěvky? " many: "Jsi si jistý, že chceš smazat tyto všechny %{count} příspěvky? " other: "Jsi si jistý, že chceš smazat tyto všechny %{count} příspěvky? " - merge: - confirm: - one: "Opravdu chceš sloučit tyto příspěvky?" - few: "Opravdu chceš sloučit %{count} příspěvky?" - many: "Opravdu chceš sloučit %{count} příspěvků?" - other: "Opravdu chceš sloučit %{count} příspěvků?" revisions: controls: first: "První revize" @@ -2784,7 +2787,6 @@ cs: download_calendar: download: "Stáhnout" tagging: - all_tags: "Všechny štítky" other_tags: "Ostatní štítky " selector_all_tags: "všechny štítky" selector_no_tags: "bez štítků" @@ -2873,8 +2875,6 @@ cs: member: "člen" regular: "pravidelný uživatel" leader: "vůdce" - user_activity: - no_replies_others: "Žádné odpovědi." sidebar: unread_count: one: "%{count} nepřečtené" @@ -2887,7 +2887,10 @@ cs: many: "%{count} nových" other: "%{count} nové" more: "Více..." + all_categories: "Všechny kategorie" sections: + about: + header_link_text: "O fóru" messages: header_link_text: "Zprávy" links: @@ -2898,15 +2901,20 @@ cs: unread_with_count: "Nepřečtená (%{count})" archive: "Archív" tags: - header_link_title: "všechny štítky" header_link_text: "Tagy" categories: - header_link_title: "všechny kategorie" header_link_text: "Kategorie" community: - header_link_title: "domů" header_link_text: "Komunita" links: + about: + content: "O fóru" + admin: + content: "Administrace" + badges: + content: "Odznaky" + faq: + content: "FAQ" tracked: content: "Sledované" groups: diff --git a/config/locales/client.da.yml b/config/locales/client.da.yml index ec97a3b775..51e7c3f1f2 100644 --- a/config/locales/client.da.yml +++ b/config/locales/client.da.yml @@ -159,7 +159,6 @@ da: disabled: "fjernede banneret %{when}. Det vil ikke længere vises i toppen af alle sider." forwarded: "videresendte ovenstående e-mail" topic_admin_menu: "emnehandlinger" - wizard_required: "Velkommen til din nye Discourse! Lad os komme i gang med konfigurationsguiden ✨" emails_are_disabled: "Alle udgående emails er blevet globalt deaktiveret af en administrator. Ingen email notifikationer af nogen slags vil blive sendt." software_update_prompt: message: "Vi har opdateret dette websted, genindlæs venligst siden, ellers vil du kunne opleve uventet opførsel eller begrændset funktionalitet." @@ -168,6 +167,7 @@ da: one: "For at gøre lanceringen af dit nye forum lettere er du i \"bootstrap-tilstand\". Alle nye brugere tildeles tillidsniveau 1 og har dagligt email resume aktiveret. Dette deaktiveres automatisk, når %{count} bruger er tilsluttet." other: "For at gøre lanceringen af dit nye forum lettere er du i bootstrap-tilstand. Alle nye brugere tildeles tillidsniveau 1 og har dagligt email resume aktiveret. Dette deaktiveres automatisk, når %{count} brugere er tilsluttet." bootstrap_mode_disabled: "Bootstrap-tilstand deaktiveres inden for 24 timer." + bootstrap_invite_button_title: "Send Invitationer" themes: default_description: "Standard" broken_theme_alert: "Dit websted fungerer muligvis ikke, fordi et tema/en komponent har fejl." @@ -202,6 +202,8 @@ da: not_implemented: "Beklager! Denne funktion er ikke blevet implementeret endnu." no_value: "Nej" yes_value: "Ja" + ok_value: "OK" + cancel_value: "Annuller" submit: "Udfør" generic_error: "Beklager, der opstod en fejl." generic_error_with_reason: "Der opstod en fejl: %{error}" @@ -2230,6 +2232,13 @@ da: not_logged_in_user: "bruger side, med oversigt over aktivitet og indstillinger" current_user: "gå til din brugerside" view_all: "vis alle %{tab}" + user_menu: + tabs: + replies: "Svar" + mentions: "Omtaler" + likes: "Syntes godt om" + bookmarks: "Bogmærker" + profile: "Profil" topics: new_messages_marker: "sidste besøg" bulk: @@ -2836,10 +2845,6 @@ da: confirm: one: "Er du sikker på, at du vil slette dette indlæg?" other: "Er du sikker på, at du vil slette disse %{count}indlæg?" - merge: - confirm: - one: "Er du sikker på, at du vil flette disse indlæg?" - other: "Er du sikker på, at du vil flette disse %{count}indlæg?" revisions: controls: first: "Første udgave" @@ -3381,7 +3386,6 @@ da: google: "Google Kalender" ics: "ICS" tagging: - all_tags: "Alle Mærker" other_tags: "Andre Mærker" selector_all_tags: "alle mærker" selector_no_tags: "ingen mærker" @@ -3536,14 +3540,11 @@ da: user_activity: no_activity_title: "Ingen aktivitet endnu" no_activity_body: "Velkommen til vores fællesskab! Du er helt ny her og har endnu ikke bidraget til diskussioner. Som et første skridt, besøg Top eller Kategorier og begynde bare at læse! Vælg %{heartIcon} på indlæg, som du kan lide eller ønsker at lære mere om. Når du deltager, vil din aktivitet blive vist her." - no_activity_others: "Ingen aktivitet." no_replies_title: "Du har ikke svaret på nogen emner endnu" - no_replies_others: "Ingen svar." no_drafts_title: "Du har ikke påbegyndt nogen kladder" no_drafts_body: "Ikke helt klar til at skrive? Vi gemmer automatisk en ny kladde og viser den her, hver gang du begynder at skrive et emne, svar eller personlig besked. Vælg knappen Annuller for at kassere eller gemme din kladde for at fortsætte senere." no_likes_title: "Du har ikke 'syntes godt om' nogen emner endnu" no_likes_body: "En god måde at hoppe ind og begynde at bidrage på, er at begynde at læse samtaler, der allerede har fundet sted, og vælge %{heartIcon} på indlæg, som du kan lide!" - no_likes_others: "Ingen 'synes om'-beskeder." no_topics_title: "Du har ikke startet nogen emner endnu" no_topics_title_others: "%{username} har endnu ikke startet nogen emner" no_read_topics_title: "Du har ikke læst nogen emner endnu" @@ -3561,7 +3562,10 @@ da: one: "%{count} ny" other: "%{count} nye" more: "Mere..." + all_categories: "Alle kategorier" sections: + about: + header_link_text: "Om" messages: header_link_text: "Beskeder" links: @@ -3573,15 +3577,20 @@ da: unread_with_count: "Ulæst (%{count})" archive: "Arkiv" tags: - header_link_title: "alle mærker" header_link_text: "Tags" categories: - header_link_title: "alle kategorier" header_link_text: "Kategorier" community: - header_link_title: "hjem" header_link_text: "Fællesskab" links: + about: + content: "Om" + admin: + content: "Admin" + badges: + content: "Emblemer" + faq: + content: "OSS" tracked: content: "Sporet" groups: @@ -4750,7 +4759,6 @@ da: cant_delete_all_too_many_posts: one: "Kan ikke slette alle indlæg fordi denne bruger har flere end %{count} indlæg. (delete_all_posts_max indstillingen)" other: "Kan ikke slette alle indlæg fordi denne bruger har flere end %{count} indlæg. (delete_all_posts_max indstillingen)" - delete_confirm: "Det foretrækkes generelt at anonymisere brugere i stedet for at slette dem for at undgå at fjerne indhold fra eksisterende diskussioner.

    Er du SIKKER på, at du vil slette denne bruger? Dette er permanent!" delete_and_block: "Slet og bloker denne email og IP-adresse" delete_dont_block: "Slet kun" deleting_user: "Sletter bruger ..." @@ -4881,7 +4889,6 @@ da: recommended: "Vi anbefaler ændringer i følgende tekst:" show_overriden: "Vis kun tilsidesatte" locale: "Sprog:" - fallback_locale_warning: "Du redigerer et sprog baseret på %{fallback}. Brugere, der vælger %{fallback}, som deres grænsefladesprog vil ikke kunne se dine ændringer." more_than_50_results: "Der er mere end 50 resultater. Begræns din søgning." settings: show_overriden: "Vis kun tilsidesatte" diff --git a/config/locales/client.de.yml b/config/locales/client.de.yml index da75fdd38d..b3bf810df4 100644 --- a/config/locales/client.de.yml +++ b/config/locales/client.de.yml @@ -29,7 +29,7 @@ de: time_with_zone: "HH:mm (z)" time_short_day: "dd, HH:mm" timeline_date: "MMM YYYY" - long_no_year: "D MMM, HH:mm" + 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 [um] HH:mm" @@ -179,7 +179,6 @@ de: forwarded: "hat die obige E-Mail weitergeleitet" topic_admin_menu: "Themen-Administration" skip_to_main_content: "Zum Hauptinhalt springen" - wizard_required: "Willkommen bei deinem neuen Discourse! Lass uns mit dem Setup-Assistenten ✨ starten" emails_are_disabled: "Die ausgehende E-Mail-Kommunikation wurde von einem Administrator global deaktiviert. Es werden keinerlei Benachrichtigungen per E-Mail verschickt." emails_are_disabled_non_staff: "Ausgehende E-Mails wurden für Benutzer, die nicht zum Team gehören, deaktiviert." software_update_prompt: @@ -189,6 +188,8 @@ de: one: "Damit du mit deiner Website einfacher loslegen kannst, befindest du dich im Starthilfe-Modus. Alle neuen Benutzer erhalten die Vertrauensstufe 1 und bekommen eine tägliche E-Mail-Zusammenfassung. Der Modus wird automatisch deaktiviert, sobald sich mehr als %{count} Benutzer registriert hat." other: "Damit du mit deiner Website einfacher loslegen kannst, befindest du dich im Starthilfe-Modus. Alle neuen Benutzer erhalten die Vertrauensstufe 1 und bekommen eine tägliche E-Mail-Zusammenfassung. Der Modus wird automatisch deaktiviert, sobald sich mehr als %{count} Benutzer registriert haben." bootstrap_mode_disabled: "Der Starthilfe-Modus wird in den nächsten 24 Stunden deaktiviert." + bootstrap_invite_button_title: "Einladungen versenden" + bootstrap_wizard_link_title: "Einrichtungsassistent beenden" themes: default_description: "Standard" broken_theme_alert: "Deine Website funktioniert vielleicht nicht, weil eine Theme / eine Komponente Fehler hat." @@ -225,6 +226,8 @@ de: not_implemented: "Entschuldige, diese Funktion wurde noch nicht implementiert!" no_value: "Nein" yes_value: "Ja" + ok_value: "OK" + cancel_value: "Abbrechen" submit: "Absenden" generic_error: "Entschuldigung, ein Fehler ist aufgetreten." generic_error_with_reason: "Ein Fehler ist aufgetreten: %{error}" @@ -1053,6 +1056,7 @@ de: dismiss_notifications: "Alles gelesen" dismiss_notifications_tooltip: "Alle ungelesenen Benachrichtigungen als gelesen markieren" dismiss_bookmarks_tooltip: "Markiere alle ungelesenen Lesezeichen-Erinnerungen als gelesen" + dismiss_messages_tooltip: "Markiere alle ungelesenen persönlichen Nachrichten als gelesen" no_messages_title: "Du hast keine Nachrichten" no_messages_body: > Benötigst du ein direktes persönliches Gespräch mit jemandem außerhalb des normalen Gesprächsflusses? Sende der Person eine Nachricht, indem du ihren Avatar auswählst und die Schaltfläche %{icon} verwendest.

    Wenn du Hilfe benötigst, kannst du eine Nachricht an ein Team-Mitglied senden. @@ -1650,7 +1654,6 @@ de: set_custom_status: "Benutzerdefinierten Status festlegen" what_are_you_doing: "Was machst du da?" remove_status: "Status entfernen" - until: "Bis:" loading: "Wird geladen …" errors: prev_page: "während des Ladens" @@ -1683,6 +1686,8 @@ de: enabled: "Diese Website befindet sich im Nur-Lesen-Modus. Du kannst weiterhin Inhalte lesen, aber das Erstellen von Beiträgen, Vergeben von „Gefällt mir“ und Durchführen einiger weiterer Aktionen ist derzeit nicht möglich." login_disabled: "Die Anmeldung ist deaktiviert, während sich die Website im Nur-Lesen-Modus befindet." logout_disabled: "Die Abmeldung ist deaktiviert, während sich die Website im Nur-Lesen-Modus befindet." + staff_writes_only_mode: + enabled: "Diese Website befindet sich im Nur-Mitarbeiter-Modus. Du kannst weiterhin Inhalte lesen, aber das Erstellen von Beiträgen, Vergeben von „Gefällt mir“ und Durchführen einiger weiterer Aktionen ist derzeit nur für Mitarbeiter möglich." too_few_topics_and_posts_notice_MF: >- Lass die Diskussion beginnen! Es {currentTopics, plural, one {ist # Thema} other {sind # Themen}} und {currentPosts, plural, one {# Beitrag} other {# Beiträge}} vorhanden. Besucher brauchen mehr zum Lesen und Beantworten – wir empfehlen mindestens {requiredTopics, plural, one {# Thema} other {# Themen}} und {requiredPosts, plural, one {# Beitrag} other {# Beiträge}}. Dieser Hinweis wird nur Team-Mitgliedern angezeigt. too_few_topics_notice_MF: >- @@ -1968,6 +1973,8 @@ de: similar_topics: "Dein Thema hat Ähnlichkeit mit …" drafts_offline: "Entwürfe offline" edit_conflict: "Konflikt bearbeiten" + esc: "esc" + esc_label: "Klicken oder Esc drücken, um zu schließen" group_mentioned_limit: one: "Warnung! Du erwähnst %{group}, jedoch übersteigt die Mitgliederzahl der Gruppe das vom Administrator konfigurierte Erwähnungslimit von %{count} Benutzer. Deshalb wird niemand benachrichtigt." other: "Warnung! Du erwähnst %{group}, jedoch übersteigt die Mitgliederzahl der Gruppe das vom Administrator konfigurierte Erwähnungslimit von %{count} Benutzern. Deshalb wird niemand benachrichtigt." @@ -2059,6 +2066,7 @@ de: abandon: "Editor schließen und Entwurf verwerfen" enter_fullscreen: "Vollbild-Editor öffnen" exit_fullscreen: "Vollbild-Editor verlassen" + exit_fullscreen_prompt: "Drücke ESC um den Vollbildmodus zu verlassen." show_toolbar: "Editor-Werkzeugleiste anzeigen" hide_toolbar: "Editor-Werkzeugleiste ausblenden" modal_ok: "OK" @@ -2166,6 +2174,9 @@ de: bookmarks: one: "Bist du sicher? Du hast %{count} ungelesene Lesezeichen Erinnerung." other: "Bist du sicher? Du hast %{count} ungelesene Lesezeichen-Erinnerungen." + messages: + one: "Bist du sicher? Du hast %{count} ungelesene persönliche Nachricht." + other: "Bist du sicher? Du hast %{count} ungelesene persönliche Nachrichten." dismiss: "Alles gelesen" cancel: "Abbrechen" group_message_summary: @@ -2346,16 +2357,53 @@ de: view_all: "Alle %{tab} anzeigen" user_menu: generic_no_items: "Es gibt keine Einträge in dieser Liste." - sr_menu_tabs: "Menü-Registerkarten" + sr_menu_tabs: "Registerkarten des Benutzermenüs" view_all_notifications: "Alle Benachrichtigungen anzeigen" view_all_bookmarks: "Alle Lesezeichen anzeigen" + view_all_messages: "Alle persönlichen Nachrichten anzeigen" + tabs: + all_notifications: "Alle Benachrichtigungen" + replies: "Antworten" + replies_with_unread: + one: "Antworten - %{count} ungelesene Antwort" + other: "Antworten - %{count} ungelesene Antworten" + mentions: "Erwähnungen" + mentions_with_unread: + one: "Erwähnungen - %{count} ungelesene Erwähnung" + other: "Erwähnungen - %{count} ungelesene Erwähnungen" + likes: "Erhaltene „Gefällt mir“" + likes_with_unread: + one: "Likes - %{count} ungelesene Likes" + other: "Likes - %{count} ungelesene Likes" + watching: "Beobachtete Themen" + watching_with_unread: + one: "Beobachtete Themen - %{count} ungelesenes beobachtetes Thema" + other: "Beobachtete Themen — %{count} ungelesene beobachtete Themen" + messages: "Persönliche Nachrichten" + messages_with_unread: + one: "Persönliche Nachrichten - %{count} ungelesene Nachricht" + other: "Persönliche Nachrichten - %{count} ungelesene Nachrichten" + bookmarks: "Lesezeichen" + bookmarks_with_unread: + one: "Bookmarks - %{count} ungelesenes Lesezeichen" + other: "Lesezeichen - %{count} ungelesene Lesezeichen" + review_queue: "Warteschlange überprüfen" + review_queue_with_unread: + one: "Überprüfungswarteschlange — %{count} Artikel benötigt Überprüfung" + other: "Warteschlange für Überprüfungen — %{count} Artikel müssen überprüft werden" + other_notifications: "Andere Benachrichtigungen" + other_notifications_with_unread: + one: "Andere Benachrichtigungen - %{count} ungelesene Benachrichtigung" + other: "Andere Benachrichtigungen - %{count} Ungelesene Benachrichtigungen" + profile: "Profil" reviewable: view_all: "alle Bewertungselemente ansehen" queue: "Warteschlange" deleted_user: "(gelöschter Benutzer)" + deleted_post: "(gelöschter Beitrag)" post_number_with_topic_title: "Beitrag #%{post_number} - %{title}" new_post_in_topic: "neuer Beitrag in %{title}" - suspicious_user: "Verdächtiger Benutzer %{username}" + user_requires_approval: "%{username} erfordert eine Genehmigung" default_item: "Überprüfbarer Artikel #%{reviewable_id}" topics: new_messages_marker: "letzter Besuch" @@ -3422,6 +3470,7 @@ de: today: "Heute" other_periods: "angesagte Themen ansehen:" browser_update: 'Leider wird dein Browser nicht unterstützt. Bitte wechsle zu einem unterstützten Browser , um die Inhalte zu sehen, dich anzumelden und zu antworten.' + safari_13_warning: Diese Seite wird bald die Unterstützung für iOS und Safari Version 13 und darunter entfernen. Eine vereinfachte Nur-Lese-Version wird weiterhin verfügbar sein. (mehr Informationen) permission_types: full: "Erstellen/Antworten/Ansehen" create_post: "Antworten/Ansehen" @@ -3733,14 +3782,14 @@ de: user_activity: no_activity_title: "Noch keine Aktivität" no_activity_body: "Willkommen in unserer Community! Du bist ganz neu hier und hast noch nicht an Diskussionen teilgenommen. Besuche als ersten Schritt Top oder Kategorien und fang einfach an zu lesen! Wähle %{heartIcon} bei Beiträgen aus, die Dir gefallen oder über die Du mehr erfahren möchtest. Wenn Du teilnimmst, wird Deine Aktivität hier aufgelistet." - no_activity_others: "Keine Aktivität." no_replies_title: "Du hast noch keine Themen beantwortet" - no_replies_others: "Keine Antworten." + no_replies_title_others: "%{username} hat noch auf keine Themen geantwortet" + no_replies_body: "Wenn du eine interessante Unterhaltung entdeckst, zu der du etwas beitragen möchtest, klicke auf die Schaltfläche Antworten direkt unter einem Beitrag, um auf diesen Beitrag zu antworten. Wenn du lieber auf das allgemeine Thema als auf einen einzelnen Beitrag oder eine Person antworten möchtest, findest du die Schaltfläche Antworten ganz unten im Thema oder unter der Zeitleiste des Themas." no_drafts_title: "Du hast noch keine Entwürfe begonnen" no_drafts_body: "Noch nicht ganz bereit? Wir speichern automatisch einen neuen Entwurf und listen ihn hier auf, wenn Du ein Thema, eine Antwort oder eine persönliche Nachricht verfasst. Wähle die Abbrechen-Schaltfläche, um Deinen Entwurf zu verwerfen oder zu speichern, um später fortzufahren." no_likes_title: "Du hast noch keine Themen mit \"gefällt mir\" markiert." + no_likes_title_others: "%{username} hat noch keine Themen geliked" no_likes_body: "Eine großartige Möglichkeit einzusteigen und Beiträge zu leisten, besteht darin, bereits stattgefundene Konversationen zu lesen und die %{heartIcon} bei Beiträgen auszuwählen, die Dir gefallen!" - no_likes_others: "Keine Beiträge mit „Gefällt mir“." no_topics_title: "Du hast noch keine Themen begonnen" no_topics_body: "Es ist immer am besten, nach bestehenden Themen zu suchen, bevor du ein neues Thema eröffnest. Wenn du dir aber sicher bist, dass es das gewünschte Thema noch nicht gibt, kannst du auch einfach ein neues Thema erstellen. Suche nach der Schaltfläche + Neues Thema oben rechts in der Themenliste, der Kategorie oder dem Tag, um ein neues Thema in diesem Bereich zu erstellen." no_topics_title_others: "%{username} hat noch keine Themen begonnen" @@ -3763,9 +3812,12 @@ de: other: "%{count} neue" toggle_section: "Abschnitt umschalten" more: "Mehr …" + all_categories: "Alle Kategorien" + all_tags: "Alle Schlagwörter" sections: + about: + header_link_text: "Über uns" messages: - header_link_title: "Persönliche Nachrichten" header_link_text: "Nachrichten" header_action_title: "eine persönliche Nachricht erstellen" links: @@ -3779,23 +3831,28 @@ de: tags: none: "Du hast keine Schlagwörter hinzugefügt." click_to_get_started: "Klicke hier, um zu starten." - header_link_title: "alle Schlagwörter" header_link_text: "Schlagwörter" header_action_title: "Bearbeite die Schlagwörter in deiner Seitenleiste" categories: none: "Du hast keine Kategorien hinzugefügt." click_to_get_started: "Klicke hier, um zu starten." - header_link_title: "alle Kategorien" header_link_text: "Kategorien" header_action_title: "Bearbeite die Kategorien in deiner Seitenleiste" community: - header_link_title: "Startseite" header_link_text: "Community" header_action_title: "ein neues Thema erstellen" links: + about: + content: "Über uns" + admin: + content: "Administration" + badges: + content: "Abzeichen" everything: content: "Alles" title: "Alle Themen" + faq: + content: "FAQ" tracked: content: "Verfolgt" title: "Alle verfolgten Themen" @@ -3811,6 +3868,11 @@ de: draft_count: one: "%{count} Entwurf" other: "%{count} Entwürfe" + welcome_topic_banner: + title: "Erstelle dein Willkommensthema" + description: 'Dein Willkommensthema ist das erste, was Neuankömmlinge lesen werden. Sieh es als deinen einseitigen "Elevator Pitch" oder "Mission Statement" an.' + button_title: "Bearbeitung beginnen" + until: "Bis:" admin_js: type_to_filter: "zum Filtern hier eingeben …" admin: @@ -4368,6 +4430,8 @@ de: import_web_advanced: "Erweitert …" import_file_tip: ".tar.gz-, .zip- oder .dcstyle.json-Datei, die ein Theme enthält" is_private: "Theme ist in einem privaten Git-Repository" + finish_install: "Theme-Installation beenden" + last_attempt: "Der Installationsvorgang wurde nicht abgeschlossen, letzter Versuch:" remote_branch: "Branch-Name (optional)" public_key: "Gewähre dem folgenden öffentlichen Schlüssel den Zugriff auf das Repository:" public_key_note: "Nach Eingabe einer gültigen privaten Repository-URL wird ein SSH-Schlüssel generiert und hier angezeigt." @@ -4378,6 +4442,8 @@ de: install_git_repo: "Aus einem Git-Repository" install_create: "Neu erstellen" duplicate_remote_theme: "Die Theme-Komponente „%{name}“ ist bereits installiert. Möchtest du wirklich eine weitere Kopie installieren?" + force_install: "Das Theme kann nicht installiert werden, weil auf das Git-Repository nicht zugegriffen werden kann. Bist du sicher, dass du die Installation fortsetzen willst?" + create_placeholder: "Platzhalter erstellen" about_theme: "Über uns" license: "Lizenz" version: "Version:" @@ -4911,6 +4977,7 @@ de: suspended: "Gesperrt?" staged: "Vorbereitet?" show_admin_profile: "Administration" + manage_user: "Benutzer verwalten" show_public_profile: "Zeige öffentliches Profil" impersonate: "Nutzersicht" action_logs: "Aktionsprotokolle" @@ -5008,7 +5075,8 @@ de: cant_delete_all_too_many_posts: one: "Nicht alle Beiträge können gelöscht werden, da der Benutzer mehr als %{count} Beitrag hat. (Siehe die Einstellung „delete_all_posts_max“.)" other: "Nicht alle Beiträge können gelöscht werden, da der Benutzer mehr als %{count} Beiträge hat. (Siehe die Einstellung „delete_all_posts_max“.)" - delete_confirm: "Es ist grundsätzlich vorzuziehen, Benutzer zu anonymisieren, statt sie zu löschen, um zu vermeiden, dass Inhalt aus bestehenden Diskussionen entfernt wird.

    Bist du SICHER, dass du diesen Benutzer löschen möchtest? Dies lässt sich nicht rückgängig machen." + delete_confirm_title: "Bist du sicher, dass du diesen Benutzer löschen willst? Das ist dauerhaft!" + delete_confirm: "Im Allgemeinen ist es besser, Nutzer/innen zu anonymisieren, als sie zu löschen, um zu vermeiden, dass Inhalte aus bestehenden Diskussionen entfernt werden." delete_and_block: "Löschen und diese E-Mail-Adresse und IP-Adresse blockieren" delete_dont_block: "Nur löschen" deleting_user: "Benutzer wird gelöscht …" @@ -5139,7 +5207,6 @@ de: recommended: "Wir empfehlen, dass du den folgenden Text an deine Bedürfnisse anpasst:" show_overriden: "Nur geänderte Texte anzeigen" locale: "Sprache:" - fallback_locale_warning: "Du bearbeitest eine Sprache basierend auf %{fallback}. Benutzer, die %{fallback} als Sprache ihrer Oberfläche wählen, werden deine Änderungen nicht sehen." more_than_50_results: "Es gibt mehr als 50 Ergebnisse. Bitte grenze deine Suche weiter ein." settings: show_overriden: "Nur geänderte Texte anzeigen" diff --git a/config/locales/client.el.yml b/config/locales/client.el.yml index 45faee25ec..a9a0f8685b 100644 --- a/config/locales/client.el.yml +++ b/config/locales/client.el.yml @@ -156,11 +156,11 @@ el: disabled: "το αφαίρεσε από ανακοίνωση στις %{when}. Δε θα εμφανίζεται πλέον στην κορυφή κάθε σελίδας." forwarded: "προώθησε το παραπάνω email" topic_admin_menu: "ρυθμίσεις θέματος" - wizard_required: "Καλώς ήλθατε στο νέο σας Discourse! Ας αρχίσουμε με τον οδηγό εγκατάστασης ✨" emails_are_disabled: "Όλα τα εξερχόμενα emails έχουν απενεργοποιηθεί καθολικά από κάποιον διαχειριστή. Δε θα σταλεί καμία ειδοποίηση email." software_update_prompt: dismiss: "Απόρριψη" bootstrap_mode_disabled: "Η λειτουργία bootstrap θα απενεργοποιηθεί εντός 24 ωρών." + bootstrap_invite_button_title: "Αποστολή Προσκλήσεων" themes: default_description: "Προεπιλογή" s3: @@ -190,6 +190,8 @@ el: not_implemented: "Αυτή η λειτουργία δεν έχει υλοποιηθεί ακόμα, συγγνώμη!" no_value: "Όχι" yes_value: "Ναι" + ok_value: "OK" + cancel_value: "Ακύρωση" submit: "Υποβολή" generic_error: "Λυπάμαι, προέκυψε κάποιο σφάλμα." generic_error_with_reason: "Προέκυψε ένα σφάλμα: %{error}" @@ -1922,6 +1924,13 @@ el: go_back: "επιστροφή" not_logged_in_user: "σελίδα λογαριασμού που περιέχει σύνοψη της τρέχουσας δραστηριότητας και τις προτιμήσεις" current_user: "πήγαινε στη σελίδα του λογαριασμού σου" + user_menu: + tabs: + replies: "Απαντήσεις" + mentions: "Αναφορές" + likes: "Μου αρέσει" + bookmarks: "Σελιδοδείκτες" + profile: "Προφίλ" topics: new_messages_marker: "τελευταία επίσκεψη" bulk: @@ -2442,10 +2451,6 @@ el: confirm: one: "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την ανάρτηση;" other: "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτές τις %{count} αναρτήσεις;" - merge: - confirm: - one: "Είσαι σίγουρος πως θέλεις να συγχωνεύσεις αυτές τις δημοσιεύσεις;" - other: "Είσαι σίγουρος πως θέλεις να συγχωνεύσεις αυτές τις %{count} αναρτήσεις;" revisions: controls: first: "Πρώτη αναθεώρηση" @@ -2931,7 +2936,6 @@ el: download_calendar: download: "Κατέβασμα" tagging: - all_tags: "Όλες οι Ετικέτες" other_tags: "Άλλες ετικέτες" selector_all_tags: "όλες οι ετικέτες" selector_no_tags: "καμία ετικέτα" @@ -3058,10 +3062,6 @@ el: member: "μέλος" regular: "τακτικός" leader: "αρχηγός" - user_activity: - no_activity_others: "Χωρίς δραστηριότητα." - no_replies_others: "Χωρίς απαντήσεις." - no_likes_others: "Καμία αρεστή ανάρτηση." sidebar: unread_count: one: "%{count} μη αναγνωσμένο" @@ -3070,7 +3070,10 @@ el: one: "%{count} νέο" other: "%{count} νέα" more: "Περισσότερα..." + all_categories: "Όλες οι κατηγορίες" sections: + about: + header_link_text: "Σχετικά" messages: header_link_text: "Μηνύματα" links: @@ -3082,15 +3085,20 @@ el: unread_with_count: "Μη αναγνωσμένα (%{count})" archive: "Αρχείο" tags: - header_link_title: "όλες οι ετικέτες" header_link_text: "Ετικέτες" categories: - header_link_title: "όλες οι κατηγορίες" header_link_text: "Κατηγορίες" community: - header_link_title: "αρχική Σελίδα" header_link_text: "Κοινότητα" links: + about: + content: "Σχετικά" + admin: + content: "Διαχείριση" + badges: + content: "Παράσημα" + faq: + content: "Συχνές ερωτήσεις" tracked: content: "Παρακολουθείται" groups: @@ -4145,7 +4153,6 @@ el: cant_delete_all_too_many_posts: one: "Δεν γίνεται να σβήσεις όλες τις αναρτήσεις επειδή ο χρήστης έχει περισσότερες από %{count} αναρτήσεις. (Η ρύθμιση «delete_all_posts_max»)" other: "Δεν γίνεται να σβήσεις όλες τις αναρτήσεις επειδή ο χρήστης έχει περισσότερες από %{count} αναρτήσεις. (Η ρύθμιση «delete_all_posts_max»)" - delete_confirm: "Είναι γενικά προτιμότερο να ανωνυμοποιούνται οι χρήστες αντί να διαγράφονται, για να αποφεύγεται η αφαίρεση περιεχομένου από υπάρχουσες συζητήσεις.

    Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτόν τον χρήστη; Αυτό είναι μόνιμο!" delete_and_block: "Σβήσε και απόκλεισε αυτή την διεύθυνση email και τη διεύθυνση IP " delete_dont_block: "Μόνο διαγραφή" deleting_user: "Διαγραφή χρήστη..." diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 3b776812ef..aabda302ec 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -251,6 +251,8 @@ en: not_implemented: "That feature hasn't been implemented yet, sorry!" no_value: "No" yes_value: "Yes" + ok_value: "OK" + cancel_value: "Cancel" submit: "Submit" generic_error: "Sorry, an error has occurred." generic_error_with_reason: "An error occurred: %{error}" @@ -1803,7 +1805,6 @@ en: set_custom_status: "Set custom status" what_are_you_doing: "What are you doing?" remove_status: "Remove status" - until: "Until:" loading: "Loading..." errors: @@ -1837,6 +1838,8 @@ en: enabled: "This site is in read only mode. Please continue to browse, but replying, likes, and other actions are disabled for now." login_disabled: "Login is disabled while the site is in read only mode." logout_disabled: "Logout is disabled while the site is in read only mode." + staff_writes_only_mode: + enabled: "This site is in staff only mode. Please continue to browse, but replying, likes, and other actions are limited to staff members only." too_few_topics_and_posts_notice_MF: >- Let's start the discussion! There {currentTopics, plural, one {is # topic} other {are # topics}} and @@ -1885,7 +1888,7 @@ en: hide_forever: "no thanks" hidden_for_session: "OK, we'll ask you tomorrow. You can always use 'Log In' to create an account, too." intro: "Hello! Looks like you’re enjoying the discussion, but you haven’t signed up for an account yet." - value_prop: "Tired of scrolling through the same posts? when you create an account you’ll always come back to where you left off. With an account you can also be notified of new replies, save bookmarks, and use likes to thank others. We can all work together to make this community great. :heart:" + value_prop: "Tired of scrolling through the same posts? When you create an account you’ll always come back to where you left off. With an account you can also be notified of new replies, save bookmarks, and use likes to thank others. We can all work together to make this community great. :heart:" summary: enabled_description: "You're viewing a summary of this topic: the most interesting posts as determined by the community." @@ -2163,6 +2166,8 @@ en: similar_topics: "Your topic is similar to..." drafts_offline: "drafts offline" edit_conflict: "edit conflict" + esc: "esc" + esc_label: "Click or press Esc to dismiss" group_mentioned_limit: one: "Warning! You mentioned %{group}, however this group has more members than the administrator configured mention limit of %{count} user. Nobody will be notified." @@ -2259,6 +2264,7 @@ en: abandon: "close composer and discard draft" enter_fullscreen: "enter fullscreen composer" exit_fullscreen: "exit fullscreen composer" + exit_fullscreen_prompt: "Press ESC to exit full screen" show_toolbar: "show composer toolbar" hide_toolbar: "hide composer toolbar" modal_ok: "OK" @@ -2269,6 +2275,9 @@ en: body: "Right now this message is only being sent to yourself!" slow_mode: error: "This topic is in slow mode. You already posted recently; you can post again in %{timeLeft}." + user_not_seen_in_a_while: + single: "The person you are messaging, %{usernames}, hasn’t been seen here in a very long time – %{time_ago}. They may not receive your message. You may wish to seek out alternate methods of contacting %{usernames}." + multiple: "The following people you are messaging: %{usernames}, haven’t been seen here in a very long time – %{time_ago}. They may not receive your message. You may wish to seek out alternate methods of contacting them." admin_options_title: "Optional staff settings for this topic" @@ -2307,7 +2316,7 @@ en: image_alt_text: aria_label: Alt text for image - delete_image_button: Delete Image + delete_image_button: Delete Image notifications: tooltip: @@ -2565,17 +2574,53 @@ en: view_all: "view all %{tab}" user_menu: generic_no_items: "There are no items in this list." - sr_menu_tabs: "Menu tabs" + sr_menu_tabs: "User menu tabs" view_all_notifications: "view all notifications" view_all_bookmarks: "view all bookmarks" view_all_messages: "view all personal messages" + tabs: + all_notifications: "All notifications" + replies: "Replies" + replies_with_unread: + one: "Replies - %{count} unread reply" + other: "Replies - %{count} unread replies" + mentions: "Mentions" + mentions_with_unread: + one: "Mentions - %{count} unread mention" + other: "Mentions - %{count} unread mentions" + likes: "Likes" + likes_with_unread: + one: "Likes - %{count} unread like" + other: "Likes - %{count} unread likes" + watching: "Watched topics" + watching_with_unread: + one: "Watched topics - %{count} unread watched topic" + other: "Watched topics - %{count} unread watched topics" + messages: "Personal messages" + messages_with_unread: + one: "Personal messages - %{count} unread message" + other: "Personal messages - %{count} unread messages" + bookmarks: "Bookmarks" + bookmarks_with_unread: + one: "Bookmarks - %{count} unread bookmark" + other: "Bookmarks - %{count} unread bookmarks" + review_queue: "Review queue" + review_queue_with_unread: + one: "Review queue - %{count} item needs review" + other: "Review queue - %{count} items need review" + other_notifications: "Other notifications" + other_notifications_with_unread: + one: "Other notifications - %{count} unread notification" + other: "Other notifications - %{count} unread notifications" + profile: "Profile" reviewable: view_all: "view all review items" queue: "Queue" deleted_user: "(deleted user)" + deleted_post: "(deleted post)" post_number_with_topic_title: "post #%{post_number} - %{title}" new_post_in_topic: "new post in %{title}" - suspicious_user: "suspicious user %{username}" + user_requires_approval: "%{username} requires approval" default_item: "reviewable item #%{reviewable_id}" topics: @@ -3287,12 +3332,12 @@ en: delete: confirm: one: "Are you sure you want to delete that post?" - other: "Are you sure you want to delete those %{count} posts?" + other: "Are you sure you want to delete these %{count} posts?" merge: confirm: - one: "Are you sure you want to merge those posts?" - other: "Are you sure you want to merge those %{count} posts?" + one: "Are you sure you want to merge these posts?" + other: "Are you sure you want to merge these %{count} posts?" revisions: controls: @@ -3729,6 +3774,8 @@ en: browser_update: 'Unfortunately, your browser is unsupported. Please switch to a supported browser to view rich content, log in and reply.' + safari_13_warning: This site will soon remove support for iOS and Safari versions 13 and below. A simplified read-only version will remain available. (more information) + permission_types: full: "Create / Reply / See" create_post: "Reply / See" @@ -3884,7 +3931,7 @@ en: google: "Google Calendar" ics: "ICS" tagging: - all_tags: "All Tags" + all_tags: "All tags" other_tags: "Other Tags" selector_all_tags: "all tags" selector_no_tags: "no tags" @@ -4059,14 +4106,14 @@ en: user_activity: no_activity_title: "No activity yet" no_activity_body: "Welcome to our community! You are brand new here and have not yet contributed to discussions. As a first step, visit Top or Categories and just start reading! Select %{heartIcon} on posts that you like or want to learn more about. As you participate, your activity will be listed here." - no_activity_others: "No activity." no_replies_title: "You have not replied to any topics yet" - no_replies_others: "No replies." + no_replies_title_others: "%{username} has not replied to any topics yet" + no_replies_body: "When you discover an interesting conversation that you wish to contribute to, press the Reply button directly under any post to begin replying to that specific post. Or, if you’d prefer to reply to the general topic rather than any individual post or person, look for the Reply button at the very bottom of the topic, or under the topic timeline." no_drafts_title: "You haven’t started any drafts" no_drafts_body: "Not quite ready to post? We’ll automatically save a new draft and list it here whenever you start composing a topic, reply, or personal message. Select the cancel button to discard or save your draft to continue later." no_likes_title: "You haven’t liked any topics yet" + no_likes_title_others: "%{username} has not liked any topics yet" no_likes_body: "A great way to jump in and start contributing is to start reading conversations that have already taken place, and select the %{heartIcon} on posts that you like!" - no_likes_others: "No liked posts." no_topics_title: "You have not started any topics yet" no_topics_body: "It’s always best to search for existing topics of conversation before starting a new one, but if you’re confident the topic you want isn’t out there already, go ahead and start a new topic of your very own. Look for the + New Topic button at the top right of the topic list, category, or tag to begin creating a new topic in that area." no_topics_title_others: "%{username} has not started any topics yet" @@ -4093,9 +4140,12 @@ en: other: "%{count} new" toggle_section: "toggle section" more: "More..." + all_categories: "All categories" + all_tags: "All tags" sections: + about: + header_link_text: "About" messages: - header_link_title: "personal messages" header_link_text: "Messages" header_action_title: "create a personal message" links: @@ -4109,23 +4159,28 @@ en: tags: none: "You have not added any tags." click_to_get_started: "Click here to get started." - header_link_title: "all tags" header_link_text: "Tags" header_action_title: "edit your sidebar tags" categories: none: "You have not added any categories." click_to_get_started: "Click here to get started." - header_link_title: "all categories" header_link_text: "Categories" header_action_title: "edit your sidebar categories" community: - header_link_title: "home" header_link_text: "Community" header_action_title: "create a new topic" links: + about: + content: "About" + admin: + content: "Admin" + badges: + content: "Badges" everything: content: "Everything" title: "All topics" + faq: + content: "FAQ" tracked: content: "Tracked" title: "All tracked topics" @@ -4141,12 +4196,18 @@ en: draft_count: one: "%{count} draft" other: "%{count} drafts" + review: + content: "Review" + title: "review" + pending_count: "%{count} pending" welcome_topic_banner: title: "Create your Welcome Topic" description: 'Your welcome topic is the first thing new arrivals will read. Think of it as your one paragraph "elevator pitch" or "mission statement"' button_title: "Start Editing" + until: "Until:" + # This section is exported to the javascript for i18n in the admin section admin_js: type_to_filter: "type to filter..." @@ -5281,6 +5342,7 @@ en: suspended: "Suspended?" staged: "Staged?" show_admin_profile: "Admin" + manage_user: "Manage user" show_public_profile: "Show Public Profile" impersonate: "Impersonate" action_logs: "Action Logs" @@ -5382,7 +5444,8 @@ en: cant_delete_all_too_many_posts: one: "Can't delete all posts because the user has more than %{count} post. (delete_all_posts_max)" other: "Can't delete all posts because the user has more than %{count} posts. (delete_all_posts_max)" - delete_confirm: "It is generally preferable to anonymize users rather than deleting them, to avoid removing content from existing discussions.

    Are you SURE you want to delete this user? This is permanent!" + delete_confirm_title: "Are you SURE you want to delete this user? This is permanent!" + delete_confirm: "It is generally preferable to anonymize users rather than deleting them, to avoid removing content from existing discussions." delete_and_block: "Delete and block this email and IP address" delete_dont_block: "Delete only" deleting_user: "Deleting user..." @@ -5517,7 +5580,6 @@ en: recommended: "We recommend customizing the following text to suit your needs:" show_overriden: "Only show overridden" locale: "Language:" - fallback_locale_warning: "You are editing a language based on %{fallback}. Users who choose %{fallback} as their interface language won't see your changes." more_than_50_results: "There are more than 50 results. Please refine your search." settings: # used by theme and site settings diff --git a/config/locales/client.en_GB.yml b/config/locales/client.en_GB.yml index 745df224a3..bcab0e6c2a 100644 --- a/config/locales/client.en_GB.yml +++ b/config/locales/client.en_GB.yml @@ -30,6 +30,7 @@ en_GB: date_year: "MMM 'YY" medium: date_year: "D MMM 'YY" + bootstrap_invite_button_title: "Send invitations" groups: manage: email: @@ -161,7 +162,7 @@ en_GB: anonymize_yes: "Yes, anonymise this account" anonymize_failed: "There was a problem anonymising the account." merge_failed: "There was an error whilst merging the users." - delete_confirm: "It is generally preferable to anonymise users rather than deleting them, to avoid removing content from existing discussions.

    Are you SURE you want to delete this user? This is permanent!" + delete_confirm: "It is generally preferable to anonymise users rather than deleting them, to avoid removing content from existing discussions." site_text: description: "You can customise any of the text on your forum. Please start by searching below:" badges: diff --git a/config/locales/client.es.yml b/config/locales/client.es.yml index 4608e35840..50925a1c04 100644 --- a/config/locales/client.es.yml +++ b/config/locales/client.es.yml @@ -189,6 +189,7 @@ es: other: "Para hacer que la inauguración de tu sitio sea más fácil, el modo arranque está activado. Todas las cuentas tendrán nivel de confianza 1 y los correos electrónicos de resumen diarios están activados. Esto se desactivará automáticamente cuando se hayan registrado %{count} usuarios." bootstrap_mode_disabled: "El modo de arranque se desactivará dentro de las próximas 24 horas." bootstrap_invite_button_title: "Enviar invitaciones" + bootstrap_wizard_link_title: "Finalizar asistente de configuración" themes: default_description: "Por defecto" broken_theme_alert: "Puede que tu sitio no funcione, un tema o componente está causando errores." @@ -225,6 +226,8 @@ es: not_implemented: "¡Lo sentimos! Esa característica no se ha implementado todavía." no_value: "No" yes_value: "Sí" + ok_value: "Aceptar" + cancel_value: "Cancelar" submit: "Enviar" generic_error: "Lo sentimos, ha ocurrido un error." generic_error_with_reason: "Ha ocurrido un error: %{error}" @@ -1052,6 +1055,8 @@ es: dismiss: "Descartar" dismiss_notifications: "Descartar todo" dismiss_notifications_tooltip: "Marcar todas las notificaciones como leídas" + dismiss_bookmarks_tooltip: "Marcar todos los recordatorios de marcadores como leídos" + dismiss_messages_tooltip: "Marcar todos los mensajes personales como leídos" no_messages_title: "No tienes ningún mensaje" no_messages_body: > ¿Necesitas tener una conversación personal directamente con una persona fuera de la conversación actual? Mándale un mensaje seleccionando su foto y usando el botón de %{icon} mensaje.

    Si necesitas ayuda, puedes enviar un mensaje a alguien del equipo. @@ -1649,7 +1654,6 @@ es: set_custom_status: "Escribir estado personalizado" what_are_you_doing: "¿Qué estás haciendo?" remove_status: "Quitar estado" - until: "Hasta:" loading: "Cargando..." errors: prev_page: "mientras se intentaba cargar" @@ -1878,6 +1882,7 @@ es: categories_only: "Solo categorías" categories_with_featured_topics: "Categorías con temas destacados" categories_and_latest_topics: "Categorías y temas recientes" + categories_and_latest_topics_created_date: "Categorías y últimos temas (ordenar por la fecha de creación de los temas)" categories_and_top_topics: "Categorías y temas destacados" categories_boxes: "Cajas con subcategorías" categories_boxes_with_topics: "Cajas con temas destacados" @@ -2056,6 +2061,7 @@ es: abandon: "cerrar el editor y descartar borrador" enter_fullscreen: "entrar en el editor en pantalla completa" exit_fullscreen: "salir del editor en pantalla completa" + exit_fullscreen_prompt: "Pulsa ESC para salir del modo pantalla completa" show_toolbar: "mostrar la barra de herramientas del editor" hide_toolbar: "ocultar la barra de herramientas del editor" modal_ok: "Aceptar" @@ -2099,6 +2105,7 @@ es: ignore: "Ignorar" image_alt_text: aria_label: Texto alternativo para imagen + delete_image_button: Eliminar imagen notifications: tooltip: regular: @@ -2159,6 +2166,9 @@ es: default: one: "¿Quieres descartar? Tienes %{count} notificación importante." other: "¿Quieres descartar? Tienes %{count} notificaciones importantes." + bookmarks: + one: "¿Seguro? Tienes %{count} recordatorio de marcadores sin leer." + other: "¿Seguro? Tienes %{count} recordatorios de marcadores sin leer." dismiss: "Descartar" cancel: "Cancelar" group_message_summary: @@ -2339,8 +2349,30 @@ es: view_all: "ver todos %{tab}" user_menu: generic_no_items: "No hay elementos en esta lista." - sr_menu_tabs: "Pestañas del menú" + sr_menu_tabs: "Pestañas del menú de usuario" view_all_notifications: "ver todas las notificaciones" + view_all_bookmarks: "ver todos los marcadores" + view_all_messages: "ver todos los mensajes personales" + tabs: + all_notifications: "Todas las notificaciones" + replies: "Respuestas" + replies_with_unread: + one: "Respuestas - %{count} sin leer" + other: "Respuestas - %{count} sin leer" + mentions: "Menciones" + likes: "Me gusta dados" + bookmarks: "Marcadores" + review_queue: "Cola de revisión" + other_notifications: "Otras notificaciones" + profile: "Perfil" + reviewable: + queue: "Cola" + deleted_user: "(usuario eliminado)" + deleted_post: "(publicación eliminada)" + post_number_with_topic_title: "publicación n.º %{post_number} – %{title}" + new_post_in_topic: "nueva publicación en %{title}" + user_requires_approval: "%{username} requiere aprobación" + default_item: "elemento revisable n.º %{reviewable_id}" topics: new_messages_marker: "última visita" bulk: @@ -2985,10 +3017,6 @@ es: confirm: one: "¿Seguro que quieres eliminar esa publicación?" other: "¿Seguro de que quieres eliminar esas %{count} publicaciones?" - merge: - confirm: - one: "Seguro que quieres fusionar esas publicaciones?" - other: "¿Seguro que quieres fusionar esas %{count} publicaciones?" revisions: controls: first: "Primera edición" @@ -3406,6 +3434,7 @@ es: today: "Hoy" other_periods: "ver arriba:" browser_update: 'Por desgracia, tu navegador no es compatible. Por favor, usa otro navegador para ver el contenido completo, iniciar sesión y responder.' + safari_13_warning: Este sitio pronto dejará de ser compatible con las versiones 13 y anteriores de iOS y Safari. En su lugar, verás una versión simplificada y de solo lectura. (más información) permission_types: full: "Crear / Responder / Ver" create_post: "Responder / Ver" @@ -3717,15 +3746,15 @@ es: user_activity: no_activity_title: "Todavía no hay actividad" no_activity_body: "¡Te damos la bienvenida a la comunidad! Acabas de llegar, por lo que todavía no has participado. Como primer paso, visita los Destacados o las Categorías y empieza a leer. Dale al botón %{heartIcon} en las publicaciones que te gusten o sobre las que quieras saber más. Aquí verás tu actividad una vez empieces a participar." - no_activity_others: "Sin actividad." no_replies_title: "Todavía no has respondido a ningún tema" - no_replies_others: "No hay respuestas." + no_replies_title_others: "%{username} todavía no ha respondido a ningún tema" no_drafts_title: "Todavía no has empezado ningún borrador" no_drafts_body: "¿Todavía no quieres publicarlo? Vamos a guardar un borrador automáticamente y lo pondremos aquí cuando vayas a empezar a escribir un tema, respuesta o mensaje personal. Dale al botón de cancelar para descartarlo o guardar el borrador y seguir luego." no_likes_title: "Todavía no le has dado a me gusta en ningún tema" + no_likes_title_others: "%{username} no le ha dado me gusta a ningún tema" no_likes_body: "Una buena manera de empezar a contribuir es ir leyendo los temas ya publicados y darle a %{heartIcon} en lo que te guste" - no_likes_others: "No le ha dado me gusta a ninguna publicación." no_topics_title: "Todavía no has empezado ningún tema" + no_topics_body: "Siempre es mejor buscar temas que ya existan antes de empezar uno nuevo, pero si crees que el tema que buscas no existe todavía, no dudes en crearlo. Busca el botón + Nuevo tema arriba a la derecha de la lista de temas, en una categoría o etiqueta." no_topics_title_others: "%{username} no ha creado ningún tema todavía" no_read_topics_title: "Todavía no has leído ningún tema" no_read_topics_body: "Cuando empieces a leer temas, los verás aquí en una lista. Puedes empezar a buscar temas que te interesen en Destacados, la lista de Categorías o buscando palabras %{searchIcon}" @@ -3746,9 +3775,12 @@ es: other: "%{count} nuevos" toggle_section: "mostrar/ocultar sección" more: "Más..." + all_categories: "Todas las categorías" + all_tags: "Todas las etiquetas" sections: + about: + header_link_text: "Acerca de" messages: - header_link_title: "mensajes personales" header_link_text: "Mensajes" header_action_title: "crear un mensaje personal" links: @@ -3762,23 +3794,28 @@ es: tags: none: "No has añadido ninguna etiqueta." click_to_get_started: "Haz clic aquí para empezar." - header_link_title: "todas las etiquetas" header_link_text: "Etiquetas" header_action_title: "editar las etiquetas de tu barra lateral" categories: none: "No has añadido ninguna categoría." click_to_get_started: "Haz clic aquí para empezar." - header_link_title: "todas las categorías" header_link_text: "Categorías" header_action_title: "editar las categorías de tu barra lateral" community: - header_link_title: "inicio" header_link_text: "Comunidad" header_action_title: "crear un nuevo tema" links: + about: + content: "Acerca de" + admin: + content: "Administrador" + badges: + content: "Insignias" everything: content: "Todo" title: "Todos los temas" + faq: + content: "Preguntas frecuentes" tracked: content: "Siguiendo" title: "Todos los temas seguidos" @@ -3794,6 +3831,11 @@ es: draft_count: one: "%{count} borrador" other: "%{count} borradores" + welcome_topic_banner: + title: "Crea tu tema de bienvenida" + description: 'Tu tema de bienvenid es lo primero que la gente nueva leerá al llegar. Piensa en este párrafo como si fuera un "discurso breve" o una "declaración de motivos"' + button_title: "Empezar a editar" + until: "Hasta:" admin_js: type_to_filter: "filtrar opciones..." admin: @@ -4350,6 +4392,8 @@ es: import_web_advanced: "Avanzado..." import_file_tip: "archivo .tar.gz, .zip o .dcstyle.json que contiene un tema" is_private: "El tema está en un repositorio privado de git" + finish_install: "Terminar la instalación del tema" + last_attempt: "La instalación no ha terminado, último intento:" remote_branch: "Nombre de la rama (opcional)" public_key: "Conceda la siguiente clave pública de acceso al repositorio:" public_key_note: "Después de poner una URL de repositorio privado válida, se generará una clave SSH y se mostrará aquí." @@ -4360,6 +4404,7 @@ es: install_git_repo: "Desde un repositorio git" install_create: "Crear nuevo" duplicate_remote_theme: "El componente de tema «%{name}» ya está instalado, ¿seguro que quieres instalar otra copia?" + force_install: "No se ha podido instalar el tema porque su repositorio Git no es accesible. ¿Seguro que quieres continuar con la instalación?" about_theme: "Acerca de" license: "Licencia" version: "Versión:" @@ -4569,6 +4614,7 @@ es: address_placeholder: "nombre@ejemplo.com" type_placeholder: "resumen, registro..." reply_key_placeholder: "clave de respuesta" + smtp_transaction_response_placeholder: "ID de SMTP" moderation_history: performed_by: "Realizado por" no_results: "No hay historial de moderación disponible." @@ -4751,6 +4797,7 @@ es: show_words: one: "ver %{count} palabra" other: "ver %{count} palabras" + case_sensitive: "(distingue entre mayúsculas y minúsculas)" download: Descargar clear_all: Limpiar todo clear_all_confirm: "¿Quitar todas las palabras vigiladas para la acción %{action}?" @@ -4788,6 +4835,7 @@ es: exists: "Ya existe" upload: "Añadir desde archivo" upload_successful: "Subida completada. Las palabras se han añadido." + case_sensitivity_label: "Distingue entre mayúsculas y minúsculas" test: button_label: "Prueba" modal_title: "%{action}: Prueba de palabras vigiladas" @@ -4888,6 +4936,7 @@ es: suspended: "¿Suspendido?" staged: "¿Temporal?" show_admin_profile: "Administrador" + manage_user: "Administrar usuario" show_public_profile: "Ver perfil público" impersonate: "Suplantar" action_logs: "Registros de acciones" @@ -4985,7 +5034,8 @@ es: cant_delete_all_too_many_posts: one: "No se pueden eliminar todas las publicaciones porque el usuario tiene más de %{count}. (delete_all_posts_max)" other: "No se pueden eliminar todas las publicaciones porque el usuario tiene más de %{count}. (delete_all_posts_max)" - delete_confirm: "Por lo general es preferible anonimizar usuarios en vez de eliminarlos para evitar quitar contenido de debates existentes.

    ¿SEGURO que quieres eliminar este usuario? ¡Esta acción es permanente!" + delete_confirm_title: "¿SEGURO que quieres eliminar este usuario? ¡Esta acción es permanente!" + delete_confirm: "Normalmente, es mejor anonimizar usuarios en vez de eliminarlos. Así, evitas eliminar contenido de temas existentes." delete_and_block: "Eliminar y bloquear este correo electrónico y esta dirección IP" delete_dont_block: "Solo eliminar" deleting_user: "Eliminando usuario..." @@ -5116,7 +5166,6 @@ es: recommended: "Te recomendamos que ajustes los siguientes textos a tu comunidad:" show_overriden: "Mostrar solo los sobrescritos" locale: "Idioma:" - fallback_locale_warning: "Estás editando un idioma basado en %{fallback}. Los usuarios que seleccionen %{fallback} como su idioma de interfaz no verán tus cambios." more_than_50_results: "Hay más de 50 resultados. Por favor, afina tu búsqueda." settings: show_overriden: "Mostrar solo los sobrescritos" diff --git a/config/locales/client.et.yml b/config/locales/client.et.yml index 2a7aea1473..5cdfbe9a12 100644 --- a/config/locales/client.et.yml +++ b/config/locales/client.et.yml @@ -150,10 +150,10 @@ et: disabled: "eemaldas selle bänneri %{when}. Seda ei kuvata enam iga lehe ülaosas." forwarded: "edastas ülaltoodud e-kirja" topic_admin_menu: "teema toimingud" - wizard_required: "Tere tulemast uude Discourse’i! Alusta häälestusviisardiga ✨" emails_are_disabled: "Kõik väljuvad meilid on administraatori poolt blokeeritud. Ühtegi teavitust meili teel ei saadeta." software_update_prompt: dismiss: "Ignoreeri" + bootstrap_invite_button_title: "Saada kutsed" themes: default_description: "Vaikimisi" s3: @@ -179,6 +179,8 @@ et: not_implemented: "Seda omadust pole veel rakendatud, vabandame!" no_value: "Ei" yes_value: "Jah" + ok_value: "OK" + cancel_value: "Tühista" submit: "Saada" generic_error: "Vabandust, tekkis viga." generic_error_with_reason: "Tekkis viga: %{error}" @@ -1547,6 +1549,13 @@ et: not_logged_in_user: "kasutajaleht koos toimingute ja eelistuste kokkuvõttega" current_user: "mine oma kasutajalehele" view_all: "vaata kõiki %{tab}" + user_menu: + tabs: + replies: "Vastused" + mentions: "Mainimisi" + likes: "Meeldimisi antud" + bookmarks: "Järjehoidjat" + profile: "Profiil" topics: new_messages_marker: "viimane visiit" bulk: @@ -2027,10 +2036,6 @@ et: confirm: one: "Oled sa kindel, et soovid seda postitust kustutada?" other: "Oled sa kindel, et soovid neid %{count} postitust kustutada?" - merge: - confirm: - one: "Oled kindel, et soovid need postitused ühendada?" - other: "Oled kindel, et soovid need %{count} postitust ühendada?" revisions: controls: first: "Esimene redaktsioon" @@ -2451,7 +2456,6 @@ et: download_calendar: download: "Lae alla" tagging: - all_tags: "Kõik sildid" other_tags: "Muud sildid" selector_all_tags: "kõik sildid" selector_no_tags: "sildid puuduvad" @@ -2528,10 +2532,6 @@ et: member: "liige" regular: "tavaline" leader: "juht" - user_activity: - no_activity_others: "Tegevusi pole." - no_replies_others: "Vastuseid pole." - no_likes_others: "Meeldimisega postitusi veel pole." sidebar: unread_count: one: "%{count} lugemata" @@ -2540,7 +2540,10 @@ et: one: "%{count} uus" other: "%{count} uut" more: "Veel..." + all_categories: "Kõik foorumid" sections: + about: + header_link_text: "Teave" messages: header_link_text: "Sõnumid" links: @@ -2552,15 +2555,20 @@ et: unread_with_count: "Lugemata (%{count})" archive: "Arhiiv" tags: - header_link_title: "kõik sildid" header_link_text: "Sildid" categories: - header_link_title: "kõik foorumid" header_link_text: "Liigid" community: - header_link_title: "avaleht" header_link_text: "Kogukond" links: + about: + content: "Teave" + admin: + content: "Admin" + badges: + content: "Märgised" + faq: + content: "KKK" tracked: content: "Jälgitud" groups: diff --git a/config/locales/client.fa_IR.yml b/config/locales/client.fa_IR.yml index 3b3df213d1..7034f30563 100644 --- a/config/locales/client.fa_IR.yml +++ b/config/locales/client.fa_IR.yml @@ -163,12 +163,12 @@ fa_IR: forwarded: "ایمیل بالا را ارسال کرد" topic_admin_menu: "اقدامات موضوع" skip_to_main_content: "رفتن به محتوای اصلی" - wizard_required: "به دیسکورس خوش آمدید! برای شروع نصب کلیک کنید ✨" emails_are_disabled: "تمام ایمیل های خروجی بصورت کلی توسط مدیر قطع شده است. هیچگونه ایمیل اگاه سازی ارسال نخواهد شد." software_update_prompt: message: "سایت بروز رسانی شده٬ لطفا برای پرهیز از بروز خطای احتمالی صفحه خود را دوباره بارگزاری/ریفرش کنید." dismiss: "رد کردن" bootstrap_mode_disabled: "حالت خود راه انداز در 24 ساعت آینده غیر‌فعال خواهد شد." + bootstrap_invite_button_title: "ارسال دعوت‌نامه" themes: default_description: "پیش‌فرض" s3: @@ -201,6 +201,8 @@ fa_IR: not_implemented: "آن ویژگی هنوز به کار گرفته نشده، متأسفیم!" no_value: "خیر" yes_value: "بله" + ok_value: "تایید" + cancel_value: "انصراف" submit: "ارسال" generic_error: "متأسفیم، خطایی روی داده." generic_error_with_reason: "خطایی روی داد: %{error}" @@ -991,6 +993,7 @@ fa_IR: dismiss_notifications: "پنهان کردن همه" dismiss_notifications_tooltip: "علامت گذاری همه اطلاعیه های خوانده نشده به عنوان خوانده شده" dismiss_bookmarks_tooltip: "علامت‌گذاری تمام یادآوری‌های نشانک شده، خوانده نشده به عنوان خوانده شده" + dismiss_messages_tooltip: "همه آگاه‌سازی‌های پیام‌های شخصی خوانده نشده را به عنوان خوانده شده، علامت گذاری کنید" no_messages_title: "پیامی ندارید" no_bookmarks_title: "شما هنوز چیزی را نشانه‌گذاری نکرده‌اید" no_bookmarks_search: "هیچ نشانکی با درخواست جستجوی شده یافت نشد." @@ -1563,6 +1566,8 @@ fa_IR: enabled: "سایت در حال فقط خواندنی است. می‌توانید موضوعات را مشاهده کنید ولی امکان ارسال پاسخ، پسندیدن و سایر عملیات در حال حاضر غیر‌فعال است." login_disabled: "ورود به سیستم غیر فعال شده همزمان با اینکه سایت در حال فقط خواندنی است." logout_disabled: "سایت در حال فقط خواندنی است و امکان خروج در این حالت وجود ندارد." + staff_writes_only_mode: + enabled: "این سایت در حالت فقط کارکنان است. می‌توانید موضوعات را مشاهده کنید، ولی امکان پاسخ دادن، پسندیدن و سایر اقدامات فقط برای اعضای کارکنان محدود شده است." logs_error_rate_notice: 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/hour} other {# errors/hour}} به حد مجاز از {limit, plural, one {# error/hour} other {# errors/hour}} رسیده است." @@ -1898,6 +1903,7 @@ fa_IR: abandon: "پنل نوشتن را ببند و پیش‌نویس را حذف کن" enter_fullscreen: "کامپوزر تمام صفحه" exit_fullscreen: "خارج شدن از حالت نوشتار تمام‌صفحه" + exit_fullscreen_prompt: "برای خروج از تمام صفحه، دکمه ESC را فشار دهید" modal_ok: "تایید" modal_cancel: "لغو" cant_send_pm: "متاسفانه , شما نمیتوانید به %{username} پیام بفرستید." @@ -1991,6 +1997,9 @@ fa_IR: bookmarks: one: "آيا مطمئن هستی؟ شما %{count} یادآوری نشانک شده، خوانده نشده دارید." other: "آيا مطمئن هستی؟ شما %{count} یادآوری نشانک شده، خوانده نشده دارید." + messages: + one: "آیا مطمئن هستی؟ شما %{count} پیام شخصی خوانده نشده دارید." + other: "آیا مطمئن هستی؟ شما %{count} پیام شخصی خوانده نشده دارید." dismiss: "نادیده گرفتن" cancel: "انصراف" group_message_summary: @@ -2028,6 +2037,7 @@ fa_IR: topic_reminder: "اگاهسازی مبحث" liked_consolidated: "پسندیده‌های جدید" post_approved: "نوشته تایید شده" + reaction: "واکنش جدید" upload_selector: uploading: "در حال بروز‌رسانی " select_file: "انتخاب فایل" @@ -2135,16 +2145,41 @@ fa_IR: view_all: "نمایش همه %{tab}" user_menu: generic_no_items: "هیچ موردی در این فهرست وجود ندارد." - sr_menu_tabs: "زبان‌های منو" + sr_menu_tabs: "زبانه‌های منو کاربر" view_all_notifications: "مشاهده همه آگاه‌سازی‌ها" view_all_bookmarks: "مشاهده همه نشانک‌ها" + view_all_messages: "مشاهده تمام پیام‌های شخصی" + tabs: + all_notifications: "همه آگاه‌سازی‌ها" + replies: "پاسخ‌ها" + replies_with_unread: + one: "پاسخ‌ها - %{count} پاسخ خوانده نشده" + other: "پاسخ‌ها - %{count} پاسخ خوانده نشده" + mentions: "اشاره‌ها" + mentions_with_unread: + one: "اشاره‌ها - %{count} اشاره خوانده نشده" + other: "اشاره‌ها - %{count} اشاره خوانده نشده" + likes: "پسندیده‌ها" + likes_with_unread: + one: "پسندیده‌ها - %{count} پسندیده خوانده نشده" + other: "پسندیده‌ها - %{count} پسندیده خوانده نشده" + messages: "پیام‌های شخصی" + messages_with_unread: + one: "پیام‌های شخصی - %{count} پیام خوانده نشده" + other: "پیام‌های شخصی - %{count} پیام خوانده نشده" + bookmarks: "نشانک‌ها" + bookmarks_with_unread: + one: "نشانک‌ها - %{count} نشانک خوانده نشده" + other: "نشانک‌ها - %{count} نشانک خوانده نشده" + profile: "نمایه" reviewable: view_all: "مشاهده تمام موارد بازبینی" queue: "صف" deleted_user: "«کاربر حذف شده»" + deleted_post: "«نوشته حذف شده»" post_number_with_topic_title: "نوشته #%{post_number} - %{title}" new_post_in_topic: "نوشته‌ی جدید در %{title}" - suspicious_user: "کاربر مشکوک %{username}" + user_requires_approval: "%{username} نیاز به تایید دارد" default_item: "مورد قابل بازبینی #%{reviewable_id}" topics: new_messages_marker: "آخرین بازدید" @@ -2662,8 +2697,8 @@ fa_IR: other: "آیا مطمئن هستید که می‌خواهید آن %{count} فرسته را حذف کنید؟" merge: confirm: - one: "آیا مطمئن هستید که می خواهید آن پست ها را ادغام کنید؟" - other: "آیا مطمئن هستید که می‌خواهید آن %{count} فرسته را ادغام کنید؟" + one: "آیا مطمئن هستید که می‌خواهید این نوشته‌ها را ادغام کنید؟" + other: "آیا مطمئن هستید که می‌خواهید این %{count} نوشته را ادغام کنید؟" revisions: controls: first: "بازبینی نخست" @@ -3008,6 +3043,7 @@ fa_IR: this_month: "ماه" this_week: "هفته" today: "امروز" + safari_13_warning: این سایت به زودی از iOS و Safari، نسخه ۱۳ به بالا پشتیبانی نخواهد کرد. یک نسخه فقط خواندنی ساده در دسترس باقی خواهد ماند. (اطلاعات بیشتر) permission_types: full: "ساختن / پاسخ دادن / دیدن" create_post: "پاسخ دادن / دیدن" @@ -3246,10 +3282,10 @@ fa_IR: leader: "راهبر" user_activity: no_replies_title: "شما هنوز به هیچ موضوعی پاسخ نداده اید" - no_replies_others: "بدون پاسخ" + no_replies_title_others: "%{username} هنوز در هیچ موضوعی، پاسخی نداده است" no_drafts_title: "شما هنوز هیچ پیش‌نویسی شروع نکرده‌اید" no_drafts_body: "برای ارسال کاملا آماده نیستید؟ هر زمان که شروع به نوشتن موضوع، پاسخ یا پیام شخصی کنید، پیش‌نویس جدیدی را به‌طور خودکار ذخیره می‌کنیم و آن را در اینجا فهرست می‌کنیم. برای صرف‌نظر کردن، دکمه لغو را انتخاب کنید یا پیش‌نویس خود را ذخیره کنید تا بعدا ادامه دهید." - no_likes_others: "فرسته‌ی موردپسندیدی نیست." + no_likes_title_others: "%{username} هنوز هیچ موضوعی را نپسندیده." sidebar: unread_count: one: "%{count} خوانده نشده" @@ -3259,9 +3295,12 @@ fa_IR: other: "%{count} تازه" toggle_section: "تغییر بخش" more: "بیشتر..." + all_categories: "همه‌ی دسته‌بندی‌ها" + all_tags: "همه برچسب‌ها" sections: + about: + header_link_text: "درباره" messages: - header_link_title: "پیام‌های شخصی" header_link_text: "پیام‌ها" header_action_title: "ایجاد پیام شخصی" links: @@ -3275,23 +3314,28 @@ fa_IR: tags: none: "شما هنوز هیچ برچسبی اضافه نکرده‌اید." click_to_get_started: "برای شروع اینجا را کلیک کنید." - header_link_title: "تمام برچسب‌ها" header_link_text: "برچسب" header_action_title: "برچسب‌های نوار کناری خود را ویرایش کنید" categories: none: "شما هنوز هیچ دسته‌بندی اضافه نکرده‌اید." click_to_get_started: "برای شروع اینجا را کلیک کنید." - header_link_title: "همه‌ی دسته‌بندی‌ها" header_link_text: "دسته‌بندی‌ها" header_action_title: "دسته‌بندی‌های نوار کناری خود را ویرایش کنید" community: - header_link_title: "خانه" header_link_text: "انجمن" header_action_title: "ایجاد موضوع جدید" links: + about: + content: "درباره" + admin: + content: "مدیر کل" + badges: + content: "نشان‌ها" everything: content: "همه چیز" title: "همه موضوعات" + faq: + content: "پرسش‌های متداول" tracked: content: "پی‌گیری شده" title: "همه موضوعات پیگیری شده" @@ -3307,6 +3351,7 @@ fa_IR: draft_count: one: "%{count} پیش‌نویس" other: "%{count} پیش‌نویس" + until: "تا وقتی که:" admin_js: type_to_filter: "بنویسید تا فیلتر کنید..." admin: @@ -4070,6 +4115,7 @@ fa_IR: suspended: "تعلیق شد؟" staged: "کاربر خودکار؟" show_admin_profile: "مدیر ارشد" + manage_user: "مدیریت کاربر" show_public_profile: "نمایش نمایه عمومی" impersonate: "جعل هویت کردن" action_logs: "گزارش گار" @@ -4128,6 +4174,7 @@ fa_IR: cant_delete_all_too_many_posts: one: "نمی توان همه نوشته ها را خذف کرد. چون تعداد کاربران از %{count} تعداد نوشته ها بیشتر است.(delete_all_posts_max)" other: "نمی توان همه نوشته ها را خذف کرد. چون تعداد کاربران از %{count} تعداد نوشته ها بیشتر است.(delete_all_posts_max)" + delete_confirm_title: "آیا مطمئن هستید که می‌خواهید این کاربر را حذف کنید؟ این دائمی است!" delete_and_block: "آدرس IP و ایمیل را حذف و مسدودکن." delete_dont_block: "فقط حذف" deleting_user: "درحال حذف کاربر..." diff --git a/config/locales/client.fi.yml b/config/locales/client.fi.yml index 6e7058aed4..1d5f886707 100644 --- a/config/locales/client.fi.yml +++ b/config/locales/client.fi.yml @@ -156,7 +156,6 @@ fi: disabled: "poistettu banneri näkyvistä %{when}. Sitä ei enää näytetä jokaisen sivun ylälaidassa." forwarded: "välitetty yllä oleva sähköposti" topic_admin_menu: "ketjun toiminnot" - wizard_required: "Tervetuloa uuteen Discourseesi! Aloitetaan ohjattu asennus ✨" emails_are_disabled: "Ylläpitäjä on estänyt kaiken lähtevän sähköpostiliikenteen. Mitään sähköposti-ilmoituksia ei lähetetä." software_update_prompt: message: "Sivusto on juuri päivitetty, päivitä sivu, tai sivusto voi käyttäytyä odottamattomasti." @@ -165,6 +164,7 @@ fi: one: "Jotta sivusto saisi lentävämmän lähdön, olet aloitustilassa. Kaikki käyttäjät nousevat heti luottamustasolle 1, ja päivittäiset sähköpostitiivistelmät kytketään päälle. Tila kytkeytyy pois päältä, kun %{count} käyttäjä on liittynyt." other: "Jotta sivusto saisi lentävämmän lähdön, olet aloitustilassa. Kaikki käyttäjät nousevat heti luottamustasolle 1, ja päivittäiset sähköpostitiivistelmät kytketään päälle. Tila kytkeytyy pois päältä, kun %{count} käyttäjää on liittynyt." bootstrap_mode_disabled: "Aloitustila poistetaan käytöstä seuraavan 24 tunnin aikana." + bootstrap_invite_button_title: "Lähetä kutsuja" themes: default_description: "Oletus" s3: @@ -196,6 +196,8 @@ fi: not_implemented: "Tätä toimintoa ei ole vielä toteutettu, pahoittelut!" no_value: "Ei" yes_value: "Kyllä" + ok_value: "OK" + cancel_value: "Peruuta" submit: "Lähetä" generic_error: "On tapahtunut virhe." generic_error_with_reason: "Tapahtui virhe: %{error}" @@ -2174,6 +2176,13 @@ fi: not_logged_in_user: "käyttäjäsivu, jossa on yhteenveto käyttäjän viimeaikaisesta toiminnasta sekä käyttäjäasetukset" current_user: "siirry omalle käyttäjäsivullesi" view_all: "näytä kaikki %{tab}" + user_menu: + tabs: + replies: "Vastaukset" + mentions: "Maininnat" + likes: "Tykkäykset" + bookmarks: "Kirjanmerkit" + profile: "Profiili" topics: new_messages_marker: "edellinen vierailu" bulk: @@ -2779,10 +2788,6 @@ fi: confirm: one: "Oletko varma, että haluat poistaa viestin?" other: "Oletko varma, että haluat poistaa %{count} viestiä?" - merge: - confirm: - one: "Oletko varma, että haluat yhdistää nämä viestit?" - other: "Oletko varma, että haluat yhdistää nämä %{count} viestiä?" revisions: controls: first: "Ensimmäinen revisio" @@ -3310,7 +3315,6 @@ fi: download_calendar: download: "Lataa" tagging: - all_tags: "Kaikki tunnisteet" other_tags: "Muut tunnisteet" selector_all_tags: "kaikki tunnisteet" selector_no_tags: "ei tunnisteita" @@ -3455,10 +3459,6 @@ fi: regular: "mestari" leader: "johtaja" detailed_name: "%{level}: %{name}" - user_activity: - no_activity_others: "Ei toimintaa." - no_replies_others: "Ei vastauksia." - no_likes_others: "Ei tykättyjä viestejä." sidebar: unread_count: one: "%{count} lukematta" @@ -3467,7 +3467,10 @@ fi: one: "%{count} uusi" other: "%{count} uutta" more: "Lisää..." + all_categories: "Kaikki alueet" sections: + about: + header_link_text: "Tietoa" messages: header_link_text: "Viestit" links: @@ -3479,15 +3482,20 @@ fi: unread_with_count: "Lukematta (%{count})" archive: "Arkisto" tags: - header_link_title: "kaikki tunnisteet" header_link_text: "Tunnisteet" categories: - header_link_title: "kaikki alueet" header_link_text: "Alueet" community: - header_link_title: "aloitus" header_link_text: "Yhteisö" links: + about: + content: "Tietoa" + admin: + content: "Ylläpitäjä" + badges: + content: "Kunniamerkit" + faq: + content: "UKK" tracked: content: "Seuratut" groups: @@ -4637,7 +4645,6 @@ fi: cant_delete_all_too_many_posts: one: "Kaikkia viestejä ei voi poistaa, koska käyttäjällä on enemmän kuin %{count} viesti. (delete_all_posts_max)" other: "Kaikkia viestejä ei voi poistaa, koska käyttäjällä on enemmän kuin %{count} viestiä. (delete_all_posts_max)" - delete_confirm: "On yleisesti kannattavampaa anonymisoida käyttäjä kuin poistaa hänet, jottei olemassa olevista keskusteluista poistu sisältöä.

    Oletko VARMA, että haluat poistaa tämän käyttäjän? Peruuttaminen ei ole mahdollista!" delete_and_block: "Poista ja estä tämä sähköposti ja IP-osoite" delete_dont_block: "Ainoastaan poista" deleting_user: "Poistetaan käyttäjää..." @@ -4767,7 +4774,6 @@ fi: recommended: "On suositeltavaa muokata seuraavaa tekstiä tarpeidesi mukaan:" show_overriden: "Näytä vain korvatut" locale: "Kieli:" - fallback_locale_warning: "Olet muokkaamassa kieltä, joka perustuu kieleen %{fallback}. Käyttäjät, jotka valitsevat näyttöliittymänsä kieleksi kielen %{fallback}, eivät näe muutoksiasi." more_than_50_results: "Hakutuloksia on yli 50. Rajaa hakuasi." settings: show_overriden: "Näytä vain korvatut" diff --git a/config/locales/client.fr.yml b/config/locales/client.fr.yml index 01daf7c65e..471ee8cfff 100644 --- a/config/locales/client.fr.yml +++ b/config/locales/client.fr.yml @@ -179,7 +179,6 @@ fr: forwarded: "a transmis le courriel ci-dessus" topic_admin_menu: "actions du sujet" skip_to_main_content: "Passer au contenu principal" - wizard_required: "Bienvenue sur votre nouveau Discourse ! Démarrons par l'assistant de configuration ✨" emails_are_disabled: "Le courriel sortant a été désactivé par un administrateur. Aucune notification par courriel ne sera envoyée." emails_are_disabled_non_staff: "L'envoi de courriel est désactivé pour les utilisateurs ne faisant pas partie des responsables." software_update_prompt: @@ -189,6 +188,8 @@ fr: one: "Pour faciliter son lancement, votre nouveau site se trouve en mode d'amorçage. Chaque nouvel utilisateur se verra accorder le niveau de confiance 1 et recevra des résumés quotidiens par courriel. Ce mode sera automatiquement désactivé dès que votre site possédera %{count} utilisateur." other: "Pour faciliter son lancement, votre nouveau site se trouve en mode d'amorçage. Chaque nouvel utilisateur se verra accorder le niveau de confiance 1 et recevra des résumés quotidiens par courriel. Ce mode sera automatiquement désactivé dès que votre site possédera %{count} utilisateurs." bootstrap_mode_disabled: "Le mode d'amorçage sera désactivé dans les prochaines 24 heures." + bootstrap_invite_button_title: "Envoyer des invitations" + bootstrap_wizard_link_title: "Fin de l'assistant d'installation" themes: default_description: "Par défaut" broken_theme_alert: "Votre site risque de ne pas fonctionner car un thème ou un composant de thème a déclenché une ou plusieurs erreurs." @@ -225,6 +226,8 @@ fr: not_implemented: "Cette fonctionnalité n'est pas encore disponible." no_value: "Non" yes_value: "Oui" + ok_value: "OK" + cancel_value: "Annuler" submit: "Envoyer" generic_error: "Nous sommes désolés, une erreur est survenue." generic_error_with_reason: "Une erreur est survenue : %{error}" @@ -1052,6 +1055,8 @@ fr: dismiss: "Vu" dismiss_notifications: "Tout vu" dismiss_notifications_tooltip: "Marquer les notifications comme lues" + dismiss_bookmarks_tooltip: "Marquer tous les rappels de favoris non-lus comme lus" + dismiss_messages_tooltip: "Marquer toutes les notifications de messages directs non-lues comme lues" no_messages_title: "Vous n'avez aucun message" no_messages_body: > Besoin d'échanger directement avec une personne en-dehors de la conversation principale ? Sélectionnez son avatar et utilisez le bouton %{icon} pour lui écrire un message.

    Pour obtenir de l'aide, adressez-vous à l'un des responsables du site. @@ -1179,7 +1184,7 @@ fr: personal: "Personnels" latest: "Récents" sent: "Envoyés" - unread: "Non lues" + unread: "Non lus" unread_with_count: one: "Non lu (%{count})" other: "Non lu (%{count})" @@ -1197,6 +1202,7 @@ fr: read_more_in_group: "Envie d'en lire encore ? Consultez d'autres messages dans %{groupLink}." read_more: "Envie d'en lire encore ? Consultez d'autres messages dans vos messages personnels." read_more_group_pm_MF: "Il reste { UNREAD, plural, =0 {} one {1 sujet non lu} other {# sujets non lus} } { NEW, plural, =0 {} one { { BOTH, select, true { et } false {} other {} }1 nouveau sujet} other { { BOTH, select, true { et } false {} other {} } # nouveaux sujets}}, ou vous pouvez aussi consulter les autres sujets dans {groupLink}" + read_more_personal_pm_MF: "Il reste { UNREAD, plural, =0 {} one {un message non lu} other {# messages non lus} } { NEW, plural, =0 {} one { { BOTH, select, true { et } false {} other {} }un nouveau message} other { { BOTH, select, true { et } false {} other {} } # nouveaux messages}}, ou vous pouvez aussi consulter les autres messages personnels" preferences_nav: account: "Compte" security: "Sécurité" @@ -1648,7 +1654,6 @@ fr: set_custom_status: "Définir un statut personnalisé" what_are_you_doing: "« Que faites-vous ? »" remove_status: "Supprimer le statut" - until: "Jusqu'à :" loading: "Chargement…" errors: prev_page: "lors du chargement de" @@ -1877,6 +1882,7 @@ fr: categories_only: "Catégories seules" categories_with_featured_topics: "Catégories avec sujets à la une" categories_and_latest_topics: "Catégories et sujets récents" + categories_and_latest_topics_created_date: "Catégories et Sujets récents (trier par date de création du sujet)" categories_and_top_topics: "Catégories et meilleurs sujets" categories_boxes: "Boîtes avec sous-catégories" categories_boxes_with_topics: "Boîtes avec sujets à la une" @@ -2055,6 +2061,7 @@ fr: abandon: "fermer le panneau d'édition et supprimer le brouillon" enter_fullscreen: "utiliser l'éditeur plein écran" exit_fullscreen: "sortir de l'éditeur plein écran" + exit_fullscreen_prompt: "Appuyer sur ESC pour sortir du plein écran" show_toolbar: "afficher la barre d'outils de l'éditeur" hide_toolbar: "masquer la barre d'outils de l'éditeur" modal_ok: "OK" @@ -2098,6 +2105,7 @@ fr: ignore: "Ignorer" image_alt_text: aria_label: Texte alternatif pour l'image + delete_image_button: Supprimer l'image notifications: tooltip: regular: @@ -2157,6 +2165,9 @@ fr: default: one: "Vous avez %{count} notification importante. Voulez-vous continuer?" other: "Vous avez %{count} notifications importantes. Voulez-vous continuer?" + messages: + one: "Êtes-vous sûr·e ? Vous avez %{count} message personnel non lu." + other: "Êtes-vous sûr·e ? Vous avez %{count} messages personnels non lus." dismiss: "Vu" cancel: "Annuler" group_message_summary: @@ -2337,10 +2348,30 @@ fr: view_all: "voir les %{tab}" user_menu: generic_no_items: "Cette liste ne contient aucun élément." - sr_menu_tabs: "Onglets du menu" + sr_menu_tabs: "Onglets du menu utilisateur" view_all_notifications: "Afficher toutes les notifications" + view_all_bookmarks: "voir tous les signets" + view_all_messages: "voir tous les messages personnels" + tabs: + all_notifications: "Toutes les notifications" + replies: "Réponses" + mentions: "Mentions" + likes: "« J'aime » attribués" + watching: "Sujets suivis" + messages: "Messages directs" + bookmarks: "Signets" + review_queue: "Examiner la file d'attente" + other_notifications: "Autres notifications" + profile: "Profil" reviewable: + view_all: "Afficher tous les éléments à examiner" queue: "File d'attente" + deleted_user: "(utilisateur supprimé)" + deleted_post: "(message supprimé)" + post_number_with_topic_title: "publication #%{post_number} - %{title}" + new_post_in_topic: "nouvelle contribution dans %{title}" + user_requires_approval: "%{username} requiert une approbation" + default_item: "élément à examiner #%{reviewable_id}" topics: new_messages_marker: "dernière visite" bulk: @@ -2844,6 +2875,7 @@ fr: one: "Ce message a reçu %{count} réponse. Cliquez pour développer l'affichage" other: "Ce message a reçu %{count} réponses. Cliquez pour développer l'affichage" expand_collapse: "développer/réduire" + sr_below_embedded_posts_description: "réponses à la publication #%{post_number}" sr_embedded_reply_description: "réponse de @%{username} au message #%{post_number}" locked: "un responsable a verrouillé ce message pour empêcher sa modification" gap: @@ -2984,10 +3016,6 @@ fr: confirm: one: "Voulez-vous vraiment supprimer ce message ?" other: "Voulez-vous vraiment supprimer ces %{count} messages ?" - merge: - confirm: - one: "Voulez-vous vraiment fusionner ces messages ?" - other: "Voulez-vous vraiment fusionner ces %{count} messages ?" revisions: controls: first: "Première révision" @@ -3404,6 +3432,8 @@ fr: this_week: "Semaine" today: "Aujourd'hui" other_periods: "voir le top :" + browser_update: 'Malheureusement, votre navigateur n''est pas pris en charge. Merci de mettre à jour votre navigateur pour afficher le contenu enrichi, vous connecter et répondre.' + safari_13_warning: Ce site va bientôt supprimer la prise en charge des versions 13 et inférieures d'iOS et de Safari. Une version simplifiée en lecture seule restera disponible. (plus d'informations) permission_types: full: "Créer/Répondre/Voir" create_post: "Répondre/Voir" @@ -3494,6 +3524,7 @@ fr: edit: "%{shortcut} Modifier le message" delete: "%{shortcut} Supprimer le message" mark_muted: "%{shortcut} Mettre le sujet en sourdine" + mark_regular: "%{shortcut} Sujet normal (par défaut)" mark_tracking: "%{shortcut} Suivre le sujet" mark_watching: "%{shortcut} Surveiller le sujet" print: "%{shortcut} Imprimer le sujet" @@ -3714,14 +3745,11 @@ fr: user_activity: no_activity_title: "Aucune activité pour le moment." no_activity_body: "Bienvenue dans notre communauté ! Vous êtes tout nouveau ici et n'avez pas encore contribué aux discussions. Dans un premier temps, visitez Top ou Catégories et commencez simplement à lire ! Sélectionnez %{heartIcon} sur les publications que vous aimez ou sur lesquelles vous souhaitez en savoir plus. Au fur et à mesure de votre participation, votre activité sera listée ici." - no_activity_others: "Aucune activité." no_replies_title: "Vous n'avez publié de réponse à aucun sujet pour le moment" - no_replies_others: "Aucune réponse." no_drafts_title: "Vous n'avez enregistré aucun brouillon" no_drafts_body: "Vous n'êtes pas tout à fait prêt à publier ? Nous enregistrerons automatiquement un nouveau brouillon et le répertorierons ici chaque fois que vous commencerez à rédiger un sujet, une réponse ou un message personnel. Sélectionnez le bouton Annuler pour supprimer, ou enregistrez votre brouillon pour continuer plus tard." no_likes_title: "Vous n'avez encore aimé aucun sujet" no_likes_body: "Une excellente façon d'intervenir et de commencer à contribuer est de commencer à lire les conversations qui ont déjà eu lieu et de sélectionner le %{heartIcon} sur les publications que vous aimez !" - no_likes_others: "Aucun message aimé." no_topics_title: "Vous n'avez pas encore créé de sujet" no_topics_title_others: "%{username} n'a pas encore commencé de sujets." no_read_topics_title: "Vous n'avez lu aucun sujet pour le moment" @@ -3742,9 +3770,12 @@ fr: one: "%{count} nouveau" other: "%{count} nouveaux" more: "Plus…" + all_categories: "Toutes les catégories" + all_tags: "Toutes les étiquettes" sections: + about: + header_link_text: "À propos" messages: - header_link_title: "messages directs" header_link_text: "Messages" header_action_title: "créer un message direct" links: @@ -3752,29 +3783,36 @@ fr: sent: "Envoyés" new: "Nouveau" new_with_count: "Nouveau (%{count})" - unread: "Non lues" + unread: "Non lus" unread_with_count: "Non lu (%{count})" archive: "Archivés" tags: none: "Vous n'avez ajouté aucune étiquette." click_to_get_started: "Cliquez ici pour commencer." - header_link_title: "toutes les étiquettes" header_link_text: "Étiquettes" + header_action_title: "Modifier les étiquettes de votre barre latérale" categories: none: "Vous n'avez ajouté aucune catégorie." click_to_get_started: "Cliquez ici pour commencer." - header_link_title: "toutes les catégories" header_link_text: "Catégories" + header_action_title: "Modifier les catégories de votre barre latérale" community: - header_link_title: "accueil" header_link_text: "Communauté" header_action_title: "créer un nouveau sujet" links: + about: + content: "À propos" + admin: + content: "Administrateur" + badges: + content: "Badges" everything: content: "Tout" title: "Tous les sujets" + faq: + content: "FAQ" tracked: - content: "Suivies" + content: "Suivis" title: "Tous les sujets suivis" groups: content: "Groupes" @@ -3785,6 +3823,10 @@ fr: my_posts: content: "Mes messages" title: "Mes publications" + draft_count: + one: "%{count} brouillon" + other: "%{count} brouillons" + until: "Jusqu'à :" admin_js: type_to_filter: "commencez votre saisie pour filtrer…" admin: @@ -4876,6 +4918,7 @@ fr: suspended: "Suspendu ?" staged: "Distant ?" show_admin_profile: "Administration" + manage_user: "Gérer l'utilisateur" show_public_profile: "Afficher le profil public" impersonate: "Incarner" action_logs: "Journaux d'actions" @@ -4973,7 +5016,6 @@ fr: cant_delete_all_too_many_posts: one: "Impossible de supprimer tous les messages parce que l'utilisateur a plus d'un message. (delete_all_posts_max)" other: "Impossible de supprimer tous les messages parce que l'utilisateur a plus de %{count} messages. (delete_all_posts_max)" - delete_confirm: "Il est généralement préférable d'anonymiser les utilisateurs plutôt que de les supprimer, afin d'éviter de supprimer du contenu dans les discussions existantes.

    Voulez-vous vraiment supprimer cet utilisateur ? Cette opération est irréversible !" delete_and_block: "Supprimer et bloquer cette adresse courriel et adresse IP." delete_dont_block: "Supprimer uniquement" deleting_user: "Suppression de l'utilisateur…" @@ -5104,7 +5146,6 @@ fr: recommended: "Nous vous recommandons de personnaliser le texte suivant selon vos besoins :" show_overriden: "Afficher uniquement les textes modifiés" locale: "Langue :" - fallback_locale_warning: "Vous modifiez une langue basée sur %{fallback}. Les utilisateurs qui choisissent %{fallback} comme langue d'interface ne verront pas vos modifications." more_than_50_results: "Il y a plus de 50 résultats. Veuillez affiner votre recherche." settings: show_overriden: "Afficher uniquement les paramètres modifiés" diff --git a/config/locales/client.gl.yml b/config/locales/client.gl.yml index b16b5bf68c..59f447e8c8 100644 --- a/config/locales/client.gl.yml +++ b/config/locales/client.gl.yml @@ -156,7 +156,6 @@ gl: disabled: "eliminou este báner %{when}. Xa non aparecerá máis na banda superior de todas as páxinas." forwarded: "reenviou a mensaxe de correo anterior" topic_admin_menu: "accións do tema" - wizard_required: "Este é o novo Discourse! Pode comezar co asistente de configuración ✨" emails_are_disabled: "Todos as mensaxes de correo saíntes foron desactivadas globalmente por un administrador. Non se enviará ningún tipo de notificación por correo electrónico." software_update_prompt: dismiss: "Desbotar" @@ -164,6 +163,7 @@ gl: one: "Para facilitar o lanzamento do seu novo sitio, está en modo de arranque. Todos os novos usuarios recibirán o nivel de confianza 1 e terán activadas as mensaxes de correo de resumo diario. Isto desactivarase automaticamente cando se una %{count} usuario." other: "Para facilitar o lanzamento do seu novo sitio, está en modo de arranque. Todos os novos usuarios recibirán nivel de confianza 1 e terán activadas as mensaxes de correo de resumo diario. Isto desactivarase automaticamente cando se unan %{count} usuarios." bootstrap_mode_disabled: "O modo Bootstrap desactivarase nun prazo de 24 horas." + bootstrap_invite_button_title: "Enviar convites" themes: default_description: "Predeterminado" s3: @@ -195,6 +195,8 @@ gl: not_implemented: "Sentímolo pero esta funcionalidade non se implementou aínda!" no_value: "Non" yes_value: "Si" + ok_value: "De acordo" + cancel_value: "Cancelar" submit: "Enviar" generic_error: "Sentímolo pero produciuse un erro." generic_error_with_reason: "Produciuse un erro: %{error}" @@ -2108,6 +2110,13 @@ gl: not_logged_in_user: "páxina do usuario cun resumo das actividades e preferencias actuais" current_user: "ir á súa páxina do usuario" view_all: "ver todas %{tab}" + user_menu: + tabs: + replies: "Réplicas" + mentions: "Mencións" + likes: "Gústame" + bookmarks: "Marcadores" + profile: "Perfil" topics: new_messages_marker: "última visita" bulk: @@ -2689,10 +2698,6 @@ gl: confirm: one: "Confirma a eliminación desta publicación?" other: "Confirma a eliminación destas %{count} publicacións?" - merge: - confirm: - one: "Confirma a combinación desas publicacións?" - other: "Confirma a combinación destas %{count} publicacións?" revisions: controls: first: "Primeira revisión" @@ -3213,7 +3218,6 @@ gl: download_calendar: download: "Descargar" tagging: - all_tags: "Todas as etiquetas" other_tags: "Outras etiquetas" selector_all_tags: "todas as etiquetas" selector_no_tags: "sen etiquetas" @@ -3346,10 +3350,6 @@ gl: member: "membro" regular: "habitual" leader: "líder" - user_activity: - no_activity_others: "Sen actividade." - no_replies_others: "Sen respostas." - no_likes_others: "Ningún Gústame en publicacións." sidebar: unread_count: one: "%{count} pendente de lectura" @@ -3358,7 +3358,10 @@ gl: one: "%{count} novo" other: "%{count} novos" more: "Máis..." + all_categories: "Todas as categorías" sections: + about: + header_link_text: "Verbo de" messages: header_link_text: "Mensaxes" links: @@ -3370,15 +3373,20 @@ gl: unread_with_count: "(%{count}) pendente de ler" archive: "Arquivo" tags: - header_link_title: "todas as etiquetas" header_link_text: "Etiquetas" categories: - header_link_title: "todas as categorías" header_link_text: "Categorías" community: - header_link_title: "inicio" header_link_text: "Comunidade" links: + about: + content: "Verbo de" + admin: + content: "Administración" + badges: + content: "Insignias" + faq: + content: "PMF" tracked: content: "Seguido" groups: @@ -4502,7 +4510,6 @@ gl: cant_delete_all_too_many_posts: one: "Non é posíbel eliminar todas as publicacións porque o usuario ten máis dunha publicación. (delete_all_posts_max)" other: "Non é posíbel eliminar todas as publicacións porque o usuario ten máis de %{count} publicacións. (delete_all_posts_max)" - delete_confirm: "Xeralmente é preferíbel anonimizar os usuarios mellor ca eliminalos, para evitar retirar contido das discusións existentes.

    Está SEGURO de que quere eliminar este usuario? Isto é permanente!" delete_and_block: "Eliminar e bloquear este enderezo de correo e de IP" delete_dont_block: "Só eliminar" deleting_user: "Eliminando usuario..." @@ -4627,7 +4634,6 @@ gl: recommended: "Recomendamos personalizar o seguinte texto para axeitalo ás súas necesidades:" show_overriden: "Amosar só os cambios" locale: "Idioma:" - fallback_locale_warning: "Está a editar un idioma baseado en %{fallback}. Os usuarios que escollan %{fallback} como idioma de interface non verán os cambios." more_than_50_results: "Hai máis de 50 resultados. Restrinxa a busca." settings: show_overriden: "Amosar só os cambios" diff --git a/config/locales/client.he.yml b/config/locales/client.he.yml index ef0d563392..1c2c5a41dc 100644 --- a/config/locales/client.he.yml +++ b/config/locales/client.he.yml @@ -235,7 +235,6 @@ he: forwarded: "העברת ההודעה שלעיל" topic_admin_menu: "פעולות על נושא" skip_to_main_content: "דילוג לתוכן הראשי" - wizard_required: "ברוך בואך ל־Discourse החדש שלך! נתחיל עם אשף ההתקנה ✨" emails_are_disabled: "כל הדוא״ל היוצא נוטרל באופן גורף על ידי מנהל אתר. שום הודעת דוא״ל, מכל סוג שהוא, לא תשלח." emails_are_disabled_non_staff: "דוא״ל יוצא הושבת עבור משתמשים שאינם מהסגל." software_update_prompt: @@ -247,6 +246,8 @@ he: many: "כדי להקל על הקמת האתר החדש שלך, כרגע המערכת במצב אתחול ראשוני. לכל המשתמשים החדשים תוענק דרגת האמון 1 ויישלח אליהם תמצות יומי בדוא״ל. אפשרות זו תכבה אוטומטית לאחר שהצטרפו %{count} משתמשים." other: "כדי להקל על הקמת האתר החדש שלך, כרגע המערכת במצב אתחול ראשוני. לכל המשתמשים החדשים תוענק דרגת האמון 1 ויישלח אליהם תמצות יומי בדוא״ל. אפשרות זו תכבה אוטומטית לאחר שהצטרפו %{count} משתמשים." bootstrap_mode_disabled: "מצב Bootstrap יבוטל תוך 24 שעות." + bootstrap_invite_button_title: "משלוח הזמנות" + bootstrap_wizard_link_title: "סיום אשף ההקמה" themes: default_description: "ברירת מחדל" broken_theme_alert: "יתכן שהאתר שלך לא יתפקד כיוון שבערכת העיצוב / הרכיב יש שגיאות." @@ -283,6 +284,8 @@ he: not_implemented: "יכולת זו עדיין לא מומשה, עמך הסליחה!" no_value: "לא" yes_value: "כן" + ok_value: "או קיי" + cancel_value: "ביטול" submit: "הגשה" generic_error: "ארעה שגיאה, עמך הסליחה." generic_error_with_reason: "ארעה שגיאה: %{error}" @@ -1166,6 +1169,8 @@ he: dismiss: "דחה" dismiss_notifications: "להתעלם מהכול" dismiss_notifications_tooltip: "סימון כל ההתראות שלא נקראו כהתראות שנקראו" + dismiss_bookmarks_tooltip: "סימון כל תזכורות הסימניות כנקראו" + dismiss_messages_tooltip: "לסמן את כל ההתראות על ההודעות הפרטיות שלא נקראו כנקראו" no_messages_title: "אין לך הודעות כלל" no_messages_body: > עליך לנהל שיחה אישית עם מישהו או מישהי מחוץ לרצף הדיון?

    ניתן לשלוח אליו או אליה הודעה על ידי בחירת תמונת המשתמש המתאימה ואיתור הכפתור הודעה %{icon}. לקבלת עזרה, ניתן לשלוח הודעה לאחד מחברי הסגל. @@ -1791,7 +1796,6 @@ he: set_custom_status: "הגדרת מצב משלך" what_are_you_doing: "מה מעלליך?" remove_status: "הסרת מצב" - until: "עד:" loading: "טוען..." errors: prev_page: "בזמן הניסיון לטעון" @@ -1857,7 +1861,6 @@ he: hide_forever: "לא תודה" hidden_for_session: "סבבה, השאלה תופיע מחר. תמיד ניתן להשתמש ב‚כניסה’ גם כדי ליצור חשבון." intro: "שלום! נראה שאתם נהנים מהדיון, אבל לא נרשמתם לחשבון עדיין." - value_prop: "נמאס לך לעיין באותם הפוסטים? יצירת חשבון תאפשר לך לחזור בדיוק לנקודה בה עזבת בפעם האחרונה. חשבון מאפשר לך גם לקבל התראות על תגובות חדשות, לשמור סימניות ולהשתמש בלייקים כדי להודות לאחרים. כולנו יכולים לפעול ביחד כדי שהקהילה הזאת תהיה מצוינת. :heart:" summary: enabled_description: "אתם צופים בסיכום נושא זה: הפוסטים המעניינים ביותר כפי שסומנו על ידי הקהילה." description: @@ -2230,6 +2233,7 @@ he: abandon: "סגור את העורך והשלך את הטיוטה" enter_fullscreen: "היכנס לעריכה במסך מלא" exit_fullscreen: "צא מעריכה במסך מלא" + exit_fullscreen_prompt: "לחיצה על ESC תוציא אותך ממסך מלא" show_toolbar: "הצגת סרגל כתיבת הודעות" hide_toolbar: "הסתרת סרגל כתיבת הודעות" modal_ok: "אישור" @@ -2273,6 +2277,7 @@ he: ignore: "התעלמות" image_alt_text: aria_label: כיתוב חלופי לתמונה + delete_image_button: מחיקת תמונ notifications: tooltip: regular: @@ -2349,6 +2354,16 @@ he: two: "בוודאות? יש לך %{count} התראות חשובות." many: "בוודאות? יש לך %{count} התראות חשובות." other: "בוודאות? יש לך %{count} התראות חשובות." + bookmarks: + one: "להמשיך? יש לך תזכורת סימנייה %{count} שלא נקראה." + two: "להמשיך? יש לך %{count} תזכורות סימנייה שלא נקראו." + many: "להמשיך? יש לך %{count} תזכורות סימנייה שלא נקראו." + other: "להמשיך? יש לך %{count} תזכורות סימנייה שלא נקראו." + messages: + one: "להמשיך? יש לך הודעה פרטית %{count} שלא נקראה." + two: "להמשיך? יש לך %{count} הודעות פרטיות שלא נקראו." + many: "להמשיך? יש לך %{count} הודעות פרטיות שלא נקראו." + other: "להמשיך? יש לך %{count} הודעות פרטיות שלא נקראו." dismiss: "דחה" cancel: "ביטול" group_message_summary: @@ -2533,15 +2548,29 @@ he: view_all: "להציג את כל %{tab}" user_menu: generic_no_items: "אין פריטים ברשימה זו." - sr_menu_tabs: "לשוניות תפריט" + sr_menu_tabs: "לשוניות תפריט משתמש" view_all_notifications: "הצגת כל ההתראות" + view_all_bookmarks: "הצגת כל הסימניות" + view_all_messages: "הצגת כל ההודעות האישיות" + tabs: + all_notifications: "כל ההתראות" + replies: "תשובות" + mentions: "אזכורים" + likes: "לייקים שהוענקו" + watching: "נושאים במעקב" + messages: "הודעות פרטיות" + bookmarks: "סימניות" + review_queue: "תור סקירה" + other_notifications: "התראות אחרות" + profile: "פרופיל" reviewable: view_all: "הצגת כל הפריטים לסקירה" queue: "תור" deleted_user: "(משתמש שנמחק)" + deleted_post: "(פוסט שנמחק)" post_number_with_topic_title: "פוסט מס׳ %{post_number} - %{title}" new_post_in_topic: "פוסט חדש תחת %{title}" - suspicious_user: "משתמש חשוד %{username}" + user_requires_approval: "דרישת אישור מצד %{username}" default_item: "פריט מס׳ %{reviewable_id} לסקירה" topics: new_messages_marker: "ביקור אחרון" @@ -3276,10 +3305,10 @@ he: other: "למחוק את %{count} הפוסטים האלה?" merge: confirm: - one: "האם אתם בטוחים שאתם מעוניינים למזג פוסטים אלו?" - two: "האם אתם בטוחים שאתם מעוניינים למזג %{count} פוסטים אלו?" - many: "האם אתם בטוחים שאתם מעוניינים למזג %{count} פוסטים אלו?" - other: "האם אתם בטוחים שאתם מעוניינים למזג %{count} פוסטים אלו?" + one: "למזג את הפוסטים האלו?" + two: "למזג את %{count} הפוסטים האלו?" + many: "למזג את %{count} הפוסטים האלו?" + other: "למזג את %{count} הפוסטים האלו?" revisions: controls: first: "מהדורה ראשונה" @@ -3725,6 +3754,7 @@ he: today: "היום" other_periods: "להציג את המובילים:" browser_update: 'אתרע מזלך וכי דפדפנך אינו נתמך עוד. נא לעבור לדפדפן נתמך כדי לצפות בתוכן עשיר, להיכנס ולהגיב.' + safari_13_warning: אתר זה יסיר בקרוב את התמיכה בגרסאות 13 ומטה של Safari ושל iOS. גרסה מופשאת לקריאה בלבד תישאר זמינה עבורם. (מידע נוסף) permission_types: full: "יצירה / תגובה / צפייה" create_post: "תגובה / צפייה" @@ -4062,15 +4092,16 @@ he: user_activity: no_activity_title: "אין פעילות עדיין" no_activity_body: "ברוך בואך לקהילה שלנו! הצטרפת ממש לא מזמן וטרם תרמת לדיונים. כצעד ראשון, כדאי לבקר במובילים או בקטגוריות ופשוט להתחיל לקרוא. ניתן לבחור ב־%{heartIcon} בפוסטים שנשאו חן בעיניך או שמעניין אותך ללמוד עליהם יותר. הפעילות שלך תופיע כאן." - no_activity_others: "אין פעילות." no_replies_title: "עדיין לא הגבת לאף נושא" - no_replies_others: "אין תגובות." + no_replies_title_others: "אין עדיין אף תגובה של %{username} על נושא כלשהו" + no_replies_body: "כאשר נחשפת לדיון מעניין שבא לך להשתתף בו, יש ללחוץ על הכפתור תגובה ישירות מתחת לכל פוסט שהוא כדי להתחיל להגיב לאותו פוסט מסוים. או, אם העדפתך היא להגיב לנושא הכללי במקום לפוסט או מישהו מסוים, כדאי לחפש את כפתור התגובה בתחתית הנושא או מתחת לציר הזמן של הנושא." no_drafts_title: "לא התחלת טיוטות" no_drafts_body: "לא סיימת לכתוב את הפוסט? אנו נשמור טיוטה חדשה אוטומטית ונציג אותה כאן עם כל כתיבה של נושא, תגובה או הודעה פרטית חדשים. יש לבחור בכפתור הביטול כדי להתעלם או לשמור את הטיוטה שלך ולהמשיך אחר כך." no_likes_title: "עדיין לא סימנת אף נושא בלייק" + no_likes_title_others: "אין עדיין אף לייק של %{username} על נושא כלשהו" no_likes_body: "דרך נפלאה לקפוץ ישירות פנימה ולהתחיל לתרום היא להתחיל לקרוא דיונים שכבר נערכו ולבחור בסמל %{heartIcon} על פוסטים שאהבת!" - no_likes_others: "אין פוסטים שנעשה להם לייק." no_topics_title: "עדיין לא פתחת אף נושא" + no_topics_body: "תמיד עדיף לחפש דיונים קיימים בטרם פתיחת חדשים, אבל אם בוודאות לא נתקלת בנושא המבוקש, אפשר פשוט לפתוח נושא חדש משלך. הכפתור + נושא חדש אמור להופיע בפינה השמאלית העליונה של רשימת נושאים, קטגוריה או תגית כדי להתחיל ליצור נושא חדש באזור הזה." no_topics_title_others: "לא נפתח עוד אף נושא על ידי %{username}" no_read_topics_title: "טרם קראת נושאים" no_read_topics_body: "עם תחילת קריאת הדיונים, תופיע כאן רשימה. כדי להתחיל לקרוא, כדאי לחפש נושאים שמעניינים אותך תחת עליונים או קטגוריות או לחפש אחר מילת מפתח %{searchIcon}" @@ -4095,9 +4126,12 @@ he: other: "חדש (%{count})" toggle_section: "החלפת מצב הצגת סעיף" more: "עוד…" + all_categories: "כל הקטגוריות" + all_tags: "כל התגיות" sections: + about: + header_link_text: "אודות" messages: - header_link_title: "הודעות פרטיות" header_link_text: "הודעות" header_action_title: "יצירת הודעה פרטית" links: @@ -4111,23 +4145,28 @@ he: tags: none: "עדיין לא הוספת תגיות." click_to_get_started: "ללחוץ כאן כדי להתחיל." - header_link_title: "כל התגיות" header_link_text: "תגיות" header_action_title: "לערוך את תגיות סרגל הצד שלך" categories: none: "עדיין לא הוספת קטגוריות." click_to_get_started: "ללחוץ כאן כדי להתחיל." - header_link_title: "כל הקטגוריות" header_link_text: "קטגוריות" header_action_title: "לערוך את קטגוריות סרגל הצד שלך" community: - header_link_title: "בית" header_link_text: "קהילה" header_action_title: "יצירת נושא חדש" links: + about: + content: "על אודות" + admin: + content: "הנהלה" + badges: + content: "עיטורים" everything: content: "הכול" title: "כל הנושאים" + faq: + content: "שאלות נפוצות" tracked: content: "במעקב" title: "כל הנושאים במעקב" @@ -4145,6 +4184,11 @@ he: two: "%{count} טיוטות" many: "%{count} טיוטות" other: "%{count} טיוטות" + welcome_topic_banner: + title: "כאן ניתן ליצור את נושא קבלת הפנים שלך" + description: 'נושא קבלת הפנים שלך הוא הדבר הראשון שמצטרפים חדשים יקראו. אפשר לחשוב על זה כעל „נאום מעלית” או „הצהרת כוונות” במשפט אחד' + button_title: "להתחיל לערוך" + until: "עד:" admin_js: type_to_filter: "הקלידו לסינון..." admin: @@ -4712,6 +4756,8 @@ he: import_web_advanced: "מתקדם…" import_file_tip: "קובץ ‎.tar.gz,‏ ‎.zip,‏ או ‎.dcstyle.json שמכיל ערכת עיצוב" is_private: "ערכת העיצוב נמצאת במאגר git פרטי" + finish_install: "סיום התקנת ערכת עיצוב" + last_attempt: "תהליך ההתקנה לא הסתיים, ניסיון אחרון:" remote_branch: "שם ענף (רשות)" public_key: "להעניק למפתח הציבורי הבא גישה למאגר:" public_key_note: "לאחר מילוי כתובת אתר מאגר פרטית תקפה לעיל, מפתח SSH ייווצר ויוצג כאן." @@ -4722,6 +4768,8 @@ he: install_git_repo: "ממאגר git" install_create: "יצירת חדשה" duplicate_remote_theme: "רכיב ערכת העיצוב „%{name}” כבר מותקן, להתקין עותק נוסף?" + force_install: "לא ניתן להתקין את ערכת העיצוב כיוון שמאגר ה־Git אינו נגיש. להמשיך בהתקנתה?" + create_placeholder: "יצירת ממלא מקום" about_theme: "אודות" license: "רישיון" version: "גרסה:" @@ -4904,6 +4952,7 @@ he: last_seen_user: "משתמש שנראה לאחרונה:" no_result: "לא נמצאו תוצאות לתמצית." reply_key: "מפתח תגובה" + post_link_with_smtp: "הגדרות דואר ו־SMTP" skipped_reason: "דלג על סיבה" incoming_emails: from_address: "מאת" @@ -4933,6 +4982,7 @@ he: address_placeholder: "name@example.com" type_placeholder: "תמצית, הרשמה..." reply_key_placeholder: "מפתח תגובה" + smtp_transaction_response_placeholder: "מזהה SMTP" moderation_history: performed_by: "בוצע על ידי" no_results: "אין היסטוריית פעילות פיקוח זמינה." @@ -5257,6 +5307,7 @@ he: suspended: "מושעה?" staged: "מבוים?" show_admin_profile: "מנהל ראשי" + manage_user: "ניהול משתמש" show_public_profile: "הצג פרופיל פומבי" impersonate: "התחזה" action_logs: "יומני פעולות" @@ -5360,7 +5411,8 @@ he: two: "לא ניתן למחוק את כל הפוסטים בגלל שלמשתמשים יותר מ %{count} פוסטים. (delete_all_posts_max)" many: "לא ניתן למחוק את כל הפוסטים בגלל שלמשתמשים יותר מ %{count} פוסטים. (delete_all_posts_max)" other: "לא ניתן להסיר את כל הפוסטים בגלל שלמשתמשים יותר מ %{count} פוסטים. (delete_all_posts_max)" - delete_confirm: "בדרך כלל מומלץ להפוך משתמשים לאלמונים מאשר למחוק אותם כדי למנוע הסרת תוכן מדיונים קיימים.

    האם בוודאות ברצונך למחוק את המשתמש הזה? מדובר בפעולה בלתי הפיכה!" + delete_confirm_title: "למחוק את המשתמש הזה? המחיקה היא לצמיתות!" + delete_confirm: "עדיף להפוך משתמשים לאלמוניים במקום למחוק אותם כדי להימנע מהסרת תוכן מדיונים קיימים." delete_and_block: "מחיקה וחסימה של כתובות הדוא״ל וה־IP האלו" delete_dont_block: "מחיקה בלבד" deleting_user: "משתמש נמחק…" @@ -5493,7 +5545,6 @@ he: recommended: "אנו ממליצים לערוך את הטקסט הבא כדי שיתאים לצרכים שלך:" show_overriden: "להציג רק את אלו שנדרסו" locale: "שפה:" - fallback_locale_warning: "בחרת לערוך שפה שמבוססת על %{fallback}. משתמשים שבוחרים ב%{fallback} כשפת מנשק המשתמש שלהם לא יראו את השינויים שלך." more_than_50_results: "יש למעלה מ־50 תוצאות. נא למקד את החיפוש שלך." settings: show_overriden: "להציג רק את אלו שנדרסו" diff --git a/config/locales/client.hr.yml b/config/locales/client.hr.yml index 70247dcc91..198bf4681e 100644 --- a/config/locales/client.hr.yml +++ b/config/locales/client.hr.yml @@ -207,7 +207,6 @@ hr: forwarded: "proslijedio je gore navedenu e-poštu" topic_admin_menu: "mogućnosti teme" skip_to_main_content: "Preskoči na glavni sadržaj" - wizard_required: "Dobrodošao u svoj novi Discourse! Započnimo s postavljanjem ✨" emails_are_disabled: "Svi emailovi prema van su blokirani od strane administratora. Ni jedna vrsta obavijesti putem emaila neće biti poslana." emails_are_disabled_non_staff: "Odlazna e-pošta onemogućena je za korisnike koji nisu zaposleni." software_update_prompt: @@ -218,6 +217,7 @@ hr: few: "Kako bi vam olakšali pokretanje vašeg novog foruma, u bootstrap modu ste. Svim novim korisnicima biti će dodijeljena razina povjerenja 1 i omogućeni dnevni e-mailovi sa sažecima. Ovo će automatski biti isključeno kada se učlani minimalno %{count} korisnika." other: "Kako bi vam olakšali pokretanje novog foruma, nalazite se u bootstrap načinu rada. Svim novim korisnicima biti će dodijeljena razina povjerenja 1 i omogućeni dnevni e-mailovi sa sažecima. Bootstrap će se automatski isključiti čim se učlani minimalno %{count} korisnika." bootstrap_mode_disabled: "Bootstrap mod biti će isključen u sljedećih 24 sata." + bootstrap_invite_button_title: "Pošalji pozivnice" themes: default_description: "Zadano" broken_theme_alert: "Vaša stranica možda neće raditi jer tema/komponenta ima pogreške." @@ -254,6 +254,8 @@ hr: not_implemented: "Nažalost, ova mogućnost nije još implementirana." no_value: "Ne" yes_value: "Da" + ok_value: "U redu" + cancel_value: "Odustani" submit: "Pošalji" generic_error: "Dogodila se greška, ispričavamo se." generic_error_with_reason: "Dogodila se greška: %{error}" @@ -2420,6 +2422,13 @@ hr: not_logged_in_user: "stranica korisnika sa sažetkom trenutnih aktivnosti i postavki" current_user: "idi na korisničku stranicu" view_all: "pogledaj sve %{tab}" + user_menu: + tabs: + replies: "Odgovori" + mentions: "Spomeni" + likes: "Like-ova" + bookmarks: "Zabilješke" + profile: "Profil" topics: new_messages_marker: "posljednji posjet" bulk: @@ -3108,11 +3117,6 @@ hr: one: "Jeste li sigurni da želite izbrisati taj post?" few: "Jeste li sigurni da želite izbrisati %{count}\" postova?" other: "Jeste li sigurni da želite izbrisati te %{count} postove?" - merge: - confirm: - one: "Jeste li sigurni da želite spojiti taj post?" - few: "Jeste li sigurni da želite spojiti %{count} postova?" - other: "Jeste li sigurni da želite spojiti ovih %{count} objava?" revisions: controls: first: "Prva revizija" @@ -3695,7 +3699,6 @@ hr: google: "Google kalendar" ics: "ICS" tagging: - all_tags: "Sve oznake" other_tags: "Ostale oznake" selector_all_tags: "sve oznake" selector_no_tags: "bez oznaka" @@ -3866,14 +3869,11 @@ hr: user_activity: no_activity_title: "Još nema aktivnosti" no_activity_body: "Dobrodošli u našu zajednicu! Ovdje ste potpuno novi i još niste sudjelovali u raspravama. Kao prvi korak, posjetite Top ili kategorije i samo počnite čitati! Odaberite %{heartIcon} na objavama koje vam se sviđaju ili o kojima želite saznati više. Dok budete sudjelovali, vaša će aktivnost biti navedena ovdje." - no_activity_others: "Nema aktivnosti." no_replies_title: "Još niste odgovorili ni na jednu temu" - no_replies_others: "Nema odgovora." no_drafts_title: "Niste pokrenuli nikakve skice" no_drafts_body: "Niste baš spremni za objavu? Automatski ćemo spremiti novu skicu i navesti je ovdje kad god počnete sastavljati temu, odgovor ili osobnu poruku. Odaberite gumb za odustajanje da biste odbacili ili spremili skicu za nastavak kasnije." no_likes_title: "Još vam se nije svidjela nijedna tema" no_likes_body: "Sjajan način da uskočite i počnete pridonositi je da počnete čitati razgovore koji su se već vodili i odaberete %{heartIcon} na objavama koje vam se sviđaju!" - no_likes_others: "Nema likeanih objava." no_topics_title: "Još niste pokrenuli nijednu temu" no_topics_title_others: "%{username} još nije pokrenuo nijednu temu" no_read_topics_title: "Još niste pročitali nijednu temu" @@ -3896,7 +3896,10 @@ hr: few: "%{count} novih" other: "%{count} novi" more: "Više..." + all_categories: "Sve kategorije" sections: + about: + header_link_text: "O nama" messages: header_link_text: "Poruke" links: @@ -3908,19 +3911,24 @@ hr: unread_with_count: "Nepročitano (%{count})" archive: "Arhiva" tags: - header_link_title: "sve oznake" header_link_text: "Oznake" categories: - header_link_title: "sve kategorije" header_link_text: "Kategorije" community: - header_link_title: "naslovnica" header_link_text: "Zajednica" header_action_title: "otvori novu temu" links: + about: + content: "O nama" + admin: + content: "Administrator" + badges: + content: "Značke" everything: content: "Sve" title: "Sve teme" + faq: + content: "ČPP" tracked: content: "Praćeno" title: "Sve praćene teme" @@ -5133,7 +5141,6 @@ hr: one: "Ne možete obrisati sve objave jer korisnik ima više od %{count} objava. (briši_sve_objave_max)" few: "Ne možete obrisati sve objave jer korisnik ima više od %{count} objava. (briši_sve_objave_max)" other: "Ne možete obrisati sve objave jer korisnik ima više od %{count} objava. (briši_sve_objave_max)" - delete_confirm: "Općenito je poželjno anonimizirati korisnike umjesto brisanja, kako bi se izbjeglo uklanjanje sadržaja iz postojećih rasprava.

    Jeste li sigurni da želite izbrisati ovog korisnika? Ovo je trajno!" delete_and_block: "Obriši i block ovaj email i IP adresu" delete_dont_block: "Samo obriši" deleting_user: "Brisanje korisnika..." @@ -5265,7 +5272,6 @@ hr: recommended: "Preporučujemo da prilagodite sljedeći tekst tako da odgovara vašim potrebama:" show_overriden: "Pokazuj samo promijenjeno" locale: "Jezik:" - fallback_locale_warning: "Uređujete jezik temeljen na %{fallback}. Korisnici koji odaberu %{fallback} kao jezik sučelja neće vidjeti vaše promjene." more_than_50_results: "Postoji više od 50 rezultata. Molimo suzite kriterije vaše pretrage." settings: show_overriden: "Pokazuj samo promijenjeno" diff --git a/config/locales/client.hu.yml b/config/locales/client.hu.yml index 1e1a6ad415..d81350ca85 100644 --- a/config/locales/client.hu.yml +++ b/config/locales/client.hu.yml @@ -78,8 +78,8 @@ hu: date_year: "'YY. MMM" medium: less_than_x_minutes: - one: "kevesebb mint %{count} perce" - other: "kevesebb mint %{count} perce" + one: "kevesebb mint %{count} perc" + other: "kevesebb mint %{count} perc" x_minutes: one: "%{count} perc" other: "%{count} perc" @@ -179,7 +179,6 @@ hu: forwarded: "a fenti e-mail továbbítva" topic_admin_menu: "témaműveletek" skip_to_main_content: "Ugrás a fő tartalomhoz" - wizard_required: "Üdvözöljük az új Discourse-on. Kezdjük a beállításvarázslóval. ✨" emails_are_disabled: "Egy adminisztrátor letiltotta a kimenő e-maileket. Semmilyen értesítő e-mail nem lesz elküldve." emails_are_disabled_non_staff: "A kimenő e-mailek le vannak tiltva a nem stábtagok számára." software_update_prompt: @@ -189,6 +188,8 @@ hu: one: "Hogy könnyebbé tegyük az új oldala elindítását, most előkészítési módban van. Minden új felhasználó 1-es szintet kap, és be lesz állítva, hogy napi kivonat e-mailt kapjanak. Ez a beállítás automatikusan kikapcsol, ha legalább %{count} felhasználó regisztrált." other: "Hogy könnyebbé tegyük az új oldala elindítását, most előkészítési módban van. Minden új felhasználó 1-es szintet kap, és be lesz állítva, hogy napi kivonat e-mailt kapjanak. Ez a beállítás automatikusan kikapcsol, ha legalább %{count} felhasználó regisztrált." bootstrap_mode_disabled: "Az előkészítési mód 24 órán belül kikapcsol." + bootstrap_invite_button_title: "Meghívók küldése" + bootstrap_wizard_link_title: "Beállítási varázsló befejezése" themes: default_description: "Alapértelmezett" broken_theme_alert: "Lehet, hogy webhelye nem működik, mert a téma/összetevő hibába ütközött." @@ -225,6 +226,8 @@ hu: not_implemented: "Ez a funkció még nincs megvalósítva." no_value: "Nem" yes_value: "Igen" + ok_value: "Rendben" + cancel_value: "Mégse" submit: "Beküldés" generic_error: "Sajnos hiba történt." generic_error_with_reason: "Hiba történt: %{error}" @@ -305,11 +308,13 @@ hu: unbookmark_with_reminder: "Kattintson a téma valamennyi könyvjelzőjének és emlékeztetőjének törléséhez." bookmarks: created: "Könyvjelzőzte ezt a bejegyzést. %{name}" + created_generic: "Könyvjelzőzte ezt. %{name}" create: "Könyvjelző létrehozása" edit: "Könyvjelző szerkesztése" not_bookmarked: "bejegyzés könyvjelzőzése" remove_reminder_keep_bookmark: "Emlékeztető eltávolítása és könyvjelző megtartása" created_with_reminder: "Könyvjelzőzte ezt a bejegyzést, és emlékeztetőt állított be ekkorra: %{date}. %{name}" + created_with_reminder_generic: "Könyvjelzőzte ezt, és emlékeztetőt állított be ekkorra: %{date}. %{name}" remove: "Könyvjelző eltávolítása" delete: "Könyvjelző törlése" confirm_delete: "Biztos, hogy törli ezt a könyvjelzőt? Az emlékeztető is törlődni fog." @@ -584,23 +589,26 @@ hu: relative: "Relatív" time_shortcut: now: "Most" + in_one_hour: "Egy óra múlva" + in_two_hours: "Két óra múlva" later_today: "Ma később" + two_days: "Két nap múlva" next_business_day: "Következő munkanap" tomorrow: "Holnap" post_local_date: "A bejegyzésben szereplő dátum" later_this_week: "Később ezen a héten" this_weekend: "Hétvégén" start_of_next_business_week: "Hétfő" - start_of_next_business_week_alt: "Jövő hétfő" + start_of_next_business_week_alt: "Jövő hétfőn" next_week: "Jövő héten" - two_weeks: "Két hét" + two_weeks: "Két hét múlva" next_month: "Jövő hónapban" - two_months: "Két hónap" - three_months: "Három hónap" - four_months: "Négy hónap" - six_months: "Hat hónap" - one_year: "Egy év" - forever: "Örökre" + two_months: "Két hónap múlva" + three_months: "Három hónap múlva" + four_months: "Négy hónap múlva" + six_months: "Hat hónap múlva" + one_year: "Egy év múlva" + forever: "Örökké" relative: "Relatív idő" none: "Nem szükséges" never: "Soha" @@ -727,7 +735,7 @@ hu: allow_unknown_sender_topic_replies: "Engedélyezze az ismeretlen feladóktól érkező témaválaszokat." allow_unknown_sender_topic_replies_hint: "Lehetővé teszi az ismeretlen feladók számára, hogy válaszoljanak a csoport témáira. Ha ez nincs engedélyezve, akkor az e-mail szálban még nem szereplő címekről érkező válaszok új témát hoznak létre." from_alias: "Álnévből" - from_alias_hint: "A csoportos SMTP e-mailek küldésekor a \"from\" címként használandó álnév. Megjegyzés: ezt nem minden e-mail szolgáltató támogatja, tekintse meg a szolgáltató dokumentációját." + from_alias_hint: "A csoportos SMTP e-mailek küldésekor a „feladó” címként használandó álnév. Megjegyzés: ezt nem minden e-mail-szolgáltató támogatja, tekintse meg a szolgáltató dokumentációját." mailboxes: synchronized: "Szinkronizált postafiók" none_found: "Ebben az e-mail fiókban nem találhatók postaládák." @@ -1204,7 +1212,7 @@ hu: in_progress: "(az e-mail küldése folyamatban)" error: "(hiba)" emoji: "zár emodzsi" - action: "Jelszó-helyreállítási e-mail küldése" + action: "Jelszó-visszaállítási e-mail küldése" set_password: "Jelszó megadása" choose_new: "Válasszon új jelszót" choose: "Válasszon jelszót" @@ -1558,7 +1566,9 @@ hu: title: "Összefoglaló" stats: "Statisztikák" time_read: "olvasási idő" + time_read_title: "%{duration} (mindösszesen)" recent_time_read: "legutóbbi olvasási idő" + recent_time_read_title: "%{duration} (az elmúlt 60 napban)" topic_count: one: "téma létrehozva" other: "téma létrehozva" @@ -1630,6 +1640,9 @@ hu: the_topic: "a téma" user_status: save: "Mentés" + set_custom_status: "Egyéni állapot beállítása" + what_are_you_doing: "Mit csinál?" + remove_status: "Állapot eltávolítása" loading: "Betöltés…" errors: prev_page: "amíg megpróbál betölteni" @@ -1689,6 +1702,7 @@ hu: other: válasz signup_cta: sign_up: "Regisztráció" + hide_session: "Talán később" hide_forever: "nem, köszönöm" hidden_for_session: "Rendben, holnap megkérdezzük. Bármikor használhatja a „Bejelentkezés” gombot, hogy fiókot készítsen magának." intro: "Üdv! Úgy tűnik, hogy tetszik Önnek a fórumunk, de még nem regisztrált fiókot." @@ -1815,15 +1829,24 @@ hu: sr_title: "Bejelentkezés a Twitterrel" instagram: name: "Instagram" + title: "Bejelentkezés az Instagrammal" + sr_title: "Bejelentkezés az Instagrammal" facebook: name: "Facebook" + title: "Bejelentkezés a Facebookkal" + sr_title: "Bejelentkezés a Facebookkal" github: name: "GitHub" + title: "Bejelentkezés a GitHubbal" + sr_title: "Bejelentkezés a GitHubbal" discord: name: "Discord" + title: "Bejelentkezés a Discorddal" + sr_title: "Bejelentkezés a Discorddal" second_factor_toggle: totp: "Helyette hitelesítő alkalmazás használata" backup_code: "Helyette biztonsági kód használata" + security_key: "Helyette biztonsági kulcs használata" invites: accept_title: "Meghívás" emoji: "boríték emodzsi" @@ -1848,9 +1871,11 @@ hu: categories_only: "Csak kategóriák szerint" categories_with_featured_topics: "Kategóriák funkciók szerint" categories_and_latest_topics: "Kategóriák és legutóbbi témák" + categories_and_latest_topics_created_date: "Kategóriák és legutóbbi témák (rendezése a téma létrehozási dátuma szerint)" categories_and_top_topics: "Kategóriák és legnépszerűbb témák" categories_boxes: "Dobozok alkategóriákkal" categories_boxes_with_topics: "Dobozok kiemelt témákkal" + subcategories_with_featured_topics: "Alkategóriák kiemelt témákkal" shortcut_modifier_key: shift: "Shift" ctrl: "Ctrl" @@ -1887,6 +1912,8 @@ hu: one: "Válasszon legalább %{count} elemet." other: "Válasszon legalább %{count} elemet." components: + tag_drop: + filter_for_more: Szűrés a továbbiakhoz… categories_admin_dropdown: title: "Kategóriák kezelése" date_time_picker: @@ -1932,6 +1959,8 @@ hu: similar_topics: "A témája erre hasonlít…" drafts_offline: "vázlatok offline" edit_conflict: "szerkesztési ütközés" + esc: "Esc" + esc_label: "Kattintson vagy nyomja meg az Esc billentyűt az eltüntetéshez" group_mentioned_limit: one: "Figyelem!Megemlítette a(z) %{group} csoportot, azonban ennek a csoportnak több mint %{count} tagja van, amely több, mint a rendszergazda által beállított megemlítési korlát. Senki nem lesz értesítve." other: "Figyelem!Megemlítette a(z) %{group} csoportot, azonban ennek a csoportnak több mint %{count} tagja van, amely több, mint a rendszergazda által beállított megemlítési korlát. Senki nem lesz értesítve." @@ -1978,6 +2007,7 @@ hu: create_shared_draft: "Megosztott vázlat létrehozása" edit_shared_draft: "Megosztott vázlat szerkesztése" title: "Vagy nyomjon %{modifier}Entert" + users_placeholder: "Felhasználók vagy csoportok hozzáadása" title_placeholder: "Mi lesz a témája ennek a beszélgetésnek egy rövid mondatban?" title_or_link_placeholder: "Írja be a címet, vagy illesszen be ide egy hivatkozást" edit_reason_placeholder: "miért szerkeszt?" @@ -2022,6 +2052,7 @@ hu: abandon: "szerkesztő bezárása és a vázlat elvetése" enter_fullscreen: "belépés a teljes képernyős szerkesztőbe" exit_fullscreen: "kilépés a teljes képernyős szerkesztőből" + exit_fullscreen_prompt: "Nyomja meg a ESC gombot a teljes képernyőről való kilépéshez" show_toolbar: "szerkesztő eszköztár megjelenítése" hide_toolbar: "szerkesztő eszköztár elrejtése" modal_ok: "Rendben" @@ -2059,9 +2090,13 @@ hu: label: "Megosztott vázlat" desc: "Témavázlat készítése, amely csak az engedélyezett felhasználók számára látható" toggle_topic_bump: + label: "Téma előrehozása be/ki" desc: "Válasz a legutóbbi válasz dátumának módosítása nélkül" reload: "Újratöltés" ignore: "Letiltás" + image_alt_text: + aria_label: Alternatív szöveg a képhez + delete_image_button: Kép törlése notifications: tooltip: regular: @@ -2079,6 +2114,7 @@ hu: post_approved: "A bejegyzését jóváhagyták" reviewable_items: "felülvizsgálatot igénylő elemek" watching_first_post_label: "Új téma" + user_moved_post: "%{username} áthelyezve" mentioned: "%{username} %{description}" group_mentioned: "%{username} %{description}" quoted: "%{username} %{description}" @@ -2093,8 +2129,8 @@ hu: other: "%{username}, %{username2} és még %{count} felhasználó %{description}" liked_by_2_users: "%{username}, %{username2}" liked_by_multiple_users: - one: "%{username}, %{username2} %{count} más" - other: "%{username}, %{username2} és %{count} mások" + one: "%{username}, %{username2} és még %{count} felhasználó" + other: "%{username}, %{username2} és még %{count} felhasználó" liked_consolidated_description: one: "kedvelte %{count} bejegyzését" other: "kedvelte %{count} bejegyzését" @@ -2103,6 +2139,7 @@ hu: invited_to_private_message: "

    %{username} %{description}" invited_to_topic: "%{username} %{description}" invitee_accepted: "%{username} elfogadta a meghívását" + invitee_accepted_your_invitation: "elfogadta a meghívását" moved_post: "%{username} áthelyezte: %{description}" linked: "%{username} %{description}" granted_badge: "Új jelvény: „%{description}”" @@ -2120,6 +2157,12 @@ hu: default: one: "Biztos benne? %{count} fontos értesítése van." other: "Biztos benne? %{count} fontos értesítése van." + bookmarks: + one: "Biztos benne? %{count} olvasatlan könyvjelző-emlékeztetője van." + other: "Biztos benne? %{count} olvasatlan könyvjelző-emlékeztetője van." + messages: + one: "Biztos benne? %{count} olvasatlan személyes üzenete van." + other: "Biztos benne? %{count} olvasatlan személyes üzenete van." dismiss: "Elvetés" cancel: "Mégse" group_message_summary: @@ -2161,6 +2204,7 @@ hu: post_approved: "bejegyzés jóváhagyva" membership_request_consolidated: "új tagsági kérés" reaction: "új reakció" + votes_released: "A szavazat feloldásra került" upload_selector: uploading: "Feltöltés" processing: "Feltöltés feldolgozása" @@ -2201,6 +2245,8 @@ hu: in: "ebben:" in_this_topic: "ebben a témában" in_this_topic_tooltip: "váltás az összes téma keresésére" + in_messages: "az üzenetekben" + in_messages_tooltip: "váltás a szokásos témák keresésére" in_topics_posts: "az összes témában és bejegyzésben" enter_hint: "vagy nyomjon Entert" in_posts_by: "%{username} bejegyzéseiben" @@ -2295,6 +2341,56 @@ hu: not_logged_in_user: "felhasználói oldal a jelenlegi tevékenységek és beállítások összesítésével" current_user: "ugrás a felhasználói oldalára" view_all: "összes %{tab} megtekintése" + user_menu: + generic_no_items: "Nincsenek elemek ebben a listában." + sr_menu_tabs: "Felhasználói menü lapjai" + view_all_notifications: "összes értesítés megtekintése" + view_all_bookmarks: "összes könyvjelző megtekintése" + view_all_messages: "összes személyes üzenet megtekintése" + tabs: + all_notifications: "Az összes értesítés" + replies: "Válaszok" + replies_with_unread: + one: "Válaszok – %{count} olvasatlan válasz" + other: "Válaszok – %{count} olvasatlan válasz" + mentions: "Említések" + mentions_with_unread: + one: "Említések – %{count} olvasatlan említés" + other: "Említések – %{count} olvasatlan említés" + likes: "Kapott kedvelések" + likes_with_unread: + one: "Kedvelések – %{count} olvasatlan kedvelés" + other: "Kedvelések – %{count} olvasatlan kedvelés" + watching: "Megfigyelt témák" + watching_with_unread: + one: "Megfigyelt témák – %{count} olvasatlan megfigyelt téma" + other: "Megfigyelt témák – %{count} olvasatlan megfigyelt téma" + messages: "Személyes üzenetek" + messages_with_unread: + one: "Személyes üzenetek – %{count} olvasatlan üzenet" + other: "Személyes üzenetek – %{count} olvasatlan üzenet" + bookmarks: "Könyvjelzők" + bookmarks_with_unread: + one: "Könyvjelzők – %{count} olvasatlan könyvjelző" + other: "Könyvjelzők – %{count} olvasatlan könyvjelző" + review_queue: "Felülvizsgálati sor" + review_queue_with_unread: + one: "Felülvizsgálati sor – %{count} elem szorul felülvizsgálatra" + other: "Felülvizsgálati sor – %{count} elem szorul felülvizsgálatra" + other_notifications: "Egyéb értesítések" + other_notifications_with_unread: + one: "Egyéb értesítések – %{count} olvasatlan értesítés" + other: "Egyéb értesítések – %{count} olvasatlan értesítés" + profile: "Profil" + reviewable: + view_all: "összes felülvizsgálati elem megtekintése" + queue: "Sor" + deleted_user: "(törölt felhasználó)" + deleted_post: "(törölt bejegyzés)" + post_number_with_topic_title: "%{post_number}. bejegyzés – %{title}" + new_post_in_topic: "új bejegyzés itt: %{title}" + user_requires_approval: "%{username} jóváhagyása szükséges" + default_item: "felülvizsgálandó elem: #%{reviewable_id}" topics: new_messages_marker: "utolsó látogatás" bulk: @@ -2302,6 +2398,7 @@ hu: clear_all: "Összes törlése" unlist_topics: "Témák listázásnak megszüntetése" relist_topics: "Újralistázott témák" + reset_bump_dates: "Előrehozási dátumok alaphelyzetbe állítása" defer: "Elhalasztás" delete: "Témák törlése" dismiss: "Elvetés" @@ -2461,7 +2558,7 @@ hu: remove: "Időzítő eltávolítása" publish_to: "Közzététel itt:" when: "Mikor:" - time_frame_required: "Kérjük, válassz ki egy időkeretet" + time_frame_required: "Válasszon egy időkeretet" min_duration: "Az időtartamnak 0-nál nagyobbnak kell lennie" max_duration: "Az időtartamnak 20 évnél rövidebbnek kell lennie" duration: "Időtartam" @@ -2482,6 +2579,8 @@ hu: title: "Téma automatikus bezárása az utolsó hozzászólás után" auto_delete: title: "Téma automatikus törlése" + auto_bump: + title: "Téma automatikus előrehozása" reminder: title: "Emlékeztető" auto_delete_replies: @@ -2490,6 +2589,7 @@ hu: auto_open: "Ez a téma %{timeLeft} automatikusan megnyílik." auto_close: "Ez a téma %{timeLeft} automatikusan lezárul." auto_close_after_last_post: "Ez a téma az utolsó válasz után %{duration} idővel zár le." + auto_bump: "Ez a téma %{timeLeft} automatikusan előre lesz hozva." auto_close_title: "Automatikus lezárási beállítások" timeline: back: "Vissza" @@ -2499,80 +2599,81 @@ hu: title: téma állapota jump_prompt: "ugrás..." jump_prompt_long: "Ugrás..." - jump_prompt_to_date: "Mostanáig" + jump_prompt_to_date: "mostanáig" jump_prompt_or: "vagy" notifications: - title: módosítsd a témakörről érkező értesítések gyakoriságát + title: a témáról érkező értesítések gyakoriságának módosítása reasons: - mailing_list_mode: "Engedélyezte a levelezőlista módot, ezért értesítést fog kapni e-mailben a válaszokról." - "3_10": "Értesítést fogsz kapni, mert figyeled a téma egyik címkéjét." - "3_6": "Értesítést fogsz kapni, mert figyeled ezt a kategóriát." - "3_5": "Értesítést fogsz kapni, mert automatikusan figyelni kezdted ezt a témát." - "3_2": "Értesítést fogsz kapni, mert figyeled ezt a témát." - "3_1": "Értesítést fogsz kapni, mert te hoztad létre ezt a témát." - "3": "Értesítést fogsz kapni, mert figyeled ezt a témát." + mailing_list_mode: "Engedélyezte a levelezőlista módot, ezért értesítést fog kapni e-mailben a téma válaszairól." + "3_10": "Értesítést fog kapni, mert figyeli a téma egyik címkéjét." + "3_6": "Értesítést fog kapni, mert figyeli ezt a kategóriát." + "3_5": "Értesítést fog kapni, mert automatikusan figyelni kezdte ezt a témát." + "3_2": "Értesítést fog kapni, mert figyeli ezt a témát." + "3_1": "Értesítést fog kapni, mert Ön hozta létre ezt a témát." + "3": "Értesítést fog kapni, mert figyeli ezt a témát." "2": 'You will see a count of new replies because you read this topic.' - "1_2": "Csak akkor leszel értesítve, ha valaki megemlíti a @nevedet vagy válaszol neked." - "1": "Csak akkor leszel értesítve, ha valaki megemlíti a @nevedet vagy válaszol neked." - "0_7": "Nem kapsz értesítést erről a kategóriáról." - "0_2": "Nem kapsz értesítést erről a témáról." - "0": "Nem kapsz értesítést erről a témáról." + "1_2": "Értesítve lesz, ha valaki megemlíti a @nevét vagy válaszol Önnek." + "1": "Értesítve lesz, ha valaki megemlíti a @nevét vagy válaszol Önnek." + "0_7": "Nem kap értesítést erről a kategóriáról." + "0_2": "Nem kap értesítést erről a témáról." + "0": "Nem kap értesítést erről a témáról." watching_pm: title: "Figyelés" - description: "Értesítést kapsz minden erre az üzenetre érkező új válaszról és látni fogod az új válaszok számát." + description: "Értesítést kap minden erre az üzenetre érkező új válaszról és látni fogja az új válaszok számát." watching: title: "Figyelés" - description: "Értesítést kapsz minden új válaszról ebben a témakörben és látni fogod az új válaszok számát." + description: "Értesítést kap minden ebbe a témára érkező új válaszról és látni fogja az új válaszok számát." tracking_pm: title: "Követés" - description: "Látni fogod az erre az üzenetre érkező válaszok számát. Értesítést fogsz kapni ha valaki említi a @nevedet vagy válaszol neked." + description: "Látni fogja az erre az üzenetre érkező válaszok számát. Értesítést fog kapni ha valaki említi a @nevét vagy válaszol Önnek." tracking: title: "Követés" - description: "Látni fogod az ebbe a témakörbe érkező új hozzászólások számát. Értesítve leszel ha valaki megemlíti a @nevedet vagy válaszol neked." + description: "Látni fogja az ebbe a témába érkező válaszok számát. Értesítést fog kapni ha valaki említi a @nevét vagy válaszol Önnek." regular: title: "Normál" - description: "Csak akkor leszel értesítve, ha valaki megemlíti a @nevedet vagy válaszol neked." + description: "Értesítve lesz, ha valaki megemlíti a @nevét vagy válaszol Önnek." regular_pm: title: "Normál" - description: "Csak akkor leszel értesítve, ha valaki megemlíti a @nevedet vagy válaszol neked." + description: "Értesítve lesz, ha valaki megemlíti a @nevét vagy válaszol Önnek." muted_pm: title: "Némítás" - description: "Egyáltalán nem fogsz értesítést kapni erről az üzenetről." + description: "Egyáltalán nem fog értesítést kapni erről az üzenetről." muted: title: "Némítás" - description: "Egyáltalán nem fogsz semmilyen értesítést sem kapni erről a témakörről és a legújabbak között sem nem fog szerepelni." + description: "Egyáltalán nem fog semmilyen értesítést kapni erről a témáról és a legújabbak között sem nem fog megjelenni." actions: title: "Műveletek" recover: "Téma törlésének visszavonása" delete: "Téma törlése" open: "Téma megnyitása" close: "Téma lezárása" - multi_select: "Bejegyzések Kiválasztása" + multi_select: "Bejegyzések kiválasztása…" slow_mode: "Lassú mód beállítása…" - timed_update: "Téma időzítőjének beállítása" - pin: "Témakör kiemelése..." - unpin: "Témakör kiemelésének megszüntetése..." - unarchive: "Témakör archiválásának megszüntetése" - archive: "Témakör archiválása" + timed_update: "Téma időzítőjének beállítása…" + pin: "Téma kitűzése…" + unpin: "Téma kitűzésének megszüntetése…" + unarchive: "Téma archiválásának megszüntetése" + archive: "Téma archiválása" invisible: "Téma listázásnak megszüntetése" visible: "Téma listázása" - reset_read: "Olvasási adatok visszaállítása" + reset_read: "Olvasási adatok alaphelyzetbe állítása" make_public: "Téma nyilvánossá tétele" make_private: "Személyes üzenet írása" + reset_bump_date: "Előrehozási dátum alaphelyzetbe állítása" feature: - pin: "Témakör kiemelése" - unpin: "Témakör kiemelésének megszüntetése" - pin_globally: "Témakör globális kiemelése" + pin: "Téma kitűzése" + unpin: "Téma kitűzésének megszüntetése" + pin_globally: "Témakör globális kitűzése" make_banner: "Kiemelt téma létrehozása" - remove_banner: "Kiemelt Téma eltávolítása" + remove_banner: "Kiemelt téma eltávolítása" reply: title: "Válasz" - help: "kezdj választ írni erre a témára" + help: "kezdjen el választ írni ehhez a témához" share: title: "Téma megosztása" - extended_title: "Link megosztása" - help: "a témakör hivatkozásának megosztása" - instructions: "Ossza meg a témához tartozó hivatkozást:" + extended_title: "Hivatkozás megosztása" + help: "téma hivatkozásának megosztása" + instructions: "Téma hivatkozásának megosztása:" copied: "Témahivatkozás másolva." restricted_groups: one: "Csak a csoport tagjai számára látható: %{groupNames}" @@ -2583,50 +2684,50 @@ hu: help: "A téma nyomtatóbarát változatának megnyitása" flag_topic: title: "Megjelölés" - success_message: "Sikeresen megjelölted ezt a témát." + success_message: "Sikeresen megjelölte ezt a témát." feature_topic: title: "Téma kiemelése" - unpin: "Téma eltávolítása a %{categoryLink} kategória elejéről." - not_pinned: "Nincsenek kiemelt %{categoryLink} témák. " + unpin: "Téma eltávolítása a(z) %{categoryLink} kategória elejéről." + not_pinned: "Nincsenek kiemelt témák a(z) %{categoryLink} kategóriában. " confirm_pin_globally: - one: "Jelenleg %{count} kiemelt témaköröd van. Túl sok kiemelt téma megzavarhatja az új vagy névtelen felhasználókat. Biztosan kiemelsz egy újabb témát ebben a kategóriában?" - other: "Jelenleg %{count} kiemelt témaköröd van. Túl sok kiemelt téma megzavarhatja az új vagy névtelen felhasználókat. Biztosan kiemelsz egy újabb témát ebben a kategóriában?" + one: "Jelenleg %{count} kítűzött témája van. A túl sok kiemelt téma megzavarhatja az új vagy névtelen felhasználókat. Biztos, hogy kitűz egy újabb témát ebben a kategóriában?" + other: "Jelenleg %{count} kítűzött témája van. A túl sok kiemelt téma megzavarhatja az új vagy névtelen felhasználókat. Biztos, hogy kitűz egy újabb témát ebben a kategóriában?" already_pinned_globally: - one: "Jelenleg globálisan rögzített témák: %{count}" + one: "Jelenleg globálisan kitűzött témák: %{count}" other: "Jelenleg globálisan kítűzött témák: %{count}" - banner_exists: "Jelenleg van egy banner téma." - inviting: "Meghívás..." + banner_exists: "Jelenleg van kiemelt téma." + inviting: "Meghívás…" invite_private: - title: "Meghívás személyes üzenet-váltásra" + title: "Meghívás személyes üzenetváltáshoz" email_or_username: "A meghívott e-mail-címe vagy felhasználóneve" email_or_username_placeholder: "e-mail-cím vagy felhasználónév" action: "Meghívás" success: "Meghívtuk a felhasználót, hogy vegyen részt ebben az üzenetben." success_group: "Meghívtuk a csoportot, hogy vegyen részt ebben az üzenetben." - error: "Sajnos hiba történt a felhasználó meghívásakor." - not_allowed: "Sajnáljuk, a felhasználót nem lehet meghívni." + error: "Sajnos hiba történt a felhasználó meghívása során." + not_allowed: "Sajnos a felhasználót nem lehet meghívni." group_name: "csoport neve" - controls: "Témák kezelése" + controls: "Témavezérlők" invite_reply: title: "Meghívás" username_placeholder: "felhasználónév" action: "Meghívó küldése" help: "mások meghívása ebbe a témába e-mailben vagy értesítéssel" - to_forum: "Küldünk egy rövid e-mailt, amely lehetővé teszi, hogy a barátod azonnal és egyszerűen csatlakozni tudjon egyetlen linkre kattintva." - discourse_connect_enabled: "Írd be annak a felhasználónevét, akit meg szeretnél hívni ebbe a témába." + to_forum: "Küldünk egy rövid e-mailt, amely lehetővé teszi, hogy a barátja azonnal és egyszerűen csatlakozni tudjon egy hivatkozásra kattintva." + discourse_connect_enabled: "Adja meg a témába meghívandó személy felhasználónevét." to_topic_blank: "Adja meg a témába meghívandó személy felhasználónevét vagy e-mail-címét." - to_topic_email: "Megadtál egy e-mail címet. Erre küldünk egy rövid e-mailt, amely lehetővé teszi, hogy a barátod azonnal és egyszerűen csatlakozni tudjon egyetlen linkre kattintva." - to_topic_username: "Megadtál egy felhasználónevet. Küldünk egy rövid e-mailt, amely lehetővé teszi, hogy a barátod azonnal és egyszerűen csatlakozni tudjon egyetlen linkre kattintva." - to_username: "Írd be annak a felhasználónevét, akit meg szeretnél hívni. Értesítést fogunk neki küldeni, ennek a témának a linkjével." + to_topic_email: "Megadott egy e-mail-címet. Erre küldünk egy rövid e-mailt, amely lehetővé teszi, hogy a barátja azonnal és egyszerűen csatlakozni tudjon egyetlen hivatkozásra kattintva." + to_topic_username: "Megadott egy felhasználónevet. Erre küldünk egy hivatkozást tartalmazó értesítést, amely meghívja őt ebbe a témába." + to_username: "Adja meg a meghívandó személy felhasználónevét. Erre küldünk egy hivatkozást tartalmazó értesítést, amely meghívja őt ebbe a témába." email_placeholder: "név@example.com" - success_email: "Meghívót küldtünk ki a %{invitee}címre. Értesíteni fogunk, ha a meghívót elfogadják. Ellenőrizd a meghívók fület a felhasználói oldaladon, hogy nyomon kövesd a meghívásaidat." - success_existing_email: "Létezik felhasználó ezzel az e-mail címmel: %{emailOrUsername} . Meghívtuk a felhasználót, hogy vegyen részt ebben a témában zajló beszélgetésben." - login_reply: "Jelentkezz be, hogy válaszolhass" + success_email: "Meghívót küldtünk %{invitee} részére. Értesítjük, ha elfogadta a meghívót. Ellenőrizze a meghívók fület a felhasználói oldalán, hogy nyomon kövesse a meghívásait." + success_existing_email: "Már létezik felhasználó ezzel az e-mail-címmel: %{emailOrUsername}. Meghívtuk a felhasználót, hogy vegyen részt ebben a témában zajló beszélgetésben." + login_reply: "Jelentkezzen be, hogy válaszolhasson" filters: n_posts: one: "%{count} bejegyzés" other: "%{count} bejegyzés" - cancel: "Szűrő törlése" + cancel: "Szűrő eltávolítása" move_to: title: "Áthelyezés ide:" action: "áthelyezés ide:" @@ -2636,14 +2737,14 @@ hu: action: "áthelyezés új témába" topic_name: "Új téma címe" radio_label: "Új téma" - error: "Hiba lépett fel a bejegyzés új témakörbe való helyezése során!" + error: "Hiba történt a bejegyzések új témába történő áthelyezése során." instructions: one: "Egy új témát fog létrehozni, és feltölti a kiválasztott hozzászólással." other: "Egy új témát fog létrehozni, és feltölti azt a kiválasztott %{count} hozzászólással." merge_topic: - title: "Áthelyezés létező témába" - action: "áthelyezés létező témába" - error: "Hiba történt a bejegyzések áthelyezésekor ebben a témába." + title: "Áthelyezés egy meglévő témába" + action: "áthelyezés egy meglévő témába" + error: "Hiba történt a bejegyzések abba a témába történő áthelyezése során." radio_label: "Meglévő téma" instructions: one: "Válassza ki azt a témát, ahová áthelyezi a hozzászólást." @@ -2652,7 +2753,7 @@ hu: title: "Áthelyezés az új üzenethez" action: "áthelyezés az új üzenethez" message_title: "Új üzenet címe" - radio_label: "Új Üzenet" + radio_label: "Új üzenet" participants: "Résztvevők" move_to_existing_message: title: "Áthelyezés egy meglévő üzenethez" @@ -2673,109 +2774,112 @@ hu: change_owner: title: "Tulajdonosváltás" action: "tulajdonjog módosítása" - error: "Hiba történt a bejegyzések átruházásakor." + error: "Hiba történt a bejegyzések átruházása során." placeholder: "az új tulajdonos felhasználóneve" change_timestamp: title: "Időbélyeg szerkesztése…" - action: "Időbélyeg módosítása" + action: "időbélyeg módosítása" multi_select: select: "kiválasztás" selected: "kiválasztva (%{count})" select_post: - label: "Kiválasztás" - title: "Hozzászólás hozzáadása a kiválasztáshoz" + label: "kiválasztás" + title: "Bejegyzés hozzáadása a kiválasztáshoz" selected_post: - label: "Kiválasztott" - title: "Ide kattintva eltávolíthatja a bejegyzést a kijelölésből" + label: "kiválasztott" + title: "Kattintson a bejegyzés eltávolításához a kiválasztásból" select_replies: - label: "kiválaszt +válaszok" + label: "kiválasztás válaszokkal együtt" title: "A hozzászólás és összes válaszának hozzáadása a kiválasztáshoz" select_below: - label: "Kiválaszt +alatta" - title: "Add hozzá a választ és minden utána következőt a kiválasztáshoz" + label: "Kiválasztás az alatt lévőkkel együtt" + title: "A bejegyzés és az összes utána következő hozzáadása a kiválasztáshoz" delete: kiválasztottak törlése cancel: kiválasztások visszavonása - select_all: mind kiválasztása - deselect_all: kijelölések törlése + select_all: összes kiválasztása + deselect_all: kiválasztások törlése description: - one: Kijelöltél %{count} hozzászólást. - other: "Kijelöltél %{count} hozzászólást." + one: Kiválasztott %{count} bejegyzést. + other: "Kiválasztott %{count} bejegyzést." post: confirm_delete: "Biztos, hogy törli ezt a bejegyzést?" quote_reply: "Idézet" quote_edit: "Szerkesztés" quote_share: "Megosztás" - edit_reason: "Ok:" - post_number: "bejegyzés %{number}" + edit_reason: "Ok: " + post_number: "%{number}. bejegyzés" ignored: "Letiltott tartalom" - reply_as_new_topic: "Válasz csatolt üzenetként" + reply_as_new_topic: "Válasz kapcsolódó témaként" reply_as_new_private_message: "Válasz új üzenetként ugyanazoknak a címzetteknek" follow_quote: "ugrás az idézett bejegyzéshez" show_full: "Teljes bejegyzés megtekintése" show_hidden: "Letiltott tartalom megtekintése" - collapse: "Összeomlás" - expand_collapse: "kinyitás/bezárás" + collapse: "összecsukás" + expand_collapse: "kibontás/összecsukás" gap: one: "%{count} rejtett válasz megtekintése" other: "%{count} rejtett válasz megtekintése" notice: - new_user: "Ez az első alkalom, hogy %{user} posztolt - üdvözöljük a közösségünkben!" - unread: "Olvasatlan bejegyzés" + new_user: "Ez az első alkalom, hogy %{user} bejegyzést tett közzé – üdvözöljük a közösségünkben!" + unread: "A bejegyzés olvasatlan" has_replies: one: "%{count} válasz" other: "%{count} válasz" has_likes_title: - one: "%{count} emberek tetszett ez a bejegyzés" - other: "%{count} emberek tetszett ez a bejegyzés" - has_likes_title_only_you: "kedvelted ezt a bejegyzést" + one: "%{count} embernek tetszett ez a bejegyzés" + other: "%{count} embernek tetszett ez a bejegyzés" + has_likes_title_only_you: "kedvelte ezt a bejegyzést" has_likes_title_you: - one: "rajtad kívül %{count} embernek tetszett ez a bejegyzés" - other: "rajtad kívül %{count} embernek tetszett ez a bejegyzés" - in_reply_to: "Szülő bejegyzés betöltése" + one: "Önön kívül még %{count} embernek tetszett ez a bejegyzés" + other: "Önön kívül még %{count} embernek tetszett ez a bejegyzés" + in_reply_to: "Szülőbejegyzés betöltése" view_all_posts: "Az összes válasz megtekintése" errors: - create: "Sajnáljuk, de a bejegyzésed létrehozása közben hiba lépett fel. Kérünk próbáld újra!" - edit: "Sajnáljuk, de a bejegyzésed szerkesztése közben hiba lépett fel. Kérünk próbáld újra!" - upload: "Sajnáljuk, de a fájl feltöltése közben hiba lépett fel. Kérünk próbáld újra!" - file_size_zero: "Sajnáljuk, úgy tűnik, hogy valami hiba történt, a feltöltendő fájl 0 bájtos. Próbálja újra." - too_many_uploads: "Sajnáljuk, de egyszerre csak egy fájlt tölthetsz fel!" - image_upload_not_allowed_for_new_user: "Sajnáljuk, de az új felhasználók nem tölthetnek fel képeket!" - attachment_upload_not_allowed_for_new_user: "Sajnáljuk, de az új felhasználók nem tölthetnek fel csatolmányokat!" - attachment_download_requires_login: "Sajnáljuk, de be kell jelentkezned, hogy letölthess csatolmányokat!" + create: "Sajnos hiba történt a bejegyzése létrehozása során. Próbálja újra." + edit: "Sajnos hiba történt a bejegyzése szerkesztése során. Próbálja újra." + upload: "Sajnos hiba történt a fájl feltöltése során. Próbálja újra." + file_size_zero: "Sajnos úgy tűnik, hogy valami hiba történt, a feltöltendő fájl 0 bájtos. Próbálja újra." + too_many_uploads: "Sajnos egyszerre csak egy fájlt tölthet fel." + image_upload_not_allowed_for_new_user: "Sajnos az új felhasználók nem tölthetnek fel képeket." + attachment_upload_not_allowed_for_new_user: "Sajnos az új felhasználók nem tölthetnek fel mellékleteket." + attachment_download_requires_login: "Sajnos be kell jelentkeznie, hogy letölthesse a mellékleteket." cancel_composer: discard: "Elvetés" save_draft: "Vázlat mentése későbbre" via_email: "ez a válasz e-mailben érkezett" - via_auto_generated_email: "ez a bejegyzés egy automatikusan generált e-mailen keresztül érkezett" - few_likes_left: "Köszönjük, hogy aktívan osztod a kedveléseket! A jóból is megárt a sok: már csak néhány kiosztható kedvelésed maradt mára." + via_auto_generated_email: "ez a bejegyzés egy automatikusan előállított e-mailen keresztül érkezett" + few_likes_left: "Köszönjük, hogy aktívan osztja a kedveléseket! Már csak néhány kiosztható kedvelése maradt mára." controls: - reply: "kezdje meg a választ erre a bejegyzésre" + reply: "kezdjen el választ írni ehhez a bejegyzéshez" like: "bejegyzés kedvelése" - has_liked: "kedvelted ezt a bejegyzést" + has_liked: "kedvelte ezt a bejegyzést" read_indicator: "tagok, akik elolvasták ezt a bejegyzést" undo_like: "kedvelés visszavonása" edit: "bejegyzés szerkesztése" edit_action: "Szerkesztés" - edit_anonymous: "Sajnáljuk, de be kell jelentkezned, hogy szerkeszthesd ezt a bejegyzést!" - flag: "Titkosan jelöld meg ezt a bejegyzést, hogy felhívd rá a moderátorok figyelmét, vagy küldj privát értesítést róla" + edit_anonymous: "Sajnos be kell jelentkeznie, hogy szerkeszthesse ezt a bejegyzést." + flag: "a bejegyzés titkos megjelölése, hogy felhívja rá a moderátorok figyelmét, vagy privát értesítést küldjön róla" delete: "bejegyzés törlése" undelete: "bejegyzés visszaállítása" - share: "bejegyzés megosztása link-kel" + share: "bejegyzés hivatkozásának megosztása" more: "Több" delete_replies: just_the_post: "Nem, csak ezt a bejegyzést" admin: "admin műveletek" wiki: "Wiki létrehozása" unwiki: "Wiki eltávolítása" - convert_to_moderator: "Stáb szín hozzáadása" - revert_to_regular: "Stáb szín eltávolítása" + convert_to_moderator: "Stábszín hozzáadása" + revert_to_regular: "Stábszín eltávolítása" rebake: "HTML újjáépítése" unhide: "Elrejtés visszavonása" lock_post: "Bejegyzés zárolása" unlock_post: "Bejegyzés zárolásának feloldása" - delete_topic_confirm_modal_yes: "Igen, töröld ezt a témát" - delete_topic_confirm_modal_no: "Nem, tartsa meg ezt a témát" - delete_topic: "témakör törlése" + delete_topic_confirm_modal_yes: "Igen, a téma törlése" + delete_topic_confirm_modal_no: "Nem, a téma megtartása" + delete_topic: "téma törlése" + add_post_notice: "Stábnak szóló megjegyzés hozzáadása…" + change_post_notice: "Stábnak szóló megjegyzés módosítása…" + delete_post_notice: "Stábnak szóló megjegyzés törlése" actions: people: like: @@ -2785,10 +2889,10 @@ hu: one: "olvasd ezt el" other: "olvasd ezt el" like_capped: - one: "és %{count} ezt likeolták" - other: "és %{count} embernek tetszett" + one: "és még %{count} embernek tetszett" + other: "és még %{count} embernek tetszett" by_you: - off_topic: "Nem a témába tartozónak jelölve" + off_topic: "Megjelölte nem a témához tartozóként" spam: "Spam-ként jelölted" inappropriate: "Ezt ide nem illőnek jelölte." notify_moderators: "Moderálásra jelölted" @@ -2797,10 +2901,6 @@ hu: confirm: one: "Biztosan törlöd ezt a bejegyzést?" other: "Biztosan törlöd ezt a %{count} bejegyzést?" - merge: - confirm: - one: "Biztos, hogy egyesíteni szeretnéd ezeket a bejegyzéseket?" - other: "Biztos, hogy egyesíteni kívánod ezt a %{count} bejegyzést?" revisions: controls: hide: "Átdolgozás elrejtése" @@ -2903,6 +3003,7 @@ hu: default_position: "Alapértelmezett pozíció" position_disabled: "A kategóriák aktivitási sorrendben jelennek meg. A kategóriák sorrendjének listákban való szabályzásához," parent: "Szülő kategória" + num_auto_bump_daily: "A naponta automatikusan előrehozandó nyitott témák száma:" navigate_to_first_post_after_read: "A témák elolvasása után navigáljon az első hozzászóláshoz" notifications: watching: @@ -2958,7 +3059,7 @@ hu: hidden_email_address: "(elrejtett)" submit_tooltip: "A titkos jelzés elküldése" cant: "Sajnáljuk, most nem jelölheted meg ezt a bejegyzést." - notify_staff: "A személyzet titkos értesítése" + notify_staff: "A stáb értesítése privátban" formatted_name: off_topic: "Ez nem tartozik a témakörbe" inappropriate: "Ez ide nem illő" @@ -3208,7 +3309,6 @@ hu: download_calendar: download: "Letöltés" tagging: - all_tags: "Összes címke" other_tags: "Egyéb címkék" selector_all_tags: "összes címke" selector_no_tags: "címke nélküli" @@ -3292,11 +3392,8 @@ hu: regular: "rendes tag" leader: "vezető" user_activity: - no_activity_others: "Nincsenek tevékenységek." - no_replies_others: "Nincsenek válaszok." no_drafts_title: "Még nem kezdett el egyetlen vázlatot sem" no_drafts_body: "Még nem áll készen a bejegyzés létrehozására? Automatikusan mentve lesz egy új vázlat, és itt fel lesz sorolva, ha egy új témát, választ vagy személyes üzenetet kezd el írni. Válassza a Mégse gombot, hogy elvesse, vagy mentse a vázlatot a későbbi folytatáshoz." - no_likes_others: "Nincsenek kedvelt bejegyzések." fullscreen_table: expand_btn: "Táblázat kibontása" sidebar: @@ -3307,7 +3404,10 @@ hu: one: "%{count} új" other: "%{count} új" more: "Továbbiak..." + all_categories: "Minden kategória" sections: + about: + header_link_text: "Névjegy" messages: header_link_text: "Üzenetek" links: @@ -3319,15 +3419,20 @@ hu: unread_with_count: "Olvasatlan (%{count})" archive: "Archívum" tags: - header_link_title: "összes címke" header_link_text: "Címkék" categories: - header_link_title: "összes kategória" header_link_text: "Kategóriák" community: - header_link_title: "kezdőlap" header_link_text: "Közösség" links: + about: + content: "Névjegy" + admin: + content: "Adminisztrátor" + badges: + content: "Jelvények" + faq: + content: "GYIK" tracked: content: "Követett" groups: @@ -3337,6 +3442,11 @@ hu: content: "Felhasználók" my_posts: content: "Saját bejegyzéseim" + welcome_topic_banner: + title: "Hozzon létre üdvözlő témát" + description: 'Az üdvözlő téma az első, amit az újonnan érkezők olvasnak. Gondoljon rá úgy mint egy bekezdésnyi bemutatkozóra vagy „küldetésnyilatkozatra”.' + button_title: "Szerkesztés megkezdése" + until: "Eddig:" admin_js: type_to_filter: "Írj ide a szűréshez.." admin: @@ -3436,6 +3546,7 @@ hu: visibility_levels: title: "Ki láthatja ezt a csoportot?" public: "Mindenki" + staff: "Csoporttulajdonosok és moderátorok" membership: automatic: Autómatikus trust_levels_title: "Új tagok hozzáadásakor automatikusan kapott Bizalmi szint: " @@ -3610,7 +3721,7 @@ hu: button_text: "Exportálás" button_title: user: "Teljes felhasználói lista exportálása CSV formátumban." - staff_action: "Személyzeti tevékenységnapló exportálása CSV formátumban." + staff_action: "Stáb teljes tevékenységnaplójának exportálása CSV formátumban." screened_email: "Teljes email lista exportálása CSV formátumban" screened_ip: "Tejles IP lista exportálása CSV formátumban" screened_url: "Teljes URL lista exportálása CSV formátumban" @@ -3707,6 +3818,7 @@ hu: copy_name_prefix: "másolata" undo: "Visszavonás" revert: "Visszaállítás" + revert_title: "A szín visszaállítása a Discouse alapértelmezett színpalettájának megfelelőre." primary: name: "Elsődleges" description: "valamenyi szövegek,ikonok és szegélyek" @@ -3819,7 +3931,7 @@ hu: staff_actions: all: "Összes" filter: "Szűrő:" - title: "Szervezői műveletek" + title: "Stábműveletek" clear_filters: "Mind mutatása" staff_user: "Felhasználó" target_user: "Célzott felhasználó" @@ -3875,7 +3987,7 @@ hu: change_readonly_mode: "Írásvédett mód megváltoztatása" backup_download: "Biztonsági mentés letöltése" backup_destroy: "Biztonsági mentés megsemmisítése" - reviewed_post: "áttekintett bejegyzés" + reviewed_post: "Jóváhagyott bejegyzés" custom_staff: "Kiegészítő egyedi eljárása" post_locked: "Bejegyzés lezárva" post_edit: "Bejegyzés szerkesztése" @@ -3895,7 +4007,8 @@ hu: add_email: "e-mail-cím hozzáadása" update_email: "e-mail frissítése" destroy_email: "e-mail megsemmisítése" - post_staff_note_create: "személyzeti megjegyzés hozzáadása" + post_staff_note_create: "stábnak szóló megjegyzés hozzáadása" + post_staff_note_destroy: "stábnak szóló megjegyzés megsemmisítése" screened_emails: title: "Szűrt e-mailek" email: "E-mail cím" @@ -4066,7 +4179,7 @@ hu: deactivate_account: "Fiók deaktiválása" unsilence_failed: "Probléma merült fel a felhasználó némításának feloldásakor." reset_bounce_score: - label: "Alaphelyzet" + label: "Alaphelyzetbe állítás" visit_profile: "A profil szerkesztéséhez látogasson el a felhasználói beállítások oldalára" deactivate_explanation: "A deaktivált felhasználónak újra érvényesítenie kell az e-mailj címét." bounce_score_explanation: diff --git a/config/locales/client.hy.yml b/config/locales/client.hy.yml index 304d6596b3..e5d2a34e46 100644 --- a/config/locales/client.hy.yml +++ b/config/locales/client.hy.yml @@ -152,11 +152,11 @@ hy: disabled: "հեռացրել է այս բանները %{when}: Այն այլևս չի հայտնվի յուրաքանչյուր էջի վերևում:" forwarded: "վերահասցեագրել նշված նամակը" topic_admin_menu: "թեմայի ադմինի գործողություններ" - wizard_required: "Բարի գալուստ Ձեր նոր Discourse! Սկսենք տեղակայման մասնագետ-ի հետ ✨" emails_are_disabled: "Բոլոր ելքային էլ. նամակները անջատվել են ադմինիստրատորի կողմից: Էլ. փոստով ոչ մի տեսակի ծանուցում չի ուղարկվի:" software_update_prompt: dismiss: "Չեղարկել" bootstrap_mode_disabled: "Սկզբնաբեռնման(Bootstrap) ռեժիմը կանջատվի 24 ժամվա ընթացքում:" + bootstrap_invite_button_title: "Ուղարկել Հրավերներ" themes: default_description: "Լռելյայն" s3: @@ -186,6 +186,8 @@ hy: not_implemented: "Այդ հատկանիշը դեռևս չի իրագործվել, ներողություն!" no_value: "Ոչ" yes_value: "Այո" + ok_value: "ՕԿ" + cancel_value: "Չեղարկել" submit: "Հաստատել" generic_error: "Տեղի է ունեցել սխալ, ներողություն:" generic_error_with_reason: "Տեղի է ունեցել սխալ՝ %{error}" @@ -1786,6 +1788,13 @@ hy: go_back: "ետ գնալ" not_logged_in_user: "օգտատիրոջ էջը՝ ընթացիկ ակտիվության և նախընտրությունների ամփոփումով" current_user: "գնալ իմ էջը" + user_menu: + tabs: + replies: "Պատասխաններ" + mentions: "Հիշատակումներ" + likes: "Հավանում" + bookmarks: "Էջանշաններ" + profile: "Պրոֆիլ" topics: new_messages_marker: "վերջին այցելությունը" bulk: @@ -2279,10 +2288,6 @@ hy: confirm: one: "Դուք համոզվա՞ծ եք, որ ցանկանում եք ջնջել այդ հրապարակումը:" other: "Դուք համոզվա՞ծ եք, որ ցանկանում եք ջնջել այդ%{count} գրառումները:" - merge: - confirm: - one: "Դուք համոզվա՞ծ եք, որ ցանկանում եք միավորել այդ հրապարակումները:" - other: "Դուք համոզվա՞ծ եք, որ ցանկանում եք միավորել այդ %{count} գրառումները:" revisions: controls: first: "Առաջին խմբագրությունը" @@ -2761,7 +2766,6 @@ hy: download_calendar: download: "Ներբեռնել" tagging: - all_tags: "Բոլոր Թեգերը" other_tags: "Այլ Թեգեր" selector_all_tags: "բոլոր թեգերը" selector_no_tags: "առանց թեգերի" @@ -2869,10 +2873,6 @@ hy: member: "անդամ" regular: "սովորական" leader: "առաջնորդ" - user_activity: - no_activity_others: "Ակտիվություն չկա:" - no_replies_others: "Պատասխան չկա:" - no_likes_others: "Հավանած գրառումներ չկան:" sidebar: unread_count: one: "%{count} չկարդացած" @@ -2881,7 +2881,10 @@ hy: one: "%{count} նոր" other: "%{count} նոր" more: "Ավելին..." + all_categories: "Բոլոր կատեգորիաները" sections: + about: + header_link_text: "Մասին" messages: header_link_text: "Հաղորդագրություններ" links: @@ -2893,15 +2896,20 @@ hy: unread_with_count: "Չկարդացած (%{count})" archive: "Արխիվ" tags: - header_link_title: "բոլոր թեգերը" header_link_text: "Թեգեր" categories: - header_link_title: "բոլոր կատեգորիաները" header_link_text: "Կատեգորիաներ" community: - header_link_title: "գլխավոր էջ" header_link_text: "Համայնք" links: + about: + content: "Մասին" + admin: + content: "Ադմին" + badges: + content: "Կրծքանշաններ" + faq: + content: "ՀՏՀ" tracked: content: "Հետևած" groups: @@ -3922,7 +3930,6 @@ hy: cant_delete_all_too_many_posts: one: "Հնարավոր չէ ջնջել բոլոր գրառումները, քանի որ օգտատերն ունի ավելի քան %{count} գրառում: (delete_all_posts_max)" other: "Հնարավոր չէ ջնջել բոլոր գրառումները, քանի որ օգտատերն ունի ավելի քան %{count} գրառում: (delete_all_posts_max)" - delete_confirm: "Սովորաբար ավելի նախընտրելի է անվանազրկել օգտատիրոջը, քան ջնջել նրանց՝ գոյություն ունեցող քննարկումների պարունակությունը ջնջելուց խուսափելու համար:

    Դուք ՀԱՄՈԶՎԱ՞Ծ ԵՔ, որ ցանկանում եք ջնջել այս օգտատիրոջը: Սա մշտական է!" delete_and_block: "Ջնջել և արգելափակել այս էլ. և IP հասցեները:" delete_dont_block: "Միայն ջնջել " deleting_user: "Օգտատերը ջնջվում է..." diff --git a/config/locales/client.id.yml b/config/locales/client.id.yml index d29462c75a..03c79e3808 100644 --- a/config/locales/client.id.yml +++ b/config/locales/client.id.yml @@ -151,7 +151,6 @@ id: forwarded: "meneruskan email di atas" topic_admin_menu: "tindakan topik" skip_to_main_content: "Lewati ke konten utama" - wizard_required: "Selamat datang di Discourse baru Anda! Mari kita mulai dengan wizard pengaturan ✨" emails_are_disabled: "Semua surel yang keluar telah dinonaktifkan oleh administrator. Tidak ada pemberitahuan email yang akan dikirimkan." emails_are_disabled_non_staff: "Surel keluar telah dimatikan untuk pengguna yang bukan staf." software_update_prompt: @@ -196,6 +195,8 @@ id: not_implemented: "Maaf, fitur ini belum diimplementasikan." no_value: "Tidak" yes_value: "Ya" + ok_value: "OK" + cancel_value: "Batal" submit: "Kirimkan" generic_error: "Maaf, terjadi kesalahan." generic_error_with_reason: "Terjadi kesalahan: %{error}" @@ -1519,6 +1520,13 @@ id: count: label: Pos new_item: "baru" + user_menu: + tabs: + replies: "balasan" + mentions: "Balasan-balasan" + likes: "Likes Diberikan" + bookmarks: "Markah" + profile: "Profil" topics: bulk: select_all: "Pilih Semua" @@ -1792,6 +1800,8 @@ id: new_count: other: "%{count} baru" sections: + about: + header_link_text: "Tentang" messages: header_link_text: "Pesan-pesan" links: @@ -1804,11 +1814,15 @@ id: tags: header_link_text: "Label" categories: - header_link_title: "Semua kategori" header_link_text: "Kategori" community: - header_link_title: "beranda" links: + about: + content: "Tentang" + admin: + content: "Admin" + faq: + content: "FAQ" tracked: content: "Dilacak" groups: diff --git a/config/locales/client.it.yml b/config/locales/client.it.yml index 32fb013360..0dc84bcd40 100644 --- a/config/locales/client.it.yml +++ b/config/locales/client.it.yml @@ -179,7 +179,6 @@ it: forwarded: "ha inoltrato l'email sopra" topic_admin_menu: "azioni argomento" skip_to_main_content: "Passa al contenuto principale" - wizard_required: "Benvenuto al tuo nuovo sito Discourse! Inizia la procedura guidata di configurazione ✨" emails_are_disabled: "Tutte le e-mail in uscita sono state disabilitate a livello globale da un amministratore. Non sarà inviato nessun tipo di notifica via e-mail." emails_are_disabled_non_staff: "La posta in uscita è stata disattivata per gli utenti al di fuori dello staff." software_update_prompt: @@ -189,6 +188,7 @@ it: one: "Per rendere più facile il lancio del nuovo sito, sei in modalità bootstrap. A tutti i nuovi utenti verrà concesso il livello di attendibilità 1 e verranno attivate le email di riepilogo giornaliere. Questa modalità verrà disattivata automaticamente quando %{count} utente si sarà unito." other: "Per rendere più facile il lancio del nuovo sito, sei in modalità bootstrap. A tutti i nuovi utenti verrà concesso il livello di attendibilità 1 e verranno attivate le email di riepilogo giornaliere. Questa modalità verrà disattivata automaticamente quando %{count} utenti si saranno uniti." bootstrap_mode_disabled: "La modalità bootstrap sarà disattivata entro 24 ore." + bootstrap_invite_button_title: "Manda Inviti" themes: default_description: "Predefinito" broken_theme_alert: "Il sito potrebbe non funzionare a causa di errori in un tema / componente." @@ -225,6 +225,8 @@ it: not_implemented: "Spiacenti! Questa funzione non è stata ancora implementata." no_value: "No" yes_value: "Sì" + ok_value: "OK" + cancel_value: "Annulla" submit: "Invia" generic_error: "Spiacenti, c'è stato un errore." generic_error_with_reason: "Si è verificato un errore: %{error}" @@ -1053,6 +1055,7 @@ it: dismiss_notifications: "Ignora tutti" dismiss_notifications_tooltip: "Imposta tutte le notifiche non lette come lette " dismiss_bookmarks_tooltip: "Contrassegna tutti i promemoria dei segnalibri non letti come già letti" + dismiss_messages_tooltip: "Segna come lette tutte le notifiche di messaggi personali non letti" no_messages_title: "Non hai messaggi" no_messages_body: > Hai la necessità di avere una conversazione privata con qualcuno? Invia un messaggio selezionando l'avatar e utilizzando il pulsante del messaggio %{icon}

    Se hai bisogno di aiuto, puoi inviare un messaggio a un membro dello staff. @@ -1648,7 +1651,6 @@ it: set_custom_status: "Imposta stato personalizzato" what_are_you_doing: "Cosa fai?" remove_status: "Rimuovi lo stato" - until: "Fino a:" loading: " Caricamento..." errors: prev_page: "durante il caricamento" @@ -1712,7 +1714,6 @@ it: hide_forever: "no grazie" hidden_for_session: "OK, te lo chiederemo domani. Puoi sempre utilizzare \"Accedi\" anche per creare un account." intro: "Ciao! Sembra che la discussione ti interessi, ma non hai ancora registrato un account." - value_prop: "Non ti piace dover scorrere gli stessi messaggi? Quando crei un account, riprenderai sempre dall'ultimo messaggio letto. Potrai anche ricevere notifiche di nuove risposte, salvare segnalibri e usare i \"mi piace\" per ringraziare gli altri. Possiamo lavorare tutti insieme per rendere questa comunità un posto fantastico. :heart:" summary: enabled_description: "Stai visualizzando un riepilogo dell'argomento: è la comunità a determinare quali sono i messaggi più interessanti." description: @@ -1966,6 +1967,8 @@ it: similar_topics: "Il tuo argomento è simile a..." drafts_offline: "bozze offline" edit_conflict: "modifica conflitto" + esc: "esc" + esc_label: "Clicca o premi Esc per chiudere" group_mentioned_limit: one: "Attenzione! Hai menzionato %{group}, tuttavia questo gruppo ha più membri rispetto al limite di %{count} menzione di utente configurato dall'amministratore. Non ci saranno notifiche." other: "Attenzione! Hai menzionato %{group}, tuttavia questo gruppo ha più membri rispetto al limite di %{count} menzioni di utenti configurato dall'amministratore. Non ci saranno notifiche." @@ -2057,6 +2060,7 @@ it: abandon: "chiudi il composer e scarta la bozza" enter_fullscreen: "Espandi il composer a tutto schermo" exit_fullscreen: "esci dal composer a tutto schermo" + exit_fullscreen_prompt: "Premi ESC per uscire dallo schermo intero." show_toolbar: "mostra la barra degli strumenti del Composer" hide_toolbar: "nascondi la barra degli strumenti del Composer" modal_ok: "OK" @@ -2161,6 +2165,9 @@ it: default: one: "Sei sicuro/a? Hai %{count} notifica importante." other: "Sei sicuro? Hai %{count} notifiche importanti." + messages: + one: "Sei sicuro/a? Hai %{count} messaggio personale non letto." + other: "Sei sicuro/a? Hai %{count} messaggi personali non letti." dismiss: "Ignora" cancel: "Annulla" group_message_summary: @@ -2341,15 +2348,20 @@ it: view_all: "visualizza tutto in %{tab}" user_menu: generic_no_items: "Non ci sono elementi in questo elenco." - sr_menu_tabs: "Schede del menu" view_all_notifications: "visualizza tutte le notifiche" view_all_bookmarks: "visualizza tutti i segnalibri" + view_all_messages: "visualizza tutti i messaggi personali" + tabs: + replies: "Risposte" + mentions: "Menzioni" + likes: "Mi piace - Assegnati" + bookmarks: "Segnalibri" + profile: "Profilo" reviewable: queue: "Coda" deleted_user: "(utente cancellato)" post_number_with_topic_title: "messaggio #%{post_number} - %{title}" new_post_in_topic: "nuovo messaggio in %{title}" - suspicious_user: "utente sospetto %{username}" default_item: "elemento da rivedere #%{reviewable_id}" topics: new_messages_marker: "ultima visita" @@ -2992,10 +3004,6 @@ it: confirm: one: "Vuoi davvero eliminare il messaggio?" other: "Vuoi davvero eliminare questi %{count} messaggi?" - merge: - confirm: - one: "Sicuro di voler unire questi messaggi?" - other: "Sicuro di voler unire questi %{count} messaggi?" revisions: controls: first: "Prima revisione" @@ -3562,7 +3570,6 @@ it: google: "Google Calendar" ics: "ICS" tagging: - all_tags: "Tutte le Etichette" other_tags: "Altre Etichette" selector_all_tags: "tutte le etichette" selector_no_tags: "nessuna etichetta" @@ -3724,14 +3731,13 @@ it: user_activity: no_activity_title: "Ancora nessuna attività" no_activity_body: "Ti diamo il benvenuto nella nostra comunità! Sei nuovo/a e non hai ancora contribuito a nessuna discussione. Per cominciare, clicca su Popolari o Categorie e inizia a leggere! Seleziona %{heartIcon} sui post che ti piacciono o che vuoi approfondire. A mano a mano che partecipi, le tue attività saranno elencate qui." - no_activity_others: "Nessuna attività." no_replies_title: "Non hai ancora risposto a nessun argomento" - no_replies_others: "Nessuna risposta." + no_replies_title_others: "%{username} non ha ancora risposto a nessun argomento" no_drafts_title: "Non hai iniziato nessuna bozza" no_drafts_body: "Non sei ancora pronto/a a pubblicare? Salveremo automaticamente una nuova bozza e la elencheremo qui ogni volta che inizierai a scrivere un argomento, una risposta o un messaggio personale. Seleziona il pulsante Annulla per eliminare o salvare la bozza e continuare a scrivere più avanti." no_likes_title: "Non hai ancora messo \"mi piace\" a nessun argomento" + no_likes_title_others: "%{username} non ha ancora messo Mi piace a nessun argomento" no_likes_body: "Un ottimo modo per iniziare a contribuire è mettersi a leggere le conversazioni già avvenute e assegnare un %{heartIcon} ai post che ti piacciono!" - no_likes_others: "Nessun messaggio con \"Mi piace\"." no_topics_title: "Non hai ancora avviato nessun argomento" no_topics_body: "È sempre meglio cercare argomenti di conversazione già esistenti prima di iniziarne uno nuovo, ma se sei sicuro che l'argomento che desideri non sia già presente, procedi a creare un nuovo argomento tutto tuo. Cerca il pulsante + Nuovo Argomento vicino all'elenco di argomenti, categorie o etichette per iniziare a creare un nuovo argomento in quell'area." no_topics_title_others: "%{username} non ha ancora iniziato nessun argomento" @@ -3754,9 +3760,11 @@ it: other: "%{count} nuovi" toggle_section: "inverti sezione" more: "Altro..." + all_categories: "Tutte le categorie" sections: + about: + header_link_text: "Informazioni su" messages: - header_link_title: "messaggi personali" header_link_text: "Messaggi" header_action_title: "crea un messaggio personale" links: @@ -3770,23 +3778,28 @@ it: tags: none: "Non hai aggiunto nessuna etichetta." click_to_get_started: "Clicca qui per iniziare." - header_link_title: "tutte le etichette" header_link_text: "Etichette" header_action_title: "modifica le etichette nella barra laterale" categories: none: "Non hai aggiunto nessuna categoria." click_to_get_started: "Clicca qui per iniziare." - header_link_title: "tutte le categorie" header_link_text: "Categorie" header_action_title: "modifica le categorie nella barra laterale" community: - header_link_title: "home" header_link_text: "Comunità" header_action_title: "crea un nuovo argomento" links: + about: + content: "Informazioni su" + admin: + content: "Amministrazione" + badges: + content: "Distintivi" everything: content: "Tutti" title: "Tutti gli argomenti" + faq: + content: "FAQ" tracked: content: "Seguite" title: "Tutti gli argomenti seguiti" @@ -3802,6 +3815,10 @@ it: draft_count: one: "%{count} bozza" other: "%{count} bozze" + welcome_topic_banner: + title: "Crea il tuo argomento di benvenuto" + button_title: "Inizia a modificare" + until: "Fino a:" admin_js: type_to_filter: "digita per filtrare..." admin: @@ -4358,6 +4375,8 @@ it: import_web_advanced: "Avanzate..." import_file_tip: "File .tar.gz, .zip, o .dcstyle.json contenente il tema" is_private: "Il tema è in un archivio git privato" + finish_install: "Completa l'installazione del tema" + last_attempt: "Il processo di installazione non si è concluso, ultimo tentativo:" remote_branch: "Nome del branch (opzionale)" public_key: "Concedi l'accesso all'archivio con la seguente chiave pubblica:" public_key_note: "Dopo l’inserimento di un URL valido di archivio riservato, verrà generata e qui visualizzata una corrispondente chiave SSH." @@ -4368,6 +4387,8 @@ it: install_git_repo: "Da un archivio git" install_create: "Crea nuovo" duplicate_remote_theme: "Il componente del tema «%{name}» è già installato, sei sicuro di volerne installare un'altra copia?" + force_install: "Il tema non può essere installato perché il repository Git è inaccessibile. Sei sicuro di voler continuare l'installazione?" + create_placeholder: "Crea Segnaposto" about_theme: "Informazioni su" license: "Licenza" version: "Versione:" @@ -4998,7 +5019,8 @@ it: cant_delete_all_too_many_posts: one: "Impossibile cancellare tutti i messaggi perché l'utente ha più di %{count} messaggio. (delete_all_posts_max)" other: "Impossibile cancellare tutti i messaggi perché l'utente ha più di %{count} messaggi. (delete_all_posts_max.)" - delete_confirm: "E' preferibile rendere anonimo un utente anziché eliminarlo, per evitare di rimuovere contenuti dalle discussioni esistenti.

    Sei SICURO di voler eliminare questo utente? Questa azione è permanente!" + delete_confirm_title: "Vuoi DAVVERO eliminare questo utente? Questa operazione è irreversibile!" + delete_confirm: "In genere è preferibile rendere anonimi gli utenti piuttosto che eliminarli, per evitare di rimuoverne i contenuti dalle discussioni esistenti." delete_and_block: "Elimina e blocca questa email e indirizzo IP" delete_dont_block: "Elimina soltanto" deleting_user: "Cancellazione utente..." @@ -5129,7 +5151,6 @@ it: recommended: "Consigliamo di personalizzare il seguente testo per adattarlo alle tue necessità:" show_overriden: "Mostra solo le opzioni sovrascritte" locale: "Lingua:" - fallback_locale_warning: "Stai modificando una lingua in base a %{fallback}. Gli utenti che scelgono %{fallback} come lingua dell'interfaccia non visualizzeranno le modifiche apportate." more_than_50_results: "Ci sono più di 50 risultati. Restringi i criteri di ricerca." settings: show_overriden: "Mostra solo le opzioni sovrascritte" diff --git a/config/locales/client.ja.yml b/config/locales/client.ja.yml index 33da63db59..56d1991d24 100644 --- a/config/locales/client.ja.yml +++ b/config/locales/client.ja.yml @@ -145,7 +145,6 @@ ja: forwarded: "上記のメールを転送しました" topic_admin_menu: "トピックの操作" skip_to_main_content: "メインコンテンツにスキップ" - wizard_required: "Discourse へようこそ! セットアップウィザードから始めましょう" emails_are_disabled: "メールの送信は管理者によって無効化されています。メール通知は一切送信されません。" software_update_prompt: message: "このサイトを更新したので、再読み込みしてください。再読み込みしない場合、予期しない動作が発生する可能性があります。" @@ -153,6 +152,7 @@ ja: bootstrap_mode_enabled: other: "新しいサイトを簡単に立ち上げられるように、ブートストラップモードになっています。すべての新規ユーザーの信頼レベルは 1 となり、要約メールを毎日受け取るように設定されています。この設定は %{count} 名のユーザーが参加すると自動的に無効になります。" bootstrap_mode_disabled: "ブートストラップモードは 24 時間以内に無効になります。" + bootstrap_invite_button_title: "招待を送信" themes: default_description: "デフォルト" s3: @@ -185,6 +185,8 @@ ja: not_implemented: "その機能はまだ実装されていません!" no_value: "いいえ" yes_value: "はい" + ok_value: "OK" + cancel_value: "キャンセル" submit: "送信" generic_error: "申し訳ありません。エラーが発生しました。" generic_error_with_reason: "エラーが発生しました: %{error}" @@ -2161,6 +2163,13 @@ ja: not_logged_in_user: "現在のアクティビティと設定に関するユーザーの概要ページ" current_user: "ユーザーページに移動" view_all: "すべての%{tab}を表示" + user_menu: + tabs: + replies: "返信" + mentions: "メンション" + likes: "「いいね!」された数" + bookmarks: "ブックマーク" + profile: "プロフィール" topics: new_messages_marker: "最後の訪問" bulk: @@ -2727,9 +2736,6 @@ ja: delete: confirm: other: "%{count} 件の投稿を削除してもよろしいですか?" - merge: - confirm: - other: "これらの %{count} 件の投稿をマージしてよろしいですか?" revisions: controls: first: "最初のリビジョン" @@ -3248,7 +3254,6 @@ ja: google: "Google カレンダー" ics: "ICS" tagging: - all_tags: "すべてのタグ" other_tags: "他のタグ" selector_all_tags: "すべてのタグ" selector_no_tags: "タグなし" @@ -3391,17 +3396,16 @@ ja: detailed_name: "%{level}: %{name}" pick_files_button: unsupported_file_picked: "サポートされていないファイルを選択しました。サポートされているファイルタイプ – %{types}。" - user_activity: - no_activity_others: "アクティビティがありません。" - no_replies_others: "返信はありません。" - no_likes_others: "「いいね!」した投稿はありません。" sidebar: unread_count: other: "未読 %{count}" new_count: other: "新規 %{count}" more: "もっと..." + all_categories: "すべてのカテゴリ" sections: + about: + header_link_text: "サイト情報" messages: header_link_text: "メッセージ" links: @@ -3413,15 +3417,20 @@ ja: unread_with_count: "未読 (%{count})" archive: "アーカイブ" tags: - header_link_title: "すべてのタグ" header_link_text: "タグ" categories: - header_link_title: "すべてのカテゴリ" header_link_text: "カテゴリ" community: - header_link_title: "ホーム" header_link_text: "コミュニティ" links: + about: + content: "サイト情報" + admin: + content: "管理者" + badges: + content: "バッジ" + faq: + content: "FAQ" tracked: content: "追跡中" groups: @@ -4566,7 +4575,6 @@ ja: other: "すべての投稿を削除できません。%{count} 日以上経過した投稿があります。(delete_user_max_post_age の設定)" cant_delete_all_too_many_posts: other: "すべての投稿を削除することはできませんでした。ユーザーは %{count} 件以上投稿しています。(delete_all_posts_max)" - delete_confirm: "既存のディスカッションからコンテンツを削除しないようにするには、通常、ユーザーを削除するよりも匿名化することが推奨されます。

    このユーザーを削除してもよろしいですか?この決定は永久的です!" delete_and_block: "このメールと IP アドレスを削除してブロックする" delete_dont_block: "削除のみ" deleting_user: "ユーザーを削除中…" @@ -4696,7 +4704,6 @@ ja: recommended: "ニーズに合わせて次のテキストをカスタマイズすることをお勧めします。" show_overriden: "上書き部分のみ表示" locale: "言語:" - fallback_locale_warning: "%{fallback} に基づいて言語を編集しています。%{fallback} をインターフェース言語として選択したユーザーに変更内容は表示されません。" more_than_50_results: "結果が 50 件以上あります。検索を絞り込んでください。" settings: show_overriden: "上書き部分のみ表示" diff --git a/config/locales/client.ko.yml b/config/locales/client.ko.yml index 4df54e0c87..c5eddf30b1 100644 --- a/config/locales/client.ko.yml +++ b/config/locales/client.ko.yml @@ -39,7 +39,7 @@ ko: long_date_with_year_without_time: "'YY MMM D" long_date_without_year_with_linebreak: "MMM D
    LT" long_date_with_year_with_linebreak: "'YY MMM D
    LT" - wrap_ago: "%{date}전" + wrap_ago: "%{date} 전" wrap_on: "%{date}" tiny: half_a_minute: "< 1분" @@ -91,34 +91,34 @@ ko: other: "%{count}달 후" x_years: other: "%{count}년 후" - previous_month: "지난 달" + previous_month: "지난달" next_month: "다음 달" placeholder: 날짜 from_placeholder: "시작 날짜" - to_placeholder: "현재까지" + to_placeholder: "종료 날짜" share: - topic_html: '글: %{topicTitle}' + topic_html: '주제: %{topicTitle}' close: "닫기" - twitter: "트위터에 공유" - facebook: "페이스북에 공유" + twitter: "Twitter에 공유" + facebook: "Facebook에 공유" email: "이메일로 공유" url: "URL 복사 및 공유" action_codes: - public_topic: "이 글을 %{when}에 공개" - open_topic: "%{when}에 글로 변환되었습니다." - private_topic: "이 글을 개인 메시지로 설정 %{when}" - split_topic: "이 글을 %{when}에 분리" - invited_user: "%{when}에 %{who}님이 초대됨" - invited_group: "%{when}에 %{who}님이 초대됨" - user_left: "%{who}님이 %{when}에 이 메시지에서 자신을 제거 했습니다" - removed_user: "%{when}에 %{who}님이 삭제됨" - removed_group: "%{when}에 %{who}님이 삭제됨" - autobumped: "%{when}에 자동으로 끌어 올려짐" + public_topic: "%{when}에 이 주제가 공개됨" + open_topic: "%{when}에 주제로 변환됨" + private_topic: "%{when}에 이 주제가 개인 메시지로 설정됨" + split_topic: "%{when}에 이 주제가 분리됨" + invited_user: "%{when}에 %{who} 님이 초대됨" + invited_group: "%{when}에 %{who} 님이 초대됨" + user_left: "%{who} 님이 %{when}에 이 메시지에서 자신을 제거함" + removed_user: "%{when}에 %{who} 님이 제거됨" + removed_group: "%{when}에 %{who} 님이 제거됨" + autobumped: "%{when}에 자동으로 끌어 올림" autoclosed: - enabled: "%{when}에 닫힘" + enabled: "%{when}에 종료됨" disabled: "%{when}에 열림" closed: - enabled: "%{when}에 닫힘" + enabled: "%{when}에 종료됨" disabled: "%{when}에 열림" archived: enabled: "%{when}에 보관됨" @@ -130,76 +130,79 @@ ko: enabled: "%{when}에 전체적으로 고정됨" disabled: "%{when}에 고정 해제됨" visible: - enabled: "%{when}에 목록에 게시" - disabled: "%{when}에 목록에서 감춤" + enabled: "%{when}에 목록에 게시됨" + disabled: "%{when}에 목록에서 숨김" banner: enabled: "%{when}에 배너를 만들었습니다. 사용자가 닫을 때까지 모든 페이지의 상단에 나타납니다." - disabled: "%{when}에 이 배너를 제거했습니다. 더 이상 모든 페이지의 상단에 표시되지 않습니다." - forwarded: "위의 이메일을 전달했습니다." - topic_admin_menu: "글 관리" + disabled: "%{when}에 이 배너를 제거했습니다. 이제 모든 페이지의 상단에 표시되지 않습니다." + forwarded: "위 이메일을 전달했습니다." + topic_admin_menu: "주제 관리" skip_to_main_content: "메인 콘텐츠로 건너뛰기" - wizard_required: "새로운 Discourse에 오신것을 환영합니다! 설치 마법사로 시작합니다 ✨" - emails_are_disabled: "관리자에 의해 모든 이메일의 발신이 비활성화 되었습니다. 어떤 종류의 이메일 알림도 전송되지 않습니다." + emails_are_disabled: "관리자에 의해 모든 이메일의 발신이 비활성화되었습니다. 어떤 종류의 이메일 알림도 전송되지 않습니다." software_update_prompt: - message: "사이트를 업데이트했습니다. 새로 고침하세요. 그렇지 않으면 예기치 않은 동작이 발생할 수 있습니다." - dismiss: "읽음" + message: "사이트가 업데이트되어 새로고침이 필요합니다. 그렇지 않으면 예기치 않은 동작이 발생할 수 있습니다." + dismiss: "무시" bootstrap_mode_enabled: - other: "쉬운 시작을 위해 부트스트랩 모드로 구동 되었습니다. 모든 새로운 사용자에게 회원 레벨 1이 부여되고 이메일로 매일 요약 전송이 활성화됩니다. %{count}명의 사용자가 가입하면 자동으로 해제됩니다." - bootstrap_mode_disabled: "Bootstrap 모드가 24시간 이내에 해제됩니다." + other: "신규 사이트를 편리하게 출시할 수 있도록 부트스트랩 모드로 구동합니다. 모든 신규 사용자는 신뢰 레벨 1이 부여되며 매일 요약 이메일을 받게 됩니다. %{count}명의 사용자가 가입하면 이 기능은 자동으로 비활성화됩니다." + bootstrap_mode_disabled: "부트스트랩 모드가 24시간 내에 해제됩니다." + bootstrap_invite_button_title: "초대장 보내기" + bootstrap_wizard_link_title: "설정 마법사 완료" themes: - default_description: "기본" + default_description: "디폴트" broken_theme_alert: "테마/구성 요소에 오류가 있어 사이트가 작동하지 않을 수 있습니다." - only_admins: "(이 메시지는 사이트 관리자에게만 표시됩니다.)" + only_admins: "(이 메시지는 사이트 관리자에게만 표시됩니다)" s3: regions: - ap_northeast_1: "아시아 태평양 (도쿄)" - ap_northeast_2: "아시아 태평양 (서울)" - ap_east_1: "아시아 태평양 (홍콩)" - ap_south_1: "아시아 태평양 (뭄바이)" - ap_southeast_1: "아시아 태평양 (싱가폴)" - ap_southeast_2: "아시아 태평양 (시드니)" - ca_central_1: "캐나다 (중부)" - cn_north_1: "중국 (베이징)" + ap_northeast_1: "아시아 태평양(도쿄)" + ap_northeast_2: "아시아 태평양(서울)" + ap_east_1: "아시아 태평양(홍콩)" + ap_south_1: "아시아 태평양(뭄바이)" + ap_southeast_1: "아시아 태평양(싱가폴)" + ap_southeast_2: "아시아 태평양(시드니)" + ca_central_1: "캐나다(중부)" + cn_north_1: "중국(베이징)" cn_northwest_1: "중국 (닝샤)" - eu_central_1: "EU (프랑크푸르트)" - eu_north_1: "EU (스톡홀름)" - eu_south_1: "EU (밀라노)" - eu_west_1: "EU (아일랜드)" - eu_west_2: "EU (런던)" - eu_west_3: "EU (파리)" - sa_east_1: "남아메리카 (상파울루)" - us_east_1: "미국 동부 (버지니아 북부)" - us_east_2: "미국 동부 (오하이오)" - us_gov_east_1: "AWS GovCloud (미국 동부)" - us_gov_west_1: "AWS GovCloud (미국 서부)" - us_west_1: "미국 서부 (N. 캘리포니아)" - us_west_2: "미국 서부 (오리건)" + eu_central_1: "EU(프랑크푸르트)" + eu_north_1: "EU(스톡홀름)" + eu_south_1: "EU(밀라노)" + eu_west_1: "EU(아일랜드)" + eu_west_2: "EU(런던)" + eu_west_3: "EU(파리)" + 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: "미국 서부(오리건)" clear_input: "입력 지우기" - edit: "이 글의 제목과 카테고리 편집" - expand: "확장" + edit: "이 주제의 제목과 카테고리 편집" + expand: "펼치기" not_implemented: "죄송합니다. 아직 사용할 수 없는 기능입니다." no_value: "아니오" yes_value: "예" + ok_value: "확인" + cancel_value: "취소" submit: "확인" generic_error: "죄송합니다. 오류가 발생했습니다." - generic_error_with_reason: "오류가 발생했습니다: %{error}" + generic_error_with_reason: "오류가 발생했습니다. %{error}" sign_up: "회원가입" log_in: "로그인" age: "나이" - joined: "가입" + joined: "가입일" admin_title: "관리자" - show_more: "더 보기" + show_more: "자세히 보기" show_help: "옵션" links: "링크" links_lowercase: other: "링크" faq: "자주하는 질문" guidelines: "가이드라인" - privacy_policy: "개인 정보 보호 정책" - privacy: "개인 정보 처리 방침" - tos: "서비스 약관" + privacy_policy: "개인정보 취급방침" + privacy: "개인정보" + tos: "이용약관" rules: "규칙" - conduct: "행동 강령" + conduct: "준수 사항" mobile_view: "모바일 보기" desktop_view: "데스크톱 보기" or: "또는" @@ -207,34 +210,34 @@ ko: read_more: "더 보기" more: "더 보기" x_more: - other: "%{count}개 더보기" - never: "전혀" + other: "%{count}개 더 보기" + never: "거부" every_30_minutes: "30분마다" - every_hour: "매 시간마다" + every_hour: "매시간" daily: "매일" weekly: "매주" every_month: "매달" every_six_months: "6개월마다" max_of_count: "최대 %{count}" character_count: - other: "%{count} 글자" + other: "%{count}자" period_chooser: aria_label: "기간별 필터링" related_messages: title: "관련 메시지" - see_all: '@%{username}의 모든 메시지 보기...' + see_all: '@%{username} 님의 모든 메시지보기…' suggested_topics: - title: "주요 글" - pm_title: "제안 메시지" + title: "제안된 주제" + pm_title: "제안된 메시지" about: - simple_title: "소개" - title: "소개: %{title}" + simple_title: "정보" + title: "정보: %{title}" stats: "사이트 통계" our_admins: "관리자" our_moderators: "관리자" moderators: "관리자" stat: - all_time: "전체" + all_time: "전체 기간" last_day: "지난 24시간" last_7_days: "지난 7일" last_30_days: "지난 30일" @@ -244,39 +247,39 @@ ko: user_count: "사용자" active_user_count: "활성 사용자" contact: "문의하기" - contact_info: "이 사이트에 영향을 미치는 중대한 문제 또는 긴급한 문제가 발생하는 경우 %{contact_info} 에 문의하십시오." + contact_info: "이 사이트에 영향을 미치는 중대하거나 긴급한 문제가 발생한 경우 %{contact_info}으로 문의하세요." bookmarked: title: "북마크" - edit_bookmark: "북마크 수정" - clear_bookmarks: "북마크 취소" + edit_bookmark: "북마크 편집" + clear_bookmarks: "북마크 지우기" help: - bookmark: "이 글의 첫 번째 게시물을 북마크하려면 클릭하세요." - edit_bookmark: "이 글에 대한 북마크를 편집하려면 클릭하십시오." - edit_bookmark_for_topic: "이 글에 대한 북마크를 편집하려면 클릭하십시오." - unbookmark: "이 항목의 모든 북마크를 제거하려면 클릭하십시오." - unbookmark_with_reminder: "이 항목의 모든 북마크 및 미리 알림을 제거하려면 클릭하십시오." + bookmark: "이 주제의 첫 번째 게시물을 북마크하려면 클릭하세요" + edit_bookmark: "이 주제의 북마크를 편집하려면 클릭하세요" + edit_bookmark_for_topic: "이 주제의 북마크를 편집하려면 클릭하세요" + unbookmark: "이 주제의 모든 북마크를 제거하려면 클릭하세요" + unbookmark_with_reminder: "이 주제의 모든 북마크 및 미리 알림을 제거하려면 클릭하세요" bookmarks: - created: "이 글을 북마크했습니다. %{name}" + created: "이 게시물을 북마크했습니다. %{name}" create: "북마크 만들기" - edit: "북마크 수정" - not_bookmarked: "이 글을 북마크" - remove_reminder_keep_bookmark: "알림 제거 및 북마크 유지" - created_with_reminder: "알림 %{date}으로 이 글을 북마크했습니다. %{name}" - remove: "북마크 삭제" + edit: "북마크 편집" + not_bookmarked: "이 게시물 북마크하기" + remove_reminder_keep_bookmark: "미리 알림 제거 및 북마크 유지" + created_with_reminder: "%{date} 미리 알림과 함께 이 게시물을 북마크했습니다. %{name}" + remove: "북마크 제거" delete: "북마크 삭제" - confirm_delete: "이 북마크를 삭제 하시겠습니까? 알림도 삭제됩니다." - confirm_clear: "이 글의 모든 북마크를 지우시겠습니까?" + confirm_delete: "이 북마크를 삭제할까요? 미리 알림도 삭제됩니다." + confirm_clear: "이 주제의 모든 북마크를 지울까요?" save: "저장" - no_timezone: '아직 시간대를 설정하지 않았습니다. 미리 알림을 설정할 수 없습니다. 프로필에서 설정 하세요.' - invalid_custom_datetime: "입력한 날짜와 시간이 잘못되었습니다. 다시 시도하십시오." - list_permission_denied: "이 사용자의 북마크를 볼 수있는 권한이 없습니다." - no_user_bookmarks: "북마크된 게시물이 없습니다. 북마크를 사용하면 특정 게시물을 빠르게 확인 할 수 있습니다." + no_timezone: '아직 시간대를 설정하지 않아 미리 알림을 설정할 수 없습니다. 프로필에서 설정하세요.' + invalid_custom_datetime: "입력한 날짜와 시간이 유효하지 않습니다. 다시 시도하세요." + list_permission_denied: "이 사용자의 북마크를 볼 권한이 없습니다." + no_user_bookmarks: "북마크된 게시물이 없습니다. 북마크를 사용하면 특정 게시물을 빠르게 확인할 수 있습니다." auto_delete_preference: never: "북마크 유지" when_reminder_sent: "북마크 삭제" - on_owner_reply: "답장후 북마크 삭제" - clear_reminder: "북마크 유지 및 알림 지우기" - search_placeholder: "이름, 글 제목 또는 내용으로 북마크 검색" + on_owner_reply: "댓글 작성 후 북마크 삭제" + clear_reminder: "북마크 유지 및 미리 알림 지우기" + search_placeholder: "이름, 주제 또는 게시물 콘텐츠로 북마크 검색" search: "검색" reminders: today_with_time: "오늘 %{time}" @@ -286,30 +289,30 @@ ko: copy_codeblock: copied: "복사되었습니다!" copy: "클립보드에 코드 복사" - fullscreen: "전체 화면으로 코드 표시" + fullscreen: "전체화면으로 코드 표시" drafts: - label: "임시저장" - label_with_count: "임시 보관함 (%{count})" - resume: "이력서" - remove: "삭제" - remove_confirmation: "이 초안을 삭제 하시겠습니까?" - new_topic: "새 글 초안" + label: "초안" + label_with_count: "초안(%{count})" + resume: "재개" + remove: "제거" + remove_confirmation: "이 초안을 삭제할까요?" + new_topic: "새 주제 초안" new_private_message: "새 개인 메시지 초안" - topic_reply: "임시 댓글" + topic_reply: "초안 댓글" abandon: - confirm: "이 항목에 대한 초안이 진행중입니다. 무엇을 하고 싶습니까?" + confirm: "이 주제에 대한 초안이 있습니다. 어떻게 진행할까요?" yes_value: "버리기" no_value: "편집 재개" topic_count_categories: - other: "%{count}개의 새글 또는 업데이트 된 글 보기" + other: "%{count}개의 새 주제 또는 업데이트된 주제 보기" topic_count_latest: - other: "%{count}개의 새글 또는 업데이트 된 글 보기" + other: "%{count}개의 새 주제 또는 업데이트된 주제 보기" topic_count_unseen: - other: "%{count}개의 새글 또는 업데이트 된 글 보기" + other: "%{count}개의 새 주제 또는 업데이트된 주제 보기" topic_count_unread: - other: "%{count}개의 읽지 않은 글 보기" + other: "%{count}개의 읽지 않은 주제 보기" topic_count_new: - other: "%{count}개의 새로운 글 보기" + other: "%{count}개의 새 주제 보기" preview: "미리보기" cancel: "취소" deleting: "삭제 중..." @@ -321,7 +324,7 @@ ko: uploading_filename: "업로드 중: %{filename}..." processing_filename: "처리 중: %{filename}..." clipboard: "클립보드" - uploaded: "업로드 되었습니다!" + uploaded: "업로드되었습니다!" pasting: "붙여넣기 중..." enable: "활성화" disable: "비활성화" @@ -332,27 +335,27 @@ ko: switch_to_anon: "익명 모드 시작" switch_from_anon: "익명 모드 종료" banner: - close: "이 배너를 닫습니다" + close: "이 배너 해제" edit: "편집" pwa: - install_banner: "이 장치에 %{title} 바로가기를 만드시겠습니까?" + install_banner: "이 디바이스에 %{title} 배너를 설치할까요?" choose_topic: - none_found: "글을 찾을 수 없습니다." + none_found: "주제가 없습니다." title: search: "글 검색" - placeholder: "여기에 글 제목, URL 또는 ID를 입력하십시오" + placeholder: "여기에 주제 제목, URL 또는 ID를 입력하세요" choose_message: none_found: "메시지가 없습니다." title: search: "메시지 검색" - placeholder: "여기에 글 제목, URL 또는 ID를 입력하십시오" + placeholder: "여기에 메시지 제목, URL 또는 ID를 입력하세요" review: - order_by: "정렬" + order_by: "정렬 기준" date_filter: "작성된 기간" - in_reply_to: "다음에 댓글" + in_reply_to: "답장 대상" explain: - why: "이 항목이 대기열에있는 이유 설명" - title: "검토 가능한 점수" + why: "이 항목이 대기열에 있는 이유 설명" + title: "검토 가능 점수" formula: "공식" subtotal: "소계" total: "합계" @@ -360,26 +363,26 @@ ko: score_to_hide: "게시물 숨기기 점수" take_action_bonus: name: "조치를 취했습니다" - title: "관리자가 신고를 처리하면 보너스가 부여됩니다." + title: "운영진이 신고를 처리하면 보너스가 주어집니다." user_accuracy_bonus: name: "사용자 정확도" - title: "신고가 처리된 경우 신고자 에게는 보너스가 주어집니다." + title: "신고가 수락된 경우 신고자에게 보너스가 주어집니다." trust_level_bonus: - name: "회원 레벨" - title: "회원 레벨이 놓은 사용자가 만든 검토 항목의 점수가 높습니다." + name: "신뢰 레벨" + title: "신뢰 레벨이 더 높은 사용자가 만든 검토 가능 항목은 더 높은 점수를 받습니다." type_bonus: name: "유형 보너스" - title: "특정한 검토 유형에는 관리자가 보너스를 할당하여 우선 순위를 높일 수 있습니다." - stale_help: "이 검토 항목은 %{username}님에 의해 처리되었습니다." + title: "특정 검토 가능 유형에는 운영진이 보너스를 할당하여 우선순위를 높일 수 있습니다." + stale_help: "이 검토 가능 항목은 %{username} 님이 해결했습니다." claim_help: - optional: "다른 사용자가 처리하지 못하도록 이 항목을 지정 할 수 있습니다." - required: "항목을 검토하려면 먼저 항목을 검토 요청을 해야합니다." - claimed_by_you: "이 항목을 요청했으며 검토 할 수 있습니다." - claimed_by_other: "이 항목은 %{username}님에 의해서만 처리 될 수 있습니다." + optional: "다른 사용자가 검토하지 못하도록 이 항목을 독점할 수 있습니다." + required: "항목을 검토하려면 먼저 항목을 독점해야 합니다." + claimed_by_you: "이 항목을 독점했으며 이제 검토할 수 있습니다." + claimed_by_other: "이 항목은 %{username} 님만 검토할 수 있습니다." claim: - title: "이 글을 클레임" + title: "이 주제 독점하기" unclaim: - help: "이 클레임 제거" + help: "이 독점 신청 제거" awaiting_approval: "승인 대기중" delete: "삭제" settings: @@ -387,25 +390,25 @@ ko: save_changes: "변경사항 저장" title: "설정" priorities: - title: "검토 가능한 우선 순위" + title: "검토 가능 우선순위" moderation_history: "관리 히스토리" view_all: "모두 보기" - grouped_by_topic: "글 기준으로 그룹화" + grouped_by_topic: "주제 기준으로 그룹화됨" none: "검토 할 항목이 없습니다." - view_pending: "보류중 항목 보기" + view_pending: "보류 중 항목 보기" topic_has_pending: - other: "이 글에는 승인 대기중인 %{count}개의 댓글이 있습니다" + other: "이 주제에는 승인 보류 중인 %{count} 개의 게시물이 있습니다" title: "검토" - topic: "글:" - filtered_topic: "한 글에서 검토 가능한 콘텐츠로 필터링했습니다." + topic: "주제:" + filtered_topic: "한 주제에서 검토 가능 콘텐츠로 필터링했습니다." filtered_user: "사용자" filtered_reviewed_by: "검토자" - show_all_topics: "모든 글 보기" + show_all_topics: "모든 주제 보기" deleted_post: "(게시물 삭제됨)" deleted_user: "(사용자 삭제됨)" user: - bio: "바이오" - website: "웹 사이트" + bio: "소개" + website: "웹사이트" username: "사용자 이름" email: "이메일" name: "이름" @@ -413,28 +416,28 @@ ko: reject_reason: "이유" user_percentage: summary: - other: "%{agreed}, %{disagreed}, %{ignored} (최근 %{count}개의 신고중)" + other: "%{agreed}, %{disagreed}, %{ignored} (최근 %{count}개의 신고 중)" agreed: - other: "%{count}% 동의" + other: "동의 %{count}%" disagreed: - other: "%{count}% 동의안함" + other: "동의 안 함 %{count}%" ignored: - other: "%{count}% 무시" + other: "무시 %{count}%" topics: - topic: "글" + topic: "주제" reviewable_count: "수" reported_by: "신고자" - deleted: "[삭제된 글]" + deleted: "[삭제된 주제]" original: "(원래 글)" - details: "세부 정보" + details: "상세 정보" unique_users: - other: "회원 %{count}명" + other: "사용자 %{count}명" replies: - other: "댓글 %{count}" + other: "댓글 %{count}개" edit: "편집" save: "저장" cancel: "취소" - new_topic: "이 항목을 승인하면 새 글이 만들어집니다." + new_topic: "이 항목을 승인하면 새 주제가 만들어집니다." filters: all_categories: "(모든 카테고리)" type: @@ -446,19 +449,19 @@ ko: category: "카테고리" orders: score: "점수" - score_asc: "점수 (역순)" - created_at: "작성 날짜" - created_at_asc: "작성 날짜 (역순)" + score_asc: "점수(역순)" + created_at: "작성일" + created_at_asc: "작성일(역순)" priority: - title: "최소 우선 순위" - any: "(모든)" + title: "최소 우선순위" + any: "(모두)" low: "낮음" medium: "중간" high: "높음" conversation: view_full: "전체 대화 보기" scores: - about: "이 점수는 보고자의 회원 레벨, 이전 신고의 정확도 및 보고되는 항목의 우선 순위를 기준으로 계산됩니다." + about: "이 점수는 보고자의 신뢰 레벨, 이전 신고의 정확도 및 신고된 항목의 우선순위를 기준으로 계산됩니다." score: "점수" date: "날짜" type: "유형" @@ -467,7 +470,7 @@ ko: reviewed_by: "검토자" statuses: pending: - title: "보류중" + title: "보류 중" approved: title: "승인됨" rejected: @@ -482,25 +485,25 @@ ko: title: "(모두)" types: reviewable_flagged_post: - title: "신고된 글" + title: "신고된 게시물" flagged_by: "신고자" reviewable_queued_topic: - title: "대기중인 글" + title: "대기 중인 주제" reviewable_queued_post: - title: "대기중인 글" + title: "대기 중인 게시물" reviewable_user: title: "사용자" reviewable_post: - title: "글" + title: "게시물" approval: title: "승인이 필요한 게시물" - description: "새로운 게시글이 있습니다. 그러나 이 게시글이 보여지려면 운영자의 승인이 필요합니다." + description: "새 게시물이 있습니다. 그러나 이 게시물이 보여지려면 운영자의 승인이 필요합니다. 잠시 기다려 주세요." pending_posts: - other: "승인 대기중인 게시물이 %{count}개 있습니다." + other: "보류 중인 게시물이 %{count}개 있습니다." ok: "확인" - example_username: "사용자명" + example_username: "아이디" reject_reason: - title: "이 사용자를 금지하는 이유는 무엇입니까?" + title: "이 사용자를 거부하는 이유가 무엇인가요?" send_email: "거부 이메일 보내기" relative_time_picker: minutes: @@ -510,17 +513,17 @@ ko: days: other: "일" months: - other: "월" + other: "개월" years: other: "년" relative: "상대적" time_shortcut: now: "지금" - later_today: "오늘 늦게" + later_today: "오늘 중" next_business_day: "다음 영업일" tomorrow: "내일" post_local_date: "게시 날짜" - later_this_week: "이번 주말" + later_this_week: "이번 주 중" this_weekend: "이번 주말" start_of_next_business_week: "월요일" start_of_next_business_week_alt: "다음 월요일" @@ -536,71 +539,71 @@ ko: relative: "상대 시간" none: "필요 없음" never: "절대" - last_custom: "마지막 맞춤 시간" + last_custom: "마지막 사용자 지정 시간" custom: "사용자 지정 날짜 및 시간" - select_timeframe: "시간대 선택" + select_timeframe: "기간 선택" user_action: - user_posted_topic: "%{user} 사용자가 글 작성" - you_posted_topic: "사용자님글 작성" - user_replied_to_post: "%{user}님이 %{post_number}에 글을 남김" - you_replied_to_post: "사용자님%{post_number}에 글을 남김" - user_replied_to_topic: "%{user}님이 에 댓글을 작성했습니다" - you_replied_to_topic: "사용자님에 댓글을 작성했습니다" - user_mentioned_user: "%{user}님이 %{another_user}를 멘션함" - user_mentioned_you: "%{user}님이 를 멘션함" - you_mentioned_user: "내가 %{another_user}님을 멘션함" - posted_by_user: "%{user}님이 작성" - posted_by_you: "사용자님이 작성" - sent_by_user: "%{user}님이 보냄" - sent_by_you: "가 보냄" + user_posted_topic: "%{user} 님이 주제를 게시함" + you_posted_topic: "내가 주제를 게시함" + user_replied_to_post: "%{user} 님이 %{post_number}에 댓글을 남김" + you_replied_to_post: "내가 %{post_number}에 댓글을 남김" + user_replied_to_topic: "%{user} 님이 주제에 댓글을 남김" + you_replied_to_topic: "내가 주제에 댓글을 남김" + user_mentioned_user: "%{user} 님이 %{another_user} 님을 멘션함" + user_mentioned_you: "%{user} 님이 를 멘션함" + you_mentioned_user: "내가 %{another_user} 님을 멘션함" + posted_by_user: "%{user} 님이 게시함" + posted_by_you: "내가 게시함" + sent_by_user: "%{user} 님이 전송함" + sent_by_you: "내가 전송함" directory: - username: "사용자명" - filter_name: "사용자명으로 필터링" + username: "아이디" + filter_name: "아이디로 필터링" title: "사용자" - likes_given: "줌" + likes_given: "보냄" likes_received: "받음" topics_entered: "읽음" - topics_entered_long: "읽은 글" + topics_entered_long: "읽은 주제" time_read: "읽은 시간" topic_count: "글" - topic_count_long: "글 작성됨" + topic_count_long: "생성한 주제" post_count: "댓글" - post_count_long: "댓글 게시됨" + post_count_long: "게시된 댓글" no_results: "결과가 없습니다." days_visited: "방문" days_visited_long: "방문 일수" posts_read: "읽음" - posts_read_long: "게시물 읽음" - last_updated: "마지막 업데이트 :" + posts_read_long: "읽은 게시물" + last_updated: "마지막 업데이트:" total_rows: other: "사용자 %{count}명" edit_columns: - title: "디렉토리 열 편집" + title: "디렉터리 열 편집" save: "저장" - reset_to_default: "기본값으로 재설정" + reset_to_default: "디폴트로 리셋" group: all: "모든 그룹" group_histories: actions: change_group_setting: "그룹 설정 변경" add_user_to_group: "사용자 추가" - remove_user_from_group: "사용자 삭제" - make_user_group_owner: "소유자로 지정하기" - remove_user_as_group_owner: "소유자 지정 취소하기" + remove_user_from_group: "사용자 제거" + make_user_group_owner: "소유자로 지정" + remove_user_as_group_owner: "소유자 지정 취소" groups: member_added: "추가됨" - member_requested: "요청됨" + member_requested: "요청됨:" add_members: title: "%{group_name}에 사용자 추가" - description: "그룹에 초대 할 사용자 목록을 입력하거나 쉼표로 구분해 목록에 붙여 넣으십시오." + description: "그룹에 초대할 사용자 목록을 입력하거나 쉼표로 구분하여 목록에 붙여 넣으세요." usernames_placeholder: "아이디" - usernames_or_emails_placeholder: "사용자 이름 또는 이메일" + usernames_or_emails_placeholder: "아이디 또는 이메일" notify_users: "사용자에게 알림" set_owner: "사용자를 이 그룹의 소유자로 설정" requests: title: "요청" reason: "이유" - accept: "동의" + accept: "수락" accepted: "수락됨" deny: "거부" denied: "거부됨" @@ -612,39 +615,39 @@ ko: full_name: "전체 이름" add_members: "사용자 추가" invite_members: "초대" - delete_member_confirm: "'%{group}'그룹에서 '%{username}' 사용자를 제거 하시겠습니까?" + delete_member_confirm: "'%{group}' 그룹에서 '%{username}' 님을 제거할까요?" profile: title: 프로필 interaction: - title: 상호 작용 + title: 상호작용 posting: 게시 notification: 알림 email: title: "이메일" - status: "IMAP을 통해 %{old_emails} / %{total_emails} 동기화" - enable_smtp: "SMTP 사용" + status: "IMAP을 통해 %{old_emails} / %{total_emails} 동기화됨" + enable_smtp: "SMTP 활성화" enable_imap: "IMAP 활성화" test_settings: "테스트 설정" save_settings: "설정 저장" last_updated: "마지막 업데이트:" - last_updated_by: "에 의해" - settings_required: "모든 설정은 필수입니다. 유효성 검사 전에 모든 필드를 입력하십시오." + last_updated_by: "업데이트한 사용자:" + settings_required: "모든 설정은 필수입니다. 유효성 검사 전에 모든 필드를 입력하세요." smtp_settings_valid: "SMTP 설정이 유효합니다." smtp_title: "SMTP" - smtp_instructions: "그룹에 대해 SMTP를 활성화하면 그룹의받은 편지함에서 보낸 모든 아웃 바운드 이메일이 포럼에서 보낸 다른 이메일에 대해 구성된 메일 서버 대신 여기에 지정된 SMTP 설정을 통해 전송됩니다." + smtp_instructions: "그룹에 SMTP를 활성화하면 그룹의 받은 편지함에서 보낸 모든 아웃바운드 이메일이 포럼에서 보낸 다른 이메일에 대해 구성된 메일 서버 대신 여기에 지정된 SMTP 설정을 통해 전송됩니다." imap_title: "IMAP" imap_additional_settings: "추가 설정" - imap_instructions: '그룹에 대해 IMAP을 활성화하면 그룹의 받은 편지함과 제공된 IMAP 서버 및 편지함간에 이메일이 동기화됩니다. IMAP을 사용하려면 먼저 유효한 인증 정보로 SMTP를 사용하도록 설정해야합니다. SMTP에 사용되는 이메일 사용자 이름과 비밀번호는 IMAP에 사용됩니다. 자세한 내용은기능 안내를 참조하십시오.' - imap_alpha_warning: "경고: 이것은 알파 단계 기능입니다. Gmail만 공식적으로 지원됩니다. 자신의 책임하에 사용하십시오!" + imap_instructions: '그룹에 IMAP을 활성화하면 그룹의 받은 편지함과 제공된 IMAP 서버 및 편지함 간에 이메일이 동기화됩니다. IMAP을 사용하려면 먼저 테스트를 마친 유효한 크리덴셜로 SMTP를 사용하도록 설정해야 합니다. SMTP에 사용되는 이메일 아이디와 비밀번호는 IMAP에서 사용됩니다. 자세한 내용은 Discourse Meta의 기능 안내를 참조하세요.' + imap_alpha_warning: "경고: 이것은 알파 단계 기능입니다. Gmail만 공식적으로 지원됩니다. 위험을 감수할 수 있는지 신중히 생각 후 사용하세요." imap_settings_valid: "IMAP 설정이 유효합니다." - smtp_disable_confirm: "SMTP를 사용하지 않도록 설정하면 모든 SMTP 및 IMAP 설정이 재설정되고 관련 기능이 비활성화됩니다.계속하시겠습니까?" - imap_disable_confirm: "IMAP을 사용하지 않도록 설정하면 모든 IMAP 설정이 재설정되고 관련 기능이 비활성화됩니다.계속하시겠습니까?" - imap_mailbox_not_selected: "이 IMAP 구성에 대해 사서함을 선택해야합니다. 그렇지 않으면 사서함이 동기화되지 않습니다!" + smtp_disable_confirm: "SMTP를 비활성화하면 모든 SMTP 및 IMAP 설정이 리셋되고 관련 기능이 비활성화됩니다. 계속할까요?" + imap_disable_confirm: "IMAP을 비활성화하면 모든 IMAP 설정이 리셋되고 관련 기능이 비활성화됩니다. 계속할까요?" + imap_mailbox_not_selected: "이 IMAP 구성에 대해 메일함을 선택해야합니다. 그렇지 않으면 메일함이 동기화되지 않습니다!" prefill: title: "다음 설정으로 미리 채우기:" - gmail: "지메일" + gmail: "Gmail" credentials: - title: "자격 증명" + title: "크리덴셜" smtp_server: "SMTP 서버" smtp_port: "SMTP 포트" smtp_ssl: "SMTP에 SSL 사용" @@ -655,75 +658,75 @@ ko: password: "비밀번호" settings: title: "설정" - allow_unknown_sender_topic_replies: "알 수 없는 발신자 주제 응답을 허용합니다." - allow_unknown_sender_topic_replies_hint: "알 수없는 발신자가 그룹 글에 댓글을 작성 할 수 있습니다. 이 기능이 활성화되지 않은 경우 글에 아직 초대되지 않은 이메일 주소에서 답장하면 새 글이 생성됩니다." - from_alias: "보낸 사람 별칭" + allow_unknown_sender_topic_replies: "알 수 없는 발신자의 주제 댓글을 허용합니다." + allow_unknown_sender_topic_replies_hint: "알 수 없는 발신자가 그룹 주제에 댓글을 달 수 있습니다. 이 기능이 활성화되지 않은 경우 아직 초대되지 않은 이메일 주소에서 주제에 댓글을 달면 새 주제가 생성됩니다." + from_alias: "보내는 사람 별칭" mailboxes: - synchronized: "동기화된 사서함" - none_found: "현재 이메일 계정에 사서함이 없습니다." - disabled: "비활성" + synchronized: "동기화된 메일함" + none_found: "이 이메일 계정에 메일함이 없습니다." + disabled: "비활성화됨" membership: title: 멤버십 - access: 접근 + access: 액세스 categories: - title: 분류 - long_title: "카테고리 기본 알림" - description: "사용자가 이 그룹에 추가되면 카테고리 알림 설정이 기본값으로 설정됩니다. 나중에 변경할 수 있습니다." - watched_categories_instructions: "이 카테고리의 모든 글을 자동으로 봅니다. 그룹 회원에게는 모든 새 글에 대한 알림이 전송되며 새 게시물 수도 글 옆에 표시됩니다." - tracked_categories_instructions: "이 카테고리의 모든 글을 추적하도록 자동설정됩니다. 새로운 게시글의 수가 글 옆에 표시됩니다." - watching_first_post_categories_instructions: "사용자는 이 카테고리의 새 글의 첫 번째 댓글에 대한 알림을받습니다." - regular_categories_instructions: "이 카테고리가 뮤트되면 그룹 회원의 뮤트가 해제됩니다. 사용자가 언급되거나 누군가가 답글을 보내면 사용자에게 알림이 전송됩니다." - muted_categories_instructions: "이 카테고리의 새 글에 대한 알림을 받지 않으며 카테고리 또는 최글 글 페이지에 나타나지 않습니다." + title: 카테고리 + long_title: "카테고리 디폴트 알림" + description: "사용자가 이 그룹에 추가되면 카테고리 알림 설정이 이 디폴트로 설정됩니다. 나중에 변경할 수 있습니다." + watched_categories_instructions: "이 카테고리의 모든 주제를 자동으로 봅니다. 그룹 회원에게 모든 새 게시물과 주제에 대한 알림이 전송되며 새 게시물 수도 주제 옆에 표시됩니다." + tracked_categories_instructions: "이 카테고리의 모든 주제를 자동 추적합니다. 새 게시물 수가 주제 옆에 표시됩니다." + watching_first_post_categories_instructions: "사용자는 이 카테고리에 있는 각 새 주제의 첫 게시물에 대한 알림을 받습니다." + regular_categories_instructions: "이 카테고리가 뮤트되면 그룹 회원의 뮤트가 해제됩니다. 그룹 회원이 멘션되거나 누군가가 댓글을 달면 사용자에게 알림이 전송됩니다." + muted_categories_instructions: "이 카테고리의 새 주제에 대한 알림을 받지 않으며 카테고리 또는 최신 주제 페이지에 나타나지 않습니다." tags: title: 태그 - long_title: "태그 기본 알림" - description: "사용자가 이 그룹에 추가되면 태그 알림 설정이 기본값으로 설정됩니다. 나중에 변경할 수 있습니다." - watched_tags_instructions: "이 태그의 모든 글을 자동으로 봅니다. 그룹 회원에게는 모든 새 글에 대한 알림이 전송되며 새 게시물 수도 글 옆에 표시됩니다." - tracked_tags_instructions: "이 태그의 모든 글을 자동으로 확인합니다. 글 옆에 새 게시물 수가 표시됩니다." - watching_first_post_tags_instructions: "사용자는 이 태그의 새 글과 첫 번째 댓글에 대한 알림을받습니다." - regular_tags_instructions: "이 태그가 뮤트되면 그룹 회원의 뮤트가 해제됩니다. 사용자가 언급되거나 누군가가 답글을 보내면 사용자에게 알림이 전송됩니다." - muted_tags_instructions: "사용자는 이 태그가 있는 새 글에 대한 알림을받지 않으며 최근 글에 표시되지 않습니다." + long_title: "태그 디폴트 알림" + description: "사용자가 이 그룹에 추가되면 태그 알림 설정이 디폴트로 설정됩니다. 나중에 변경할 수 있습니다." + watched_tags_instructions: "이 태그의 모든 주제를 자동으로 봅니다. 그룹 회원에게는 모든 새 게시물과 주제에 대한 알림이 전송되며 새 게시물 수도 주제 옆에 표시됩니다." + tracked_tags_instructions: "이 태그의 모든 주제를 자동 추적합니다. 새 게시물 수가 주제 옆에 표시됩니다." + watching_first_post_tags_instructions: "사용자는 이 태그가 달린 각 새 주제의 첫 게시물에 대한 알림을 받습니다." + regular_tags_instructions: "이 태그가 뮤트되면 그룹 회원의 뮤트가 해제됩니다. 그룹 회원이 멘션되거나 누군가가 댓글을 달면 사용자에게 알림이 전송됩니다." + muted_tags_instructions: "사용자는 이 태그가 있는 새 주제에 대한 어떠한 알림도 받지 않으며 최신 항목에 표시되지 않습니다." logs: title: "로그" - when: "언제" - action: "처리" - acting_user: "활동하는 사용자" + when: "시기" + action: "조치" + acting_user: "조치를 취한 사용자" target_user: "대상 사용자" subject: "제목" - details: "세부 정보" - from: "보내는사람" - to: "받는사람" + details: "상세 정보" + from: "보내는 사람" + to: "받는 사람" permissions: title: "권한" none: "이 그룹과 관련된 카테고리가 없습니다." - description: "이 그룹의 회원은 이 카테고리에 접근 할 수 있습니다." - public_admission: "사용자가 그룹에 자유롭게 가입할 수 있도록 허용합니다. (공개 그룹이어야 함)" - public_exit: "사용자가 스스로 그룹에서 탈퇴 할 수 있도록 허용" + description: "이 그룹의 회원은 이 카테고리에 액세스할 수 있습니다." + public_admission: "사용자가 그룹에 자유롭게 가입하도록 허용(공개 그룹이어야 함)" + public_exit: "사용자가 자유롭게 그룹에서 탈퇴하도록 허용" empty: - posts: "이 그룹에는 아직 회원들이 글을 작성하지 않았습니다." + posts: "이 그룹의 회원이 작성한 게시물이 없습니다." members: "이 그룹에는 회원이 없습니다." requests: "이 그룹에 대한 멤버십 요청이 없습니다." - mentions: "이 그룹에 대한 언급이 없습니다." + mentions: "이 그룹에 대한 멘션이 없습니다." messages: "이 그룹에 대한 메시지가 없습니다." - topics: "이 그룹의 회원이 작성한 글이 없습니다." + topics: "이 그룹의 회원이 작성한 주제가 없습니다." logs: "이 그룹에 대한 로그가 없습니다." add: "추가" join: "가입" - leave: "나가기" + leave: "탈퇴" request: "요청" message: "메시지" - confirm_leave: "이 그룹을 탈퇴 하시겠습니까?" - allow_membership_requests: "사용자가 그룹 소유자에게 멤버십 요청을 보낼 수 있도록 허용 (공개 그룹이어야 함)" - membership_request_template: "멤버십 요청을 보낼 때 사용자에게 표시 할 사용자 지정 템플릿" + confirm_leave: "이 그룹을 탈퇴할까요?" + allow_membership_requests: "사용자가 그룹 소유자에게 멤버십 요청을 보내도록 허용(공개 그룹이어야 함)" + membership_request_template: "멤버십 요청을 보낼 때 사용자에게 표시할 사용자 지정 템플릿" membership_request: - submit: "요청 보내기" - title: "@%{group_name}에 가입 요청하기" - reason: "그룹 소유자에게 왜 이 그룹에 속해야하는지 알립니다." + submit: "요청 제출" + title: "@%{group_name}에 가입 요청" + reason: "그룹 소유자에게 왜 이 그룹에 속해야 하는지 알려주세요" membership: "멤버십" name: "이름" group_name: "그룹 이름" user_count: "사용자" - bio: "그룹 소개" + bio: "그룹 정보" selector_placeholder: "사용자 이름 입력" owner: "소유자" index: @@ -748,78 +751,78 @@ ko: activity: "활동" members: title: "회원" - filter_placeholder_admin: "아이디 혹은 이메일" + filter_placeholder_admin: "아이디 또는 이메일" filter_placeholder: "사용자명" - remove_member: "회원 삭제" - remove_member_description: "이 그룹에서 %{username} 제거" + remove_member: "회원 제거" + remove_member_description: "이 그룹에서 %{username} 님 제거" make_owner: "소유자로 만들기" - make_owner_description: "%{username} 사용자를 이 그룹의 소유자로 만들기" - remove_owner: "소유자로 제거" - remove_owner_description: "%{username}님을 이 그룹의 소유자에서 제거" - make_primary: "기본으로 설정" - make_primary_description: "이 그룹의 %{username}님의 기본 그룹으로 설정합니다" + make_owner_description: "%{username} 님을 이 그룹의 소유자로 만들기" + remove_owner: "소유자에서 제거" + remove_owner_description: "%{username} 님을 이 그룹의 소유자에서 제거" + make_primary: "기본으로 만들기" + make_primary_description: "%{username} 님의 기본 그룹으로 만들기" remove_primary: "기본에서 제거" - remove_primary_description: "이 그룹을 %{username}님의 기본 그룹에서 제거 합니다" - remove_members: "회원 삭제" + remove_primary_description: "%{username} 님의 기본 그룹에서 제거" + remove_members: "회원 제거" remove_members_description: "이 그룹에서 선택한 사용자 제거" make_owners: "소유자로 만들기" - make_owners_description: "선택한 사용자를 이 그룹의 소유자로 지정" + make_owners_description: "선택한 사용자를 이 그룹의 소유자로 만들기" remove_owners: "소유자 제거" remove_owners_description: "선택한 사용자를 이 그룹의 소유자에서 제거" - make_all_primary: "모두 기본으로 설정" - make_all_primary_description: "선택한 모든 사용자의 기본 그룹으로 설정" + make_all_primary: "모두 기본으로 만들기" + make_all_primary_description: "선택한 모든 사용자의 기본 그룹으로 만들기" remove_all_primary: "기본에서 제거" remove_all_primary_description: "이 그룹을 기본 그룹에서 제거" owner: "소유자" primary: "기본" - forbidden: "회원을 볼 수 없습니다." + forbidden: "회원을 볼 권한이 없습니다." no_filter_matches: "검색어와 일치하는 회원이 없습니다." topics: "글" posts: "게시글" mentions: "멘션" messages: "메시지" - notification_level: "그룹 메시지에 대한 기본 알림 수준" + notification_level: "그룹 메시지에 대한 디폴트 알림 수준" alias_levels: - mentionable: "이 그룹은 누가 @mention 할 수 있습니까?" + mentionable: "누가 이 그룹을 @멘션 할 수 있나요?" messageable: "누가 이 그룹에 메시지를 보낼 수 있습니까?" - nobody: "0명" + nobody: "모두 불가" only_admins: "관리자 전용" mods_and_admins: "운영자 및 관리자만" - members_mods_and_admins: "그룹 멤버, 운영자, 관리자만" + members_mods_and_admins: "그룹 회원, 운영자, 관리자만" owners_mods_and_admins: "그룹 소유자, 운영자 및 관리자만" everyone: "모두" notifications: watching: - title: "주시중" - description: "모든 메시지의 모든 새 게시물에 대한 알림을 받게되며 새 댓글 개수가 표시됩니다." + title: "구독" + description: "모든 메시지의 모든 새 게시물에 대한 알림을 받으며 새 댓글 수가 표시됩니다." watching_first_post: - title: "새글 알림" - description: "이 그룹의 새 메시지에 대한 알림을 받지만 메시지에 회신하지는 않습니다." + title: "첫 게시물 구독" + description: "이 그룹의 새 메시지에 대한 알림을 받지만 메시지 답장은 제외합니다." tracking: - title: "알림" - description: "누군가 사용자님을 @name 형식으로 언급하거나 사용자님에게 댓글을 보내면 알림을 받게되며 새 댓글 수가 표시됩니다." + title: "추적" + description: "누군가 나를 @이름 형식으로 멘션하거나 나에게 댓글을 보내면 알림을 받으며 새 댓글 수가 표시됩니다." regular: - title: "보통" - description: "누군가 사용자님을 @name 형식으로 언급하거나 사용자님에게 댓글을 보내면 알림을 받게됩니다." + title: "일반" + description: "누군가 나를 @이름 형식으로 멘션하거나 나에게 댓글을 달면 알림을 받습니다." muted: title: "뮤트" - description: "이 그룹의 메시지에 대한 알림을받지 않습니다." + description: "이 그룹의 메시지에 대한 어떤 알림도 받지 않습니다." flair_url: "아바타 플레어 이미지" flair_upload_description: "20 x 20픽셀보다 작은 정사각형 이미지를 사용하세요." flair_bg_color: "아바타 플레어 배경 색상" - flair_bg_color_placeholder: "(선택 사항) 16진수 색상 값" + flair_bg_color_placeholder: "(선택사항) 16진수 색상 값" flair_color: "아바타 플레어 색상" - flair_color_placeholder: "(선택 사항) 16진수 색상 값" + flair_color_placeholder: "(선택사항) 16진수 색상 값" flair_preview_icon: "미리보기 아이콘" flair_preview_image: "미리보기 이미지" flair_type: icon: "아이콘 선택" image: "이미지 업로드" default_notifications: - modal_title: "사용자 기본 알림" - modal_description: "이 변경 사항을 일괄 적용 하시겠습니까? 기존 사용자 %{count}명의 환경 설정이 변경됩니다." + modal_title: "사용자 디폴트 알림" + modal_description: "이 변경사항을 기존 항목에도 일괄 적용할까요? 기존 사용자 %{count}명의 환경설정이 변경됩니다." modal_yes: "예" - modal_no: "아니요, 앞으로 만 변경 사항을 적용하십시오." + modal_no: "아니요, 지금부터 적용합니다" user_action_groups: "1": "좋아요" "2": "좋아요" @@ -832,7 +835,7 @@ ko: "11": "편집" "12": "보낸 편지함" "13": "받은 편지함" - "14": "보류중" + "14": "보류 중" "15": "임시저장" categories: all: "모든 카테고리" @@ -849,10 +852,10 @@ ko: posts: "게시글" topics: "글" latest: "최신" - subcategories: "하위 카테고리" + subcategories: "서브카테고리" muted: "뮤트된 카테고리" topic_sentence: - other: "%{count}개의 글" + other: "%{count}개의 주제" topic_stat: other: "%{number} / %{unit}" topic_stat_unit: @@ -861,48 +864,48 @@ ko: topic_stat_all_time: other: "총 %{number}개" topic_stat_sentence_week: - other: "지난주 %{count}개의 새 글이 있습니다." + other: "지난주 %{count}개의 새 주제가 있습니다." topic_stat_sentence_month: - other: "지난달 %{count}개의 새 글이 있습니다." - n_more: "카테고리 (%{count}개 더보기)..." + other: "지난달 %{count}개의 새 주제가 있습니다." + n_more: "카테고리(%{count}개 더 보기)..." ip_lookup: title: IP 주소 조회 hostname: 호스트 이름 location: 위치 - location_not_found: (알수없음) - organisation: 소속 + location_not_found: (알 수 없음) + organisation: 조직 phone: 전화 - other_accounts: "현재 IP주소의 다른 계정들:" + other_accounts: "이 IP 주소의 다른 계정:" delete_other_accounts: "%{count}개 삭제" username: "사용자명" trust_level: "TL" read_time: "읽은 시간" - topics_entered: "읽은 글" - post_count: "# 게시물" - confirm_delete_other_accounts: "정말 이 계정들을 삭제하시겠습니까?" + topics_entered: "참여한 주제" + post_count: "게시물 수" + confirm_delete_other_accounts: "이 계정들을 삭제할까요?" powered_by: "MaxMindDB 사용" copied: "복사됨" user_fields: none: "(옵션 선택)" - required: '"%{name}"에 대한 값을 입력하십시오.' + required: '''%{name}''에 대한 값을 입력하세요' user: said: "%{username}:" profile: "프로필" - mute: "알림 끄기" - edit: "환경 설정 편집" + mute: "뮤트" + edit: "환경설정 편집" download_archive: button_text: "모두 다운로드" - confirm: "정말로 작성한 모든 글을 다운로드할까요?" - success: "다운로드가 시작되었습니다. 다운로드 과정이 완료되면 메시지로 알려드리겠습니다." - rate_limit_error: "게시글은 하루에 한번만 다운로드할 수 있습니다. 내일 다시 시도해보세요." - new_private_message: "새로운 메시지" + confirm: "게시물을 다운로드할까요?" + success: "다운로드가 시작되었습니다. 다운로드 과정이 완료되면 메시지로 알림이 전송됩니다." + rate_limit_error: "게시물은 하루에 한 번만 다운로드할 수 있습니다. 내일 다시 시도하세요." + new_private_message: "새 메시지" private_message: "메시지" private_messages: "메시지" user_notifications: filters: filter_by: "필터 기준" all: "모두" - read: "읽기" + read: "읽음" unread: "읽지 않음" ignore_duration_title: "사용자 무시" ignore_duration_username: "사용자명" @@ -910,19 +913,19 @@ ko: ignore_duration_save: "무시" ignore_duration_note: "무시 기간이 만료되면 모든 무시가 자동으로 제거됩니다." ignore_duration_time_frame_required: "기간을 선택하세요" - ignore_no_users: "무시 된 사용자가 없습니다." + ignore_no_users: "무시된 사용자가 없습니다." ignore_option: "무시됨" - ignore_option_title: "이 사용자와 관련된 알림은 수신되지 않으며 해당 글과 댓글이 모두 숨겨집니다." + ignore_option_title: "이 사용자와 관련된 알림을 받지 않으며 해당 사용자의 주제와 댓글이 모두 숨겨집니다." add_ignored_user: "추가..." - mute_option: "알림 꺼짐" - mute_option_title: "이 사용자와 관련된 알림을 받지 않습니다." - normal_option: "보통" - normal_option_title: "이 사용자가 사용자님에게 댓글을 작성 하거나, 인용하거나, 멘션하면 알림이 전송됩니다." + mute_option: "뮤트" + mute_option_title: "이 사용자와 관련된 알림을 모두 받지 않습니다." + normal_option: "일반" + normal_option_title: "이 사용자가 나에게 댓글을 작성하거나, 인용하거나, 멘션하면 알림이 전송됩니다." notification_schedule: title: "알림 일정" - label: "사용자 지정 알림 일정 사용" + label: "사용자 지정 알림 일정 활성화" tip: "이 시간 이외에는 자동으로 '방해 금지' 상태가 됩니다." - midnight: "한밤중" + midnight: "자정" none: "없음" monday: "월요일" tuesday: "화요일" @@ -931,92 +934,93 @@ ko: friday: "금요일" saturday: "토요일" sunday: "일요일" - to: "받는사람" + to: "-" activity_stream: "활동" read: "읽음" read_help: "최근 읽은 주제" - preferences: "환경 설정" + preferences: "환경설정" feature_topic_on_profile: - open_search: "새 글 선택" - title: "글 선택" + open_search: "새 주제 선택" + title: "주제 선택" search_label: "제목으로 글 검색" save: "저장" clear: title: "지우기" - warning: "추천 글을 지우시겠습니까?" + warning: "추천 주제를 지울까요?" use_current_timezone: "현재 시간대 사용" - profile_hidden: "이 사용자의 프로필은 비공개 상태입니다." - expand_profile: "확장" - sr_expand_profile: "프로필 세부정보 펼치기" - collapse_profile: "축소" - sr_collapse_profile: "프로필 세부정보 축소" + profile_hidden: "이 사용자의 공개 프로필은 숨김 상태입니다." + expand_profile: "펼치기" + sr_expand_profile: "프로필 상세 정보 펼치기" + collapse_profile: "접기" + sr_collapse_profile: "프로필 상세 정보 접기" bookmarks: "북마크" - bio: "내 소개" + bio: "내 정보" timezone: "시간대" - invited_by: "초대 자" - trust_level: "회원 레벨" + invited_by: "초대자" + trust_level: "신뢰 레벨" notifications: "알림" statistics: "통계" desktop_notifications: label: "실시간 알림" - not_supported: "이 브라우저에서는 알림이 지원되지 않습니다. 죄송합니다." + not_supported: "이 브라우저에서는 알림이 지원되지 않습니다." perm_default: "알림 켜기" - perm_denied_btn: "사용 권한 거부됨" - perm_denied_expl: "알림을 허가하지 않으셨군요. 브라우저 설정을 통해서 알림을 허용해주세요." + perm_denied_btn: "권한 거부됨" + perm_denied_expl: "알림 권한을 거부한 상태입니다. 브라우저 설정에서 알림을 허용해 주세요." disable: "알림 비활성화" enable: "알림 활성화" - each_browser_note: '참고: 사용하는 모든 브라우저에서 이 설정을 변경해야합니다. 이 설정에 관계없이 "방해 금지"에있는 경우 모든 알림이 비활성화됩니다.' - consent_prompt: "내 글에 댓글이 달리면 실시간으로 알림을 받으시겠습니까?" - dismiss: "읽음" - dismiss_notifications: "모두 읽음" + each_browser_note: '참고: 사용하는 모든 브라우저에서 이 설정을 변경해야 합니다. 이 설정에 관계없이 ''방해 금지''에 있는 경우 모든 알림이 비활성화됩니다.' + consent_prompt: "내 게시물에 댓글이 달리면 실시간으로 알림을 받을까요?" + dismiss: "해제" + dismiss_notifications: "모두 해제" dismiss_notifications_tooltip: "읽지 않은 알림을 모두 읽음으로 표시" - no_messages_title: "메시지가 없습니다." + dismiss_messages_tooltip: "읽지 않은 모든 개인 메시지 알림들을 읽음으로 표시" + no_messages_title: "메시지가 없습니다" no_messages_body: > - 다른 사람과 직접 개인적인 대화를 해야합니까? 아바타를 선택하고 %{icon} 메시지 버튼을 클릭하여 메시지를 보냅니다.

    도움이 필요하면 관리자에게 메시지로 문의하세요. - no_bookmarks_title: "아직 북마크가 없습니다." + 다른 사람과 개인적인 대화를 해야 하나요? 아바타를 선택하고 %{icon} 메시지 버튼을 클릭하여 메시지를 보내세요.

    도움이 필요하면 운영진에게 메시지를 전송할 수 있습니다. + no_bookmarks_title: "아직 북마크가 없습니다" no_bookmarks_body: > - %{icon} 버튼으로 게시물 북마크를 시작하면 쉽게 참조 할 수 있도록 여기에 나열됩니다. 알림을 예약 할 수도 있습니다! - no_bookmarks_search: "검색어와 일치하는 북마크를 찾을 수 없습니다." - no_notifications_title: "아직 알림이 없습니다." + %{icon} 버튼으로 게시물 북마크를 시작하면 쉽게 참조할 수 있도록 여기에 나열됩니다. 미리 알림을 예약할 수도 있습니다! + no_bookmarks_search: "검색어와 일치하는 북마크가 없습니다." + no_notifications_title: "아직 알림이 없습니다" no_notifications_body: > - 이 패널에서는 글 및 댓글에 대한 답글을 포함하여 직접적으로 관련된 활동에 대한 알림을 받게됩니다. 누군가 사용자님을 @멘션 또는 인용하고 사용자님이 팔로우중인 글에 댓글을 올릴 때. 한동안 로그인하지 않은 경우에도 알림이 이메일로 전송됩니다.

    알림을받을 특정 주제, 카테고리 및 태그를 살펴보세요 %{icon}. 자세한 내용은 알림 기본 설정을 참조하십시오. - no_notifications_page_title: "아직 알림이 없습니다." - first_notification: "첫 번째 알림! 시작하려면 선택하세요." - dynamic_favicon: "브라우저 아이콘에 수 표시" + 이 패널에서는 나와 직접적으로 관련된 활동에 대한 알림을 받습니다. 예를 들면 내 주제 및 게시물에 대한 댓글, 누군가 나를 @멘션 또는 인용할 때, 내가 구독하는 주제에 댓글을 달 때입니다. 한동안 로그인하지 않은 경우에도 이메일로 알림이 전송됩니다.

    %{icon} 아이콘으로 알림을 받을 특정 주제, 카테고리 및 태그를 살펴보세요. 자세한 내용은 알림 환경설정을 참조하세요. + no_notifications_page_title: "아직 알림이 없습니다" + first_notification: "첫 알림입니다! 시작하려면 선택하세요." + dynamic_favicon: "브라우저 아이콘에 개수 표시" skip_new_user_tips: description: "새 사용자 온보딩 팁 및 배지 건너뛰기" - not_first_time: "처음이 아니십니까?" - skip_link: "이 팁 건너 뛰기" - read_later: "나중에 읽어 볼게요." - theme_default_on_all_devices: "이 테마를 모든 기기에서 기본 테마로 설정" - color_scheme_default_on_all_devices: "모든 장치에서 기본 색 구성표 설정" + not_first_time: "처음이 아니신가요?" + skip_link: "이 팁 건너뛰기" + read_later: "나중에 읽어볼게요." + theme_default_on_all_devices: "이 테마를 모든 디바이스에서 디폴트 테마로 설정" + color_scheme_default_on_all_devices: "모든 디바이스에서 디폴트 색상 구성표 설정" color_scheme: "색상 구성표" color_schemes: - default_description: "테마 기본값" + default_description: "디폴트 테마" disable_dark_scheme: "일반과 동일" - dark_instructions: "기기의 어두운 모드를 전환하여 어두운 모드 색 구성표를 미리 볼 수 있습니다." - undo: "초기화" + dark_instructions: "디바이스의 다크 모드를 전환하여 다크 모드 색상 구성표를 미리 볼 수 있습니다." + undo: "리셋" regular: "일반" - dark: "어두운 모드" - default_dark_scheme: "(사이트 기본값)" - dark_mode: "어두운 모드" - dark_mode_enable: "어두운 모드 색 구성표 자동 사용" - text_size_default_on_all_devices: "모든 장치에서 기본 텍스트 크기로 설정" - allow_private_messages: "다른 사용자가 나에게 개인 메시지를 보내는것을 허용" + dark: "다크 모드" + default_dark_scheme: "(사이트 디폴트)" + dark_mode: "다크 모드" + dark_mode_enable: "다크 모드 색상 구성표 자동 활성화" + text_size_default_on_all_devices: "모든 디바이스에서 디폴트 텍스트 크기로 설정" + allow_private_messages: "다른 사용자가 나에게 개인 메시지 보내기 허용" external_links_in_new_tab: "새 탭에서 모든 외부 링크 열기" - enable_quoting: "강조 표시된 텍스트에 대한 알림 활성화" - enable_defer: "글을 읽지 않은 상태로 표시 연장" + enable_quoting: "하이라이트된 텍스트에 대한 인용 댓글 활성화" + enable_defer: "주제를 읽지 않은 상태로 표시하도록 연기 활성화" experimental_sidebar: options: "옵션" change: "변경" - featured_topic: "주요 글" - moderator: "%{user}님은 운영자입니다" - admin: "%{user}님은 관리자 입니다" - moderator_tooltip: "이 회원은 운영자 입니다" - admin_tooltip: "이 회원은 관리자입니다." - silenced_tooltip: "이 회원은 차단되었습니다" - suspended_notice: "이 사용자는 %{date}까지 계정이 일시 중지되었습니다." - suspended_permanently: "이 회원은 일시정지 되었습니다." + featured_topic: "추천 주제" + moderator: "%{user} 님은 운영자입니다" + admin: "%{user} 님은 관리자입니다" + moderator_tooltip: "이 사용자는 운영자입니다" + admin_tooltip: "이 사용자는 관리자입니다" + silenced_tooltip: "이 사용자는 차단되었습니다" + suspended_notice: "이 사용자는 %{date}까지 정지되었습니다." + suspended_permanently: "이 사용자는 정지되었습니다." suspended_reason: "이유: " github_profile: "GitHub" email_activity_summary: "활동 요약" @@ -1024,86 +1028,86 @@ ko: label: "메일링 리스트 모드" enabled: "메일링 리스트 모드 활성화" instructions: | - 이 설정은 활동 요약보다 우선합니다.
    - 뮤트된 글 및 카테고리는 이메일에 포함되지 않습니다. - individual: "모든 새 게시물에 대한 이메일 보내기" + 이 설정은 활동 요약을 오버라이드합니다.
    + 뮤트된 주제 및 카테고리는 이메일에 포함되지 않습니다. + individual: "모든 새 게시물에 대해 이메일 보내기" individual_no_echo: "내 게시물을 제외한 모든 새 게시물에 대해 이메일 보내기" - many_per_day: "모든 새 게시물에 대해 이메일을 보냅니다 (하루에 약 %{dailyEmailEstimate}개)" - few_per_day: "모든 새 게시물에 대해 이메일을 보냅니다 (하루에 약 2개)." - warning: "메일링 리스트 모드가 활성화되었습니다. 이메일 알림 설정이 재설정 됩니다." + many_per_day: "모든 새 게시물에 대해 나에게 이메일을 보냅니다(하루에 약 %{dailyEmailEstimate}개)" + few_per_day: "모든 새 게시물에 대해 나에게 이메일을 보냅니다(하루에 약 2개)" + warning: "메일링 리스트 모드가 활성화되었습니다. 이메일 알림 설정을 오버라이드합니다." tag_settings: "태그" - watched_tags: "주시중" - watched_tags_instructions: "이 태그가 있는 모든 글을 자동으로 볼 수 있습니다. 모든 새 글에 대한 알림이 표시되고 글 옆에 새 게시물 개수도 표시됩니다." - tracked_tags: "팔로우중" - tracked_tags_instructions: "이 태그를 사용하여 모든 글을 자동으로 팔로우 합니다. 글 옆에 새 게시물 수가 표시됩니다." - muted_tags: "알림 끔" - muted_tags_instructions: "이 태그를 사용하면 새 글에 대한 알림을 받지 않으며 최신 항목에도 표시되지 않습니다." - watched_categories: "주시중" - watched_categories_instructions: "이 카테고리의 모든 글을 자동으로 팔로우하게 됩니다. 모든 새 글에 대한 알림을 받게되며 새 게시물 수도 글 옆에 표시됩니다." - tracked_categories: "팔로우중" - tracked_categories_instructions: "이 카테고리의 모든 글을 자동으로 팔로우 합니다. 글 옆에 새 게시물 수가 표시됩니다." - watched_first_post_categories: "새글 알림" - watched_first_post_categories_instructions: "이 카테고리의 각 새 글에 대한 첫 번째 댓글 알림을 받습니다." - watched_first_post_tags: "새글 알림" - watched_first_post_tags_instructions: "이 태그를 사용하여 각 새 글에 대한 첫 번째 댓글 알림을 받습니다." - muted_categories: "알림 끔" - muted_categories_instructions: "이 카테고리의 새로운 글에 대한 알림은 제공되지 않으며 카테고리 또는 최근 글 페이지에 표시되지 않습니다." - muted_categories_instructions_dont_hide: "이 카테고리의 새로운 글에 대한 알림은 받지 않습니다." - regular_categories: "보통" - regular_categories_instructions: "“최근 글” 및 “주요 글” 목록에서 이 카테고리를 볼 수 있습니다." - no_category_access: "관리자로서 카테고리 접근이 제한되어 있으므로 저장이 비활성화됩니다." + watched_tags: "구독" + watched_tags_instructions: "이 태그의 모든 주제를 자동으로 봅니다. 모든 새 게시물과 주제에 대한 알림이 전송되며 새 게시물 수도 주제 옆에 표시됩니다." + tracked_tags: "추적" + tracked_tags_instructions: "이 태그의 모든 주제를 자동 추적합니다. 새 게시물 수가 주제 옆에 표시됩니다." + muted_tags: "뮤트" + muted_tags_instructions: "이 태그가 있는 새 주제에 대한 어떠한 알림도 받지 않으며 최신 항목에 표시되지 않습니다." + watched_categories: "구독" + watched_categories_instructions: "이 카테고리의 모든 주제를 자동으로 봅니다. 모든 새 게시물과 주제에 대한 알림이 전송되며 새 게시물 수도 주제 옆에 표시됩니다." + tracked_categories: "추적" + tracked_categories_instructions: "이 카테고리의 모든 주제를 자동 추적합니다. 새 게시물 수가 주제 옆에 표시됩니다." + watched_first_post_categories: "첫 게시물 구독" + watched_first_post_categories_instructions: "이 카테고리에 있는 각 새 주제의 첫 게시물에 대한 알림을 받습니다." + watched_first_post_tags: "첫 게시물 구독" + watched_first_post_tags_instructions: "이 태그가 달린 각 새 주제의 첫 게시물에 대한 알림을 받습니다." + muted_categories: "뮤트" + muted_categories_instructions: "이 카테고리의 새 주제에 대한 알림을 받지 않으며 카테고리 또는 최신 페이지에 나타나지 않습니다." + muted_categories_instructions_dont_hide: "이 카테고리의 새 주제에 대한 모든 알림을 받지 않습니다." + regular_categories: "일반" + regular_categories_instructions: "'최신' 및 '주요' 주제 목록에서 이 카테고리를 볼 수 있습니다." + no_category_access: "운영자로서 카테고리 액세스가 제한되어 있으므로 저장이 비활성화됩니다." delete_account: "내 계정 삭제" - delete_account_confirm: "계정을 영구적으로 삭제 하시겠습니까? 이 작업은 취소 할 수 없습니다!" - deleted_yourself: "사용자님의 계정이 삭제되었습니다." - delete_yourself_not_allowed: "계정 삭제를 원하시면 관리자에게 문의하시기 바랍니다." + delete_account_confirm: "계정을 영구적으로 삭제할까요? 이 작업은 취소할 수 없습니다!" + deleted_yourself: "계정이 삭제되었습니다." + delete_yourself_not_allowed: "계정 삭제를 원하시면 운영진에게 문의하세요." unread_message_count: "메시지" admin_delete: "삭제" users: "사용자" - muted_users: "알림 끔" - muted_users_instructions: "이 사용자의 모든 알림 및 개인 메시지를 표시하지 않습니다." + muted_users: "뮤트" + muted_users_instructions: "이 사용자의 모든 알림 및 개인 메시지를 거부합니다." allowed_pm_users: "허용됨" allowed_pm_users_instructions: "이 사용자의 개인 메시지만 허용합니다." - allow_private_messages_from_specific_users: "특정 사용자만 나에게 개인 메시지를 보내도록 허용" + allow_private_messages_from_specific_users: "특정 사용자만 나에게 개인 메시지를 보내도록 허용합니다." ignored_users: "무시됨" - ignored_users_instructions: "이 사용자의 모든 게시물, 알림 및 개인 메시지를 표시하지 않습니다." - tracked_topics_link: "보이기" - automatically_unpin_topics: "글 끝에 도달하면 글을 자동으로 고정 해제합니다." + ignored_users_instructions: "이 사용자의 모든 게시물, 알림 및 개인 메시지를 거부합니다." + tracked_topics_link: "표시" + automatically_unpin_topics: "주제 하단에 도달하면 주제를 자동으로 고정 해제합니다." apps: "앱" - revoke_access: "접근 권한을 취소" - undo_revoke_access: "접근 권한 해지 취소" + revoke_access: "액세스 취소" + undo_revoke_access: "액세스 취소 실행 취소" api_approved: "승인됨:" - api_last_used_at: "마지막 사용 :" + api_last_used_at: "마지막 사용:" theme: "테마" - save_to_change_theme: '"%{save_text}"을 클릭하면 테마가 업데이트됩니다.' - home: "기본 홈페이지" - staged: "격리됨" + save_to_change_theme: '''%{save_text}''을 클릭하면 테마가 업데이트됩니다' + home: "디폴트 홈페이지" + staged: "스테이징됨" staff_counters: flags_given: "유용한 신고" - flagged_posts: "신고된 글" + flagged_posts: "신고된 게시물" deleted_posts: "삭제된 글" - suspensions: "차단" + suspensions: "정지" warnings_received: "경고" rejected_posts: "거부된 게시물" messages: all: "모든 받은 편지함" inbox: "받은 편지함" - personal: "개인용" + personal: "개인" latest: "최신" - sent: "보낸 편지함" + sent: "전송됨" unread: "읽지 않음" unread_with_count: - other: "읽지 않은 글 (%{count})" - new: "새글" + other: "읽지 않음(%{count})" + new: "신규" new_with_count: - other: "새글 (%{count})" - archive: "저장함" + other: "신규(%{count})" + archive: "보관" groups: "내 그룹" move_to_inbox: "받은 편지함으로 이동" - move_to_archive: "저장함" - failed_to_move: "선택한 메시지를 이동하지 못했습니다. (네트워크가 다운되었을 수 있음)" + move_to_archive: "보관" + failed_to_move: "선택한 메시지를 이동하지 못했습니다(네트워크가 다운되었을 수 있음)" tags: "태그" warnings: "공식 경고" - read_more_in_group: "더 읽을거리가 필요하신가요? %{groupLink}에서 다른 메시지를 찾아보십시오." + read_more_in_group: "더 읽고 싶으신가요? %{groupLink}에서 다른 메시지를 찾아보세요." preferences_nav: account: "계정" security: "보안" @@ -1116,102 +1120,102 @@ ko: interface: "인터페이스" apps: "앱" change_password: - success: "(이메일 전송)" + success: "(이메일 전송됨)" in_progress: "(이메일 전송 중)" error: "(오류)" emoji: "이모티콘 잠금" - action: "비밀번호 재설정 이메일 보내기" + action: "비밀번호 리셋 이메일 보내기" set_password: "비밀번호 설정" choose_new: "새 비밀번호를 입력하세요" choose: "비밀번호를 입력하세요" second_factor_backup: title: "2단계 백업 코드" regenerate: "재생성" - disable: "비활성" + disable: "비활성화" enable: "활성화" - enable_long: "백업 코드 사용" + enable_long: "백업 코드 활성화" manage: other: "백업 코드를 관리합니다. %{count}개의 백업 코드가 남아 있습니다." - copy_to_clipboard: "클립 보드에 복사" + copy_to_clipboard: "클립보드에 복사" copy_to_clipboard_error: "데이터를 클립보드로 복사하는 중 오류 발생" copied_to_clipboard: "클립보드에 복사됨" download_backup_codes: "백업 코드 다운로드" remaining_codes: other: "%{count}개의 백업 코드가 남아 있습니다." use: "백업 코드 사용" - enable_prerequisites: "백업 코드를 생성하기 전에 기본 2단계 방법을 활성화해야 합니다." + enable_prerequisites: "백업 코드를 생성하기 전에 기본 2단계 인증 방법을 활성화해야 합니다." codes: - title: "생성된 백업 코드" - description: "이 백업 코드는 한 번만 사용할 수 있습니다. 안전한 곳에 보관하십시오." + title: "백업 코드 생성됨" + description: "각 백업 코드는 한 번만 사용할 수 있습니다. 액세스 가능한 안전한 곳에 보관하세요." second_factor: title: "2단계 인증" enable: "2단계 인증 관리" disable_all: "모두 비활성화" - forgot_password: "비밀번호를 잊으셨습니까?" + forgot_password: "비밀번호가 기억나지 않나요?" confirm_password_description: "계속하려면 비밀번호를 입력하세요" name: "이름" label: "코드" - rate_limit: "다른 인증 코드를 시도하기 전에 잠시 기다려 주십시오." + rate_limit: "다른 인증 코드를 시도하기 전에 잠시 기다려 주세요." enable_description: | - 지원되는 앱 (AndroidiOS)에서 이 QR코드를 스캔하고 인증 코드를 입력하세요. + 지원되는 앱(AndroidiOS)에서 이 QR 코드를 스캔하고 인증 코드를 입력하세요. disable_description: "앱의 인증 코드를 입력하세요" show_key_description: "수동으로 입력" short_description: | - 일회용 보안 코드로 계정을 보호하십시오. + 일회용 보안 코드로 계정을 보호하세요. extended_description: | - 이중 인증은 암호 외에 일회성 토큰을 요구하여 계정에 보안을 강화합니다. 토큰은 안드로이드iOS 장치에서 생성 될 수 있습니다. + 2단계 인증은 암호 외에 일회성 토큰을 요구하여 계정에 보안을 강화합니다. 토큰은 AndroidiOS 디바이스에서 생성될 수 있습니다. oauth_enabled_warning: "계정에서 2단계 인증이 활성화되면 소셜 로그인이 비활성화됩니다." - use: "Authenticator 앱 사용" - enforced_notice: "이 사이트에 접근하려면 2단계 인증을 활성화해야합니다." - disable: "해제" - disable_confirm: "모든 2단계 인증을 비활성화 하시겠습니까?" + use: "인증 앱 사용" + enforced_notice: "이 사이트에 액세스하려면 2단계 인증을 활성화해야 합니다." + disable: "비활성화" + disable_confirm: "모든 2단계 인증 방법을 비활성화할까요?" save: "저장" edit: "편집" - edit_title: "인증자 편집" - edit_description: "인증자 명칭" + edit_title: "인증 편집" + edit_description: "인증 이름" enable_security_key_description: | - 하드웨어 보안 키가 준비되었다면 아래의 등록 버튼을 누르십시오. + 하드웨어 보안 키가 준비되었다면 아래의 등록 버튼을 누르세요. totp: - title: "토큰 기반 인증 자" - add: "인증자 추가" - default_name: "내 인증 자" - name_and_code_required_error: "인증 앱의 이름과 코드를 제공해야합니다." + title: "토큰 기반 인증" + add: "인증 추가" + default_name: "내 인증" + name_and_code_required_error: "인증 앱의 이름과 코드를 제공해야 합니다." security_key: - register: "등록하기" + register: "등록" title: "보안 키" add: "보안 키 추가" default_name: "기본 보안 키" not_allowed_error: "보안 키 등록 프로세스가 시간 초과되었거나 취소되었습니다." - already_added_error: "이 보안 키를 이미 등록했습니다. 다시 등록 할 필요가 없습니다." + already_added_error: "이 보안 키는 이미 등록되어 있으므로 다시 등록하지 않아도 됩니다." edit: "보안 키 편집" save: "저장" edit_description: "보안 키 이름" name_required_error: "보안 키의 이름을 제공해야 합니다." change_about: - title: "내 소개 변경" + title: "내 정보 변경" error: "이 값을 변경하는 중에 오류가 발생했습니다." change_username: title: "사용자명 변경" - confirm: "사용자명을 변경 하시겠습니까?" - taken: "죄송합니다. 사용중인 사용자명 입니다." - invalid: "해당 사용자명이 잘못되었습니다. 숫자와 문자만 포함해야 합니다." + confirm: "아이디를 변경할까요?" + taken: "이미 사용 중인 아이디입니다." + invalid: "이 아이디는 유효하지 않습니다. 숫자와 문자만 포함해야 합니다." add_email: title: "이메일 추가" add: "추가" change_email: title: "이메일 변경" - taken: "죄송합니다. 해당 이메일은 사용 할 수 없습니다." - error: "이메일 변경 중 오류가 발생했습니다. 이미 사용 중인 이메일인지 확인해주세요." - success: "이메일 발송이 완료되었습니다. 확인하신 후 절차에 따라주세요." - success_via_admin: "해당 주소로 이메일을 보냈습니다. 이메일에 있는 확인 지침을 따라야 합니다." - success_staff: "현재 주소로 이메일을 보냈습니다. 확인 절차에 따라 진행해 주세요." + taken: "이 이메일은 사용할 수 없습니다." + error: "이메일 변경 중 오류가 발생했습니다. 이미 사용 중인 이메일일 수 있습니다." + success: "이 주소로 이메일을 전송했습니다. 확인 지침을 따라주세요." + success_via_admin: "이 주소로 이메일을 전송했습니다. 사용자는 이메일에 있는 확인 지침을 따라야 합니다." + success_staff: "현재 주소로 이메일을 전송했습니다. 확인 지침을 따라주세요." change_avatar: title: "프로필 사진 변경" - gravatar: "%{gravatarName} 기반" - gravatar_title: "%{gravatarName}의 웹 사이트에서 아바타 변경" - gravatar_failed: "해당 이메일 주소로 %{gravatarName}을 찾을 수 없습니다." - refresh_gravatar_title: "%{gravatarName} 새로 고침" - letter_based: "자동 생성된 아바타" + gravatar: "%{gravatarName}, 기반:" + gravatar_title: "%{gravatarName}의 웹사이트에서 아바타 변경" + gravatar_failed: "이 이메일 주소로 %{gravatarName} 검색이 불가합니다." + refresh_gravatar_title: "%{gravatarName} 새로고침" + letter_based: "시스템 할당 프로필 사진" uploaded_avatar: "사용자 지정 사진" uploaded_avatar_empty: "사용자 지정 사진 추가" upload_title: "사진 업로드" @@ -1219,12 +1223,12 @@ ko: logo_small: "사이트의 작은 로고. 기본적으로 사용됩니다." change_profile_background: title: "프로필 헤더" - instructions: "프로필 헤더는 중앙에 위치하며 기본 너비는 1110px입니다." + instructions: "프로필 헤더는 중앙에 위치하며 디폴트 너비는 1110px입니다." change_card_background: title: "사용자 카드 배경" - instructions: "배경 이미지는 중앙에 배치되며 기본 너비는 590px 입니다." + instructions: "배경 이미지는 중앙에 위치하며 디폴트 너비는 590px입니다." change_featured_topic: - title: "주요 글" + title: "추천 주제" instructions: "이 글에 대한 링크는 사용자 카드 및 프로필에 있습니다." email: title: "이메일" @@ -1232,26 +1236,26 @@ ko: secondary: "보조 이메일" primary_label: "기본" unconfirmed_label: "미확인" - resend_label: "활성화 이메일 재전송" - resending_label: "보내는 중..." - resent_label: "이메일 보냄" + resend_label: "확인 이메일 재전송" + resending_label: "전송 중..." + resent_label: "이메일 전송됨" update_email: "이메일 변경" set_primary: "기본 이메일 설정" destroy: "이메일 제거" add_email: "보조 이메일 추가" - auth_override_instructions: "인증 제공 업체에서 이메일을 업데이트 할 수 있습니다." + auth_override_instructions: "인증 제공자를 통해 이메일을 업데이트할 수 있습니다." no_secondary: "보조 이메일이 없습니다" instructions: "다른 사용자에게 공개되지 않습니다." - admin_note: "참고 : 관리자가 아닌 다른 사용자의 이메일을 변경하는 관리자는 사용자가 원래 이메일 계정에 액세스할 수 없음을 나타내므로 비밀번호 재설정 이메일이 새 주소로 전송됩니다. 사용자의 이메일은 비밀번호 재설정 프로세스를 완료할 때까지 변경되지 않습니다." - ok: "확인을 위해 이메일을 보내드립니다." - required: "이메일 주소를 입력하십시오" - invalid: "유효한 이메일 주소를 입력하십시오." - authenticated: "사용자님의 이메일은 %{provider}에 의해 인증되었습니다." - invite_auth_email_invalid: "초대 이메일이 %{provider}에 인증된 이메일과 일치하지 않습니다." - authenticated_by_invite: "사용자님의 이메일은 초대에 의해 인증되었습니다" - frequency_immediately: "만약 전송된 메일을 읽지 않았을 경우, 즉시 메일을 다시 보내드립니다." + admin_note: "참고 : 관리자가 관리자가 아닌 다른 사용자의 이메일을 변경할 경우 해당 사용자는 원래 이메일 계정에 액세스할 수 없기 때문에 비밀번호 리셋 이메일이 새 주소로 전송됩니다. 사용자의 이메일은 비밀번호 리셋 프로세스를 완료할 때까지 변경되지 않습니다." + ok: "확인을 위해 이메일을 보내드립니다" + required: "이메일 주소를 입력하세요" + invalid: "유효한 이메일 주소를 입력하세요." + authenticated: "이메일이 %{provider}에 의해 인증되었습니다" + invite_auth_email_invalid: "초대 이메일이 %{provider}에서 인증한 이메일과 일치하지 않습니다" + authenticated_by_invite: "이메일이 초대 이메일로 인증되었습니다" + frequency_immediately: "만약 전송된 이메일을 읽지 않았을 경우, 즉시 이메일을 다시 보내드립니다." frequency: - other: "최근 %{count}분 동안 접속하지 않을 경우에만 메일이 전송됩니다." + other: "최근 %{count}분 동안 접속하지 않을 경우에만 이메일이 전송됩니다." associated_accounts: title: "연결된 계정" connect: "연결" @@ -1261,113 +1265,113 @@ ko: confirm_modal_title: "%{provider} 계정 연결" confirm_description: disconnect: "기존 %{provider} 계정 '%{account_description}' 연결이 해제됩니다." - account_specific: "사용자님의 %{provider} 계정 '%{account_description}'이 인증에 사용됩니다." + account_specific: "%{provider} 계정 '%{account_description}'|hpp(이,가) 인증에 사용됩니다." generic: "%{provider} 계정이 인증에 사용됩니다." name: title: "이름" - instructions: "전체 이름 (선택 사항)" + instructions: "전체 이름(선택사항)" instructions_required: "전체 이름" required: "이름을 입력하세요" too_short: "이름이 너무 짧습니다." - ok: "사용 가능한 이름입니다." + ok: "올바른 이름입니다" username: title: "사용자명" - instructions: "공백없이, 짧고 특이하게" - short_instructions: "다른 사용자가 사용자님을 @%{username} 으로 멘션 할 수 있습니다." - available: "사용자명으로 사용할 수 있습니다." - not_available: "사용할 수 없습니다. %{suggestion}는 어떠세요?" + instructions: "공백 없이 짧고 고유해야 합니다" + short_instructions: "다른 사용자가 나를 @%{username} 형식으로 멘션할 수 있습니다" + available: "아이디로 사용할 수 있습니다" + not_available: "사용할 수 없습니다. %{suggestion} 아이디는 어떠세요?" not_available_no_suggestion: "사용할 수 없음" too_short: "사용자명 너무 짧습니다" - too_long: "사용자명이 너무 깁니다." - checking: "사용자명 사용 가능 여부 확인 중..." - prefilled: "이메일이 등록된 사용자명과 일치합니다." - required: "사용자명을 입력 해주세요" - edit: "아이디 수정" + too_long: "아이디가 너무 깁니다" + checking: "아이디 사용 가능 여부 확인 중..." + prefilled: "이메일이 등록된 아이디와 일치합니다." + required: "아이디를 입력하세요" + edit: "아이디 편집" locale: title: "인터페이스 언어" - instructions: "사용자 인터페이스 언어를 변경 후 페이지 새로 고침하면 반영됩니다." - default: "(기본)" - any: "모든" + instructions: "사용자 인터페이스 언어입니다. 페이지를 새로고침하면 반영됩니다." + default: "(디폴트)" + any: "모두" password_confirmation: title: "비밀번호 다시 입력" invite_code: title: "초대 코드" - instructions: "계정을 등록하려면 초대 코드가 필요합니다." + instructions: "계정을 등록하려면 초대 코드가 필요합니다" auth_tokens: - title: "최근에 사용한 장치" - details: "세부 정보" + title: "최근에 사용한 디바이스" + details: "상세 정보" log_out_all: "모두 로그아웃" - not_you: "사용자님이 아닌가요?" - show_all: "모두 보기 (%{count})" + not_you: "본인이 아닌가요?" + show_all: "모두 보기(%{count})" show_few: "간략히 보기" - was_this_you: "사용자님 이었나요?" + was_this_you: "본인인가요?" was_this_you_description: "본인이 아닌 경우 비밀번호를 변경하고 모든 곳에서 로그아웃하는 것이 좋습니다." browser_and_device: "%{device}의 %{browser}" - secure_account: "내 계정 보안" + secure_account: "내 계정 보호" latest_post: "마지막 작성…" device_location: '%{device}%{location}' browser_active: '%{browser} | 현재 사용' browser_last_seen: "%{browser} | %{date}" - last_posted: "마지막 글" + last_posted: "마지막 게시물" last_seen: "마지막 접속" - created: "가입" + created: "가입일" log_out: "로그아웃" location: "위치" website: "웹 사이트" email_settings: "이메일" - hide_profile_and_presence: "내 공개 프로필 및 현재 상태 기능 숨기기" + hide_profile_and_presence: "내 공개 프로필 및 접속여부 기능 숨기기" enable_physical_keyboard: "iPad에서 실제 키보드 지원 활성화" text_size: - title: "글자 크기" - smallest: "가장 작음" - smaller: "더 작음" - normal: "보통" - larger: "큼" - largest: "가장 큼" + title: "텍스트 크기" + smallest: "가장 작게" + smaller: "더 작게" + normal: "일반" + larger: "더 크게" + largest: "가장 크게" title_count_mode: - title: "배경 페이지 제목에 다음 개수가 표시됩니다:" - notifications: "새로운 알림" - contextual: "새 페이지 내용" + title: "배경 페이지 제목에 다음 개수가 표시됩니다." + notifications: "새 알림" + contextual: "새 페이지 콘텐츠" like_notification_frequency: - title: "좋아요를 받았을 때 알림받기" + title: "좋아요 받았을 때 알림" always: "항상" - first_time_and_daily: "글이 첫 좋아요를 받았을 때부터 매일 알림받기" - first_time: "게시물이 처음 좋아요를 받았을때" - never: "알림 받지 않기" + first_time_and_daily: "게시물이 첫 좋아요를 받았을 때부터 매일 알림" + first_time: "게시물이 첫 좋아요를 받았을 때" + never: "거부" email_previous_replies: - title: "이메일 하단에 예전에 읽은 댓글도 포함하기" - unless_emailed: "확인하지 않은 댓글만 포함하기" + title: "이메일 하단에 기존 댓글 포함" + unless_emailed: "기존에 전송되지 않은 것만" always: "항상 알림 받기" - never: "알림 받지 않기" + never: "거부" email_digests: - title: "여기를 방문하지 않을 경우 인기있는 글 및 댓글에 대한 요약 이메일을 보내주세요." - every_30_minutes: "30분 마다" + title: "이곳을 방문하지 않을 경우 인기 주제 및 댓글에 대한 요약 이메일 보내기" + every_30_minutes: "30분마다" every_hour: "매시간" daily: "매일" weekly: "매주" every_month: "매달" every_six_months: "6개월마다" email_level: - title: "내가 인용되거나 댓글을 받았을 때, 내 @username이 언급되었을 때 또는 내가 본 카테고리, 태그 또는 글에 새로운 활동이 있을 때 이메일을 보내십시오." + title: "내가 인용되거나 댓글을 받았을 때, 내 아이디(@username)가 언급되었을 때 또는 내가 구독한 카테고리, 태그 또는 주제에 새로운 활동이 있을 때 이메일 보내기" always: "항상 알림 받기" - only_when_away: "방문이 없을때 알림 받기" - never: "알림 받지 않음" - email_messages_level: "개인 메시지를 받으면 이메일을 보내주세요" - include_tl0_in_digests: "신규 사용자가 작성한 내용도 요약 메일에 포함시키기" - email_in_reply_to: "이메일에 댓글 내용을 발췌해서 포함" + only_when_away: "접속 중이 아닐 때만" + never: "거부" + email_messages_level: "개인 메시지를 받으면 이메일 보내기" + include_tl0_in_digests: "신규 사용자의 콘텐츠도 요약 메일에 포함" + email_in_reply_to: "이메일에 게시물의 댓글을 발췌해서 포함" other_settings: "기타" categories_settings: "카테고리" new_topic_duration: - label: "아래 조건에 해당하면 새로운 글로 간주" - not_viewed: "아직 읽어 보지 못했어요" - last_here: "마지막 방문 이후 작성된 글" - after_1_day: "지난 하루간 작성된 글" - after_2_days: "지난 2일 동안 작성된 글" - after_1_week: "지난주에 작성된 글" - after_2_weeks: "지난 2주 동안 작성된 글" - auto_track_topics: "내가 작성한 글 자동 팔로우" + label: "아래 조건에 해당하면 새 주제로 간주" + not_viewed: "아직 읽지 않음" + last_here: "마지막 방문 이후 생성됨" + after_1_day: "지난 하루간 생성됨" + after_2_days: "지난 2일간 생성됨" + after_1_week: "지난주에 생성됨" + after_2_weeks: "지난 2주간 생성됨" + auto_track_topics: "내가 참여한 주제 자동 추적" auto_track_options: - never: "하지않음" + never: "거부" immediately: "즉시" after_30_seconds: "30초 후" after_1_minute: "1분 후" @@ -1376,62 +1380,62 @@ ko: after_4_minutes: "4분 후" after_5_minutes: "5분 후" after_10_minutes: "10분 후" - notification_level_when_replying: "글에 댓글을 쓰면 그 글을 다음으로 설정" + notification_level_when_replying: "게시물에 댓글을 달면 그 주제를 다음으로 설정" invited: title: "초대" - pending_tab: "보류중" - pending_tab_with_count: "보류중 (%{count})" + pending_tab: "보류 중" + pending_tab_with_count: "보류 중(%{count})" expired_tab: "만료됨" - expired_tab_with_count: "만료됨 (%{count})" + expired_tab_with_count: "만료됨(%{count})" redeemed_tab: "사용됨" - redeemed_tab_with_count: "사용됨 (%{count})" + redeemed_tab_with_count: "사용됨(%{count})" invited_via: "초대" groups: "그룹" - topic: "글" + topic: "주제" sent: "생성됨/마지막 보낸 날짜" expires_at: "만료" - edit: "수정" + edit: "편집" remove: "제거" copy_link: "링크 가져오기" reinvite: "이메일 재전송" - reinvited: "초대 메일 재전송 됨" + reinvited: "초대 재전송됨" removed: "제거됨" search: "초대를 검색하려면 입력..." user: "초대된 사용자" - none: "표시 할 초대가 없습니다." + none: "표시할 초대가 없습니다." truncated: - other: "처음 %{count}개의 초대를 표시합니다." + other: "첫 %{count}개의 초대를 표시합니다." redeemed: "사용된 초대" redeemed_at: "사용됨" pending: "보류 중인 초대" - topics_entered: "읽은 글" - posts_read_count: "읽은 댓글" - expired: "이 초대장의 기한이 만료되었습니다." + topics_entered: "읽은 주제" + posts_read_count: "읽은 게시물" + expired: "이 초대는 만료되었습니다." remove_all: "만료된 초대 제거" removed_all: "만료된 모든 초대가 제거되었습니다!" - remove_all_confirm: "만료된 초대를 모두 제거 하시겠습니까?" - reinvite_all: "모든 초대 다시 보내기" - reinvite_all_confirm: "정말로 모든 초대를 다시 보내시겠습니까?" - reinvited_all: "모든 초대장이 다시 발송되었습니다!" + remove_all_confirm: "만료된 초대를 모두 제거할까요?" + reinvite_all: "모든 초대 재전송" + reinvite_all_confirm: "정말로 모든 초대를 재전송할까요?" + reinvited_all: "모든 초대가 재전송되었습니다!" time_read: "읽은 시간" - days_visited: "방문 일수" - account_age_days: "계정 사용 기간 (일)" + days_visited: "방문일 수" + account_age_days: "계정 사용 기간(일)" create: "초대" generate_link: "초대 링크 만들기" - link_generated: "초대 링크는 다음과 같습니다!" - valid_for: "초대 링크는 다음 이메일 주소에만 유효합니다: %{email}" + link_generated: "초대 링크가 생성되었습니다!" + valid_for: "초대 링크는 다음 이메일 주소에만 유효합니다. %{email}" single_user: "이메일로 초대" multiple_user: "링크로 초대" invite_link: title: "초대 링크" success: "초대 링크가 성공적으로 생성되었습니다!" - error: "초대 링크를 생성하는 중에 오류가 발생했습니다." + error: "초대 링크를 생성하는 중에 오류가 발생했습니다" invite: - new_title: "초대 링크 만들기" - edit_title: "초대 수정" - instructions: "이 링크를 공유하여 이 사이트에 대한 사용 권한을 즉시 부여할 수 있습니다." + new_title: "초대 만들기" + edit_title: "초대 편집" + instructions: "이 링크를 공유하여 이 사이트의 액세스 권한을 즉시 부여할 수 있습니다." copy_link: "링크 복사" - expires_in_time: "%{time}후에 만료" + expires_in_time: "%{time} 후에 만료" expired_at_time: "%{time}에 만료됨" show_advanced: "고급 옵션 표시" hide_advanced: "고급 옵션 숨기기" @@ -1439,30 +1443,30 @@ ko: restrict_email: "이메일로 제한" restrict_domain: "도메인으로 제한" email_or_domain_placeholder: "name@example.com 또는 example.com" - max_redemptions_allowed: "최대 사용" + max_redemptions_allowed: "최대 사용 한도" add_to_groups: "그룹에 추가" expires_at: "다음 후 만료" custom_message: "개인 메시지 옵션" - send_invite_email: "이메일 저장 및 보내기" + send_invite_email: "저장 및 이메일 전송" save_invite: "초대 저장" invite_saved: "초대가 저장되었습니다." bulk_invite: none: "이 페이지에 표시할 초대장이 없습니다." text: "일괄 초대" instructions: | -

    사용자 리스트를 이용해 초대를 빠르게 진행하십시오. 초대하려는 사용자의 이메일 주소를 한 라인당 하나씩 입력한 CSV 파일을 준비하십시오. 그룹에 사람을 추가하거나 처음 로그인 할 때 특정 주제로 보내려는 경우 쉼표로 구분해 정보를 제공 할 수 있습니다.

    -
    john@smith.com,첫 번째 그룹명;두 번째 그룹명,글_id
    -

    CSV 파일에서에 입력된 모든 이메일 주소로 초대장이 전송되며 나중에 관리 할 수 있습니다.

    - progress: "%{progress}% 업로드..." +

    사용자를 일괄 초대하여 커뮤니티를 빠르게 조성하세요. 초대하려는 사용자의 이메일 주소당 최소 한 행을 포함하는 CSV 파일을 준비하세요. 그룹에 사람을 추가하거나 처음 로그인할 때 특정 주제로 보내려는 경우 다음과 같이 쉼표로 구분한 정보를 제공하셔도 좋습니다.

    +
    john@smith.com,first_group_name;second_group_name,topic_id
    +

    업로드한 CSV 파일에 입력된 모든 이메일 주소로 초대장이 전송되며 나중에 관리할 수 있습니다.

    + progress: "%{progress}% 업로드됨..." success: "파일이 성공적으로 업로드되었습니다. 프로세스가 완료되면 메시지를 통해 알려드립니다." - error: "죄송합니다. 파일은 CSV 형식이어야 합니다." + error: "파일은 CSV 포맷이어야 합니다." password: title: "비밀번호" too_short: "비밀번호가 너무 짧습니다." - common: "이 비밀번호는 너무 평범합니다." + common: "비밀번호가 너무 평범합니다." same_as_username: "비밀번호가 사용자명과 동일합니다." same_as_email: "비밀번호가 이메일과 동일합니다." - ok: "적절한 비밀번호 입니다." + ok: "올바른 비밀번호입니다." instructions: "%{count}자 이상" required: "비밀번호를 입력하세요" summary: @@ -1471,37 +1475,37 @@ ko: time_read: "읽은 시간" recent_time_read: "최근 읽은 시간" topic_count: - other: "작성 글" + other: "생성한 주제" post_count: - other: "작성 댓글" + other: "생성한 게시물" likes_given: - other: "줌" + other: "보냄" likes_received: other: "받음" days_visited: - other: "방문 일수" + other: "방문일 수" topics_entered: - other: "읽은 글" + other: "읽은 주제" posts_read: - other: "게시물 읽음" + other: "읽은 게시물" bookmark_count: other: "북마크" top_replies: "주요 댓글" no_replies: "아직 댓글이 없습니다." more_replies: "댓글 더 보기" - top_topics: "주요 글" + top_topics: "주요 주제" no_topics: "아직 글이 없습니다." more_topics: "더 많은 글" top_badges: "주요 배지" no_badges: "아직 배지가 없습니다." more_badges: "배지 더 보기" - top_links: "상위 링크" + top_links: "주요 링크" no_links: "아직 링크가 없습니다." - most_liked_by: "가장 많은 좋아요를 받은 사용자" - most_liked_users: "가장 많이 좋아요를 받은" - most_replied_to_users: "댓글을 가장 많이 단 사람" + most_liked_by: "가장 많이 좋아요를 누름" + most_liked_users: "가장 많이 좋아요를 받음" + most_replied_to_users: "가장 많이 댓글을 달음" no_likes: "아직 좋아요가 없습니다." - top_categories: "상위 카테고리" + top_categories: "주요 카테고리" topics: "글" replies: "댓글" ip_address: @@ -1514,9 +1518,9 @@ ko: name_and_description: "%{name} - %{description}" edit: "프로필 사진 변경" title: - title: "제목" + title: "직책" none: "(없음)" - instructions: "사용자 아이디 뒤에 나타납니다." + instructions: "사용자 아이디 뒤에 표시됩니다" flair: title: "플레어" none: "(없음)" @@ -1527,7 +1531,7 @@ ko: filters: all: "모두" stream: - posted_by: "게시자 :" + posted_by: "게시자" sent_by: "보낸 사람" private_message: "메시지" the_topic: "글" @@ -1539,72 +1543,73 @@ ko: reasons: network: "네트워크 오류" server: "서버 오류" - forbidden: "접근 거부됨" + forbidden: "액세스 거부됨" unknown: "오류" - not_found: "페이지를 찾을 수 없습니다" + not_found: "페이지를 찾을 수 없음" desc: - network: "연결 상태를 확인하십시오." + network: "연결 상태를 확인하세요." network_fixed: "문제가 해결된 것으로 보입니다." server: "오류 코드: %{status}" - forbidden: "사용자님은 볼 수 없습니다." - not_found: "죄송합니다. 애플리케이션이 존재하지 않는 URL을 로드하려고 했습니다." + forbidden: "확인할 권한이 없습니다." + not_found: "애플리케이션이 존재하지 않는 URL을 로드하려고 했습니다." unknown: "문제가 발생했습니다." buttons: back: "뒤로 가기" again: "다시 시도" - fixed: "페이지 열기" + fixed: "페이지 로드" modal: close: "닫기" dismiss_error: "오류 무시" close: "닫기" - assets_changed_confirm: "이 사이트는 방금 소프트웨어 업그레이드를 받았습니다. 지금 최신 버전을 받으시겠습니까?" - logout: "로그아웃 되었습니다." + assets_changed_confirm: "이 사이트에 소프트웨어 업그레이드가 존재합니다. 지금 최신 버전을 받을까요?" + logout: "로그아웃되었습니다." refresh: "새로 고침" home: "홈" read_only_mode: - enabled: "이 사이트는 현재 읽기전용 모드입니다. 브라우징은 가능하지만, 댓글 달기, 좋아요 및 기타 작업을 사용할 수 없습니다." + 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 {# 댓글}}을 읽고 작성하도록 권장합니다. 이 메시지는 관리자만 볼 수 있습니다. + 토론을 시작하세요! 현재 {currentTopics, plural, one {is #개의 주제} other {are #개의 주제}} 및 {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}}을 (를) 권장합니다. 직원 만이 메시지를 볼 수 있습니다. + 토론을 시작하세요! 현재 {currentTopics, plural, one {is #개의 주제} other {are #개의 주제}}가 있습니다. 방문자에게 다양한 주제와 게시물을 선보이고 댓글을 독려할 수 있도록 최소 {requiredTopics, plural, one {#개의 주제} other {#개의 주제}}를 제공하세요. 운영진만 이 메시지를 볼 수 있습니다. too_few_posts_notice_MF: >- - 토론을 시작 합시다 ! {currentPosts, plural, one {is # post} other {are # posts}}가 있습니다. 방문자는 더 읽고 답장해야합니다. – {requiredPosts, plural, one { # post} other { # posts}} 이상을 권장합니다. 직원 만이 메시지를 볼 수 있습니다. + 토론을 시작하세요! 현재 {currentPosts, plural, one {is #개의 게시물} other {are #개의 게시물}}이 있습니다. 방문자에게 다양한 주제와 게시물을 선보이고 댓글을 독려할 수 있도록 최소 {requiredPosts, plural, one { #개의 게시물} other { #개의 게시물}}을 제공하세요. 운영진만 이 메시지를 볼 수 있습니다. logs_error_rate_notice: - 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}}" + reached_hour_MF: "{relativeAge}{rate, plural, one {#개의 오류/시간} other {#개의 오류/시간}}이 사이트 설정 한계인 {limit, plural, one {#개의 오류/시간} other {#개의 오류/시간}}에 도달했습니다." + reached_minute_MF: "{relativeAge}{rate, plural, one {#개의 오류/분} other {#개의 오류/분}}이 사이트 설정 한계인 {limit, plural, one {#개의 오류/분} other {#개의 오류/분}}에 도달했습니다." + exceeded_hour_MF: "{relativeAge}{rate, plural, one {#개의 오류/시간} other {#개의 오류/시간}}이 사이트 설정 한계인 {limit, plural, one {#개의 오류/시간} other {#개의 오류/시간}}을 초과했습니다." + exceeded_minute_MF: "{relativeAge}{rate, plural, one {#개의 오류/분} other {#개의 오류/분}}이 사이트 설정 한계인 {limit, plural, one {#개의 오류/분} other {#개의 오류/분}}을 초과했습니다." learn_more: "더 알아보기..." - first_post: 첫 번째 글 - mute: 알림끔 - unmute: 알림끔 해제 + first_post: 첫 게시물 + mute: 뮤트 + unmute: 뮤트 해제 last_post: 게시됨 - local_time: "현지 시각" + local_time: "현지 시간" time_read: 읽음 time_read_recently: "최근 %{time_read}" - time_read_tooltip: "읽은 총 시간 %{time_read}" - time_read_recently_tooltip: "%{time_read} 총 읽기 시간 (지난 60 일 동안 %{recent_time_read})" + time_read_tooltip: "총 읽은 시간 %{time_read}" + time_read_recently_tooltip: "총 읽은 시간 %{time_read}(지난 60일 동안 %{recent_time_read})" last_reply_lowercase: 마지막 댓글 replies_lowercase: other: 댓글 signup_cta: sign_up: "회원가입" - hide_forever: "사양합니다." - hidden_for_session: "알겠습니다. 내일 다시 물어볼께요. 언제든지 '로그인'을 통해서도 계정을 만들 수 있습니다." - intro: "사이트에 관심이 있지만 아직 계정을 만들지 않은 것 같습니다." + hide_session: "내일 알려주세요" + hide_forever: "괜찮습니다" + hidden_for_session: "알겠습니다. 내일 알려드리겠습니다. 언제든 '로그인'을 통해서도 계정을 만들 수 있습니다." + intro: "환영합니다! 토론에 관심이 있지만 아직 계정을 만들지 않은 것 같습니다." summary: - enabled_description: "이 글에 대한 요약: 현재 커뮤니티의 주요 글 요약본을 보고 있습니다" + enabled_description: "이 주제의 요약을 보고 있습니다. 커뮤니티에서 선정한 가장 흥미로운 게시물입니다." description: other: "%{count}개의 댓글이 있습니다." - enable: "이 글 요약" - disable: "모든 글 표시" + enable: "이 주제 요약" + disable: "모든 게시물 표시" short_label: "요약하기" - short_title: "이 글의 요약: 커뮤니티의 인기 게시물" + short_title: "이 주제의 요약 표시: 커뮤니티에서 선정한 가장 흥미로운 게시물입니다" deleted_filter: - enabled_description: "이 글에는 숨겨진 삭제 된 게시물이 있습니다." - disabled_description: "글에 삭제 된 게시물이 표시됩니다." + enabled_description: "이 주제에는 숨김 처리된 삭제된 게시물이 있습니다." + disabled_description: "주제에 삭제된 게시물이 표시됩니다." enable: "삭제된 게시물 숨기기" disable: "삭제된 게시물 표시" private_message_info: @@ -1613,98 +1618,98 @@ ko: edit: "추가 또는 제거..." remove: "제거..." add: "추가..." - leave_message: "정말 이 메시지를 남기시겠습니까?" - remove_allowed_user: "%{name}에게서 온 메시지를 삭제할까요?" - remove_allowed_group: "%{name}에게서 온 메시지를 삭제할까요?" + leave_message: "이 메시지를 남길까요?" + remove_allowed_user: "%{name} 님을 메시지에서 제거할까요?" + remove_allowed_group: "%{name} 님을 메시지에서 제거할까요?" email: "이메일" username: "사용자명" last_seen: "마지막 접속" - created: "생성됨" - created_lowercase: "생성됨" - trust_level: "회원 레벨" - search_hint: "사용자명, 이메일 또는 IP 주소" + created: "생성일" + created_lowercase: "생성일" + trust_level: "신뢰 레벨" + search_hint: "아이디, 이메일 또는 IP 주소" create_account: - header_title: "어서 오세요!" + header_title: "환영합니다!" subheader_title: "계정을 만드세요" - disclaimer: "등록하면 개인 정보 보호 정책서비스 약관에 동의하게됩니다." + disclaimer: "등록하면 개인정보 취급방침이용약관에 동의하게 됩니다." title: "계정 만들기" - failed: "문제가 발생했습니다. 이 이메일이 이미 등록되어있을 수 있습니다. 비밀번호 찾기 링크를 시도해보세요." - associate: "이미 계정이 있습니까? 로그인해 %{provider} 계정을 연결합니다." + failed: "문제가 발생했습니다. 이 이메일이 이미 등록되어 있을 수 있습니다. 비밀번호 찾기 링크를 시도해 보세요." + associate: "이미 계정이 있나요? 로그인하여 %{provider} 계정을 연결하세요." forgot_password: - title: "비밀번호 재설정" - action: "비밀번호를 잊어버렸습니다." - invite: "사용자명 또는 이메일 주소를 입력하면 비밀번호 재설정 이메일을 보내드립니다." - invite_no_username: "이메일 주소를 입력하면 비밀번호 재설정 이메일이 전송됩니다." - reset: "비밀번호 재설정" - complete_username: "계정의 사용자명이 %{username}와 일치하면 곧 비밀번호 재설정 방법에 대한 지침이 포함 된 이메일을 받게됩니다." - complete_email: "%{email}이 계정의 이메일과 일치하면, 비밀번호를 재설정하는 방법에 대한 지침이 포함 된 이메일을 받게됩니다." - complete_username_found: "사용자명 %{username}와 일치하는 계정을 찾았습니다. 곧 비밀번호 재설정 방법에 대한 지침이 포함 된 이메일을 받게됩니다." - complete_email_found: "%{email}와 일치하는 계정을 찾았습니다. 곧 비밀번호 재설정 방법에 대한 지침이 포함 된 이메일을 받게됩니다." - complete_username_not_found: "%{username}과 일치하는 계정이 없습니다." - complete_email_not_found: "%{email}과 일치하는 계정이 없습니다." - help: "이메일이 도착하지 않았습니까? 먼저 스팸 폴더를 확인해보세요.

    어떤 이메일 주소를 사용했는지 잘 모르시겠습니까? 이메일 주소를 여기에 입력하면 기록이 있는지 확인해 드리겠습니다.

    만약 더 이상 그 이메일 주소로 접근할 수 없다면, 사이트 관리자에게 도움을 요청하세요.

    " + title: "비밀번호 리셋" + action: "비밀번호가 기억나지 않습니다" + invite: "아이디 또는 이메일 주소를 입력하면 비밀번호 리셋 이메일을 보내드립니다." + invite_no_username: "이메일 주소를 입력하면 비밀번호 리셋 이메일이 전송됩니다." + reset: "비밀번호 리셋" + complete_username: "계정이 %{username} 아이디와 일치하면 곧 비밀번호 리셋 방법이 설명된 이메일을 받게 됩니다." + complete_email: "계정이 %{email} 이메일과 일치하면 곧 비밀번호 리셋 방법이 설명된 이메일을 받게 됩니다." + complete_username_found: "%{username} 아이디와 일치하는 계정을 찾았습니다. 곧 비밀번호 리셋 방법이 설명된 이메일을 받게 됩니다." + complete_email_found: "%{email} 이메일과 일치하는 계정을 찾았습니다. 곧 비밀번호 리셋 방법이 설명된 이메일을 받게 됩니다." + complete_username_not_found: "%{username} 아이디와 일치하는 계정이 없습니다." + complete_email_not_found: "%{email} 이메일과 일치하는 계정이 없습니다." + help: "이메일을 받지 못하셨나요? 먼저 스팸 폴더를 확인해 보세요.

    어떤 이메일 주소를 사용했는지 기억나지 않으신가요? 이메일 주소를 여기에 입력하면 기록이 있는지 확인해 드리겠습니다.

    이 이메일 주소로 액세스할 수 없다면 운영진에게 도움을 요청하세요.

    " button_ok: "확인" button_help: "도움말" email_login: - link_label: "로그인 링크를 이메일로 보내기" + link_label: "이메일로 로그인 링크 보내기" button_label: "이메일 사용" - login_link: "비밀번호 건너뛰기; 로그인 링크를 이메일로 보내주십시오." + login_link: "비밀번호 건너뛰기. 로그인 링크를 이메일로 보내주세요" emoji: "이모티콘 잠금" - complete_username: "계정이 사용자 이름 %{username} 과 일치하면 곧 로그인 링크가 포함 된 이메일을 받게됩니다." - complete_email: "계정이 %{email} 과 일치하면 곧 로그인 링크가 포함 된 이메일을 받게됩니다." - complete_username_found: "사용자명이 %{username}와 일치하는 계정을 찾았습니다. 곧 로그인 링크가 포함 된 이메일을 받게됩니다." - complete_email_found: "%{email} 와 일치하는 계정을 찾았습니다. 곧 로그인 링크가 포함 된 이메일을 받게됩니다." - complete_username_not_found: "%{username}과 일치하는 계정이 없습니다." - complete_email_not_found: "%{email}과 일치하는 계정이 없습니다." - confirm_title: '%{site_name}으로 가기' - logging_in_as: '%{email}으로 로그인' + complete_username: "계정이 %{username} 아이디와 일치하면 곧 로그인 링크가 포함된 이메일을 받게 됩니다." + complete_email: "계정이 %{email} 이메일과 일치하면 곧 로그인 링크가 포함된 이메일을 받게 됩니다." + complete_username_found: "%{username} 아이디와 일치하는 계정을 찾았습니다. 곧 로그인 링크가 포함된 이메일을 받게 됩니다." + complete_email_found: "%{email} 이메일과 일치하는 계정을 찾았습니다. 곧 로그인 링크가 포함된 이메일을 받게 됩니다." + complete_username_not_found: "%{username} 아이디와 일치하는 계정이 없습니다." + complete_email_not_found: "%{email} 이메일과 일치하는 계정이 없습니다." + confirm_title: '%{site_name}에서 계속하기' + logging_in_as: '%{email} 이메일로 로그인' confirm_button: 로그인 완료 login: header_title: "환영합니다" - subheader_title: "계정에 로그인하십시오." + subheader_title: "계정에 로그인하세요" title: "로그인" username: "사용자" password: "비밀번호" second_factor_title: "2단계 인증" - second_factor_description: "앱에서 인증 코드를 입력하십시오 :" - second_factor_backup: "백업 코드를 사용하여 로그인" + second_factor_description: "앱의 인증 코드를 입력하세요." + second_factor_backup: "백업 코드로 로그인" second_factor_backup_title: "2단계 백업" - second_factor_backup_description: "백업 코드 중 하나를 입력하세요:" - second_factor: "OTP 앱을 사용하여 로그인" - security_key_description: "실제 보안 키가 준비되면 아래의 보안 키로 인증 버튼을 누릅니다." + second_factor_backup_description: "백업 코드 중 하나를 입력하세요." + second_factor: "인증 앱으로 로그인" + security_key_description: "실제 보안 키가 준비되면 보안 키와 함께 아래의 인증 버튼을 누르세요." security_key_alternative: "다른 방법으로 시도" security_key_authenticate: "보안 키로 인증" security_key_not_allowed_error: "보안 키 인증 프로세스가 시간 초과되었거나 취소되었습니다." - security_key_no_matching_credential_error: "제공된 보안 키에서 일치하는 자격 증명을 찾을 수 없습니다." - security_key_support_missing_error: "현재 장치 또는 브라우저가 보안 키 사용을 지원하지 않습니다. 다른 방법을 사용하십시오." + security_key_no_matching_credential_error: "제공한 보안 키에서 일치하는 크리덴셜을 찾을 수 없습니다." + security_key_support_missing_error: "현재 디바이스 또는 브라우저가 보안 키 사용을 지원하지 않습니다. 다른 방법을 사용하세요." email_placeholder: "이메일 / 아이디" - caps_lock_warning: "Caps Lock 켜짐" - error: "알 수없는 오류" - cookies_error: "브라우저의 쿠키가 비활성화 된 것 같습니다. 먼저 활성화하지 않으면 로그인하지 못할 수 있습니다." - rate_limit: "다시 로그인을 시도하기 전에 잠시 기다려주십시오." - blank_username: "이메일 또는 사용자명을 입력하십시오." - blank_username_or_password: "이메일 또는 사용자명, 비밀번호를 입력하십시오." - reset_password: "비밀번호 재설정" + caps_lock_warning: "CapsLock 켜짐" + error: "알 수 없는 오류" + cookies_error: "브라우저의 쿠키가 비활성화된 것 같습니다. 먼저 쿠키를 활성화하지 않으면 로그인이 불가할 수 있습니다." + rate_limit: "다시 로그인을 시도하기 전에 잠시 기다려 주세요." + blank_username: "이메일 또는 아이디를 입력하세요." + blank_username_or_password: "이메일 또는 아이디, 비밀번호를 입력하세요." + reset_password: "비밀번호 리셋" logging_in: "로그인 중.." or: "또는" authenticating: "인증 중..." - awaiting_activation: "계정이 아직 미활성 상태입니다. 활성화 메일을 보내려면 비밀번호 찾기 링크를 사용하세요." - awaiting_approval: "사용자님의 계정은 아직 관리자의 승인이 처리되지 않았습니다. 승인되면 이메일이 전송됩니다." - requires_invite: "죄송합니다. 이 포럼에 대한 접근은 초대를 통해서만 가능합니다." - not_activated: "아직 로그인 할 수 없습니다. 이전에 활성화 이메일을 %{sentTo}로 보냈습니다. 해당 이메일의 지침에 따라 계정을 활성화하십시오." - not_allowed_from_ip_address: "해당 IP 주소로는 로그인 할 수 없습니다." - admin_not_allowed_from_ip_address: "해당 IP 주소에서는 관리자로 로그인 할 수 없습니다." - resend_activation_email: "활성화 이메일을 다시 보내려면 여기를 클릭하십시오." - omniauth_disallow_totp: "계정의 2단계 인증이 활성화되어 있습니다. 비밀번호로 로그인하세요." - resend_title: "활성화 이메일 다시 보내기" + awaiting_activation: "계정이 아직 활성 대기 중입니다. 활성화 메일을 다시 보내려면 비밀번호 찾기 링크를 사용하세요." + awaiting_approval: "계정이 아직 운영진의 승인을 받지 않았습니다. 승인되면 이메일이 전송됩니다." + requires_invite: "이 포럼은 초대를 통해서만 액세스 가능합니다." + not_activated: "아직 로그인할 수 없습니다. 이전에 활성화 이메일을 %{sentTo} 주소로 보냈습니다. 해당 이메일의 지침에 따라 계정을 활성화하세요." + not_allowed_from_ip_address: "이 IP 주소로는 로그인할 수 없습니다." + admin_not_allowed_from_ip_address: "이 IP 주소로는 관리자로 로그인할 수 없습니다." + resend_activation_email: "활성화 이메일을 다시 보내려면 여기를 클릭하세요." + omniauth_disallow_totp: "계정에 2단계 인증이 활성화되어 있습니다. 비밀번호로 로그인하세요." + resend_title: "활성화 이메일 재전송" change_email: "이메일 주소 변경" provide_new_email: "새 주소를 입력하면 확인 이메일이 다시 전송됩니다." submit_new_email: "이메일 주소 업데이트" - sent_activation_email_again: "%{currentEmail} 주소로 다른 계정 활성화 이메일을 보냈습니다. 도착하는데 몇 분 정도 걸릴 수 있습니다. 스팸 폴더를 확인하십시오." - sent_activation_email_again_generic: "다른 활성화 이메일을 보냈습니다. 도착하는 데 몇 분이 걸릴 수 있습니다. 스팸 폴더를 확인하십시오." - to_continue: "로그인 해주세요" - preferences: "사용자 기본 설정을 변경하려면 로그인해야 합니다." - not_approved: "계정이 아직 승인되지 않았습니다. 승인 되면 이메일로 알림을 받게 됩니다." + sent_activation_email_again: "%{currentEmail} 주소로 다시 활성화 이메일을 보냈습니다. 전송에는 몇 분 정도 걸릴 수 있습니다. 스팸 폴더도 확인하세요." + sent_activation_email_again_generic: "다시 활성화 이메일을 보냈습니다. 전송에는 몇 분 정도 걸릴 수 있습니다. 스팸 폴더도 확인하세요." + to_continue: "로그인하세요" + preferences: "사용자 환경설정을 변경하려면 로그인해야 합니다." + not_approved: "계정이 아직 승인되지 않았습니다. 로그인이 가능하게 되면 이메일로 알림이 전송됩니다." google_oauth2: name: "구글" twitter: @@ -1718,22 +1723,22 @@ ko: discord: name: "디스코드" second_factor_toggle: - totp: "대신 인증 자 앱을 사용하십시오." + totp: "대신 인증 앱 사용" backup_code: "대신 백업 코드 사용" security_key: "대신 보안 키 사용" invites: accept_title: "초대" emoji: "봉투 이모티콘" welcome_to: "%{site_name}에 오신 것을 환영합니다!" - invited_by: "사용자님을 초대한 사람 :" - social_login_available: "또한 해당 이메일을 사용하여 소셜 로그인으로 로그인 할 수 있습니다." - your_email: "사용자님의 계정 이메일 주소는 %{email}입니다." + invited_by: "초대자:" + social_login_available: "또한, 이 이메일을 사용하여 소셜 로그인으로 로그인할 수 있습니다." + your_email: "계정 이메일 주소는 %{email}입니다." accept_invite: "초대 수락" - success: "사용자님의 계정이 생성되었으며 이제 로그인 되었습니다." + success: "계정이 생성되었으며 이제 로그인되었습니다." name_label: "이름" password_label: "비밀번호" password_reset: - continue: "%{site_name}으로 가기" + continue: "%{site_name}에서 계속하기" emoji_set: apple_international: "애플/인터내셔널" google: "구글" @@ -1743,38 +1748,38 @@ ko: facebook_messenger: "페이스북 메신저" category_page_style: categories_only: "카테고리만" - categories_with_featured_topics: "주요 글이 있는 카테고리" - categories_and_latest_topics: "카테고리와 최신 글" + categories_with_featured_topics: "추천 주제가 있는 카테고리" + categories_and_latest_topics: "카테고리 및 최신 주제" categories_and_top_topics: "카테고리 및 주요 글" - categories_boxes: "하위 카테고리가 있는 상자" - categories_boxes_with_topics: "주요 글이 있는 상자" + categories_boxes: "서브카테고리가 있는 박스" + categories_boxes_with_topics: "추천 주제의 박스" shortcut_modifier_key: shift: "Shift" ctrl: "Ctrl" alt: "Alt" - enter: "시작하다" + enter: "시작" conditional_loading_section: loading: 로드 중... category_row: topic_count: - other: "이 카테고리에는 %{count}개의 글이 있습니다" + other: "이 카테고리에는 %{count}개의 주제가 있습니다" plus_subcategories_title: - other: "%{name} 및 %{count}개의 하위 카테고리" + other: "%{name} 및 %{count}개의 서브카테고리" plus_subcategories: - other: "+ %{count}개의 하위 카테고리" + other: "+ %{count}개의 서브카테고리" select_kit: - delete_item: "%{name}개 삭제" + delete_item: "%{name} 삭제" filter_by: "필터링 기준: %{name}" - select_to_filter: "필터링 기준 선택" + select_to_filter: "필터링 기준 값 선택" default_header_text: 선택... - no_content: 일치하는 항목을 찾을 수 없음 + no_content: 일치하는 항목이 없음 results_count: other: "%{count}개의 결과" filter_placeholder: 검색... filter_placeholder_with_any: 검색 또는 생성... - create: "만들기: '%{content}'" + create: "생성: '%{content}'" max_content_reached: - other: "%{count}개 항목만 선택할 수 있습니다." + other: "%{count}개의 항목만 선택할 수 있습니다." min_content_not_reached: other: "항목을 %{count}개 이상 선택하세요." components: @@ -1783,164 +1788,165 @@ ko: categories_admin_dropdown: title: "카테고리 관리" date_time_picker: - from: 보내는사람 - to: 받는사람 + from: 시작 + to: 끝 emoji_picker: filter_placeholder: 이모티콘 검색 smileys_&_emotion: 웃는 얼굴과 감정 - people_&_body: 사람과 몸 - animals_&_nature: 동물과 자연 - food_&_drink: 음식과 음료 + people_&_body: 사람 및 몸 + animals_&_nature: 동물 및 자연 + food_&_drink: 음식 및 음료 travel_&_places: 여행 및 장소 activities: 활동 objects: 사물 symbols: 기호 - flags: 신고 + flags: 깃발 recent: 최근 사용 default_tone: 피부색 없음 light_tone: 밝은 피부색 - medium_light_tone: 중간 밝기 피부색 + medium_light_tone: 중간 정도 밝은 피부색 medium_tone: 중간 피부색 - medium_dark_tone: 중간 정도의 어두운 피부색 + medium_dark_tone: 중간 정도 어두운 피부색 dark_tone: 어두운 피부색 - default: 사용자 정의 이모티콘 + default: 사용자 지정 이모티콘 shared_drafts: title: "공유 초안" - notice: "이 항목은 공유 초안을 게시할 수 있는 사용자만 볼 수 있습니다." + notice: "이 주제는 공유 초안을 게시할 수 있는 사용자만 볼 수 있습니다." destination_category: "대상 카테고리" publish: "공유 초안 게시" - confirm_publish: "이 초안을 게시 하시겠습니까?" - publishing: "글 게시 중..." + confirm_publish: "이 초안을 게시할까요?" + publishing: "주제 게시 중..." composer: - emoji: "이모티콘:)" - more_emoji: "더보기..." + emoji: "이모티콘 :)" + more_emoji: "더 보기..." options: "옵션" whisper: "귓속말" unlist: "목록에서 제외됨" - add_warning: "경고 메시지" - toggle_whisper: "귀속말 켜고 끄기" - toggle_unlisted: "목록제외 켜고 끄기" - posting_not_on_topic: "어떤 글에 댓글을 작성하시겠습니까?" - saved_local_draft_tip: "로컬에 저장" - similar_topics: "작성하려는 내용과 비슷한 글들..." + add_warning: "공식 경고입니다." + toggle_whisper: "귓속말 토글" + toggle_unlisted: "목록에서 제외 토글" + posting_not_on_topic: "어떤 주제에 댓글을 달까요?" + saved_local_draft_tip: "로컬에 저장됨" + similar_topics: "비슷한 주제가 있습니다..." drafts_offline: "오프라인 초안" edit_conflict: "충돌 편집" group_mentioned_limit: - other: "경고! %{group}을 언급했지만 이 그룹에는 관리자가 구성한 멘션 제한인 %{count}명의 사용자보다 많은 회원이 있습니다. 아무도 알림을 받지 않습니다." + other: "경고! %{group} 그룹을 멘션했지만 이 그룹에는 관리자가 구성한 멘션 제한인 %{count}명의 사용자보다 많은 회원이 있습니다. 아무도 알림을 받지 않습니다." group_mentioned: - other: "%{group}을 언급하면, %{count}명의 회원에게 알림이 전송됩니다. 그렇게 하시겠습니까?" - duplicate_link: "이 글에는 이미%{domain}의 링크가 @%{username}님이 %{ago}에 쓴 게시글에 포함되어 있습니다. 그래도 다시 작성하시겠습니까?" + other: "%{group} 그룹을 멘션하면 %{count}명의 사람에게 알림이 전송됩니다. 계속할까요?" + duplicate_link: "이 주제에는 이미 @%{username} 님이 %{ago}에 게시한 %{domain} 링크가 있습니다. 그래도 다시 게시할까요?" reference_topic_title: "RE : %{title}" error: title_missing: "제목은 필수 항목입니다" title_too_short: other: "제목은 %{count}자 이상이어야 합니다." title_too_long: - other: "제목은 %{count}자를 초과 할 수 없습니다." - post_missing: "게시물은 비워 둘 수 없습니다" + other: "제목은 %{count}자를 초과할 수 없습니다." + post_missing: "게시물 내용은 비워둘 수 없습니다" post_length: - other: "내용은 %{count}자 이상이어야 합니다." - try_like: "%{heart} 버튼을 사용해 보셨습니까?" - category_missing: "카테고리를 선택해주세요." + other: "게시물 내용은 %{count}자 이상이어야 합니다." + try_like: "%{heart} 버튼을 사용해 보셨나요?" + category_missing: "카테고리를 선택하세요" tags_missing: - other: "최소한 %{count}개의 태그를 선택해야 합니다." - topic_template_not_modified: "글 템플릿을 편집하여 글에 세부 정보와 세부 사항을 추가하십시오." + other: "최소 %{count}개의 태그를 선택해야 합니다." + topic_template_not_modified: "주제 템플릿을 편집하여 주제에 상세 정보와 세부 사항을 추가하세요." save_edit: "편집 저장" - overwrite_edit: "덮어 쓰기 편집" - reply_original: "기존 글에 대한 댓글 작성" - reply_here: "여기에 댓글을 작성하세요." - reply: "댓글" + overwrite_edit: "편집 덮어쓰기" + reply_original: "원래 주제에 댓글 달기" + reply_here: "여기에 댓글을 작성하세요" + reply: "댓글 달기" cancel: "취소" - create_topic: "새글 작성" + create_topic: "주제 생성" create_pm: "메시지" create_whisper: "귓속말" - create_shared_draft: "공유 초안 만들기" + create_shared_draft: "공유 초안 생성" edit_shared_draft: "공유 초안 편집" - title: "또는 %{modifier}Enter 키를 누릅니다." - title_placeholder: "이야기 나누고자 하는 내용을 한문장으로 적는다면?" - title_or_link_placeholder: "여기에 제목을 입력하거나 링크를 붙여 넣으세요." - edit_reason_placeholder: "왜 편집 중입니까?" - topic_featured_link_placeholder: "제목과 함께 표시된 링크를 입력하십시오." - remove_featured_link: "글에서 링크를 제거하십시오." - reply_placeholder: "여기에 입력하세요. Markdown, BBCode 또는 HTML을 사용하여 입력 할 수 있습니다. 이미지를 드래그하거나 붙여 넣을 수 있습니다." - reply_placeholder_no_images: "여기에 입력하세요. Markdown, BBCode 또는 HTML을 사용하여 작성합니다." - reply_placeholder_choose_category: "여기에 입력하기 전에 카테고리를 선택하십시오." - view_new_post: "새로운 글을 볼 수 있습니다." - saving: "저장하는 중" + title: "또는 %{modifier}Enter를 누르세요" + title_placeholder: "토론 주제를 한 문장으로 적으세요" + title_or_link_placeholder: "여기에 제목을 입력하거나 링크를 붙여 넣으세요" + edit_reason_placeholder: "편집 이유" + topic_featured_link_placeholder: "제목과 함께 표시된 링크를 입력하세요." + remove_featured_link: "주제에서 링크를 제거하세요." + reply_placeholder: "여기에 입력하세요. 포맷은 Markdown, BBCode 또는 HTML을 지원합니다. 이미지를 드래그하거나 붙여 넣을 수 있습니다." + reply_placeholder_no_images: "여기에 입력하세요. 포맷은 Markdown, BBCode 또는 HTML을 지원합니다." + reply_placeholder_choose_category: "여기에 입력하기 전에 카테고리를 선택하세요." + view_new_post: "새 게시물을 확인하세요." + saving: "저장 중" saved: "저장되었습니다!" - saved_draft: "초안 게시가 진행 중입니다. 다시 시작하려면 탭하세요." + saved_draft: "초안을 게시 중입니다. 재개하려면 탭하세요." uploading: "업로드 중..." show_preview: "미리보기 표시" hide_preview: "미리보기 숨기기" - quote_post_title: "전체 글을 인용" + quote_post_title: "전체 게시물 인용" bold_label: "B" bold_title: "굵게" - bold_text: "굵게하기" + bold_text: "굵은 텍스트" italic_label: "I" - italic_title: "기울이기 적용" - italic_text: "강조하기" + italic_title: "기울이기" + italic_text: "기울이기 적용된 텍스트" link_title: "하이퍼링크" - link_description: "여기에 링크 설명을 입력하십시오." + link_description: "여기에 링크 설명을 입력하세요" link_dialog_title: "하이퍼링크 삽입" - link_optional_text: "선택적 제목" - link_url_placeholder: "글을 검색하려면 URL을 붙여 넣거나 입력하세요." - blockquote_title: "인용구" - blockquote_text: "인용구" - code_title: "코드" + link_optional_text: "제목(선택사항)" + link_url_placeholder: "주제를 검색하려면 URL을 붙여 넣거나 입력하세요" + blockquote_title: "블록 따옴표" + blockquote_text: "블록 따옴표" + code_title: "미리 서식이 지정된 텍스트" code_text: "미리 서식이 지정된 텍스트를 4칸 들여쓰기" - paste_code_text: "여기에 코드를 입력하거나 붙여 넣습니다." + paste_code_text: "여기에 코드를 입력하거나 붙여 넣으세요" upload_title: "업로드" - upload_description: "여기에 업로드 설명을 입력하십시오." + upload_description: "여기에 업로드 설명을 입력하세요" olist_title: "번호 매기기 목록" - ulist_title: "글 머리 기호 목록" + ulist_title: "글머리 기호 목록" list_item: "목록 항목" toggle_direction: "방향 전환" help: "Markdown 편집 도움말" - collapse: "글쓰기 화면 최소화" - open: "글쓰기 화면을 엽니다" - abandon: "글쓰기 화면을 닫고 초안을 삭제합니다." - enter_fullscreen: "전체 화면으로 글쓰기" - exit_fullscreen: "전체 화면 글쓰기 종료" - show_toolbar: "글 입력기 도구 모음 표시" - hide_toolbar: "글 입력기 도구 모음 숨기기" + collapse: "작성기 패널 최소화" + open: "작성기 패널 열기" + abandon: "작성기 닫기 및 초안 버리기" + enter_fullscreen: "전체화면으로 작성기 보기" + exit_fullscreen: "작성기 전체화면 종료" + exit_fullscreen_prompt: "전체 화면에서 나가려면 ESC를 누르세요." + show_toolbar: "작성기 툴바 표시" + hide_toolbar: "작성기 툴바 숨기기" modal_ok: "확인" modal_cancel: "취소" - cant_send_pm: "죄송합니다. %{username}님에게 메시지를 보낼 수 없습니다." + cant_send_pm: "%{username} 님에게 메시지를 보낼 수 없습니다." yourself_confirm: title: "받는 사람 추가를 잊으셨나요?" body: "지금 이 메시지는 자신에게만 전송됩니다!" slow_mode: - error: "이 항목은 느린 모드입니다. 최근에 이미 게시했습니다; %{timeLeft}후 다시 게시 할 수 있습니다." - admin_options_title: "이 글에 대한 옵션 설정" + error: "이 주제는 느린 모드입니다. 최근에 이미 게시했습니다. %{timeLeft} 후 다시 게시할 수 있습니다." + admin_options_title: "(선택사항) 이 주제의 운영진 설정" composer_actions: - reply: 댓글쓰기 - draft: 임시저장 + reply: 댓글 달기 + draft: 초안 edit: 편집 reply_to_post: - label: '%{postUsername}님 게시물에 답장' - desc: 특정 게시물에 답장 + label: '%{postUsername} 님 게시물에 댓글 달기' + desc: 특정 게시물에 댓글을 답니다 reply_as_new_topic: - label: 링크 된 글로 답장 - desc: 이 글에 링크된 새로운 글 쓰기 - confirm: 새 글 초안이 저장되어 있으며 링크된 글을 만들면 덮어 쓰게됩니다. + label: 링크된 주제로 댓글 달기 + desc: 이 주제에 링크된 새 주제를 만듭니다 + confirm: 새 주제 초안을 저장했으며 링크된 주제를 만들면 덮어쓰게 됩니다. reply_as_new_group_message: - label: 새 그룹 메시지로 답장 - desc: 동일한 수신자에게 새 메시지 쓰기 + label: 새 그룹 메시지로 댓글 달기 + desc: 동일한 수신자에게 새 메시지를 작성합니다 reply_to_topic: - label: 댓글 쓰기 - desc: 특정 게시물이 아닌 글에 대한 댓글 + label: 주제에 댓글 달기 + desc: 특정 게시물이 아닌 주제에 댓글을 답니다 toggle_whisper: - label: 귀속말 켜고 끄기 - desc: 귓속말은 관리자만 볼 수 있습니다. + label: 귓속말 토글 + desc: 귓속말은 운영진만 볼 수 있습니다 create_topic: - label: "새 글" + label: "새 주제" shared_draft: label: "공유 초안" - desc: "허용된 사용자만 볼 수 있는 글 초안 작성" + desc: "허용된 사용자만 볼 수 있는 주제 초안을 작성합니다" toggle_topic_bump: - label: "글 범프 전환" - desc: "최신 회신 날짜를 변경하지 않고 회신" - reload: "새로 고침" + label: "주제 끌어 올리기 토글" + desc: "최신 댓글 날짜를 변경하지 않고 댓글을 답니다" + reload: "리로드" ignore: "무시" image_alt_text: aria_label: 이미지의 대체 텍스트 @@ -1949,13 +1955,13 @@ ko: regular: other: "%{count}개의 확인하지 않은 알림이 있습니다" message: - other: "%{count}개의 읽지않은 메시지가 있습니다" + other: "%{count}개의 읽지 않은 메시지가 있습니다" high_priority: - other: "읽지 않은 높은 우선 순위의 알림 %{count}개" - title: "@name 멘션 알림, 글에 대한 댓글, 개인 메시지 등에 대한 알림" - none: "현재 알림을 불러올 수 없습니다." + other: "%{count}개의 읽지 않은 높은 우선순위 알림이 있습니다" + title: "@이름 멘션, 내 게시물 및 주제의 댓글, 메시지 등에 대한 알림" + none: "현재 알림을 로드할 수 없습니다." empty: "알림이 없습니다." - post_approved: "사용자님의 게시물이 승인되었습니다" + post_approved: "게시물이 승인되었습니다" reviewable_items: "검토가 필요한 항목" watching_first_post_label: "새 글" mentioned: "%{username} %{description}" @@ -1968,25 +1974,25 @@ ko: liked: "%{username} %{description}" liked_2: "%{username}, %{username2} %{description}" liked_many: - other: "%{username}, %{username2} 그리고 %{count} 그외 %{description}" + other: "%{username}, %{username2} 및 이외 %{count}명 %{description}" liked_by_2_users: "%{username}, %{username2}" liked_by_multiple_users: other: "%{username}, %{username2} 외 %{count} 명의 사용자가" liked_consolidated_description: - other: "내 게시물 중 %{count}개를 좋아합니다." + 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} (을)를 이동했습니다" + moved_post: "%{username} 님이 %{description} 게시물을 이동했습니다" linked: "%{username} %{description}" granted_badge: "'%{description}' 획득" topic_reminder: "%{username} %{description}" - watching_first_post: "새 글 %{description}" - membership_request_accepted: "'%{group_name}'에 회원 가입" + watching_first_post: "새 주제 %{description}" + membership_request_accepted: "'%{group_name}' 멤버십이 승인되었습니다" membership_request_consolidated: - other: "'%{group_name}'의 회원 가입 요청 %{count}건" + other: "'%{group_name}'의 진행 중인 멤버십 요청 %{count}건" reaction: "%{username} %{description}" reaction_2: "%{username}, %{username2} %{description}" votes_released: "%{description} - 완료됨" @@ -1994,47 +2000,49 @@ ko: body: default: other: "확실한가요? %{count}개의 중요한 알림이 있습니다." - dismiss: "읽음" + messages: + other: "확실한가요? 읽지 않은 개인 메시지가 %{count}개 있습니다." + dismiss: "무시" cancel: "취소" group_message_summary: - other: " %{group_name} 사서함에 %{count}개의 메시지가 있습니다" + other: " %{group_name} 받은 편지함에 %{count}개의 메시지가 있습니다" popup: - mentioned: '"%{topic}"에서 %{username}님이 나를 멘션했습니다 - %{site_title}' - group_mentioned: '"%{topic}"에서 %{username}님이 사용자님을 언급했습니다 - %{site_title}' - quoted: '"%{topic}"에서 %{username}님이 사용자님을 인용했습니다 - %{site_title}' - replied: '"%{topic}"에서 %{username}님이 사용자님에게 댓글을 달았습니다 - %{site_title}' - posted: '"%{topic}"에서 %{username}님이 글을 게시하였습니다 - %{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: "%{site_title}의 %{username}님의 알림" + mentioned: '''%{topic}'' - %{site_title}에서 %{username} 님이 나를 멘션했습니다' + group_mentioned: '''%{topic}'' - %{site_title}에서 %{username} 님이 나를 멘션했습니다' + quoted: '''%{topic}'' - %{site_title}에서 %{username} 님이 나를 인용했습니다' + replied: '''%{topic}'' - %{site_title}에서 %{username} 님이 나에게 댓글을 달았습니다' + posted: '''%{topic}'' - %{site_title}에서 %{username} 님이 게시했습니다' + private_message: '''%{topic}'' -%{site_title}에서 %{username} 님이 나에게 개인 메시지를 보냈습니다' + linked: '%{username} 님이 ''%{topic}'' - %{site_title}의 내 게시물에 링크했습니다' + watching_first_post: '%{username} 님이 새 주제(''%{topic}'' - %{site_title})를 만들었습니다' + confirm_title: "알림 활성화됨 - %{site_title}" + confirm_body: "알림이 활성화되었습니다." + custom: "%{site_title}의 %{username} 님의 알림" titles: - mentioned: "멘션" + mentioned: "멘션됨" replied: "새 댓글" quoted: "인용됨" edited: "편집됨" - liked: "새로운 좋아요" - private_message: "새 개인 메시지" + liked: "새 좋아요" + private_message: "새 비공개 메시지" invited_to_private_message: "비공개 메시지에 초대됨" - invitee_accepted: "초대 수락" - posted: "새 글" + invitee_accepted: "초대 수락됨" + posted: "새 게시물" moved_post: "게시물 이동됨" - linked: "연결됨" - bookmark_reminder: "북마크 알림" - bookmark_reminder_with_name: "북마크 알림 - %{name}" - granted_badge: "부여된 배지" - invited_to_topic: "글에 초대" - group_mentioned: "언급 된 그룹" + linked: "링크됨" + bookmark_reminder: "북마크 미리 알림" + bookmark_reminder_with_name: "북마크 미리 알림 - %{name}" + granted_badge: "배지 부여됨" + invited_to_topic: "주제에 초대됨" + group_mentioned: "멘션된 그룹" group_message_summary: "새 그룹 메시지" - watching_first_post: "새 글" + watching_first_post: "새 주제" topic_reminder: "글 알림" - liked_consolidated: "새로운 좋아요" - post_approved: "게시물 승인됨" - membership_request_consolidated: "신규 멤버십 요청" - reaction: "새로운 반응" - votes_released: "투표가 발표되었습니다" + liked_consolidated: "새 좋아요" + post_approved: "승인된 게시물" + membership_request_consolidated: "새 멤버십 요청" + reaction: "새 반응" + votes_released: "투표가 시작되었습니다" upload_selector: uploading: "업로드 중" processing: "업로드 처리 중" @@ -2043,65 +2051,65 @@ ko: search: sort_by: "정렬 기준" relevance: "관련성" - latest_post: "최신 글" - latest_topic: "최신 글" - most_viewed: "가장 많이 봄" - most_liked: "가장 좋아함" + latest_post: "최신 게시물" + latest_topic: "최신 주제" + most_viewed: "가장 높은 조회수" + most_liked: "가장 많은 좋아요" select_all: "모두 선택" clear_all: "모두 지우기" too_short: "검색어가 너무 짧습니다." - open_advanced: "상세 검색 열기" + open_advanced: "고급 검색 열기" clear_search: "검색 지우기" sort_or_bulk_actions: "결과 정렬 또는 일괄 선택" result_count: - other: "%{term}에 대한 %{count}%{plus}개의 검색 결과" + other: "%{term}에 대한 결과 %{count}%{plus}개" title: "검색" full_page_title: "검색" - no_results: "검색 결과가 없습니다" + no_results: "검색 결과가 없습니다." no_more_results: "더 이상 결과가 없습니다." - post_format: "%{username}님의 글 #%{post_number}" + post_format: "%{username} 님의 게시물 #%{post_number}" results_page: "'%{term}'에 대한 검색 결과" more_results: "검색 결과가 많습니다. 검색 조건을 좁혀보세요." - cant_find: "원하는 것을 찾을 수 없습니까?" - start_new_topic: "새 글을 만들어볼까요?" - or_search_google: "혹은 구글에서 검색해볼 수도 있습니다." - search_google: "대신 구글에서 검색해보세요." + cant_find: "원하는 결과가 없나요?" + start_new_topic: "새 주제를 만들어 보세요" + or_search_google: "또는 Google에서 검색해 보세요." + search_google: "대신 Google에서 검색해 보세요." search_google_button: "구글" search_button: "검색" search_term_label: "검색 키워드 입력" categories: "카테고리" tags: "태그" - in_this_topic: "이 글에서" - in_this_topic_tooltip: "모든 글 검색으로 전환" - in_topics_posts: "모든 글과 댓글에서" - enter_hint: "또는 Enter 키를 누르십시오." - in_posts_by: "%{username}님의 글에서" + in_this_topic: "이 주제 내에서" + in_this_topic_tooltip: "모든 주제 검색으로 전환" + in_topics_posts: "모든 주제와 게시물에서" + enter_hint: "또는 Enter를 누르세요" + in_posts_by: "%{username} 님의 게시물에서" browser_tip: "%{modifier} + f" browser_tip_description: "다시 기본 브라우저 검색 사용" recent: "최근 검색" clear_recent: "최근 검색 지우기" type: - default: "글/댓글" + default: "주제/게시물" users: "사용자" categories: "카테고리" categories_and_tags: "카테고리/태그" context: - user: "@%{username}님의 글 검색" + user: "@%{username} 님의 게시물 검색" category: "#%{category} 카테고리에서 검색" tag: "#%{tag} 태그 검색" - topic: "이 글에서 검색" + topic: "이 주제에서 검색" private_messages: "메시지 검색" tips: - category_tag: "카테고리 또는 태그별 필터" - author: "게시물 작성자별 필터" - in: "메타데이터별 필터 (예: in:title, in:personal, in:pinned)" - status: "글 상태별 필터" + category_tag: "카테고리 또는 태그로 필터링" + author: "게시물 작성자로 필터링" + in: "메타데이터로 필터링(예: in:title, in:personal, in:pinned)" + status: "주제 상태로 필터링" full_search: "전체 페이지 검색 시작" full_search_key: "%{modifier} + 엔터" advanced: - title: 상세검색 + title: 고급 필터 posted_by: - label: '글쓴이:' + label: 게시자 aria_label: 게시물 작성자로 필터링 in_category: label: 분류됨 @@ -2110,36 +2118,36 @@ ko: with_badge: label: 배지 포함 with_tags: - label: 태그 됨 + label: 태그됨 aria_label: 태그로 필터링 filters: - label: 항목/게시물 만 반환... - title: 제목에서만 일치 + label: 다음 주제/게시물만 반환... + title: 제목만 일치 likes: 내가 좋아요 누름 - posted: 내가 쓴 글 - created: 내가 작성함 - watching: 내가 주시중 - tracking: 내가 팔로우중 - private: 내 메시지 - bookmarks: 내 북마크 - first: 첫 번째 게시물입니다 + posted: 내가 게시한 위치 + created: 내가 생성함 + watching: 내가 구독 중 + tracking: 내가 추적 중 + private: 내 메시지 내 + bookmarks: 내가 북마크함 + first: 첫 게시물 pinned: 고정됨 seen: 읽음 unseen: 읽지 않음 - wiki: 위키입니다 + wiki: 위키 images: 이미지 포함 all_tags: 위의 모든 태그 statuses: - label: 글 상태 - open: 가 열렸습니다 - closed: 가 닫혔습니다 + label: 주제 상태 + open: 진행 중 + closed: 종료됨 public: 공개 - archived: 보관 됨 - noreplies: 댓글이 없습니다 - single_user: 1명의 사용자를 포함합니다 + archived: 보관됨 + noreplies: 댓글 없음 + single_user: 단일 사용자 포함 post: count: - label: 글 + label: 게시물 min: placeholder: 최소 aria_label: 최소 게시물 수로 필터링 @@ -2147,12 +2155,12 @@ ko: placeholder: 최대 aria_label: 최대 게시물 수로 필터링 time: - label: 게시 됨 + label: 게시됨 aria_label: 게시 날짜로 필터링 before: 이전 after: 이후 views: - label: 조회 + label: 조회수 min_views: placeholder: 최소 aria_label: 최소 조회수로 필터링 @@ -2160,152 +2168,158 @@ ko: placeholder: 최대 aria_label: 최대 조회수로 필터링 additional_options: - label: "게시물 수 및 글 조회수로 필터링" + label: "게시물 수 및 주제 조회수로 필터링" hamburger_menu: "메뉴" - new_item: "새 항목" - go_back: "돌아가기" - not_logged_in_user: "현재 활동 및 기본 설정에 대한 요약이 포함된 사용자 페이지" + new_item: "신규" + go_back: "뒤로 가기" + not_logged_in_user: "현재 활동 및 환경설정에 대한 요약이 포함된 사용자 페이지" current_user: "사용자 페이지로 이동" - view_all: "모두보기 %{tab}" + view_all: "%{tab} 모두 보기" user_menu: + view_all_messages: "모든 개인 메시지 보기" + tabs: + replies: "댓글" + mentions: "멘션" + likes: "좋아요 수" + bookmarks: "북마크들" + profile: "프로필" reviewable: view_all: "모든 리뷰 항목 보기" queue: "대기열" deleted_user: "(삭제된 사용자)" post_number_with_topic_title: "게시물 #%{post_number} - %{title}" new_post_in_topic: "%{title}의 새 게시물" - suspicious_user: "의심스러운 사용자 %{username}" default_item: "검토 가능한 항목 #%{reviewable_id}" topics: new_messages_marker: "마지막 방문" bulk: select_all: "모두 선택" clear_all: "모두 지우기" - unlist_topics: "목록에서 글 숨기기" - relist_topics: "목록에서 글 다시 보이기" + unlist_topics: "목록에서 주제 숨기기" + relist_topics: "목록에서 주제 다시 표시" defer: "연기" delete: "글 삭제" - dismiss: "읽음" - dismiss_read: "읽지 않은 항목 모두 읽음" + dismiss: "무시" + dismiss_read: "읽지 않은 항목 모두 무시" dismiss_read_with_selected: - other: "읽지 않은 %{count}개 읽음 처리" - dismiss_button: "읽은 글로 표시..." + other: "%{count}개의 읽지 않은 항목 무시" + dismiss_button: "무시..." dismiss_button_with_selected: - other: "읽음 처리(%{count}개)..." - dismiss_tooltip: "새 게시물만 닫거나 글 팔로우 중지" - also_dismiss_topics: "이 글 팔로우를 중지하여 다시 읽지 않은 것으로 표시되지 않도록합니다." - dismiss_new: "새글 모두 읽음" + other: "무시(%{count})..." + dismiss_tooltip: "새 게시물만 무시하거나 주제 추적 중지" + also_dismiss_topics: "이 주제 추적을 중지하여 읽지 않은 항목으로 다시 표시되지 않도록 합니다" + dismiss_new: "새 항목 무시" dismiss_new_with_selected: - other: "새글 읽음 처리 (%{count}개)" - toggle: "글 일괄 선택 전환" - actions: "일괄 적용" + other: "새 항목 무시(%{count})" + toggle: "주제 일괄 선택 토글" + actions: "일괄 작업" change_category: "카테고리 설정..." close_topics: "글 닫기" - archive_topics: "글 보관" + archive_topics: "주제 보관" move_messages_to_inbox: "받은 편지함으로 이동" notification_level: "알림..." change_notification_level: "알림 수준 변경" - choose_new_category: "글에 대한 새 카테고리 선택:" + choose_new_category: "주제에 대한 새 카테고리 선택:" selected: - other: "사용자님은 %{count}개의 글을 선택했습니다." - change_tags: "태그 바꾸기" + other: "%{count}개의 주제를 선택했습니다." + change_tags: "태그 대체" append_tags: "태그 추가" - choose_new_tags: "다음 글에 대한 새 태그를 선택하십시오:" - choose_append_tags: "다음 글에 추가 할 새 태그를 선택하십시오:" - changed_tags: "해당 글의 태그가 변경되었습니다." + choose_new_tags: "다음 주제에 새 태그 선택:" + choose_append_tags: "다음 주제에 추가할 새 태그 선택:" + changed_tags: "이 주제의 태그가 변경되었습니다." remove_tags: "모든 태그 제거" confirm_remove_tags: - other: "%{count}개의 글에서 모든 태그가 제거됩니다. 확실한가요?" + other: "%{count}개의 주제에서 태그가 모두 제거됩니다. 계속할까요?" progress: - other: "진행률: %{count}개의 글" + other: "진행률: %{count}개의 주제" none: unread: "읽지 않은 글이 없습니다." - unseen: "보지 않은 글이 없습니다." - new: "새로운 글이 없습니다." - read: "아직 읽은 글이 없습니다." - posted: "아직 어떤 글도 게시하지 않았습니다." + unseen: "확인하지 않은 주제가 없습니다." + new: "새 주제가 없습니다." + read: "아직 읽은 주제가 없습니다." + posted: "아직 게시한 주제가 없습니다." latest: "모두 확인했습니다!" bookmarks: "아직 북마크된 글이 없습니다." - category: "%{category}에 글이 없습니다." - top: "주요 글이 없습니다." + category: "%{category} 주제가 없습니다." + top: "주요 주제가 없습니다." educate: - new: '

    새로운 글이 여기에 표시됩니다. 기본적으로 지난 2일 이내에 작성된 글은 새로운 글로 간주되며 가 표시됩니다.

    이 기준을 변경하려면 환경설정에서 변경 하십시오.

    ' - unread: '

    읽지 않은 글은 여기에 표시됩니다.

    기본적으로 글은 읽지 않은 것으로 간주하고 다음과 같은 조건 중 하나를 만족하면 읽지 않은 글수 1 을 표시합니다:

    • 새로운 글 작성
    • 글에 댓글 작성
    • 글을 4분 이상 읽기

    또는 글을 팔로우 하거나 지켜보기 위해 각 글의 밑부분에 달린 알림 제어판에서 설정하는 경우도 포함됩니다.

    설정을 바꾸려면 환경설정 페이지로 가세요.

    ' + new: '

    새 주제가 여기에 표시됩니다. 기본적으로 지난 2일 이내에 작성된 주제는 새 주제로 간주되며 표시로 확인할 수 있습니다.

    이 기준을 변경하려면 환경설정에서 변경하세요.

    ' + unread: '

    읽지 않은 주제는 여기에 표시됩니다.

    기본적으로 주제는 읽지 않은 것으로 간주되며 다음과 같은 조건 중 하나를 만족하면 읽지 않은 주제 개수 1이 표시됩니다.

    • 새 주제 작성
    • 주제에 댓글 작성
    • 주제를 4분 이상 읽음

    또는 각 주제의 알림 아이콘에서 주제를 추적하거나 구독하도록 설정하는 경우도 포함됩니다.

    설정을 변경하려면 환경설정 페이지로 이동하세요.

    ' bottom: - latest: "더 이상 최근 글이 없습니다." - posted: "더 이상 작성한 글이 없습니다." - read: "더 이상 읽을 글이 없습니다." - new: "더 이상 새로운 글이 없습니다." - unread: "더 이상 읽지 않은 글이 없습니다." - unseen: "더 이상 보지 않는 글이 없습니다." - category: "더 이상 %{category}에 글이 없습니다." - tag: "더 이상 %{tag}의 글이 없습니다." - top: "더 이상 주요 글이 없습니다." - bookmarks: "더이상 북마크한 글이 없습니다." + latest: "더 이상 최근 주제가 없습니다." + posted: "더 이상 게시한 주제가 없습니다." + read: "더 이상 읽은 주제가 없습니다." + new: "더 이상 새 주제가 없습니다." + unread: "더 이상 읽지 않은 주제가 없습니다." + unseen: "더 이상 확인하지 않은 주제가 없습니다." + category: "더 이상 %{category} 주제가 없습니다." + tag: "더 이상 %{tag} 주제가 없습니다." + top: "더 이상 주요 주제가 없습니다." + bookmarks: "더 이상 북마크한 주제가 없습니다." topic: filter_to: - other: "이 글에 %{count}개의 게시글" - create: "새글 쓰기" - create_long: "새글 쓰기" + other: "이 주제의 게시물 %{count}개" + create: "새 주제" + create_long: "새 주제 생성" open_draft: "초안 열기" private_message: "메시지 시작" archive_message: - help: "저장함으로 이동" - title: "저장됨" + help: "보관함으로 메시지 이동" + title: "보관" move_to_inbox: title: "받은 편지함으로 이동" help: "메시지를 받은 편지함으로 다시 이동" edit_message: - help: "메시지의 첫 번째 게시물 수정" + help: "메시지의 첫 게시물 편집" title: "편집" defer: - help: "읽지 않은 상태로 표시" + help: "읽지 않음으로 표시" title: "연기" list: "글" - new: "새 글" + new: "새 주제" unread: "읽지 않음" new_topics: - other: "%{count}개의 새로운 글" + other: "%{count}개의 새 주제" unread_topics: other: "%{count}개의 읽지 않은 글" title: "글" invalid_access: - title: "비공개 글입니다." - description: "죄송합니다. 해당 글에 접근 할 수 없습니다!" - login_required: "해당 글을 보려면 로그인이 필요합니다." + title: "비공개 주제입니다" + description: "이 주제에 액세스할 수 없습니다!" + login_required: "이 주제를 보려면 로그인이 필요합니다." server_error: - title: "글을 불러오지 못했습니다." - description: "죄송합니다. 연결 문제로 인해 해당 글을 불러올 수 없습니다. 다시 시도하십시오. 문제가 지속되면 문의해 주시기 바랍니다" + title: "주제를 로드하지 못했습니다" + description: "이 주제를 로드할 수 없습니다. 연결 문제일 수 있습니다. 다시 시도하세요. 문제가 지속되면 저희에게 문의하세요." not_found: - title: "글을 찾을 수 없음" - description: "죄송합니다. 해당 글을 찾을 수 없습니다. 관리자가 삭제 한 것일 수 있습니다." + title: "주제를 찾을 수 없음" + description: "이 주제를 찾을 수 없습니다. 운영자가 제거했을 수 있습니다." unread_posts: - other: "이 글에 %{count}개의 읽지 않은 댓글이 있습니다." + other: "이 주제에 %{count}개의 읽지 않은 게시물이 있습니다" likes: - other: "이 글에 %{count}개의 좋아요가 있습니다." - back_to_list: "글 목록으로 돌아 가기" + other: "이 주제에 %{count}개의 좋아요가 있습니다" + back_to_list: "주제 목록으로 돌아가기" options: "글 옵션" - show_links: "이 글의 링크 표시" - collapse_details: "글의 세부 정보를 축소" - expand_details: "글의 세부 정보를 확장" - read_more_in_category: "더 읽을거리가 필요하신가요? %{catLink} 또는 %{latestLink}를 살펴보세요." - read_more: "%{catLink} 또는 %{latestLink}에서 더 많은 글을 찾으실 수 있습니다." - unread_indicator: "아직 이 글의 마지막 게시물을 읽은 회원이 없습니다." + show_links: "이 주제에 링크 표시" + collapse_details: "주제 상세 정보 접기" + expand_details: "주제 상세 정보 펼치기" + read_more_in_category: "더 읽고 싶으신가요? %{catLink} 또는 %{latestLink}에서 다른 주제를 찾아보세요." + read_more: "더 읽고 싶으신가요? %{catLink} 또는 %{latestLink}에서 확인하세요." + unread_indicator: "아직 이 주제의 마지막 게시물을 읽은 회원이 없습니다." bumped_at_title_MF: "{FIRST_POST}: {CREATED_AT}\n{LAST_POST}: {BUMPED_AT}" - browse_all_categories: 모든 카테고리 보기 - browse_all_tags: 모든 태그 보기 + browse_all_categories: 모든 카테고리 탐색 + browse_all_tags: 모든 태그 탐색 view_latest_topics: 최근 글 보기 - suggest_create_topic: 새 대화를 시작할 준비가 되셨습니까? - jump_reply_up: 이전 답글로 이동 - jump_reply_down: 이후 답글로 이동 + suggest_create_topic: 새 대화를 시작할 준비가 되었나요? + jump_reply_up: 이전 댓글로 이동 + jump_reply_down: 다음 댓글로 이동 deleted: "글이 삭제되었습니다." slow_mode_update: title: "느린 모드" - select: "사용자는 이 글에 한 번 씩만 댓글을 작성 할 수 있습니다." - description: "빠르게 진행되거나 논쟁이되는 대화에서 신중한 대화를 유도하기위해 사용자는이 글에 추가로 글을 작성하기 위해서는 기다려야합니다." + select: "사용자는 이 주제에서 다음을 기준으로 한 번만 게시할 수 있습니다." + description: "빠르게 진행되거나 논쟁이 되는 토론에서 신중한 대화를 유도하기 위해 사용자는 이 주제에 추가로 글을 게시하려면 기다려야 합니다." enable: "활성화" update: "업데이트" - enabled_until: "다음까지 사용 가능:" + enabled_until: "다음 기간까지 활성화됨:" remove: "비활성화" hours: "시간:" minutes: "분:" @@ -2323,455 +2337,452 @@ ko: 24_hours: "24시간" custom: "사용자 지정 기간" slow_mode_notice: - duration: "이 글에 댓글을 작성하려면 %{duration}을 기다려야합니다." + duration: "%{duration} 후 이 주제에 추가로 게시할 수 있습니다." topic_status_update: - title: "글 타이머" + title: "주제 타이머" save: "타이머 설정" num_of_hours: "시간:" num_of_days: "일 수:" - remove: "타이머 제거하기" - publish_to: "게시되는 곳:" + remove: "타이머 제거" + publish_to: "게시 위치:" when: "게시일:" - time_frame_required: "기간을 선택하세요." - min_duration: "기간은 0보다 커야 합니다." - max_duration: "기간은 20년 미만이어야 합니다." + time_frame_required: "기간을 선택하세요" + min_duration: "기간은 0보다 커야 합니다" + max_duration: "기간은 20년 미만이어야 합니다" duration: "기간" publish_to_category: title: "게시 예약" temp_open: title: "임시로 열기" auto_reopen: - title: "자동으로 열린 글" + title: "주제 자동 열기" temp_close: - title: "임시로 닫기" + title: "임시로 종료" auto_close: - title: "글 자동 잠금" - label: "자동으로 글 닫기 시간:" - error: "유효한 값을 입력하십시오." - based_on_last_post: "글의 마지막 게시물이 이보다 오래 될 때까지 닫지 마십시오." + title: "주제 자동 종료" + label: "다음 이후 주제 자동 종료:" + error: "유효한 값을 입력하세요." + based_on_last_post: "주제의 마지막 게시물이 이 기간보다 오래될 때까지 닫지 마세요." auto_close_after_last_post: - title: "마지막 댓글후 글 자동 닫기" + title: "마지막 게시물 후 주제 자동 종료" auto_delete: - title: "글 자동 삭제" + title: "주제 자동 삭제" auto_bump: - title: "자동 끌어올림 글" + title: "주제 자동 끌어 올림" reminder: - title: "알림" + title: "알림 받기" auto_delete_replies: title: "댓글 자동 삭제" status_update_notice: - auto_open: "이 글은 %{timeLeft}에 자동으로 열립니다." - auto_close: "이 글은 %{timeLeft}에 자동으로 닫힙니다." - auto_publish_to_category: "이 글은 #%{categoryName}에 %{timeLeft} 후 게시됩니다." - auto_close_after_last_post: "이 글은 마지막 댓글이 달리고 %{duration} 후 닫힙니다." - auto_delete: "이 글은 %{timeLeft}에 자동으로 삭제됩니다." - auto_bump: "이 글은 %{timeLeft}에 자동으로 끌어올려 집니다." - auto_reminder: "%{timeLeft}에 현재 글 알림" - auto_delete_replies: "이 글에 대한 댓글은 %{duration}후에 자동으로 삭제됩니다." - auto_close_title: "자동 닫기 설정" + auto_open: "이 주제는 %{timeLeft} 후 자동으로 열립니다." + auto_close: "이 주제는 %{timeLeft} 후 자동으로 종료됩니다." + auto_publish_to_category: "이 주제는 #%{categoryName}에 %{timeLeft} 후 게시됩니다." + auto_close_after_last_post: "이 주제는 마지막 댓글이 달리고 %{duration} 후 종료됩니다." + auto_delete: "이 주제는 %{timeLeft} 후 자동으로 삭제됩니다." + auto_bump: "이 주제는 %{timeLeft} 후 자동으로 끌어 올림 됩니다." + auto_reminder: "%{timeLeft} 후 이 주제에 대한 알림을 받습니다." + auto_delete_replies: "이 주제의 댓글은 %{duration} 후에 자동으로 삭제됩니다." + auto_close_title: "자동 종료 설정" auto_close_immediate: - other: "글의 마지막 게시물은 이미 %{count}시간이 지났으므로 해당 글은 즉시 닫힙니다." + other: "주제의 마지막 게시물은 이미 %{count} 시간이 지났으므로 이 주제는 즉시 종료됩니다." auto_close_momentarily: - other: "글의 마지막 게시물은 이미 %{count}시간이 지났으므로 일시적으로 닫힙니다." + other: "주제의 마지막 게시물은 이미 %{count} 시간이 지났으므로 이 주제는 일시적으로 종료됩니다." timeline: - back: "뒤로" - back_description: "읽지 않은 마지막 게시물로 돌아가기" + back: "뒤로 가기" + back_description: "읽지 않은 마지막 게시물로 이동합니다" replies_short: "%{current} / %{total}" progress: title: 진행 중인 주제 jump_prompt: "이동..." jump_prompt_of: - other: "번째, %{count}개 중" + other: "/ %{count}개의 게시물" jump_prompt_long: "이동..." jump_prompt_to_date: "현재까지" jump_prompt_or: "또는" notifications: - title: 이 글에 대한 알림을 받는 빈도 변경 + title: 이 주제에 대한 알림을 받는 빈도 변경 reasons: - mailing_list_mode: "메일링 리스트 모드가 활성화되어 있으므로 이 글의 댓글을 메일로 받게 됩니다." - "3_10": "이 글에 대한 태그를 주시중이므로 알림을 받게됩니다." - "3_10_stale": "과거에 이 글의 태그를 팔로우했기 때문에 알림을 받게됩니다." - "3_6": "이 카테고리를 주시중이므로 알림을 받게됩니다." - "3_6_stale": "과거에 이 카테고리를 팔로우했기 때문에 알림을 받게됩니다." - "3_5": "이 글을 자동으로 주시하기 시작 했으므로 알림을 받게됩니다." - "3_2": "이 글을 보고 있으므로 알림을 받게됩니다." - "3_1": "이 글을 작성 했으므로 알림을 받게됩니다." - "3": "이 글을 보고 있으므로 알림을 받게됩니다." - "2_8": "이 카테고리를 팔로우 하고 있으므로 새 댓글 수가 표시됩니다." - "2_8_stale": "과거에 이 카테고리를 팔로우했기 때문에 새 댓글 수가 표시됩니다." - "2_4": "이 글에 댓글을 작성했기 때문에 새 글 수가 표시됩니다." - "2_2": "이 글을 팔로우 하고 있기 때문에 새 글 수가 표시됩니다." - "2": '이 글을 읽었으므로 새 댓글 수가 표시됩니다.' - "1_2": "누군가가 사용자님을 @name 형식으로 멘션하거나 사용자님에게 댓글을 보내면 알림을 받게됩니다." - "1": "누군가 @name 형식으로 나에게 멘션 했거나 내 글에 댓글이 달릴 때 알림을 받게 됩니다." + mailing_list_mode: "메일링 리스트 모드가 활성화되어 있으므로 메일로 이 주제의 댓글 알림을 받게 됩니다." + "3_10": "이 주제에 대한 태그를 구독 중이므로 알림을 받게 됩니다." + "3_10_stale": "과거에 이 주제의 태그를 구독했기 때문에 알림을 받게 됩니다." + "3_6": "이 카테고리를 구독 중이므로 알림을 받게 됩니다." + "3_6_stale": "과거에 이 카테고리를 구독했기 때문에 알림을 받게 됩니다." + "3_5": "이 주제를 자동으로 구독하기 시작했으므로 알림을 받게 됩니다." + "3_2": "이 주제를 구독 중이므로 알림을 받게 됩니다." + "3_1": "이 주제를 생성했으므로 알림을 받게 됩니다." + "3": "이 주제를 구독 중이므로 알림을 받게 됩니다." + "2_8": "이 카테고리를 추적 중이므로 새 댓글 수가 표시됩니다." + "2_8_stale": "과거에 이 카테고리를 추적했으므로 새 댓글 수가 표시됩니다." + "2_4": "이 주제에 댓글을 달았으므로 새 댓글 수가 표시됩니다." + "2_2": "이 주제를 추적 중이므로 새 댓글 수가 표시됩니다." + "2": '이 주제를 읽었으므로 새 댓글 수가 표시됩니다.' + "1_2": "누군가 나를 @이름 형식으로 멘션하거나 나에게 댓글을 달면 알림을 받습니다." + "1": "누군가 나를 @이름 형식으로 멘션하거나 나에게 댓글을 달면 알림을 받습니다." "0_7": "이 카테고리의 모든 알림을 무시하고 있습니다." - "0_2": "이 글에 대한 모든 알림을 무시하고 있습니다." - "0": "이 글에 대한 모든 알림을 무시하고 있습니다." + "0_2": "이 주제에 대한 모든 알림을 무시하고 있습니다." + "0": "이 주제에 대한 모든 알림을 무시하고 있습니다." watching_pm: - title: "모든 알림" - description: "이 메시지의 모든 새 답글에 대한 알림을 받게되며 새 답글 수가 표시됩니다." + title: "구독" + description: "이 메시지의 모든 새 댓글에 대한 알림을 받으며 새 댓글 수가 표시됩니다." watching: - title: "모든 알림" - description: "이 글의 모든 새 댓글에 대한 알림을 받게되며 새 댓글 수가 표시됩니다." + title: "구독" + description: "이 주제의 모든 새 댓글에 대한 알림을 받으며 새 댓글 수가 표시됩니다." tracking_pm: - title: "알림" - description: "이 메시지에 대한 새 답변 수가 표시됩니다. 누군가가 @name 형식으로 사용자님을 멘션하거나 사용자님에게 답글을 보내면 알림을 받게됩니다." + title: "추적" + description: "이 메시지의 새 댓글 수가 표시됩니다. 누군가가 @이름 형식으로 나를 멘션하거나 나에게 댓글을 달면 알림을 받게 됩니다." tracking: - title: "알림" - description: "이 글에 대한 새 답글 수가 표시됩니다. 누군가가 @name 형식으로 사용자님을 멘션하거나 사용자님에게 답글을 보내면 알림을 받게됩니다." + title: "추적" + description: "이 주제의 새 댓글 수가 표시됩니다. 누군가가 @이름 형식으로 나를 멘션하거나 나에게 댓글을 달면 알림을 받게 됩니다." regular: title: "일반" - description: "누군가가 @name 형식으로 사용자님에게 멘션하거나 사용자님에게 답글을 보내면 알림을 받게됩니다." + description: "누군가 나를 @이름 형식으로 멘션하거나 나에게 댓글을 달면 알림을 받습니다." regular_pm: title: "일반" - description: "누군가 @name 형식으로 사용자님에게 멘션하거나 사용자님에게 답글을 보내면 알림을 받게됩니다." + description: "누군가 나를 @이름 형식으로 멘션하거나 나에게 댓글을 달면 알림을 받습니다." muted_pm: - title: "알림끔" + title: "뮤트" description: "이 메시지에 대해 어떠한 알림도 받지 않지 않습니다." muted: - title: "알림 꺼짐" - description: "이 글에 대한 어떠한 알림도 받지 않고 최근글 목록에도 표시되지 않습니다." + title: "뮤트" + description: "이 주제에 대한 어떠한 알림도 받지 않고 최신 항목에 표시되지 않습니다." actions: title: "작업" - recover: "글 삭제 취소" + recover: "주제 삭제 취소" delete: "글 삭제" open: "글 열기" - close: "글 닫기" + close: "주제 종료" multi_select: "게시물 선택…" - slow_mode: "슬로우 모드 설정..." - timed_update: "글 타이머 설정..." + slow_mode: "느린 모드 설정..." + timed_update: "주제 타이머 설정..." pin: "글 고정..." - unpin: "글 고정 해제..." + unpin: "주제 고정 해제..." unarchive: "글 보관 취소" archive: "글 보관" - reset_read: "값 재설정" - make_public: "공개 글로 만들기..." + reset_read: "읽은 데이터 리셋" + make_public: "공개 주제로 만들기..." make_private: "개인 메시지 작성" - reset_bump_date: "끌어올림 날짜 초기화" + reset_bump_date: "끌어 올림 날짜 리셋" feature: pin: "글 고정" - unpin: "글 고정 해제" - pin_globally: "전체 공지글로 설정하기" - make_banner: "배너 글 만들기" + unpin: "주제 고정 해제" + pin_globally: "전체적으로 주제 고정" + make_banner: "배너 주제 생성" remove_banner: "배너 주제 제거" reply: - title: "댓글쓰기" - help: "이 글에 대한 댓글을 작성합니다" + title: "댓글 달기" + help: "이 주제에 대한 댓글 작성을 시작합니다" share: - title: "글 공유" + title: "주제 공유" extended_title: "링크 공유" - help: "이 글의 링크 공유" - instructions: "이 글의 링크 공유:" - copied: "글 링크가 복사되었습니다." + help: "이 주제의 링크 공유" + instructions: "이 주제의 링크 공유:" + copied: "주제 링크를 복사했습니다." restricted_groups: other: "그룹 구성원만 볼 수 있음: %{groupNames}" invite_users: "초대" print: title: "프린트하기" - help: "이 토픽을 인쇄하기 좋은 버전으로 보기" + help: "이 주제를 인쇄하기 좋은 버전으로 열기" flag_topic: title: "신고하기" - help: "이 주제를 주의깊게 보거나 비밀리에 주의성 알림을 보내기 위해 신고합니다" - success_message: "신고했습니다" + help: "이 주제에 주의를 주거나 비공개로 알림을 보내기 위해 비공개로 신고합니다" + success_message: "주제를 신고했습니다" make_public: title: "공개 주제로 변환" - choose_category: "공개 주제의 카테고리를 선택하십시오 :" + choose_category: "공개 주제의 카테고리를 선택하세요." feature_topic: - title: "주요 주제로 설정" - pin: " %{categoryLink} 카테고리 주제 목록 상단에 고정 until" - unpin: "이 주제를 %{categoryLink} 카테고리 상단에서 제거 합니다." - unpin_until: "%{categoryLink} 카테고리 주제 목록 상단에서 이 주제를 제거하거나 %{until}까지 기다림." - pin_note: "개별적으로 사용자가 주제 고정을 취소할 수 있습니다." + title: "이 주제 추천" + pin: " 이 주제를 다음 기간까지 %{categoryLink} 카테고리 상단에 표시" + unpin: "이 주제를 %{categoryLink} 카테고리 상단에서 제거합니다." + unpin_until: "%{categoryLink} 카테고리 상단에서 이 주제를 제거하거나 %{until}까지 기다립니다." + pin_note: "사용자가 개별적으로 직접 주제 고정을 취소할 수 있습니다." pin_validation: "주제를 고정하려면 날짜를 지정해야 합니다." - not_pinned: " %{categoryLink} 카테고리에 고정된 주제가 없습니다." + not_pinned: " %{categoryLink}에 고정된 주제가 없습니다." already_pinned: - other: "%{categoryLink}에 고정된 주제 개수: %{count}" - pin_globally: "모든 주제 목록 상단 고정 until" + other: "현재 %{categoryLink}에 고정된 주제 개수: %{count}" + pin_globally: "이 주제를 다음 기간까지 모든 주제 목록의 상단에 고정" confirm_pin_globally: - other: "이미 전체적으로 고정 된 글이 %{count}개 있습니다. 고정 된 글이 너무 많으면 사용자들에게 불편을 줄 수 있습니다. 추가로 글을 전체 고정 하시겠습니까?" - unpin_globally: "모든 주제 목록 상단에서 이 주제를 제거" - unpin_globally_until: "모든 주제 목록 상단에서 이 주제를 제거하거나 %{until}까지 기다림." - global_pin_note: "개별적으로 사용자가 주제 고정을 취소할 수 있습니다." - not_pinned_globally: "전체 공지된 주제가 없습니다." + other: "이미 전체적으로 고정된 주제가 %{count}개 있습니다. 고정된 주제가 너무 많으면 사용자에게 불편을 줄 수 있습니다. 추가로 주제를 전체적으로 고정할까요?" + unpin_globally: "모든 주제 목록 상단에서 이 주제 제거" + unpin_globally_until: "모든 주제 목록 상단에서 이 주제를 제거하거나 %{until}까지 기다립니다." + global_pin_note: "사용자가 개별적으로 직접 주제 고정을 취소할 수 있습니다." + not_pinned_globally: "전체적으로 고정된 주제가 없습니다." already_pinned_globally: - other: "전체 공지된 주제 개수: %{count}" - make_banner: "이 주제를 모든 페이지의 상단에 나타나는 배너로 만들기" - remove_banner: "모든 페이지에서 나타나는 배너에서 제거" - banner_note: "사용자는 배너를 닫음으로써 배너를 나타나지 않게 할 수 있습니다. 단지 어떤 기간동안 딱 하나의 주제만이 배너로 지정 가능합니다." + other: "전체적으로 고정된 주제 개수: %{count}" + make_banner: "이 주제를 모든 페이지의 상단에 표시되는 배너로 만들기" + remove_banner: "모든 페이지에서 표시되는 배너 제거" + banner_note: "사용자는 배너를 닫아 배너를 나타나지 않게 할 수 있습니다. 주어진 기간에 하나의 주제만 배너로 표시할 수 있습니다." no_banner_exists: "배너 주제가 없습니다." banner_exists: "현재 배너 주제가 있습니다." inviting: "초대 중..." - automatically_add_to_groups: "이 초청은 다음 그룹에 대한 접근권한도 포함합니다:" + automatically_add_to_groups: "이 초대는 다음 그룹에 대한 액세스도 포함합니다." invite_private: - title: "초대 메시지" + title: "메시지에 초대" email_or_username: "초대하려는 이메일 또는 아이디" - email_or_username_placeholder: "이메일 또는 아이디" + email_or_username_placeholder: "이메일 주소 또는 아이디" action: "초대" - success: "사용자가 메세지에 참여할 수 있도록 초대했습니다." - success_group: "해당 사용자가 메세지에 참여할 수 있도록 초대했습니다." - error: "죄송합니다. 해당 사용자를 초대하는 도중 오류가 발생했습니다." - not_allowed: "죄송합니다. 해당 사용자를 초대할 수 없습니다." + success: "이 메세지에 참여할 수 있도록 사용자를 초대했습니다." + success_group: "이 메세지에 참여할 수 있도록 그룹을 초대했습니다." + error: "이 사용자를 초대하는 도중 오류가 발생했습니다." + not_allowed: "이 사용자를 초대할 수 없습니다." group_name: "그룹명" - controls: "글 관리" + controls: "주제 관리" invite_reply: title: "초대하기" username_placeholder: "아이디" - action: "초대장 보내기" - help: "이메일을 통해 다른 사람을 이 주제에 초대합니다." + action: "초대 전송" + help: "이메일 또는 알림을 통해 다른 사용자를 이 주제에 초대합니다" to_forum: "링크를 클릭하여 친구가 즉시 참여할 수 있도록 간단한 이메일을 보내드립니다." - discourse_connect_enabled: "이 글에 초대하려는 사람의 아이디를 입력합니다." - to_topic_blank: "이 글에 초대 할 사람의 사용자명 또는 이메일 주소를 입력하십시오." - to_topic_email: "이메일 주소를 입력했습니다. 친구가 이 글에 즉시 댓글을 작성 할 수있는 초대장을 이메일로 보내드립니다." - to_topic_username: "아이디를 입력하셨습니다. 이 주제에 초대하는 링크와 함께 알림을 보내겠습니다." - to_username: "초대하려는 사용자의 아이디를 입력하세요. 이 주제에 초대하는 링크와 함께 알림을 보내겠습니다." + discourse_connect_enabled: "이 주제에 초대할 사용자의 아이디를 입력합니다." + to_topic_blank: "이 주제에 초대할 사용자의 아이디 또는 이메일 주소를 입력합니다." + to_topic_email: "이메일 주소를 입력했습니다. 친구가 이 주제에 즉시 댓글을 달 수 있는 초대장을 이메일로 보내드립니다." + to_topic_username: "아이디를 입력하셨습니다. 이 주제에 초대 링크와 함께 알림을 보내드립니다." + to_username: "초대할 사용자의 아이디를 입력하세요. 이 주제에 초대하는 링크와 함께 알림을 보내겠습니다." email_placeholder: "이메일 주소" - success_email: "%{invitee}로 초대장을 발송했습니다. 초대를 수락하면 알려 드리겠습니다. 초대상태를 확인하려면 사용자 페이지에서 '초대장' 탭을 선택하세요." - success_username: "사용자가 이 주제에 참여할 수 있도록 초대했습니다." - error: "그 사람을 초대할 수 없습니다. 혹시 이미 초대하진 않았나요? (Invites are rate limited)" - success_existing_email: "해당 email을 사용하고 있는 사용자 %{emailOrUsername} 가 이미 존재합니다. 그 사용자를 이 토픽에 참여하도록 초청했습니다." - login_reply: "로그인하고 댓글 쓰기" + success_email: "%{invitee}에게 초대 메일을 전송했습니다. 초대를 수락하면 알려드리겠습니다. 초대를 추적하려면 사용자 페이지에서 초대 탭을 확인하세요." + success_username: "이 주제에 참여할 수 있도록 사용자를 초대했습니다." + error: "이 사용자를 초대할 수 없습니다. 혹시 이미 초대하진 않았나요? (초대는 비율 제한이 있습니다)" + success_existing_email: "%{emailOrUsername} 이메일을 사용하는 사용자가 이미 있습니다. 이 주제에 참여할 수 있도록 사용자를 초대했습니다." + login_reply: "로그인하고 댓글 달기" filters: n_posts: - other: "%{count} 글" + other: "%{count}개의 게시물" cancel: "필터 제거" move_to: - title: "로 이동" - action: "로 이동" - error: "소식을 이동하는 중에 오류가 발생했습니다." + title: "다음으로 이동" + action: "다음으로 이동합니다" + error: "게시물을 이동하는 중에 오류가 발생했습니다." split_topic: - title: "새로운 주제로 이동" - action: "새로운 주제로 이동" - topic_name: "새로운 주제 제목" - radio_label: "새 주제글" - error: "새로운 주제로 이동시키는데 문제가 발생하였습니다." + title: "새 주제로 이동" + action: "새 주제로 이동합니다" + topic_name: "새 주제 제목" + radio_label: "새 주제" + error: "새 주제로 게시물을 이동하는 데 문제가 발생했습니다." instructions: - other: "새로운 주제를 생성하여, 선택한 %{count}개의 글로 채우려고 합니다." + other: "새 주제를 생성하여 선택한 %{count}개의 게시물로 채우려고 합니다." merge_topic: - title: "이미 있는 주제로 옮기기" - action: "이미 있는 주제로 옮기기" - error: "이 주제를 이동시키는데 문제가 발생하였습니다." + title: "기존 주제로 이동" + action: "기존 주제로 이동합니다" + error: "게시물을 이 주제로 이동하는 데 문제가 발생했습니다." radio_label: "기존 주제" instructions: - other: " %{count}개의 글을 옮길 주제를 선택해주세요." + other: " %{count}개의 게시물을 옮길 주제를 선택하세요." move_to_new_message: title: "새 메시지로 이동" - action: "새 메시지로 이동" + action: "새 메시지로 이동합니다" message_title: "새 메시지 제목" radio_label: "새로운 메시지" participants: "참여자" instructions: - other: "새 메시지를 작성하고 선택한 %{count}개의 게시물로 채우려고 합니다." + other: "새 메시지를 작성하여 선택한 %{count}개의 게시물로 채우려고 합니다." move_to_existing_message: title: "기존 메시지로 이동" - action: "기존 메시지로 이동" + action: "기존 메시지로 이동합니다" radio_label: "기존 메시지" participants: "참여자" instructions: - other: "이동하고자 하는 %{count}개의 게시물을 선택하십시오." + other: "%{count}개의 게시물을 옮길 메시지를 선택하세요." merge_posts: - title: "선택한 게시글 합치기" - action: "선택한 게시글 합치기" - error: "선택한 게시글을 합치는 중 에러가 발생했습니다." + title: "선택한 게시물 병합" + action: "선택한 게시물을 병합합니다" + error: "선택한 게시물을 병합하는 중에 오류가 발생했습니다." publish_page: - title: "페이지 출판" + title: "페이지 게시" publish: "게시" - description: "주제가 페이지로 게시되면 해당 URL을 공유 할 수 있으며 사용자 정의 스타일과 함께 표시됩니다." + description: "주제가 페이지로 게시되면 해당 URL을 공유할 수 있으며 사용자 지정 스타일과 함께 표시됩니다." slug: "강타" public: "공개" - public_description: "관련 글이 비공개인 경우에도 해당 페이지를 볼 수 있습니다." - publish_url: "귀하의 페이지는 다음 위치에 게시되었습니다." - topic_published: "귀하의 주제는 다음 위치에 게시되었습니다." - preview_url: "귀하의 페이지는 다음 위치에 게시됩니다." - invalid_slug: "이 페이지를 게시 할 수 없습니다." + public_description: "관련 주제가 비공개인 경우에도 이 페이지를 볼 수 있습니다." + publish_url: "페이지가 다음 위치에 게시되었습니다." + topic_published: "주제가 다음 위치에 게시되었습니다." + preview_url: "페이지가 다음 위치에 게시됩니다." + invalid_slug: "이 페이지를 게시할 수 없습니다." unpublish: "게시 취소" - unpublished: "귀하의 페이지가 게시 해제되었으며 더 이상 액세스 할 수 없습니다." + unpublished: "페이지가 게시 취소되었으며 이제 액세스할 수 없습니다." publishing_settings: "게시 설정" change_owner: title: "소유자 변경" - action: "작성자 바꾸기" - error: "작성자를 바꾸는 중 에러가 발생하였습니다." - placeholder: "새로운 작성자의 아이디" + action: "소유자를 변경합니다" + error: "소유자를 변경하는 중에 오류가 발생했습니다." + placeholder: "새 소유자의 아이디" instructions: - other: "%{count}개의 @%{old_user}님 게시물에 대한 새 소유자를 선택하십시오." + other: "@%{old_user} 님의 %{count}개의 게시물에 대한 새 소유자를 선택하세요." instructions_without_old_user: - other: "%{count}개의 게시물에 대한 새 소유자를 선택하십시오." + other: "%{count}개의 게시물에 대한 새 소유자를 선택하세요." change_timestamp: - title: "타임스탬프 변경하기..." - action: "타임스탬프 변경" - invalid_timestamp: "타임스탬프는 미래값으로 할 수 없습니다." - error: "주제의 시간을 변경하는 중 오류가 발생하였습니다." - instructions: "토픽의 새로운 타임스탬프를 선택해주세요. 토픽에 속한 게시글은 같은 시간 간격으로 조정됩니다." + title: "타임스탬프 변경..." + action: "타임스탬프를 변경합니다" + invalid_timestamp: "타임스탬프는 미래일 수 없습니다." + error: "주제의 타임스탬프를 변경하는 중에 오류가 발생했습니다." + instructions: "주제의 새로운 타임스탬프를 선택하세요. 주제에 속한 게시물은 같은 시차로 업데이트됩니다." multi_select: select: "선택" - selected: "(%{count})개가 선택됨" + selected: "선택됨(%{count})" select_post: label: "선택" title: "선택에 게시물 추가" selected_post: label: "선택됨" - title: "선택에서 게시물을 삭제하려면 클릭" + title: "클릭하여 선택에서 게시물 제거" select_replies: - label: "선택 + 답글" - title: "게시물과 모든 답글을 선택에 추가" + label: "선택 + 댓글" + title: "게시물과 모든 댓글을 선택에 추가" select_below: - label: "+ 아래에서 선택" - title: "선택 후 게시물 및 게시물 추가" - delete: 선택 삭제 + label: "선택 + 이후 게시물" + title: "게시물 및 이후 게시물 선택에 추가" + delete: 선택 삭제됨 cancel: 선택을 취소 select_all: 전체 선택 deselect_all: 전체 선택 해제 description: - other: "%{count}개의 개시글을 선택하셨어요." - deleted_by_author_simple: "(작성자가 삭제한 글)" + other: "%{count}개의 개시물을 선택했습니다." + deleted_by_author_simple: "(작성자가 삭제한 주제)" post: quote_reply: "인용하기" - quote_reply_shortcut: "또는 q를 누르십시오." + quote_reply_shortcut: "또는 q를 누르세요" quote_edit: "편집" - quote_edit_shortcut: "또는 e를 누르십시오." + quote_edit_shortcut: "또는 e를 누르세요" quote_share: "공유" edit_reason: "사유: " post_number: "%{number}번째 글" - ignored: "무시 된 콘텐츠" - wiki_last_edited_on: "%{dateTime}에 마지막으로 편집 된 위키" - last_edited_on: "%{dateTime}에 마지막으로 수정 된 글" - reply_as_new_topic: "연결된 주제로 답글 작성하기" - reply_as_new_private_message: "같은 수신자에게 새로운 메시지로 답글쓰기" - continue_discussion: "%{postLink}에서 토론을 계속:" - follow_quote: "인용 글로 이동" - show_full: "전체 글 보기" - show_hidden: "무시 된 내용을 봅니다." - deleted_by_author_simple: "(작성자가 삭제한 댓글)" - collapse: "축소" - expand_collapse: "확장/축소" - locked: "이 글은 운영진에 의해 수정이 금지 되었습니다." + ignored: "무시된 콘텐츠" + wiki_last_edited_on: "%{dateTime}에 마지막으로 편집된 위키" + last_edited_on: "%{dateTime}에 마지막으로 편집된 게시물" + reply_as_new_topic: "링크된 주제로 댓글 달기" + reply_as_new_private_message: "같은 수신자에게 새 메시지로 댓글 달기" + continue_discussion: "%{postLink}에서 토론 계속하기:" + follow_quote: "인용한 게시물로 이동" + show_full: "전체 게시물 표시" + show_hidden: "무시된 콘텐츠를 봅니다." + deleted_by_author_simple: "(작성자가 삭제한 게시물)" + collapse: "접기" + expand_collapse: "펼치기/접기" + locked: "이 게시물은 운영진에 의해 편집이 금지되었습니다." gap: - other: "%{count}개의 숨겨진 답글 보기" + other: "%{count}개의 숨겨진 댓글 보기" notice: - new_user: "%{user}님이 처음으로 작성한 글 입니다. 커뮤니티에 온 것을 환영해주세요!" - returning_user: "우리가 %{user}을 본 지 오래되었습니다. 마지막 게시물은 %{time}입니다." - unread: "읽지 않은 포스트" + new_user: "%{user} 님의 첫 게시물입니다. 커뮤니티에 온 것을 환영해 주세요!" + returning_user: "%{user} 님이 오랜만에 찾아주셨네요. 마지막 게시일은 %{time}입니다." + unread: "읽지 않은 게시물" has_replies: other: "%{count}개의 댓글" has_replies_count: "%{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}명이 이 글을 좋아합니다" + other: "나와 %{count}명이 이 게시물을 좋아합니다" filtered_replies_hint: - other: "이 글과 %{count}개의 댓글 보기" + other: "이 게시물과 %{count}개의 댓글 보기" filtered_replies_viewing: - other: "댓글 %{count}개 보기" + other: "다음의 댓글 %{count}개 보기" in_reply_to: "상위 게시물 로드" - view_all_posts: "모든 글 보기" + view_all_posts: "모든 게시물 보기" errors: - create: "죄송합니다. 글을 만드는 동안 오류가 발생했습니다. 다시 시도하십시오." - edit: "죄송합니다. 글을 수정하는 중에 오류가 발생했습니다. 다시 시도하십시오." - upload: "죄송합니다. 해당 파일을 업로드하는 중에 오류가 발생했습니다. 다시 시도하십시오." - file_too_large: "죄송합니다, 해당 파일이 너무 큽니다. (최대 %{max_size_kb}KB) 대용량 파일은 클라우드 공유 서비스에 업로드 한 다음 링크를 붙여 넣으십시오." - file_too_large_humanized: "죄송합니다. 파일이 너무 큽니다. (최대 크기는 %{max_size}). 대용량 파일을 클라우드 공유 서비스에 업로드한 다음 링크를 붙여넣으십시오." - too_many_uploads: "한번에 한 파일만 업로드 하실 수 있습니다." + create: "게시물을 생성하는 중에 오류가 발생했습니다. 다시 시도하세요." + edit: "게시물을 편집하는 중에 오류가 발생했습니다. 다시 시도하세요." + upload: "파일을 업로드하는 중에 오류가 발생했습니다. 다시 시도하세요." + file_too_large: "파일이 너무 큽니다(최대 허용 크기: %{max_size_kb}KB). 대용량 파일은 클라우드 공유 서비스에 업로드한 다음 링크를 붙여 넣는 것이 좋습니다." + file_too_large_humanized: "파일이 너무 큽니다(최대 허용 크기: %{max_size}). 대용량 파일은 클라우드 공유 서비스에 업로드한 다음 링크를 붙여 넣는 것이 좋습니다." + too_many_uploads: "한 번에 한 파일만 업로드할 수 있습니다." too_many_dragged_and_dropped_files: - other: "죄송합니다. 한 번에 %{count}개의 파일만 업로드 할 수 있습니다." - upload_not_authorized: "죄송합니다. 허가되지 않은 확장자의 파일이 있습니다. (허가된 확장자: %{authorized_extensions})." - image_upload_not_allowed_for_new_user: "죄송합니다. 새로운 유저는 이미지를 업로드 하실 수 없습니다." - attachment_upload_not_allowed_for_new_user: "죄송합니다. 새로운 유저는 파일 첨부를 업로드 하실 수 없습니다." - attachment_download_requires_login: "죄송합니다. 첨부 파일을 받으려면 로그인이 필요합니다." + other: "한 번에 %{count}개의 파일만 업로드할 수 있습니다." + upload_not_authorized: "업로드하려는 파일 확장자는 허용되지 않습니다(허용 확장자: %{authorized_extensions})." + image_upload_not_allowed_for_new_user: "신규 사용자는 이미지를 업로드할 수 없습니다." + attachment_upload_not_allowed_for_new_user: "신규 사용자는 첨부 파일을 업로드할 수 없습니다." + attachment_download_requires_login: "첨부 파일을 다운로드하려면 로그인이 필요합니다." cancel_composer: - confirm: "사용자님의 게시물에 대해 무엇을하고 싶습니까?" - discard: "포기" + confirm: "게시물에 어떤 작업을 하고 싶나요?" + discard: "버리기" save_draft: "나중을 위해 초안 저장" keep_editing: "편집 유지" - via_email: "이 주제는 이메일을 통해 등록되었습니다." - via_auto_generated_email: "이 게시글은 자동 생성된 이메일로 작성되었습니다" - whisper: "이 포스트는 운영자를 위한 비공개 귓말입니다." + via_email: "이 게시물은 이메일을 통해 전달됐습니다" + via_auto_generated_email: "이 게시물은 자동 생성된 이메일로 전달됐습니다" + whisper: "이 게시물은 운영자를 위한 비공개 귓속말입니다" wiki: - about: "이 게시글은 위키입니다" - few_likes_left: "사랑을 나누어주셔서 감사합니다! 오늘 표시할 수 있는 좋아요가 얼마 남지 않았습니다." + about: "이 게시물은 위키입니다" + few_likes_left: "긍정적인 활동에 감사합니다! 오늘 표시할 수 있는 좋아요가 얼마 남지 않았습니다." controls: - reply: "이 글에 대한 답글을 작성합니다." - like: "이 글을 좋아합니다." - has_liked: "이 글을 좋아합니다." - read_indicator: "이 게시물을 읽는 회원" - undo_like: "'좋아요' 취소" - edit: "이 글 편집" + reply: "이 게시물에 대한 댓글 작성을 시작합니다" + like: "이 게시물에 좋아요 누르기" + has_liked: "이 게시물을 좋아합니다" + read_indicator: "이 게시물을 읽은 회원" + undo_like: "좋아요 취소" + edit: "이 게시물 편집" edit_action: "편집" - edit_anonymous: "이 주제를 수정하려면 먼저 로그인을 해야합니다." - flag: "이 글을 신고하고 개인 알림을 받습니다" - delete: "이 글을 삭제합니다." + edit_anonymous: "이 게시물을 편집하려면 로그인이 필요합니다." + flag: "이 게시물에 주의를 주거나 비공개로 알림을 보내기 위해 비공개로 신고합니다" + delete: "이 게시물 삭제" undelete: "이 글 삭제를 취소합니다." - share: "이 글의 링크 공유" - more: "더" + share: "이 게시물의 링크 공유" + more: "더 보기" delete_replies: - confirm: "이 글에 대한 댓글을 삭제 하시겠습니까?" + confirm: "이 게시물에 대한 댓글을 삭제할까요?" direct_replies: - other: "예, %{count}개 직접 답장" + other: "예, %{count}개의 직접 댓글" all_replies: - other: "예, %{count}개 모두 답변" - just_the_post: "아니오, 글만 삭제합니다." - admin: "관리자 기능" - permanently_delete: "영구적으로 삭제" - permanently_delete_confirmation: "이 게시물을 영구적으로 삭제하시겠습니까? 복구할 수 없습니다." + other: "예, %{count}개의 모든 댓글" + just_the_post: "아니요, 이 게시물만 삭제합니다" + admin: "게시물 관리자 작업" + permanently_delete: "영구 삭제" + permanently_delete_confirmation: "이 게시물을 영구적으로 삭제할까요? 삭제된 게시물은 복구할 수 없습니다." wiki: "위키 만들기" - unwiki: "위키 제거하기" - convert_to_moderator: "스태프 색상 추가하기" - revert_to_regular: "스태프 색상 제거하기" - rebake: "HTML 다시 빌드하기" - publish_page: "페이지 출판" - unhide: "숨기지 않기" - change_owner: "작성자 변경..." + unwiki: "위키 제거" + convert_to_moderator: "운영진 색상 추가" + revert_to_regular: "운영진 색상 제거" + rebake: "HTML 리빌드" + publish_page: "페이지 게시" + unhide: "숨기기 취소" + change_owner: "소유자 변경..." grant_badge: "배지 부여..." - lock_post: "글 잠그기" - lock_post_description: "포스터가이 게시물을 편집하지 못하도록 방지" - unlock_post: "글 잠금 해제" - unlock_post_description: "작성자가 글을 수정하도록 허용" - delete_topic_disallowed_modal: "이 주제를 삭제할 권한이 없습니다. 실제로 삭제하려면 추론과 함께 중재자주의 플래그를 제출하십시오." - delete_topic_disallowed: "이 글을 삭제할 수있는 권한이 없습니다" + lock_post: "게시물 잠금" + lock_post_description: "게시자가 이 게시물을 편집하지 못하도록 방지" + unlock_post: "게시물 잠금 해제" + unlock_post_description: "게시자가 이 게시물을 편집하도록 허용" + delete_topic_disallowed_modal: "이 주제를 삭제할 권한이 없습니다. 정말 삭제하려면 이유와 함께 신고를 제출하여 운영자에게 주의를 보내세요." + delete_topic_disallowed: "이 주제를 삭제할 권한이 없습니다" delete_topic_confirm_modal: - other: "이 글은 현재 조회수가 %{count}회 이상이며 인기 글 검색 대상 일 수 있습니다. 이 글을 개선하기 위해 편집하는 대신 완전히 삭제 하시겠습니까?" - delete_topic_confirm_modal_yes: "예, 이 글을 삭제합니다." - delete_topic_confirm_modal_no: "아니요, 이 글을 유지합니다." - delete_topic_error: "이 항목을 삭제하는 동안 오류가 발생했습니다." - delete_topic: "글 삭제" - add_post_notice: "관리자 공지 추가..." - change_post_notice: "관리자 공지 변경..." - delete_post_notice: "관리자 공지 삭제" - remove_timer: "타이머를 제거" - edit_timer: "편집 타이머" + other: "이 주제는 현재 조회수가 %{count}회 이상이며 인기 검색 주제일 수 있습니다. 이 주제를 개선하기 위해 편집하는 대신 완전히 삭제할까요?" + delete_topic_confirm_modal_yes: "예, 이 주제를 삭제합니다" + delete_topic_confirm_modal_no: "아니요, 이 주제를 유지합니다" + delete_topic_error: "이 주제를 삭제하는 중에 오류가 발생했습니다." + delete_topic: "주제 삭제" + add_post_notice: "운영진 공지 추가..." + change_post_notice: "운영진 공지 변경..." + delete_post_notice: "운영진 공지 삭제" + remove_timer: "타이머 제거" + edit_timer: "타이머 편집" actions: people: like: - other: "좋아요" + other: "이 항목을 좋아합니다" read: - other: "이것을 읽으세요" + other: "이 항목을 읽었습니다" like_capped: - other: "그리고 다른 사람들이 %{count} 좋아했습니다" + other: "그리고 %{count}명의 사용자가 좋아합니다" read_capped: - other: "그리고 다른 사람들이 %{count}회 읽었습니다" + other: "그리고 %{count}명의 사용자가 읽었습니다" by_you: - off_topic: "이글을 주제에서 벗어났다고 신고했습니다" - spam: "이글을 스팸으로 신고했습니다" - inappropriate: "이 글을 부적절한 컨텐츠로 신고했습니다" - notify_moderators: "운영자에게 알렸습니다" - notify_user: "글쓴이에게 메시지를 보냈습니다" + off_topic: "이 항목이 주제에서 벗어났다고 신고했습니다" + spam: "이 항목을 스팸으로 신고했습니다" + inappropriate: "이 항목을 부적절한 콘텐츠로 신고했습니다" + notify_moderators: "이 항목을 운영자에게 알렸습니다" + notify_user: "이 사용자에게 메시지를 보냈습니다" delete: confirm: - other: "정말로 %{count}개의 글을 삭제 하시겠습니까?" - merge: - confirm: - other: "정말로 이 %{count}개의 게시글을 합칠까요?" + other: "%{count}개의 게시물을 삭제할까요?" revisions: controls: - first: "초판" - previous: "이전 판" - next: "다음 판" - last: "최신판" - hide: "편집 기록 가리기" - show: "편집 기록 보기" - revert: "%{revision} 수정본으로 되돌리기" + first: "첫 수정 버전" + previous: "이전 수정 버전" + next: "다음 수정 버전" + last: "마지막 수정 버전" + hide: "수정 버전 숨기기" + show: "수정 버전 표시" + revert: "%{revision} 수정 버전으로 되돌리기" edit_wiki: "Wiki 편집" - edit_post: "포스트 편집" + edit_post: "게시물 편집" comparing_previous_to_current_out_of_total: "%{previous} %{icon} %{current} / %{total}" displays: inline: @@ -2781,290 +2792,290 @@ ko: title: "Show the rendered output diffs side-by-side" button: "HTML" side_by_side_markdown: - title: "Raw source diff를 양쪽으로 보기" + title: "원본 소스 버전 비교를 양면에 표시" button: "Raw" raw_email: displays: raw: - title: "raw 이메일 표시하기" + title: "원본 이메일 표시" button: "Raw" text_part: - title: "이메일 텍스트 파트 보이기" + title: "이메일 텍스트 파트 표시" button: "텍스트" html_part: - title: "이메일 HTML 파트 보이기" + title: "이메일 HTML 파트 표시" button: "HTML" bookmarks: create: "북마크 만들기" - create_for_topic: "글에 대한 북마크 만들기" - edit: "북마크 수정" - edit_for_topic: "글에 대한 북마크 수정" - created: "생성일자" - updated: "업데이트됨" + create_for_topic: "주제에 대한 북마크 만들기" + edit: "북마크 편집" + edit_for_topic: "주제에 대한 북마크 편집" + created: "생성일" + updated: "업데이트일" name: "이름" - name_placeholder: "이 북마크는 무엇입니까?" - set_reminder: "알림" + name_placeholder: "이 북마크는 무엇인가요?" + set_reminder: "알림 받기" options: "옵션" actions: delete_bookmark: name: "북마크 삭제" - description: "프로필에서 북마크를 제거하고 북마크에 대한 모든 알림을 중지합니다" + description: "프로필에서 북마크를 제거하고 북마크에 대한 모든 미리 알림을 중지합니다" edit_bookmark: - name: "북마크 수정" - description: "북마크 이름을 수정하거나 알림 날짜 및 시간을 변경하십시오." + name: "북마크 편집" + description: "북마크 이름을 편집하거나 미리 알림 날짜 및 시간을 변경합니다" clear_bookmark_reminder: - name: "알림 지우기" - description: "알림 날짜 및 시간 지우기" + name: "미리 알림 지우기" + description: "미리 알림 날짜 및 시간 지우기" pin_bookmark: name: "북마크 고정" description: "북마크를 고정합니다. 북마크 목록 상단에 표시됩니다." unpin_bookmark: name: "북마크 고정 해제" - description: "북마크를 고정 해제합니다. 더 이상 북마크 목록 상단에 표시되지 않습니다." + description: "북마크를 고정 해제합니다. 이제 북마크 목록 상단에 표시되지 않습니다." filtered_replies: - viewing_posts_by: "%{post_count} 개의 게시물 보기" - viewing_subset: "몇 개의 댓글이 접혀 있습니다." - viewing_summary: "이 글의 요약 보기" - post_number: "%{username}, 글 #%{post_number}" - show_all: "모두 보기" + viewing_posts_by: "다음 사용자의 %{post_count}개의 게시물 보기" + viewing_subset: "일부 댓글이 접혀 있습니다" + viewing_summary: "이 주제의 요약 보기" + post_number: "%{username}, 게시물 #%{post_number}" + show_all: "모두 표시" share: - title: "글 공유 #%{post_number}" - instructions: "이 글의 링크 공유:" + title: "게시물 #%{post_number} 공유" + instructions: "이 게시물의 링크 공유:" category: none: "(카테고리 없음)" all: "모든 카테고리" choose: "카테고리…" edit: "수정" edit_dialog_title: "편집 : %{categoryName}" - view: "카테고리 안의 주제 보기" - back: "카테고리로 돌아 가기" + view: "카테고리 내 주제 보기" + back: "카테고리로 돌아가기" general: "일반" settings: "설정" topic_template: "주제 템플릿" tags: "태그" - tags_allowed_tags: "이 태그를 현재 카테고리로 제한:" - tags_allowed_tag_groups: "이 태그 그룹을 현재 카테고리로 제한:" + tags_allowed_tags: "이 태그를 이 카테고리로 제한:" + tags_allowed_tag_groups: "이 태그 그룹을 이 카테고리로 제한:" tags_placeholder: "(선택사항) 허용된 태그 목록" - tags_tab_description: "위에 지정된 태그 및 태그 그룹은 현재 카테고리 및 태그가 지정된 카테고리에서만 사용할 수 있습니다. 그외 카테고리에서는 사용할 수 없습니다." + tags_tab_description: "위에 지정된 태그 및 태그 그룹은 이 카테고리 및 이를 지정하는 기타 카테고리에서만 사용할 수 있습니다. 그외 카테고리에서는 사용할 수 없습니다." tag_groups_placeholder: "(선택사항) 허용된 태그 그룹 목록" manage_tag_groups_link: "태그 그룹 관리" allow_global_tags_label: "다른 태그도 허용" required_tag_group: delete: "삭제" - topic_featured_link_allowed: "이 카테고리에 주요 링크 허용" + topic_featured_link_allowed: "이 카테고리에 추천 링크 허용" delete: "카테고리 삭제" create: "새 카테고리" - create_long: "새 카테고리 만들기" + create_long: "새 카테고리 생성" save: "카테고리 저장" - slug: "카테고리 영문 고유명" + slug: "카테고리 슬러그" slug_placeholder: "(Optional) dashed-words for url" - creation_error: 카테고리 생성 중 오류가 발생했습니다. - save_error: 카테고리 저장 중 오류가 발생했습니다. + creation_error: 카테고리 생성 중에 오류가 발생했습니다. + save_error: 카테고리 저장 중에 오류가 발생했습니다. name: "카테고리 이름" description: "설명" logo: "카테고리 로고 이미지" background_image: "카테고리 백그라운드 이미지" badge_colors: "배지 색상" background_color: "배경 색상" - foreground_color: "글씨 색상" - name_placeholder: "짧고 간결해야합니다" - color_placeholder: "웹 색상" - delete_confirm: "이 카테고리를 삭제 하시겠습니까?" - delete_error: "카테고리를 삭제하는 동안 오류가 발생했습니다." + foreground_color: "전경 색상" + name_placeholder: "최대 1~2자" + color_placeholder: "모든 웹 색상" + delete_confirm: "이 카테고리를 삭제할까요?" + delete_error: "카테고리를 삭제하는 중에 오류가 발생했습니다." list: "카테고리 목록" - no_description: "이 카테고리에 대한 설명을 추가해주세요." + no_description: "이 카테고리에 대한 설명을 추가하세요." change_in_category_topic: "설명 편집" - already_used: "이 색은 다른 카테고리에서 사용되고 있습니다." + already_used: "이 색은 다른 카테고리에서 사용 중입니다" security: "보안" security_add_group: "그룹 추가" permissions: group: "그룹" see: "보기" - reply: "댓글" - create: "글" - no_groups_selected: "접근 권한이 부여된 그룹이 없습니다. 이 카테고리는 관리자만 볼 수 있습니다." - everyone_has_access: '이 카테고리는 공개이며, 누구나 볼 수 있고, 댓글을 작성 하고, 글을 쓸 수 있습니다. 사용 권한을 제한하려면 "everyone" 그룹에 부여된 사용 권한 중 하나 이상을 제거해야 합니다.' - toggle_reply: "토글 댓글 권한" - toggle_full: "토글 생성 권한" - inherited: '이 권한은 "everyone" 으로부터 상속됩니다.' - special_warning: "경고: 이 카테고리는 사전 생성된 카테고리이기 때문에 보안 설정 변경이 불가합니다. 이 카테고리를 사용하고 싶지 않다면, 수정하지말고 삭제하세요." - uncategorized_security_warning: "이 카테고리는 특별합니다. 카테고리가없는 주제의 보관 영역으로 사용됩니다. 보안 설정을 가질 수 없습니다." - uncategorized_general_warning: '이 카테고리는 특별합니다. 카테고리를 선택하지 않은 새 주제의 기본 카테고리로 사용됩니다. 이 동작을 방지하고 범주를 강제로 선택 하려면 여기에서 설정을 비활성화하십시오 . 이름이나 설명을 변경하려면 사용자 정의 / 텍스트 내용으로 이동하십시오 .' - pending_permission_change_alert: "이 카테고리에 %{group}을 추가하지 않았습니다. 이 버튼을 클릭하여 추가하십시오." + reply: "댓글 달기" + create: "생성" + no_groups_selected: "액세스 권한이 부여된 그룹이 없습니다. 이 카테고리는 운영진만 볼 수 있습니다." + everyone_has_access: '이 카테고리는 공개이며, 누구나 볼 수 있고, 댓글을 달고 게시물을 작성할 수 있습니다. 권한을 제한하려면 ''everyone'' 그룹에 부여된 권한 중 하나 이상을 제거해야 합니다.' + toggle_reply: "댓글 권한 토글" + toggle_full: "생성 권한 토글" + inherited: '이 권한은 ''everyone''으로부터 상속됩니다' + special_warning: "경고: 이 카테고리는 사전 생성된 카테고리이기 때문에 보안 설정 편집이 불가합니다. 이 카테고리를 사용하고 싶지 않다면, 편집 대신 삭제하세요." + uncategorized_security_warning: "특수 카테고리입니다. 카테고리가 없는 주제의 보관 영역으로 사용되므로 보안 설정을 가질 수 없습니다." + uncategorized_general_warning: '특수 카테고리입니다. 카테고리를 선택하지 않은 새 주제의 디폴트 카테고리로 사용됩니다. 이 행동을 방지하고 카테고리를 강제로 선택하려면 여기에서 설정을 비활성화하세요. 이름이나 설명을 변경하려면 사용자 지정 / 텍스트 콘텐츠로 이동하세요.' + pending_permission_change_alert: "이 카테고리에 %{group} 그룹을 추가하지 않았습니다. 이 버튼을 클릭하여 추가하세요." images: "이미지" - email_in: "incoming 메일 주소 수정" - email_in_allow_strangers: "계정이 없는 익명 유저들에게 이메일을 받습니다." - email_in_disabled: "이메일을 통한 새 글 작성은 사이트 설정에서 비활성화되어 있습니다. 이메일을 통해 새 글을 작성 하려면 " - email_in_disabled_click: '"이메일로 새 글 작성하기"를 사용하도록 설정해야 합니다.' - mailinglist_mirror: "카테고리는 메일 링리스트를 반영" - show_subcategory_list: "이 카테고리의 글 위에 하위 카테고리 목록을 표시합니다." - read_only_banner: "사용자가이 카테고리에서 글을 작성 할 수 없는 경우의 배너 텍스트:" - num_featured_topics: "카테고리 페이지에 표시되는 글 수:" - subcategory_num_featured_topics: "상위 카테고리 페이지에 표시되는 주요 글 수:" - all_topics_wiki: "기본으로 새로운 글 위키 만들기" - allow_unlimited_owner_edits_on_first_post: "첫 번째 게시물에 대해 글 작성자의 무제한 수정 허용" - subcategory_list_style: "하위 카테고리 목록 스타일:" - sort_order: "글 목록 정렬 기준:" - default_view: "글 기본 목록:" - default_top_period: "기본 Top 기간:" - default_list_filter: "목록 기본 필터:" - allow_badges_label: "배지가 이 카테고리에서 주어질 수 있도록 허용" + email_in: "수신 메일 주소 사용자 지정:" + email_in_allow_strangers: "계정이 없는 익명 사용자의 이메일을 수신합니다" + email_in_disabled: "이메일을 통한 새 주제 게시가 사이트 설정에서 비활성화되었습니다. 이메일을 통해 새 주제를 게시하려면 " + email_in_disabled_click: '''이메일'' 설정에서 활성화하세요.' + mailinglist_mirror: "카테고리가 메일링 목록 반영" + show_subcategory_list: "이 카테고리에서 주제 위에 서브카테고리 목록을 표시합니다." + read_only_banner: "사용자가 이 카테고리에서 주제를 생성할 수 없는 경우의 배너 텍스트:" + num_featured_topics: "카테고리 페이지에 표시되는 주제 수:" + subcategory_num_featured_topics: "상위 카테고리 페이지에 표시되는 추천 주제 수:" + all_topics_wiki: "기본적으로 새 주제 위키 만들기" + allow_unlimited_owner_edits_on_first_post: "첫 게시물에 대해 소유자의 무제한 편집 허용" + subcategory_list_style: "서브카테고리 목록 스타일:" + sort_order: "주제 목록 정렬 기준:" + default_view: "디폴트 주제 목록:" + default_top_period: "디폴트 상위 기간:" + default_list_filter: "디폴트 목록 필터:" + allow_badges_label: "이 카테고리에서 배지 획득 허용" edit_permissions: "권한 수정" review_group_name: "그룹명" - require_topic_approval: "모든 새 글에 대한 관리자 승인 필요" - require_reply_approval: "모든 새 댓글의 관리자 승인 필요" + require_topic_approval: "모든 새 주제에 대해 운영자 승인 필요" + require_reply_approval: "모든 새 댓글에 대해 운영자 승인 필요" this_year: "올해" - position: "카테고리 정렬 순서:" - default_position: "기본 위치" - position_disabled: "카테고리는 활동량에 따라서 표시됩니다. 목록 내의 카테고리 순서를 지정하하려면" - position_disabled_click: '"카테고리 위치 고정" 설정을 활성화 시키십시요.' - minimum_required_tags: "글 작성에 필요한 최소 태그 수:" - default_slow_mode: '이 카테고리의 새 글에 대해 “슬로우 모드”를 활성화합니다.' + position: "카테고리 페이지에서의 위치:" + default_position: "디폴트 위치" + position_disabled: "카테고리는 활동에 따라서 표시됩니다. 목록 내 카테고리 순서를 제어하려면" + position_disabled_click: '''고정 카테고리 위치'' 설정을 활성화하세요.' + minimum_required_tags: "주제에 필요한 최소 태그 수:" + default_slow_mode: '이 카테고리의 새 주제에 ''느린 모드''를 활성화합니다.' parent: "상위 카테고리" - num_auto_bump_daily: "열린 글 중 매일 자동으로 끌어올릴 수:" - navigate_to_first_post_after_read: "글을 읽은 후 첫 번째 게시물로 이동" + num_auto_bump_daily: "열린 주제 중 매일 자동으로 끌어 올릴 주제 수:" + navigate_to_first_post_after_read: "주제를 읽은 후 첫 게시물로 이동" notifications: title: "이 카테고리에 대한 알림 수준 변경" watching: - title: "주시 중" - description: "이 카테고리의 모든 글이 자동으로 관심글로 설정됩니다. 모든 글의 모든 새 댓글에 대한 알림을 받게되며 새 댓글 개수가 표시됩니다." + title: "구독" + description: "이 카테고리의 모든 주제를 자동으로 봅니다. 모든 주제의 새 게시물에 대한 알림이 전송되며 새 댓글 수도 표시됩니다." watching_first_post: - title: "새글 알림" - description: "이 카테고리의 새 주제에 대한 알림을 받지만 주제에 대한 답장은 없습니다." + title: "첫 게시물 구독" + description: "이 카테고리의 새 주제에 대한 알림을 받지만 주제 댓글은 제외합니다." tracking: - title: "추적 중" - description: "이 카테고리의 모든 글을 자동으로 팔로우합니다. 누군가 @name 형식으로 사용자님을 언급하거나 사용자님에게 댓글을 보내면 알림을 받게되며 새 댓글 개수가 표시됩니다." + title: "추적" + description: "이 카테고리의 모든 주제를 자동으로 추적합니다. 누군가 나를 @이름 형식으로 멘션하거나 나에게 댓글을 달면 알림을 받으며 새 댓글 수가 표시됩니다." regular: - title: "알림 : 일반" - description: "누군가 내 @아아디 으로 멘션했거나 당신의 글에 답글이 달릴 때 알림을 받게 됩니다." + title: "일반" + description: "누군가 나를 @이름 형식으로 멘션하거나 나에게 댓글을 달면 알림을 받습니다." muted: - title: "알림 꺼짐" - description: "이 카테고리의 새 글에 대한 알림을받지 않으며 최신 글 목록에 표시되지 않습니다." + title: "뮤트" + description: "이 카테고리의 새 주제에 대한 어떠한 알림도 받지 않으며 최신 항목에 표시되지 않습니다." search_priority: - label: "검색 우선 순위" + label: "검색 우선순위" options: - normal: "알림 : 일반" + normal: "일반" ignore: "무시" very_low: "매우 낮은" low: "낮은" high: "높음" very_high: "매우 높음" sort_options: - default: "기본값" - likes: "좋아요 수" - op_likes: "원본 게시글 좋아요 수" + default: "디폴트" + likes: "좋아요" + op_likes: "원본 게시물 좋아요" views: "조회수" posts: "게시글 수" activity: "활동" posters: "게시자" category: "카테고리" - created: "생성일자" + created: "생성일" sort_ascending: "오름차순" sort_descending: "내림차순" subcategory_list_styles: - rows: "행수" - rows_with_featured_topics: "주요 토픽의 행 스타일" + rows: "행" + rows_with_featured_topics: "추천 주제의 행" boxes: "박스" - boxes_with_featured_topics: "주요 토픽의 박스 스타일" + boxes_with_featured_topics: "추천 주제의 박스" settings_sections: general: "일반" moderation: "관리" appearance: "외관" email: "이메일" list_filters: - all: "모든 글" - none: "하위 카테고리 없음" + all: "모든 주제" + none: "서브카테고리 없음" colors_disabled: "카테고리 스타일이 없음이므로 색상을 선택할 수 없습니다." flagging: - title: "우리 커뮤니티 질서를 지키는데 도와주셔서 감사합니다!" - action: "글 신고했습니다" + title: "커뮤니티 질서를 지키는 데 도와주셔서 감사합니다!" + action: "게시물 신고" take_action: "조치하기..." take_action_options: default: title: "조치하기" - details: "더 이상 커뮤니티 플래그를 기다리지 않고 바로 플래그 임계 값에 도달합니다." + details: "추가 커뮤니티 신고를 기다리지 않고 바로 신고 한계치에 도달합니다" suspend: - title: "사용자 차단" - details: "플래그 임계 값에 도달하고 사용자를 차단합니다." + title: "사용자 정지" + details: "신고 한계치에 도달하고 사용자를 정지합니다" silence: - title: "글 작성 중지 사용자" - details: "신고가 최대치에 도달했으며, 사용자의 글 작성을 중지시킵니다." + title: "사용자 차단" + details: "신고 한계치에 도달하고 사용자를 차단합니다" notify_action: "메시지 보내기" official_warning: "공식 경고" - delete_spammer: "네, 스패머 회원을 삭제합니다" + delete_spammer: "스팸 사용자 삭제" flag_for_review: "검토 대기열" - delete_confirm_MF: "이 사용자의 {POSTS, plural, other {#개의 댓글}} 그리고 {TOPICS, plural, other {#개의 글}} 을 삭제하고, 계정을 제거한 다음 IP 주소 {ip_address}를 차단하고 이메일 주소 {email}를 영구 차단 목록에 추가합니다. 이 사용자가 정말 스팸 발송자입니까?" - yes_delete_spammer: "예, 스팸 회원을 삭제합니다" - ip_address_missing: "(알 수 없음)" + delete_confirm_MF: "이 사용자의 {POSTS, plural, one {#개의 게시물} other {#개의 게시물}} 및 {TOPICS, plural, one {#개의 주제} other {#개의 주제}}를 삭제하고, 사용자의 계정을 제거하고, 해당 IP 주소 {ip_address}의 가입을 차단하고, 해당 이메일 주소({email})를 영구 차단 목록에 추가하려 합니다. 이 사용자가 정말 스팸 사용자인가요?" + yes_delete_spammer: "예, 스팸 사용자를 삭제합니다" + ip_address_missing: "(해당 사항 없음)" hidden_email_address: "(숨김)" - submit_tooltip: "비밀 신고하기" - take_action_tooltip: "커뮤니티의 신고 수가 채워지기 기다리지 않고, 바로 신고 수를 제재 수준까지 채웁니다." - cant: "죄송합니다, 지금은 이 글을 신고할 수 없습니다" - notify_staff: "운영진에게 알리기" + submit_tooltip: "비밀 신고 제출" + take_action_tooltip: "추가 커뮤니티 신고를 기다리지 않고 바로 신고 한계치에 도달합니다" + cant: "지금은 이 게시물을 신고할 수 없습니다" + notify_staff: "운영진에게 비공개로 알리기" formatted_name: off_topic: "주제에 벗어났습니다" - inappropriate: "부적절 컨텐츠입니다" + inappropriate: "부적절합니다" spam: "스팸입니다" - custom_placeholder_notify_user: "구체적이고, 건설적이며, 항상 친절하세요." - custom_placeholder_notify_moderators: "구체적으로 회원님이 걱정하는 내용과 가능한 모든 관련된 링크를 제공해주세요." + custom_placeholder_notify_user: "구체적으로 상세히 작성하고 친절한 어투를 사용하세요." + custom_placeholder_notify_moderators: "걱정하는 내용을 구체적으로 알려주시고 가능한 한 모든 관련 링크 및 예시를 제공해 주세요." custom_message: at_least: other: "최소 %{count}자 이상 입력하세요" more: - other: "%{count} 남았습니다" + other: "%{count} 남았습니다..." left: - other: "%{count} 남았습니다" + other: "%{count} 남음" flagging_topic: - title: "우리 커뮤니티 질서를 지키는데 도와주셔서 감사합니다!" - action: "주제 신고하기" + title: "커뮤니티 질서를 지키는 데 도와주셔서 감사합니다!" + action: "주제 신고" notify_action: "메시지 보내기" topic_map: title: "주제 요약" - participants_title: "빈번한 게시자" + participants_title: "자주 게시하는 사용자" links_title: "인기 링크" - links_shown: "더 많은 링크보기..." + links_shown: "링크 더 보기..." clicks: - other: "%{count}번 클릭" + other: "클릭 수 %{count}회" post_links: - about: "이 게시글의 링크 더 보기" + about: "이 게시물의 링크 더 보기" title: other: "%{count} more" topic_statuses: warning: - help: "공식적인 주의입니다." + help: "공식 경고입니다." bookmarked: - help: "북마크한 주제" + help: "이 주제를 북마크했습니다" locked: - help: "이 주제는 폐쇄되었습니다. 더 이상 새 답글을 받을 수 없습니다." + help: "이 주제는 종료되었습니다. 더 이상 새 댓글을 받지 않습니다" archived: - help: "이 주제는 보관중입니다. 고정되어 변경이 불가능합니다." + help: "이 주제는 보관 중입니다. 고정되어 변경이 불가합니다" locked_and_archived: - help: "이 토픽은 폐쇄되어 보관중입니다. 새로운 답글을 달거나 수정할 수 없습니다." + help: "이 주제는 종료되어 보관 중 입니다. 더 이상 새 댓글을 받지 않으며 변경이 불가합니다" unpinned: title: "고정 해제" - help: "이 글은 고정 해제 상태입니다." + help: "이 주제가 고정 해제되었습니다. 일반적인 순서로 표시됩니다" pinned_globally: - title: "전체에서 고정됨" - help: "이 글은 전체에서 고정되어 있으며 최신 항목 및 해당 카테고리에 표시됩니다." + title: "전체적으로 고정됨" + help: "이 주제는 전체적으로 고정되어 있으며 최신 항목 및 카테고리 상단에 표시됩니다." pinned: title: "핀 지정됨" help: "이 주제는 고정되었습니다. 카테고리의 상단에 표시됩니다." unlisted: - help: "이 주제는 목록에서 제외됩니다. 주제 목록에 표시되지 않으며 링크를 통해서만 접근 할 수 있습니다." + help: "이 주제는 목록에서 제외되었니다. 주제 목록에 표시되지 않으며 다이렉트 링크를 통해서만 액세스할 수 있습니다." personal_message: title: "이 주제는 개인 메시지입니다" help: "이 주제는 개인 메시지입니다" posts: "글" pending_posts: - label: "보류중" - label_with_count: "보류중 (%{count})" - original_post: "원본 글" + label: "보류 중" + label_with_count: "보류 중(%{count})" + original_post: "원본 게시물" views: "조회수" views_lowercase: - other: "조회" + other: "조회수" replies: "댓글" views_long: - other: "이 토픽은 %{number}번 조회되었습니다." + other: "이 주제는 %{number}번 조회되었습니다" activity: "활동" likes: "좋아요" likes_lowercase: @@ -3073,9 +3084,9 @@ ko: users_lowercase: other: "사용자" category_title: "카테고리" - history_capped_revisions: "히스토리, 최근 100개의 리비전" + history_capped_revisions: "히스토리, 최근 100개의 수정 버전" history: "히스토리" - changed_by: "%{author}에 의해" + changed_by: "작성자: %{author}" raw_email: title: "수신 이메일" not_available: "Raw 이메일이 가능하지 않습니다." @@ -3084,80 +3095,82 @@ ko: with_topics: "%{filter} 주제" with_category: "%{filter} %{category} 주제" latest: - title: "최근글" + title: "최신" title_with_count: - other: "최근글 (%{count})" - help: "가장 최근 글" + other: "최신(%{count})" + help: "최신 게시물 포함 주제" read: - title: "읽은 글" - help: "마지막으로 순서대로 읽은 주제" + title: "읽음" + help: "읽은 주제, 마지막으로 읽은 순입니다" categories: title: "카테고리" title_in: "카테고리 - %{categoryName}" - help: "카테고리별로 그룹화 된 모든 주제" + help: "카테고리별로 그룹화된 모든 주제" unread: - title: "읽지 않은 글" + title: "읽지 않음" title_with_count: - other: "읽지 않은 글 (%{count})" - help: "팔로우 중인 읽지 않은 글" + other: "읽지 않음(%{count})" + help: "읽지 않은 게시물을 포함한 현재 구독 또는 추적 중인 주제" lower_title_with_count: other: "%{count} unread" new: lower_title_with_count: other: "%{count} new" lower_title: "new" - title: "새글" + title: "신규" title_with_count: - other: "새글 (%{count})" - help: "지난 며칠 동안 작성된 글" + other: "신규(%{count})" + help: "지난 며칠 동안 작성된 주제" posted: title: "내 글" - help: "내가 게시한 글" + help: "내가 게시한 주제" bookmarks: title: "북마크" - help: "북마크된 주제" + help: "내가 북마크한 주제" category: title: "%{categoryName}" title_with_count: other: "%{categoryName} (%{count})" - help: "%{categoryName}카테고리의 최신 주제" + help: "%{categoryName} 카테고리의 최신 주제" top: - title: "인기글" - help: "작년 또는 지난 달, 지난 주, 어제에 활발했던 주제" + title: "주요" + help: "작년, 지난달, 지난주, 어제 가장 활발했던 주제" all: - title: "전체 시간" + title: "전체 기간" yearly: - title: "연" + title: "매년" quarterly: - title: "분기마다" + title: "매분기" monthly: - title: "월" + title: "매달" weekly: - title: "주" + title: "매주" daily: title: "일" - all_time: "전체 시간" + all_time: "전체 기간" this_year: "년" this_quarter: "분기" this_month: "월" this_week: "주" today: "오늘" - other_periods: "상단 참조 :" + other_periods: "다음 주요 항목 보기:" + browser_update: '브라우저 버전이 너무 낮아 이 사이트에서 작동하지 않습니다. 브라우저를 업그레이드하여 서식 있는 콘텐츠를 표시하고 로그인하여 댓글도 달아보세요.' + safari_13_warning: 이 사이트는 곧 iOS 및 Safari 버전 13 이하에 대한 지원을 중단할 예정입니다. 단순화된 읽기 전용 버전은 계속 사용할 수 있습니다. (더 보기) permission_types: - full: "생성 / 답글 / 보기" - create_post: "답글 / 보기" + full: "생성 / 댓글 / 보기" + create_post: "댓글 / 보기" readonly: "보기" - preloader_text: "로딩중" + preloader_text: "로딩 중" lightbox: download: "다운로드" open: "원본 이미지" - previous: "이전 (왼쪽 화살표 키)" - next: "다음 (오른쪽 화살표 키)" - counter: "%total %의 %curr %" - close: "닫기 (Esc)" - content_load_error: '내용을 로드 할 수 없습니다.' - image_load_error: '이미지를 로드 할 수 없습니다.' - cannot_render_video: 브라우저가 코덱을 지원하지 않기 때문에이 동영상을 렌더링 할 수 없습니다. + previous: "이전(왼쪽 화살표 키)" + next: "다음(오른쪽 화살표 키)" + counter: "%curr% / %total%" + close: "닫기(Esc)" + content_load_error: '콘텐츠를 로드할 수 없습니다.' + image_load_error: '이미지를 로드할 수 없습니다.' + cannot_render_video: 브라우저가 코덱을 지원하지 않기 때문에 이 비디오를 렌더링할 수 없습니다. keyboard_shortcuts_help: shortcut_key_delimiter_comma: "," shortcut_key_delimiter_plus: "+" @@ -3169,96 +3182,96 @@ ko: title: "이동" home: "%{shortcut} 홈" latest: "%{shortcut} 최신" - new: "%{shortcut} 새로운" - unread: "%{shortcut} 읽지 않은" + new: "%{shortcut} 신규" + unread: "%{shortcut} 읽지 않음" categories: "%{shortcut} 카테고리" - top: "%{shortcut} 인기글" + top: "%{shortcut} 주요 항목" bookmarks: "%{shortcut} 북마크" profile: "%{shortcut} 프로필" messages: "%{shortcut} 메시지" - drafts: "초안 %{shortcut}" - next: "다음 항목 %{shortcut}" - previous: "이전 글 %{shortcut}" + drafts: "%{shortcut} 초안" + next: "%{shortcut} 다음 주제" + previous: "%{shortcut} 이전 주제" navigation: title: "탐색" - jump: "%{shortcut} 글 번호로 이동" - back: "%{shortcut} 이전" - up_down: "%{shortcut} 선택된 글 이동 ↑ ↓" - open: "%{shortcut} 선택한 토픽 열기" + jump: "%{shortcut} 게시물로 이동 #" + back: "%{shortcut} 뒤로 가기" + up_down: "%{shortcut} 선택 이동 ↑ ↓" + open: "%{shortcut} 선택한 주제 열기" next_prev: "%{shortcut} 이전/다음 섹션" go_to_unread_post: "%{shortcut} 읽지 않은 첫 번째 게시물로 이동" application: - title: "어플리케이션" - create: "%{shortcut} 새 토픽을 만듭니다." - notifications: "%{shortcut} 알림창 열기" - hamburger_menu: "%{shortcut} 햄버거 메뉴 열기" + title: "애플리케이션" + create: "%{shortcut} 새 주제 생성" + notifications: "%{shortcut} 알림 열기" + hamburger_menu: "%{shortcut} 버거 메뉴 열기" user_profile_menu: "%{shortcut} 사용자 메뉴 열기" - show_incoming_updated_topics: "%{shortcut} 갱신된 토픽 보기" - search: "%{shortcut} 를 사용하여 검색" + show_incoming_updated_topics: "%{shortcut} 업데이트된 주제 보기" + search: "%{shortcut} 검색" help: "%{shortcut} 키보드 도움말 열기" - dismiss_new: "%{shortcut} 새 글을 읽은 상태로 표시하기" - dismiss_topics: "%{shortcut} 토픽 무시하기" + dismiss_new: "%{shortcut} 신규 항목 무시" + dismiss_topics: "%{shortcut} 주제 무시" log_out: "%{shortcut} 로그아웃" composing: - title: "식자" - return: "%{shortcut} 글쓰기 화면으로 돌아가기" - fullscreen: "%{shortcut} 전체 화면으로 글쓰기" + title: "글쓰기" + return: "%{shortcut} 작성기로 돌아가기" + fullscreen: "%{shortcut} 작성기 전체화면" bookmarks: title: "북마크" - enter: "%{shortcut} 저장 후 닫기" - later_today: "%{shortcut} 나중에 오늘" - later_this_week: "%{shortcut} 이번 주 후반" - tomorrow: "내일 %{shortcut}" - next_week: "다음주에 %{shortcut}" - next_month: "다음 달 %{shortcut}" - next_business_week: "%{shortcut} 다음 주 시작" + 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} 다음 영업일" - custom: "%{shortcut} 사용자 정의 날짜 및 시간" - none: "알림 없음 %{shortcut}" + custom: "%{shortcut} 사용자 지정 날짜 및 시간" + none: "%{shortcut} 미리 알림 안 함" delete: "%{shortcut} 북마크 삭제" actions: - title: "액션" - bookmark_topic: "%{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} 토픽 알람 : 끄기" - mark_tracking: "%{shortcut} 토픽 알람 : 추적하기" - mark_watching: "%{shortcut} 토픽 알람 : 주시하기" - print: "%{shortcut} 토픽 인쇄하기" + title: "작업" + bookmark_topic: "%{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} 주제 뮤트" + mark_tracking: "%{shortcut} 주제 추적" + mark_watching: "%{shortcut} 주제 구독" + print: "%{shortcut} 주제 인쇄" defer: "%{shortcut} 주제 지연" - topic_admin_actions: "%{shortcut} 주제 열기 관리자 작업" + topic_admin_actions: "%{shortcut} 주제 관리자 작업 열기" search_menu: title: "검색 메뉴" - prev_next: "%{shortcut} 선택을 위아래로 이동" - insert_url: "%{shortcut} 열린 글 작성기에 선택 영역 삽입" - full_page_search: "%{shortcut} 전체 페이지 검색" + prev_next: "%{shortcut} 선택 항목 위아래로 이동" + insert_url: "%{shortcut} 열린 작성기에 선택 항목 삽입" + full_page_search: "%{shortcut} 전체 페이지 검색 시작" badges: earned_n_times: - other: "이 배지를 %{count}번 받았습니다" - granted_on: "%{date} 에 수여함" - others_count: "(%{count})명의 사용자가 이 배지를 가지고 있습니다" + other: "이 배지를 %{count}번 획득했습니다" + granted_on: "%{date}에 획득" + others_count: "이 배지를 획득한 다른 사용자(%{count}명)" title: 배지 - allow_title: "이 배지는 타이틀로 사용할 수 있습니다" - multiple_grant: "이 배지는 중복해서 취득할 수 있습니다" + allow_title: "이 배지를 타이틀로 사용할 수 있습니다" + multiple_grant: "이 배지는 중복해서 획득할 수 있습니다" badge_count: other: "%{count}개의 배지" more_badges: other: "+%{count}개 이상" granted: - other: "%{count}개 수여됨" - select_badge_for_title: 타이틀로 사용할 배지 선택하기 + other: "%{count}개 획득" + select_badge_for_title: 타이틀로 사용할 배지 선택 none: "(없음)" - successfully_granted: "%{username}에 %{badge}을 성공적으로 부여 함" + successfully_granted: "%{username} 님에게 %{badge} 배지를 부여함" badge_grouping: getting_started: name: 시작하기 @@ -3269,19 +3282,19 @@ ko: other: name: 기타 posting: - name: 포스팅 - favorite_max_reached: "더 이상 좋아하는 배지로 추가할 수 없습니다." - favorite_max_not_reached: "이 배지를 좋아하는 배지로 표시" - favorite_count: "%{count}/%{max}개의 배지가 좋아하는 배지로 표시" + name: 게시 + favorite_max_reached: "더 이상 즐겨 찾는 배지로 추가할 수 없습니다." + favorite_max_not_reached: "이 배지를 즐겨찾기에 표시" + favorite_count: "%{count}/%{max}개의 배지가 즐겨찾기 배지로 표시됨" download_calendar: title: "캘린더 다운로드" save_ics: ".ics 파일 다운로드" - save_google: "Google 캘린더에 추가" - remember: "다시 묻지 마세요" + save_google: "Google Calendar에 추가" + remember: "다시 묻지 않음" remember_explanation: "(사용자 환경설정에서 이 환경설정을 변경할 수 있습니다)" download: "다운로드" - default_calendar: "기본 캘린더" - default_calendar_instruction: "날짜를 저장할 때 어떤 달력을 사용해야 하는지 결정합니다." + default_calendar: "디폴트 캘린더" + default_calendar_instruction: "날짜를 저장할 때 어떤 캘린더를 사용할지 결정" add_to_calendar: "캘린더에 추가" google: "구글 캘린더" ics: "ICS" @@ -3290,36 +3303,36 @@ ko: other_tags: "기타 태그" selector_all_tags: "모든 태그" selector_no_tags: "태그 없음" - changed: "바뀐 태그:" + changed: "변경된 태그:" tags: "태그" - choose_for_topic: "태그 선택" + choose_for_topic: "태그(선택사항)" choose_for_topic_required: - other: "최소한 %{count}개의 태그를 선택해야합니다..." + other: "최소 %{count}개의 태그를 선택해야 합니다..." info: "정보" default_info: "이 태그는 카테고리로 제한되지 않으며 동의어가 없습니다." - category_restricted: "이 태그는 액세스 권한이없는 카테고리로 제한됩니다." + category_restricted: "이 태그는 액세스 권한이 없는 카테고리로 제한됩니다." synonyms: "동의어" - synonyms_description: "다음 태그를 사용하면 %{base_tag_name} 으로 대체됩니다." + synonyms_description: "다음 태그를 사용하면 %{base_tag_name} 태그로 대체됩니다." save: "태그 이름 및 설명 저장" tag_groups_info: - other: "이 태그는 다음 그룹에 속합니다: %{tag_groups}." + other: "이 태그는 %{tag_groups} 그룹에 속합니다." category_restrictions: - other: "다음 카테고리에서만 사용할 수 있습니다:" + other: "다음 카테고리에서만 사용할 수 있습니다." edit_synonyms: "동의어 편집" add_synonyms_label: "동의어 추가 :" add_synonyms: "추가" add_synonyms_explanation: - other: "현재 이 태그를 사용하는 모든 게시물의 태그가 %{tag_name}으로 변경됩니다. 정말로 변경 하시겠습니까?" - add_synonyms_failed: "다음 태그를 동의어로 추가 할 수 없습니다 : %{tag_names} . 동의어가없고 다른 태그의 동의어가 아닌지 확인하십시오." + other: "현재 이 태그를 사용하는 모든 곳의 태그가 %{tag_name} 태그로 변경됩니다. 변경사항을 진행할까요?" + add_synonyms_failed: "다음 태그를 동의어로 추가할 수 없습니다: %{tag_names}. 동의어가 없고 다른 태그의 동의어가 아닌지 확인하세요." remove_synonym: "동의어 제거" - delete_synonym_confirm: '동의어 "%{tag_name}"를 삭제 하시겠습니까?' + delete_synonym_confirm: '"%{tag_name}" 동의어를 삭제할까요?' delete_tag: "태그 삭제" delete_confirm: - other: "정말로 이 태그를 삭제하고 이 태그가 붙은 %{count} 개의 토픽에서 태그를 제거할까요?" - delete_confirm_no_topics: "정말로 이 태그를 삭제할까요?" + other: "이 태그를 삭제하고 이 태그가 할당된 %{count}개의 주제에서 태그를 제거할까요?" + delete_confirm_no_topics: "이 태그를 삭제할까요?" delete_confirm_synonyms: other: "%{count}개의 동의어도 삭제됩니다." - edit_tag: "태그 이름 및 설명 수정" + edit_tag: "태그 이름 및 설명 편집" description: "설명" sort_by: "정렬 기준:" sort_by_count: "개수" @@ -3327,92 +3340,92 @@ ko: manage_groups: "태그 그룹 관리" manage_groups_description: "태그 정리를 위한 그룹 정의" upload: "태그 업로드" - upload_description: "CSV 파일을 업로드하여 대량으로 태그 생성" - upload_instructions: "선택적으로 'tag_name, tag_group'형식의 태그 그룹이있는 한 줄에 하나씩." - upload_successful: "태그가 성공적으로 업로드되었습니다" + upload_description: "CSV 파일을 업로드하여 태그 일괄 생성" + upload_instructions: "한 줄에 하나씩. 'tag_name,tag_group' 형식으로 태그 그룹 추가 가능." + upload_successful: "태그가 업로드되었습니다" delete_unused_confirmation: - other: "%{count}개의 태그가 삭제됩니다: %{tags}" + other: "%{count}개의 태그가 삭제됩니다. %{tags}" delete_unused_confirmation_more_tags: other: "%{tags} 외 %{count}개" - delete_no_unused_tags: "사용되지 않은 태그가 없습니다." + delete_no_unused_tags: "사용하지 않은 태그가 없습니다." tag_list_joiner: ", " delete_unused: "사용하지 않은 태그 삭제" - delete_unused_description: "글 또는 개인 메시지에 첨부되지 않은 모든 태그 삭제" + delete_unused_description: "주제 또는 개인 메시지에 첨부되지 않은 모든 태그 삭제" cancel_delete_unused: "취소" filters: - without_category: "%{filter} %{tag} 토픽" - with_category: "%{category}에서 %{filter}%{tag}태그가 달린 토픽" - untagged_without_category: "%{filter} 태깅안된 토픽" - untagged_with_category: "%{category}에서 %{filter}태그가 없는 토픽" + without_category: "%{filter} %{tag} 주제" + with_category: "%{category}의 %{filter} %{tag} 주제" + untagged_without_category: "%{filter} 태그 없는 주제" + untagged_with_category: "%{category}의 %{filter} 태그 없는 주제" notifications: watching: - title: "주시중" - description: "이 태그가 있는 모든 글이 자동으로 관심글로 설정 됩니다. 모든 새 글 및 댓글에 대한 알림을 받게되며 읽지 않은 게시물 및 새 게시물의 수도 글 옆에 표시됩니다." + title: "구독" + description: "이 태그의 모든 주제를 자동으로 봅니다. 모든 새 게시물과 주제에 대한 알림이 전송되며 읽지 않은 게시물과 새 게시물 수도 주제 옆에 표시됩니다." watching_first_post: - title: "첫 게시글 주시중" - description: "이 태그의 새 글에 대한 알림은 받지만 댓글 알림은 받지 않습니다." + title: "첫 게시물 구독" + description: "이 태그의 새 주제에 대한 알림을 받지만 주제 댓글은 제외합니다." tracking: - title: "추적중" - description: "이 태그의 모든 글이 자동으로 관심글로 설정됩니다. 읽지 않은 글 및 새로운 게시물의 수가 글 옆에 표시됩니다." + title: "추적" + description: "이 태그의 모든 주제를 자동 추적합니다. 읽지 않은 게시물과 새 게시물 수가 주제 옆에 표시됩니다." regular: - title: "보통" - description: "누군가 당신의 @아이디 로 언급했거나 당신의 글에 답글이 달릴 때 알림을 받게 됩니다." + title: "일반" + description: "누군가 나를 @이름 형식으로 멘션하거나 내 게시물에 댓글을 달면 알림을 받습니다." muted: - title: "알림끔" - description: "이 태그의 새 글에 대한 알림이 표시되지 않으며, 읽지 않은 탭에도 표시되지 않습니다." + title: "뮤트" + description: "이 태그가 있는 새 주제에 대한 어떠한 알림도 받지 않으며 읽지 않음 탭에 표시되지 않습니다." groups: title: "태그 그룹" - about_heading: "태그 그룹을 선택하거나 새 그룹을 만듭니다." + about_heading: "태그 그룹을 선택하거나 새로 만듭니다." about_heading_empty: "시작하려면 새 태그 그룹을 만드세요." - about_description: "태그 그룹을 사용하면 한 곳에서 여러 태그에 대한 권한을 관리 할 수 있습니다." + about_description: "태그 그룹을 사용하면 한 곳에서 여러 태그에 대한 권한을 관리할 수 있습니다." new: "새 그룹" - new_title: "새 그룹 만들기" + new_title: "새 그룹 생성" edit_title: "태그 그룹 편집" tags_label: "이 그룹의 태그" parent_tag_label: "상위 태그" - parent_tag_description: "이 그룹의 태그는 상위 태그가있는 경우에만 사용할 수 있습니다." - one_per_topic_label: "이 그룹의 태그는 토픽당 하나만 선택할 수 있도록 제한하기" + parent_tag_description: "이 그룹의 태그는 상위 태그가 있는 경우에만 사용할 수 있습니다." + one_per_topic_label: "이 그룹에서 주제당 태그 하나로 제한" new_name: "새 태그 그룹" - name_placeholder: "그룹명" + name_placeholder: "이름" save: "저장" delete: "삭제" - confirm_delete: "이 태그 그룹을 삭제 하시겠습니까?" + confirm_delete: "이 태그 그룹을 삭제할까요?" everyone_can_use: "모든 사람이 태그를 사용할 수 있습니다" - usable_only_by_groups: "태그는 모든 사람에게 보이지만 다음 그룹만 태그를 사용할 수 있습니다." - visible_only_to_groups: "태그는 다음 그룹에만 표시됩니다." - cannot_save: "태그 그룹을 저장할 수 없습니다. 태그가 하나 이상 있고 태그 그룹 이름이 비어 있지 않으며 태그 권한에 그룹이 선택되어 있는지 확인하십시오." + usable_only_by_groups: "모든 사람에게 태그가 보이지만 다음 그룹만 태그를 사용할 수 있습니다" + visible_only_to_groups: "태그는 다음 그룹에만 표시됩니다" + cannot_save: "태그 그룹을 저장할 수 없습니다. 태그가 하나 이상 있고 태그 그룹 이름이 비어 있지 않으며 태그 권한에 그룹이 선택되어 있는지 확인하세요." tags_placeholder: "태그 검색 또는 생성" parent_tag_placeholder: "선택 사항" select_groups_placeholder: "그룹 선택..." disabled: "태그 지정이 비활성화되었습니다. " topics: none: - unread: "읽지 않은 토픽이 없습니다." - unseen: "보지 않은 글이 없습니다." - new: "새로운 토픽이 없습니다." - read: "아직 어떠한 토픽도 읽지 않았습니다." - posted: "아직 게시글을 하나도 쓰지 않았습니다." - latest: "최신 토픽이 없습니다." - bookmarks: "북마크한 토픽이 없습니다." - top: "주요 글이 없습니다." + unread: "읽지 않은 주제가 없습니다." + unseen: "확인하지 않은 주제가 없습니다." + new: "새 주제가 없습니다." + read: "아직 읽은 주제가 없습니다." + posted: "아직 게시한 주제가 없습니다." + latest: "최신 주제가 없습니다." + bookmarks: "아직 북마크한 주제가 없습니다." + top: "주요 주제가 없습니다." invite: - custom_message: "맞춤 메시지 를 작성하여 초대를 좀 더 개인적으로 만드십시오." - custom_message_placeholder: "사용자 설정 메시지를 입력하세요" - approval_not_required: "사용자는이 초대를 수락하는 즉시 자동 승인됩니다." - custom_message_template_forum: "저기요, 이 포럼에 가입하셔야 해요!" - custom_message_template_topic: "이 토픽에 흥미 있을 거 같은데요!" - forced_anonymous: "극단적 인로드로 인해 로그 아웃 한 사용자가 볼 수있는 것처럼 모든 사람에게 일시적으로 표시됩니다." - forced_anonymous_login_required: "사이트 과부하로 지금은 불러올 수 없습니다. 몇 분 후에 다시 시도하십시오." + custom_message: "사용자 지정 메시지를 작성하여 초대를 개인적으로 만드세요." + custom_message_placeholder: "사용자 지정 메시지 입력" + approval_not_required: "사용자는 이 초대를 수락하는 즉시 자동 승인됩니다." + custom_message_template_forum: "이 포럼에 참여하세요!" + custom_message_template_topic: "이 주제에 관심 있을 것 같은데요!" + forced_anonymous: "과부하로 인해 로그아웃한 사용자가 볼 수 있는 것처럼 모든 사용자에게 일시적으로 표시됩니다." + forced_anonymous_login_required: "사이트 과부하로 지금은 로드할 수 없습니다. 몇 분 후에 다시 시도하세요." footer_nav: - back: "이전" - forward: "앞으로" + back: "뒤로 가기" + forward: "앞으로 가기" share: "공유" - dismiss: "읽음" + dismiss: "무시" safe_mode: - enabled: "안전모드가 활성화 되었습니다. 안전모드를 종료하려면 이 웹브라우저창을 닫아야 합니다." + enabled: "안전 모드가 활성화되었습니다. 안전 모드를 종료하려면 이 브라우저 창을 닫으세요." image_removed: "(이미지 제거됨)" do_not_disturb: - title: "방해 금지..." + title: "다음 시간 동안 방해 금지..." label: "방해 금지" remaining: "%{remaining} 남음" options: @@ -3420,61 +3433,67 @@ ko: one_hour: "1시간" two_hours: "2시간" tomorrow: "내일까지" - custom: "사용자 정의" + custom: "사용자 지정" set_schedule: "알림 일정 설정" trust_levels: names: - newuser: "새로운 사용자" + newuser: "신규 사용자" basic: "기본 사용자" - member: "멤버" - regular: "일반" + member: "회원" + regular: "정회원" leader: "리더" detailed_name: "%{level}: %{name}" pick_files_button: unsupported_file_picked: "지원되지 않는 파일을 선택했습니다. 지원되는 파일 형식 – %{types}." user_activity: no_activity_title: "아직 활동 없음" - no_activity_others: "활동 없음." - no_replies_title: "아직 어떤 글에도 댓글을 달지 않았습니다." - no_replies_others: "답글이 없습니다." + no_replies_title: "어떤 주제에도 댓글을 달지 않았습니다." no_drafts_title: "초안을 시작하지 않았습니다." - no_drafts_body: "아직 글을 작성할 준비가 되지 않았습니까? 글, 댓글 또는 개인 메시지 작성을 시작할 때마다 새 초안을 자동으로 저장하고 여기에 나열합니다. 취소 버튼을 클릭해 삭제하거나 나중에 계속하려면 초안을 저장하세요." - no_likes_title: "아직 어떤 글에도 좋아요를 클릭하지 않으셨습니다." - no_likes_body: "참여와 기여를 시작하는 가장 좋은 방법은 다른 사용자의 글을 읽고 %{heartIcon} 을 클릭하는 것입니다!" - no_likes_others: "좋아요를 받은 게시글이 없습니다" - no_topics_title: "아직 작성한 글이 없습니다." + no_drafts_body: "아직 게시할 준비가 되지 않았나요? 주제, 댓글 또는 개인 메시지 작성을 시작할 때마다 새 초안을 자동으로 저장하고 여기에 나열합니다. 초안을 버리려면 취소 버튼을 누르고 나중에 이어서 작성하려면 초안을 저장하세요." + no_likes_title: "아직 어떤 주제에도 좋아요를 누르지 않았습니다" + no_likes_body: "참여와 기여를 시작하는 가장 좋은 방법은 이미 진행 중인 대화를 읽고 좋아하는 게시물에서 %{heartIcon} 아이콘을 클릭하는 것입니다!" + no_topics_title: "아직 시작한 주제가 없습니다" no_topics_body: "새로운 대화를 시작하기 전에 기존 주제를 검색하는 것이 좋습니다. 만약 원하시는 주제가 이미 존재하지 않을 것이라고 확신하신다면 계속 진행하셔도 좋습니다. 태그, 카테고리 또는 주제 목록의 오른쪽 상단의 + 새 주제 버튼을 눌러 해당 영역에서 새 주제 만들기를 시작하세요." - no_read_topics_title: "아직 읽은 글이 없습니다." - no_group_messages_title: "그룹 메시지가 없습니다." + no_read_topics_title: "아직 읽은 주제가 없습니다." + no_group_messages_title: "그룹 메시지가 없습니다" fullscreen_table: - expand_btn: "테이블 확장" + expand_btn: "표 펼치기" sidebar: unread_count: other: "%{count} unread" new_count: other: "%{count} new" more: "더 보기..." + all_categories: "모든 카테고리" + all_tags: "모든 태그" sections: + about: + header_link_text: "소개" messages: header_link_text: "메시지" links: inbox: "받은 편지함" - sent: "보낸 편지함" - new: "새글" - new_with_count: "새글 (%{count})" + sent: "전송됨" + new: "신규" + new_with_count: "신규(%{count})" unread: "읽지 않음" - unread_with_count: "읽지 않은 글 (%{count})" - archive: "저장함" + unread_with_count: "읽지 않음(%{count})" + archive: "보관" tags: - header_link_title: "모든 태그" header_link_text: "태그" categories: - header_link_title: "모든 카테고리" header_link_text: "카테고리" community: - header_link_title: "홈" header_link_text: "커뮤니티" links: + about: + content: "소개" + admin: + content: "관리자" + badges: + content: "배지" + faq: + content: "자주하는 질문" tracked: content: "팔로우중" groups: @@ -3487,7 +3506,7 @@ ko: draft_count: other: "초안 %{count}" admin_js: - type_to_filter: "필터를 입력하세요" + type_to_filter: "필터링하려면 입력..." admin: title: "Discourse 관리자" moderator: "운영자" @@ -3495,92 +3514,92 @@ ko: remove_muted_tags_from_latest: always: "항상 알림 받기" only_muted: "단독으로 또는 다른 뮤트 태그와 함께 사용되는 경우" - never: "하지않음" + never: "거부" reports: - title: "사용 가능한 보고서 목록" + title: "사용 가능한 리포트 목록" dashboard: title: "대시보드" - last_updated: "대시 보드 업데이트 :" - discourse_last_updated: "Discourse 업데이트:" + last_updated: "대시보드 업데이트됨:" + discourse_last_updated: "Discourse 업데이트됨:" version: "버전" up_to_date: "최신상태입니다!" critical_available: "중요 업데이트를 사용할 수 있습니다." updates_available: "업데이트를 사용할 수 있습니다." please_upgrade: "업그레이드하세요!" - no_check_performed: "업데이트 확인이 수행되지 않았습니다. sidekiq가 실행 중인지 확인하십시오." - stale_data: "최근 업데이트 확인이 수행되지 않았습니다. sidekiq가 실행 중인지 확인하십시오." - version_check_pending: "최근에 업그레이드 한 것 같습니다. 환상적입니다!" + no_check_performed: "업데이트 확인이 수행되지 않았습니다. sidekiq가 실행 중인지 확인하세요." + stale_data: "최근 업데이트 확인이 수행되지 않았습니다. sidekiq가 실행 중인지 확인하세요." + version_check_pending: "최근에 업그레이드하셨네요. 잘하셨습니다!" installed_version: "설치됨" latest_version: "최신" - problems_found: "현재 사이트 설정에 따른 몇 가지 조언" + problems_found: "현재 사이트 설정에 따른 몇 가지 권고 사항" new_features: - title: "\U0001F381 새로운 기능" - dismiss: "읽음" - learn_more: "더 보기" - last_checked: "마지막으로 확인" + title: "\U0001F381 새 기능" + dismiss: "무시" + learn_more: "더 알아보기" + last_checked: "마지막으로 확인함" refresh_problems: "새로고침" - no_problems: "아무런 문제가 발견되지 않았습니다." + no_problems: "문제가 발견되지 않았습니다." moderators: "운영자:" admins: "관리자:" - silenced: "무음 :" - suspended: "차단:" + silenced: "차단됨:" + suspended: "정지됨:" private_messages_short: "메시지" private_messages_title: "메시지" mobile_title: "모바일" - space_used: "사용 된 %{usedSize}" - space_used_and_free: "%{usedSize} (%{freeSize} 여유)" + space_used: "%{usedSize} 사용됨" + space_used_and_free: "%{usedSize}(%{freeSize} 남음)" uploads: "업로드된 파일" backups: "백업" backup_count: - other: "%{location}에 %{count}개의 백업" + other: "%{location}에 %{count}개의 백업 존재" lastest_backup: "최근: %{date}" traffic_short: "트래픽" traffic: "어플리케이션 웹 요청" - page_views: "페이지뷰" - page_views_short: "페이지뷰" - show_traffic_report: "자세한 트래픽 리포트 보기" - community_health: 커뮤니티 현황 - moderators_activity: 중재자 활동 - whats_new_in_discourse: Discourse의 새로운 기능은 무엇입니까? + page_views: "페이지 조회수" + page_views_short: "페이지 조회수" + show_traffic_report: "자세한 트래픽 리포트 표시" + community_health: 커뮤니티 상태 + moderators_activity: 운영자 활동 + whats_new_in_discourse: Discourse의 소식 activity_metrics: 활동 지표 - all_reports: "모든 보고서" + all_reports: "모든 리포트" general_tab: "일반" moderation_tab: "관리" security_tab: "보안" - reports_tab: "보고서" - report_filter_any: "무관" - disabled: 비활성 - timeout_error: 죄송합니다. 검색어가 너무 오래 걸립니다. 더 짧은 간격을 선택하십시오 - exception_error: 죄송합니다. 쿼리 실행 중 오류가 발생했습니다. - too_many_requests: 이 작업을 너무 많이 수행했습니다. 다시 시도하기 전에 기다리십시오. - not_found_error: 죄송합니다.이 보고서는 존재하지 않습니다 - filter_reports: 보고서 필터링 + reports_tab: "리포트" + report_filter_any: "모두" + disabled: 비활성화됨 + timeout_error: 쿼리가 너무 오래 걸립니다. 간격을 좁혀보세요 + exception_error: 쿼리 실행 중에 오류가 발생했습니다. + too_many_requests: 이 작업을 너무 많이 수행했습니다. 다시 시도하기 전에 잠시 기다려 주세요. + not_found_error: 이 리포트는 존재하지 않습니다 + filter_reports: 리포트 필터링 reports: - trend_title: "%{percent} 변경. 현재 %{current}은 이전 기간의 %{prev}입니다." + trend_title: "%{percent} 변경. 현재 %{current}이며, 이전 기간의 %{prev}입니다." today: "오늘" yesterday: "어제" last_7_days: "최근 7일" last_30_days: "최근 30일" - all_time: "모든 시간" + all_time: "전체 기간" 7_days_ago: "7일 전" 30_days_ago: "30일 전" all: "전체" - view_table: "테이블" + view_table: "표" view_graph: "그래프" - refresh_report: "보고서 새로고침" - daily: 일간 - monthly: 월간 - weekly: 주간 - dates: "날짜 (UTC)" + refresh_report: "리포트 새로고침" + daily: 매일 + monthly: 매달 + weekly: 매주 + dates: "날짜(UTC)" groups: "모든 그룹" - disabled: "이 보고서는 비활성화되어 있습니다" - totals_for_sample: "샘플의 총계" + disabled: "이 리포트는 비활성화되었습니다" + totals_for_sample: "샘플 합계" average_for_sample: "샘플 평균" - total: "모든 시간 합계" - no_data: "표시할 정보가 없습니다." + total: "전체 시간 합계" + no_data: "표시할 데이터가 없습니다." trending_search: more: '검색 로그' - disabled: '인기 검색 보고서가 비활성화되었습니다. 로그 검색 쿼리 를 사용하여 데이터를 수집하십시오.' + disabled: '인기 검색 리포트가 비활성화되었습니다. 로그 검색 쿼리 를 활성화하여 데이터를 수집하세요.' average_chart_label: 평균 filters: file_extension: @@ -3590,7 +3609,7 @@ ko: category: label: 카테고리 include_subcategories: - label: "하위카테고리 포함" + label: "서브카테고리 포함" groups: new: title: "새 그룹" @@ -3598,148 +3617,148 @@ ko: name: too_short: "그룹 이름이 너무 짧습니다" too_long: "그룹 이름이 너무 깁니다" - checking: "그룹 이름 가용성 확인 중 ..." - available: "사용가능한 그룹 이름" - not_available: "사용 불가능한 그룹 이름" - blank: "그룹 이름은 공백이 될 수 없습니다" + checking: "그룹 이름 사용 가능 여부 확인 중 ..." + available: "그룹 이름을 사용할 수 있습니다" + not_available: "그룹 이름을 사용할 수 없습니다" + blank: "그룹 이름은 공백일 수 없습니다" manage: interaction: email: 이메일 - incoming_email: "사용자 설정 수신 이메일 주소" + incoming_email: "사용자 지정 수신 이메일 주소" incoming_email_placeholder: "이메일 주소 입력" - visibility: 시계 + visibility: 공개 옵션 visibility_levels: title: "누가 이 그룹을 볼 수 있나요?" public: "모두" - logged_on_users: "로그온 한 사용자" - members: "그룹 소유자, 회원" - staff: "그룹 소유자와 운영진" + logged_on_users: "로그인한 사용자" + members: "그룹 소유자, 회원, 운영자" + staff: "그룹 소유자와 운영자" owners: "그룹 소유자" description: "관리자는 모든 그룹을 볼 수 있습니다." members_visibility_levels: - title: "누가이 그룹의 회원을 볼 수 있습니까?" + title: "누가 이 그룹의 회원을 볼 수 있나요?" publish_read_state: "그룹 메시지에서 그룹 읽기 상태 게시" membership: automatic: 자동 - trust_levels_title: "멤버들이 추가되면 회원등급이 자동으로 부여됩니다:" + trust_levels_title: "회원이 추가되면 신뢰 레벨이 자동으로 부여됨:" effects: 효과 trust_levels_none: "없음" - automatic_membership_email_domains: "이 목록의 있는 항목과 사용자들이 등록한 이메일 도메인이 일치할때 이 그룹에 포함" + automatic_membership_email_domains: "이 목록의 항목과 사용자가 등록한 이메일 도메인이 일치할 경우 사용자가 이 그룹에 자동으로 추가됨:" automatic_membership_user_count: - other: "%{count}명의 사용자는 새 이메일 도메인을 가지며 그룹에 추가됩니다." + other: "%{count}명의 사용자기 새 이메일 도메인을 가지며 그룹에 추가됩니다." primary_group: "기본 그룹으로 자동 설정" - name_placeholder: "그룹 이름, 공백 없이 username 규칙과 동일하게 입력하세요." + name_placeholder: "그룹 이름, 공백 없이, 아이디 규칙과 동일" primary: "주 그룹" no_primary: "(주 그룹이 없습니다.)" title: "그룹" edit: "그룹 수정" refresh: "새로고침" - about: "회원과 이름을 변경" + about: "여기서 회원과 이름 편집" group_members: "그룹 멤버" delete: "삭제" - delete_confirm: "이 그룹을 삭제 하시겠습니까?" + delete_confirm: "이 그룹을 삭제할까요?" delete_with_messages_confirm: - other: "이 그룹을 삭제하면 %{count}개의 메시지가 분리되고 그룹 회원은 더 이상 메시지에 접근 할 수 없습니다.

    삭제 하시겠습니까?" - delete_failed: "이것은 자동으로 생성된 그룹입니다. 삭제할 수 없습니다." + other: "이 그룹을 삭제하면 %{count}개의 메시지가 분리되고 그룹 회원은 더 이상 메시지에 액세스할 수 없습니다.

    삭제할까요?" + delete_failed: "그룹을 삭제할 수 없습니다. 자동 그룹인 경우 제거할 수 없습니다." delete_automatic_group: 이 그룹은 자동 그룹이므로 삭제할 수 없습니다. - delete_owner_confirm: "'%{username}' 님에게서 소유자권한을 제거할까요?" + delete_owner_confirm: "'%{username}' 님의 소유자 권한을 제거할까요?" add: "추가" custom: "Custom" automatic: "자동화" - default_title: "기본 타이틀" - default_title_description: "그룹의 모든 사용자에게 적용됩니다" + default_title: "디폴트 타이틀" + default_title_description: "그룹의 모든 사용자에게 적용됨" group_owners: 소유자 add_owners: 소유자 추가하기 none_selected: "시작할 그룹을 선택하세요" - no_custom_groups: "사용자 설정 그룹 만들기" + no_custom_groups: "새 사용자 지정 그룹 생성" api: generate_master: "마스터 API 키 생성" - none: "지금 활성화된 API 키가 없습니다." + none: "현재 활성 API 키가 없습니다." user: "사용자" title: "API" key: "키" - created: 생성일자 - updated: 업데이트 - last_used: 마지막 사용 - never_used: (못) - generate: "API 키 생성" - undo_revoke: "취소 취소" - revoke: "폐지" - all_users: "전체 유저" + created: 생성일 + updated: 업데이트일 + last_used: 마지막 사용일 + never_used: (없음) + generate: "생성" + undo_revoke: "취소 실행 취소" + revoke: "취소" + all_users: "모든 사용자" active_keys: "활성 API 키" manage_keys: 키 관리 - show_details: 세부 내용 - description: 내용 + show_details: 상세 정보 + description: 설명 no_description: (설명 없음) all_api_keys: 모든 API 키 user_mode: 사용자 레벨 scope_mode: 범위 - impersonate_all_users: 모든 사용자를 가장 + impersonate_all_users: 모든 사용자 가장 single_user: "단일 사용자" - user_placeholder: 사용자 이름을 입력하십시오 - description_placeholder: 이 키는 무엇에 사용됩니까? + user_placeholder: 아이디 입력 + description_placeholder: 이 키의 용도가 무엇인가요? save: 저장 new_key: 새로운 API 키 - revoked: 해지 - delete: 영구적으로 삭제 - not_shown_again: 이 키는 다시 표시되지 않습니다. 계속하기 전에 사본을 작성하십시오. + revoked: 취소됨 + delete: 영구 삭제 + not_shown_again: 이 키는 다시 표시되지 않습니다. 계속하기 전에 사본을 만드세요. continue: 계속 scopes: description: | - 범위를 사용할 때 API키를 특정 엔드 포인트 세트로 제한 할 수 있습니다. - 허용 할 매개 변수를 정의 할 수도 있습니다. 여러 값을 구분하려면 쉼표를 사용하십시오. + 범위를 사용할 때 API 키를 특정 엔드포인트 세트로 제한할 수 있습니다. + 허용할 파라미터를 정의할 수도 있습니다. 여러 값을 구분하려면 쉼표를 사용하세요. title: 범위 granular: 세분화 read_only: 읽기 전용 global: 글로벌 global_description: API 키에는 제한이 없으며 모든 엔드포인트에 액세스할 수 있습니다. - resource: 자원 - action: 동작 - allowed_parameters: 허용된 매개 변수 - optional_allowed_parameters: 허용된 매개변수 (선택 사항) - any_parameter: (모든 매개 변수) + resource: 리소스 + action: 작업 + allowed_parameters: 허용된 파라미터 + optional_allowed_parameters: 허용된 파라미터(선택사항) + any_parameter: (모든 파라미터) allowed_urls: 허용된 URL descriptions: global: read: API 키를 읽기 전용 엔드포인트로 제한합니다. topics: - read: 글 또는 특정 게시물을 읽으십시오. RSS도 지원됩니다. - write: 새 글 또는 기존 글에 댓글을 작성합니다. - read_lists: 주요 글, 새 글, 최근 글 등과 같은 글 목록을 읽으십시오. RSS도 지원됩니다. + read: 주제 또는 주제 내 특정 게시물을 읽습니다. RSS도 지원됩니다. + write: 새 주제를 생성하거나 기존 주제에 게시합니다. + read_lists: 주요 주제, 새 주제, 최근 주제 등의 글 주제 목록을 읽습니다. RSS도 지원됩니다. posts: - edit: 게시물 또는 특정 게시물을 편집합니다. + edit: 모든 게시물 또는 특정 게시물을 편집합니다. categories: list: 카테고리 목록을 가져옵니다. - show: ID별로 단일 카테고리를 가져옵니다. + show: ID별 단일 카테고리를 가져옵니다. uploads: create: 새 파일을 업로드하거나 외부 저장소에 단일 또는 멀티파트 직접 업로드를 시작합니다. users: - bookmarks: 사용자 북마크를 나열합니다. ICS 형식을 사용하면 북마크 알림을 반환합니다. + bookmarks: 사용자 북마크를 나열합니다. ICS 포맷을 사용하면 북마크 미리 알림을 반환합니다. sync_sso: DiscourseConnect를 사용하여 사용자를 동기화합니다. show: 사용자에 대한 정보를 얻습니다. check_emails: 사용자 이메일을 나열합니다. update: 사용자 프로필 정보를 업데이트합니다. - log_out: 사용자의 모든 세션을 로그 아웃합니다. + log_out: 사용자의 모든 세션을 로그아웃합니다. anonymize: 사용자 계정을 익명화합니다. delete: 사용자 계정을 삭제합니다. list: 사용자 목록을 가져옵니다. email: - receive_emails: 이 범위를 메일 수신자와 결합하여 수신 이메일을 처리하십시오. + receive_emails: 이 범위를 메일 수신자와 결합하여 수신 이메일을 처리합니다. badges: - create: 새 배지를 만들기 + create: 새 배지를 생성합니다. show: 배지에 대한 정보를 얻습니다. - update: 배지 업데이트 - delete: 배지 삭제 - list_user_badges: 사용자 배지 리스트 + update: 배지를 업데이트합니다. + delete: 배지를 삭제합니다. + list_user_badges: 사용자 배지를 나열합니다. assign_badge_to_user: 사용자에게 배지를 할당합니다. - revoke_badge_from_user: 사용자 배지 취소 + revoke_badge_from_user: 사용자에게서 배지를 회수합니다. web_hooks: title: "Webhook" - none: "현재 webhook이 없습니다." - instruction: "Webhook이 이 사이트에서 특정 이벤트가 발생할 경우 Discourse가 외부 서비스에 알림을 보내도록 허가하였습니다. webhook 트리거가 작동되면 POST request가 제공된 URL로 전송됩니다." - detailed_instruction: "선택된 이벤트 발생시 POST request가 제공된 URL로 전송됩니다." + none: "현재 Webhook가 없습니다." + instruction: "이 사이트에서 특정 이벤트가 발생할 경우 Webhook가 Discourse에서 외부 서비스에 알림을 보내도록 허용합니다. Webhook가 트리거되면 POST 요청이 제공된 URL로 전송됩니다." + detailed_instruction: "선택된 이벤트가 발생할 경우 POST 요청이 제공된 URL로 전송됩니다." new: "새 Webhook" - create: "생성하기" + create: "생성" save: "저장하기" destroy: "삭제하기" description: "설명" @@ -3747,94 +3766,94 @@ ko: go_back: "목록으로 돌아가기" payload_url: "Payload URL" payload_url_placeholder: "https://example.com/postreceive" - warn_local_payload_url: "웹훅을 로컬 URL에 설정하려는 것 같습니다. 로컬 주소로 이벤트가 전달되면 부작용이나 예기치 않은 동작이 발생할 수 있습니다. 계속하시겠습니까?" - secret_invalid: "Secret에는 공백이 들어갈 수 없습니다." - secret_too_short: "Secret은 최소 12자 이상이어야 합니다." + warn_local_payload_url: "Webhook를 로컬 URL에 구성하려는 것 같습니다. 로컬 주소로 이벤트가 전달되면 부작용이나 예기치 않은 행동이 발생할 수 있습니다. 계속할까요?" + secret_invalid: "Secret에는 공백이 있을 수 없습니다." + secret_too_short: "Secret은 12자 이상이어야 합니다." secret_placeholder: "시그니처를 생성하기 위한 문자열(선택사항)" - event_type_missing: "최소 한가지 이상의 Event type을 설정해야 합니다" + event_type_missing: "1개 이상의 이벤트 유형을 구성해야 합니다." content_type: "Content Type" secret: "Secret" - event_chooser: "이 webhook을 작동시키는 이벤트는 무엇인가요?" - wildcard_event: "모두 보내주세요." - individual_event: "각각의 이벤트를 선택하기" - verify_certificate: "payload URL의 TLS인증서를 체크하세요" - active: "활성화" - active_notice: "이벤트 발생 시 이벤트 상세정보를 보내드립니다." - categories_filter_instructions: "관련된 webhook은 이벤트가 특정 카테고리와 관계가 있을 때만 트리거를 작동시킵니다. 모든 카테고리에 이 webhook을 적용하고 싶을 때는 트리거에 공백을 추가하세요." - categories_filter: "트리거 설정된 카테고리" - tags_filter_instructions: "이벤트가 지정된 태그와 관련된 경우에만 관련 웹 후크가 트리거됩니다. 모든 태그에 대해 웹 후크를 트리거하려면 비워 두십시오." - tags_filter: "트리거 된 태그" - groups_filter_instructions: "관련된 webhook은 이벤트가 특정 그룹과 관계가 있을 때만 트리거를 작동시킵니다. 모든 카테고리에 이 webhook을 적용하고 싶을 때는 트리거에 공백을 추가하세요." - groups_filter: "트리거 설정된 그룹" - delete_confirm: "이 webhook을 삭제할까요?" + event_chooser: "이 Webhook를 트리거하는 이벤트는 무엇인가요?" + wildcard_event: "모두 전송해 주세요." + individual_event: "각 이벤트를 선택합니다." + verify_certificate: "페이로드 URL의 TLS 인증서 확인" + active: "활성" + active_notice: "이벤트 발생 시 이벤트 상세 정보를 보내드립니다." + categories_filter_instructions: "관련 Webhook는 이벤트가 특정 카테고리와 관계가 있을 때만 트리거됩니다. 모든 카테고리에 Webhook를 트리거하려면 공백으로 두세요." + categories_filter: "트리거된 카테고리" + tags_filter_instructions: "관련 Webhook는 이벤트가 특정 태그와 관계가 있을 때만 트리거됩니다. 모든 태그에 Webhook를 트리거하려면 공백으로 두세요." + tags_filter: "트리거된 태그" + groups_filter_instructions: "관련 Webhook는 이벤트가 특정 그룹과 관계가 있을 때만 트리거됩니다. 모든 그룹에 Webhook를 트리거하려면 공백으로 두세요." + groups_filter: "트리거된 그룹" + delete_confirm: "이 Webhook를 삭제할까요?" topic_event: - name: "토픽 이벤트" - details: "토픽이 생성, 수정, 변경, 삭제될 때." + name: "주제 이벤트" + details: "새 주제, 수정, 변경, 삭제 활동이 있을 경우" post_event: - name: "게시글 이벤트" - details: "게시글이 생성, 편집, 삭제, 재생될 때." + name: "게시물 이벤트" + details: "새 댓글, 편집, 삭제, 복구 활동이 있을 경우" user_event: name: "사용자 이벤트" - details: "사용자가 로그인, 로그아웃, 이메일 확인, 생성, 승인 또는 업데이트 될 때." + details: "사용자의 로그인/로그아웃, 이메일 확인, 생성, 승인 또는 업데이트 활동이 있을 경우" group_event: name: "그룹 이벤트" - details: "그룹이 생성, 업데이트 또는 파괴 될 때." + details: "그룹이 생성, 업데이트 또는 제거된 경우" category_event: name: "카테고리 이벤트" - details: "카테고리가 작성, 업데이트 또는 파괴 될 때." + details: "카테고리가 생성, 업데이트 또는 제거된 경우" tag_event: name: "태그 이벤트" - details: "태그가 생성, 업데이트 또는 파괴 될 때." + details: "태그가 생성, 업데이트 또는 제거된 경우" reviewable_event: - name: "검토 가능한 이벤트" - details: "새 항목을 검토 할 준비가되었고 상태가 업데이트 될 때" + name: "검토 가능 이벤트" + details: "새 항목을 검토할 준비가 되었고 상태가 업데이트된 경우" notification_event: name: "알림 이벤트" - details: "사용자가 피드에서 알림을받는 경우" + details: "사용자가 피드에서 알림을 받은 경우" user_badge_event: - name: "배지 보조금 행사" - details: "사용자가 배지를받을 때" + name: "배지 부여 이벤트" + details: "사용자가 배지를 받은 경우" group_user_event: name: "그룹 사용자 이벤트" - details: "사용자가 그룹에 추가되거나 제거되는 경우" + details: "사용자가 그룹에 추가 또는 제거된 경우" like_event: name: "좋아요 이벤트" - details: "사용자가 게시물을 좋아할 때." + details: "사용자가 게시물에 좋아요를 누른 경우" delivery_status: - title: "발송 상태" + title: "전달 상태" inactive: "비활성화" failed: "실패" successful: "성공" - disabled: "비활성" + disabled: "비활성화됨" events: - none: "연관된 이벤트가 없습니다" - redeliver: "재발송" + none: "관련 이벤트가 없습니다." + redeliver: "다시 전달" incoming: other: "%{count}개의 새로운 이벤트가 있습니다." completed_in: - other: "%{count}초 후에 완료됩니다." + other: "%{count}초 후 완료됩니다." request: "요청" response: "응답" - redeliver_confirm: "정말로 동일한 payload를 재발송하기를 원하십니까?" + redeliver_confirm: "동일한 페이로드를 다시 전달할까요?" headers: "헤더" payload: "페이로드" - body: "바디" + body: "본문" go_list: "목록으로 가기" - go_details: "webhook 편집" + go_details: "Webhook 편집" go_events: "이벤트로 가기" ping: "Ping" status: "상태 코드" event_id: "ID" - timestamp: "생성일자" + timestamp: "생성일" completion: "완료 시간" - actions: "액션" + actions: "작업" plugins: title: "플러그인" installed: "설치된 플러그인" name: "이름" none_installed: "설치된 플러그인이 없습니다." version: "버전" - enabled: "활성화?" + enabled: "활성화되었나요?" is_enabled: "예" not_enabled: "아니요" change_settings: "설정 변경" @@ -3846,120 +3865,120 @@ ko: menu: backups: "백업" logs: "로그" - none: "가능한 백업이 없습니다." + none: "사용 가능한 백업이 없습니다." read_only: enable: - title: "읽기 전용 모드 활성화하기" - label: "읽기 전용 활성화하기" - confirm: "정말로 읽기 전용 모드를 활성화할까요?" + title: "읽기 전용 모드 활성화" + label: "읽기 전용 활성화" + confirm: "읽기 전용 모드를 활성화할까요?" disable: - title: "읽기 전용 모드 비활성화 하기" - label: "읽기 전용 비활성화하기" + title: "읽기 전용 모드 비활성화" + label: "읽기 전용 비활성화" logs: - none: "아직 로그가 없어요." + none: "아직 로그가 없습니다..." columns: filename: "파일명" size: "크기" upload: label: "업로드" - title: "백업을 업로드" + title: "이 인스턴스에 백업 업로드" uploading: "업로드 중..." - uploading_progress: "업로드중... %{progress}%" - success: "'%{filename}'이 성공적으로 업로드되었습니다. 파일이 현재 처리중이며 목록에 표시되는데 최대 1분이 걸립니다." - error: "'%{filename}' 파일 업로드중 에러가 발생하였습니다. (%{message})" + uploading_progress: "업로드 중... %{progress}%" + success: "'%{filename}' 파일이 업로드되었습니다. 파일이 현재 처리 중이며 목록에 표시되는 데 최대 1분이 걸립니다." + error: "'%{filename}' 파일 업로드 중에 오류가 발생했습니다. %{message}" operations: - is_running: "실행 중입니다." - failed: "%{operation} 작업 실행하지 못했습니다. 로그를 확인해 주세요." + is_running: "현재 작업이 실행 중입니다..." + failed: "%{operation} 작업을 실행하지 못했습니다. 로그를 확인하세요." cancel: label: "취소" - title: "현제 작업 취소하기" - confirm: "정말로 현재 작업을 취소하시겠습니까?" + title: "현재 작업 취소" + confirm: "현재 작업을 취소할까요?" backup: label: "백업" title: "백업 생성" - confirm: "새로운 백업을 시작할까요?" - without_uploads: "예 (업로드를 포함하지 않음)" + confirm: "새 백업을 시작할까요?" + without_uploads: "예(업로드 포함 안 함)" download: label: "다운로드" - title: "다운로드 링크를 붙여서 이메일 보내기" - alert: "이 백업의 다운로드 링크를 당신에게 이메일로 보냈습니다" + title: "다운로드 링크와 함께 이메일 전송" + alert: "이 백업의 다운로드 링크를 내 이메일로 보냈습니다." destroy: title: "백업 삭제" - confirm: "정말 이 백업을 삭제할까요?" + confirm: "이 백업을 제거할까요?" restore: - is_disabled: "사이트 설정에서 '복구 기능'이 비활성화 되어있습니다." + is_disabled: "사이트 설정에서 복원이 비활성화되어 있습니다." label: "복구" title: "백업을 이용하여 복구" - confirm: "정말 이 백업으로 복원할까요?" + confirm: "이 백업을 복원할까요?" rollback: label: "롤백" title: "데이터베이스를 이전 workiong state로 되돌리기" - confirm: "데이타베이스를 이전 상태로 롤백 또는 되돌리기 할까요?" + confirm: "데이터베이스를 이전 작업 상태로 롤백할까요?" location: local: "로컬 스토리지" s3: "S3" - backup_storage_error: "백업 스토리지에 액세스하지 못했습니다 : %{error_message}" + backup_storage_error: "백업 스토리지에 액세스하지 못했습니다. %{error_message}" export_csv: success: "Export initiated, you will be notified via message when the process is complete." - failed: "내보내기가 실패했습니다. 로그를 확인해주세요" - button_text: "내보내기" + failed: "익스포트에 실패했습니다. 로그를 확인하세요." + button_text: "익스포트" button_title: - user: "모든 사용자 목록을 CSV 형식으로 내보내기" - staff_action: "모든 스태프 행동 로그를 CSV 형식으로 내보내기" - screened_email: "모든 이메일 목록을 CSV 형식으로 내보내기" - screened_ip: "모든 표시된 IP 목록을 CSV 형식으로 내보내기" - screened_url: "모든 표시된 URL 목록을 CSV 형식으로 내보내기" + user: "전체 사용자 목록을 CSV 포맷으로 익스포트합니다." + staff_action: "전체 운영진 활동 로그를 CSV 포맷으로 익스포트합니다." + screened_email: "전체 스크린된 이메일 목록을 CSV 포맷으로 익스포트합니다." + screened_ip: "전체 스크린된 IP 목록을 CSV 포맷으로 익스포트합니다." + screened_url: "전체 스크린된 URL 목록을 CSV 포맷으로 익스포트합니다." export_json: - button_text: "내보내기" + button_text: "익스포트" invite: - button_text: "초대장 보내기" - button_title: "초대장 보내기" + button_text: "초대 전송" + button_title: "초대 전송" customize: title: "사용자 지정" long_title: "사이트 사용자 지정" preview: "미리 보기" explain_preview: "이 테마 적용한 사이트 보기" save: "저장" - new: "새 사용자 지정" - new_style: "새로운 스타일" + new: "신규" + new_style: "새 스타일" install: "설치" delete: "삭제" - delete_confirm: '"%{theme_name}"를 삭제 하시겠습니까?' + delete_confirm: '''%{theme_name}&'' 테마를 삭제할까요?' color: "색상" opacity: "투명도" - copy_to_clipboard: "클립보드에 복사하기" + copy_to_clipboard: "클립보드에 복사" copied_to_clipboard: "클립보드로 복사됨" copy_to_clipboard_error: "클립보드로 복사하는 중 에러가 발생하였습니다" - theme_owner: "편집불가, 소유자:" + theme_owner: "편집 불가, 소유자:" email_templates: title: "이메일" subject: "제목" - multiple_subjects: "이 이메일 양식은 제목이 여러가지 있습니다." + multiple_subjects: "이 이메일 템플릿에 제목이 여러 개 있습니다." body: "본문" - revert: "변경사항 취소" - revert_confirm: "정말로 변경사항을 되돌리시겠습니까?" + revert: "변경사항 되돌리기" + revert_confirm: "변경사항을 되돌릴까요?" theme: theme: "테마" component: "구성 요소" components: "구성 요소" - filter_placeholder: "필터 입력..." + filter_placeholder: "필터링하려면 입력…" theme_name: "테마명" component_name: "구성 요소 이름" - themes_intro: "기존 테마를 선택하거나 새 테마를 설치하여 시작하십시오." + themes_intro: "기존 테마를 선택하거나 새 테마를 설치하여 시작하세요." themes_intro_emoji: "여자 아티스트 이모티콘" beginners_guide_title: "Discourse 테마 사용에 대한 초보자 가이드" developers_guide_title: "Discourse 테마에 대한 개발자 가이드" - browse_themes: "커뮤니티 테마 보기" - customize_desc: "커스터마이즈:" + browse_themes: "커뮤니티 테마 탐색" + customize_desc: "사용자 지정:" title: "테마" - create: "만들기" - create_type: "형식" + create: "생성" + create_type: "유형" create_name: "이름" - long_title: "사이트의 색상, CSS, HTML 수정하기" + long_title: "사이트의 색상, CSS, HTML 콘텐츠 수정" edit: "편집" - edit_confirm: "이 테마는 원격테마입니다. 업데이트가 실행될 때 편집된 CSS/HTML 내용이 사라지게 됩니다." - update_confirm: "이러한 로컬 변경 사항은 업데이트로 지워집니다. 너 정말 계속하고 싶니?" - update_confirm_yes: "예, 업데이트를 계속하십시오" + edit_confirm: "이 테마는 원격 테마입니다. CSS/HTML을 편집하면 다음에 테마를 업데이트할 때 변경사항이 지워집니다." + update_confirm: "이러한 로컬 변경사항은 업데이트 시 지워집니다. 계속할까요?" + update_confirm_yes: "예, 업데이트를 계속합니다" common: "공통" desktop: "데스크톱" mobile: "모바일" @@ -3967,184 +3986,184 @@ ko: translations: "번역" extra_scss: "추가 SCSS" extra_files: "추가 파일" - extra_files_upload: "이 파일을 보려면 테마를 내보내십시오." - extra_files_remote: "테마를 내보내거나 git 저장소를 확인하여 이 파일 보기" + extra_files_upload: "이 파일을 보려면 테마를 익스포트하세요." + extra_files_remote: "이 파일을 보려면 테마를 익스포트하거나 Git 저장소를 확인하세요." preview: "미리보기" show_advanced: "고급 필드 표시" hide_advanced: "고급 필드 숨기기" hide_unused_fields: "사용하지 않는 필드 숨기기" - is_default: "기본값에 의해 테마가 활성화 되었습니다" - user_selectable: "사용자가 테마를 선택하게 하기" - color_scheme_user_selectable: "사용자가 색 구성표를 선택할 수 있습니다." - auto_update: "Discourse가 업데이트되면 자동 업데이트" + is_default: "디폴트로 테마가 활성화되었습니다" + user_selectable: "사용자가 테마를 선택할 수 있습니다" + color_scheme_user_selectable: "사용자가 색상 구성표를 선택할 수 있습니다" + auto_update: "Discourse 업데이트 시 자동 업데이트" color_scheme: "색상 팔레트" - default_light_scheme: "라이트 (기본값)" - color_scheme_select: "테마에서 사용될 컬러 선택" - custom_sections: "커스텀 섹션:" - theme_components: "테마 컴포넌트:" + default_light_scheme: "라이트(디폴트)" + color_scheme_select: "테마에서 사용할 색상 선택" + custom_sections: "사용자 지정 섹션:" + theme_components: "테마 구성 요소:" add_all_themes: "모든 테마 추가" convert: "변환" - convert_component_alert: "이 구성 요소를 테마로 변환 하시겠습니까? %{relatives}에서 구성 요소로 제거됩니다." - convert_component_tooltip: "이 컴포넌트를 테마로 변환" - convert_component_alert_generic: "이 구성 요소를 테마로 변환 하시겠습니까?" - convert_theme_alert: "이 테마를 구성 요소로 변환 하시겠습니까? %{relatives}에서 부모로 제거됩니다." - convert_theme_alert_generic: "이 테마를 구성 요소로 변환 하시겠습니까?" - convert_theme_tooltip: "이 테마를 컴포넌트로 변환" + convert_component_alert: "이 구성 요소를 테마로 변환할까요? %{relatives}에서 구성 요소로 제거됩니다." + convert_component_tooltip: "이 구성 요소를 테마로 변환" + convert_component_alert_generic: "이 구성 요소를 테마로 변환할까요?" + convert_theme_alert: "이 테마를 구성 요소로 변환할까요? %{relatives}에서 부모로 제거됩니다." + convert_theme_alert_generic: "이 테마를 구성 요소로 변환할까요?" + convert_theme_tooltip: "이 테마를 구성 요소로 변환" inactive_themes: "비활성 테마:" - inactive_components: "사용하지 않은 구성 요소 :" + inactive_components: "사용하지 않은 구성 요소:" broken_theme_tooltip: "이 테마는 CSS, HTML 또는 YAML에 오류가 있습니다" disabled_component_tooltip: "이 구성 요소가 비활성화되었습니다" - default_theme_tooltip: "이 테마는 사이트의 기본 테마입니다" + default_theme_tooltip: "이 테마는 사이트의 디폴트 테마입니다" updates_available_tooltip: "이 테마에 대한 업데이트가 있습니다" - and_x_more: "그리고 %{count} 더." - collapse: 축소 - uploads: "업로드된 파일" - no_uploads: "폰트나 이미지같은 테마와 관련된 파일만 업로드 가능합니다" - add_upload: "업로드할 파일 추가하기" - upload_file_tip: "업로드할 파일 선택하기(png, woff2, 기타..)" + and_x_more: "외 %{count}개" + collapse: 접기 + uploads: "업로드" + no_uploads: "폰트나 이미지 같은 테마와 관련된 파일만 업로드할 수 있습니다" + add_upload: "업로드 추가" + upload_file_tip: "업로드할 에셋 선택(png, woff2 등)" variable_name: "SCSS 변수 이름:" - variable_name_invalid: "불가능한 변수명입니다. 알파벳만 허용되며, 문자로 시작해야 하며, 반드시 고유해야 합니다." + variable_name_invalid: "유효하지 않은 변수 이름입니다. 알파벳만 허용되며, 문자로 시작하고, 고유해야 합니다." variable_name_error: - invalid_syntax: "불가능한 변수명입니다. 알파벳만 허용되며, 문자로 시작해야 합니다." - no_overwrite: "변수 이름이 잘못되었습니다. 기존 변수를 덮어 쓰지 않아야합니다." - must_be_unique: "불가능한 변수명입니다. 반드시 고유해야 합니다." + invalid_syntax: "유효하지 않은 변수 이름입니다. 알파벳만 허용되며, 문자로 시작해야 합니다." + no_overwrite: "유효하지 않은 변수 이름입니다. 기존 변수를 덮어쓸 수 없습니다." + must_be_unique: "유효하지 않은 변수 이름입니다. 반드시 고유해야 합니다." upload: "업로드" - select_component: "구성 요소 선택 ..." - unsaved_changes_alert: "변경 사항을 아직 저장하지 않았습니다. 변경 사항을 삭제하고 계속 하시겠습니까?" - unsaved_parent_themes: "구성 요소를 테마에 지정하지 않았습니다. 계속 하시겠습니까?" - discard: "포기" - stay: "머무르다" + select_component: "구성 요소 선택..." + unsaved_changes_alert: "변경사항을 아직 저장하지 않았습니다. 변경사항을 버리고 계속할까요?" + unsaved_parent_themes: "구성 요소를 테마에 할당하지 않았습니다. 계속할까요?" + discard: "버리기" + stay: "유지" css_html: "커스텀 CSS/HTML" edit_css_html: "CSS/HTML 편집하기" - edit_css_html_help: "변경된 CSS 나 HTML이 없습니다." - delete_upload_confirm: "이 업로드를 삭제할까요? (테마 CSS가 작동중지될 수 있습니다!)" + edit_css_html_help: "편집한 CSS나 HTML이 없습니다." + delete_upload_confirm: "이 업로드를 삭제할까요? (테마 CSS가 작동 중지될 수 있습니다!)" component_on_themes: "이 테마에 구성 요소 포함" - included_components: "포함 된 구성 요소" + included_components: "포함된 구성 요소" add_all: "모두 추가" - import_web_tip: "테마가 있는 Repository" - direct_install_tip: "정말로 아래의 저장소에서 %{name}을 설치하시겠습니까?" + import_web_tip: "테마가 있는 저장소" + direct_install_tip: "아래의 저장소에서 %{name} 설치를 진행할까요?" import_web_advanced: "고급..." - import_file_tip: "테마가 포함 된 .tar.gz, .zip 또는 .dcstyle.json 파일" - is_private: "테마는 개인 git 저장소에 있습니다." - remote_branch: "브랜치 이름 (선택 사항)" - public_key: "다음 공개 키 액세스 권한을 리포지토리에 부여하십시오." - public_key_note: "위에 유효한 개인 저장소 URL을 입력하면 SSH 키가 생성되어 여기에 표시됩니다." + import_file_tip: "테마가 포함된 .tar.gz, .zip 또는 .dcstyle.json 파일" + is_private: "테마는 비공개 Git 저장소에 있습니다" + remote_branch: "브랜치 이름(선택사항)" + public_key: "다음 공개 키 액세스를 저장소에 부여하세요." + public_key_note: "위의 유효한 비공개 저장소 URL을 입력하면 SSH 키가 생성되어 여기에 표시됩니다." install: "설치" installed: "설치됨" install_popular: "인기" - install_upload: "기기에서" - install_git_repo: "git 저장소에서" - install_create: "새로 만들기" - duplicate_remote_theme: "테마 구성 요소“%{name}”은 이미 설치되어 있습니다. 다른 복사본을 설치 하시겠습니까?" - about_theme: "소개" + install_upload: "디바이스에서" + install_git_repo: "Git 저장소에서" + install_create: "새로 생성" + duplicate_remote_theme: "'%{name}' 테마 구성 요소가 이미 설치되어 있습니다. 다른 사본을 설치할까요?" + about_theme: "정보" license: "라이센스 정보" version: "버전:" - authors: "작성자 :" - creator: "작성자:" + authors: "작성자:" + creator: "생성자:" source_url: "출처" - enable: "설정" - disable: "해제" + enable: "활성화" + disable: "비활성화" disabled: "이 구성 요소가 비활성화되었습니다." - disabled_by: "이 구성 요소는" + disabled_by: "이 구성 요소가 다음에 의해 비활성화됨" required_version: error: "이 테마는이 버전의 Discourse와 호환되지 않기 때문에 자동으로 비활성화되었습니다." minimum: "Discourse 버전 %{version} 이상이 필요합니다." - maximum: "담화 버전 %{version} 이하가 필요합니다." - component_of: "구성 요소 :" - update_to_latest: "최신버전으로 업데이트하기" + maximum: "Discourse 버전 %{version} 이하가 필요합니다." + component_of: "구성 요소:" + update_to_latest: "최신으로 업데이트" check_for_updates: "업데이트 체크하기" updating: "업데이트 중..." - up_to_date: "테마가 최신 상태입니다. 마지막 확인:" - has_overwritten_history: "강제 푸시로 Git 기록을 덮어 썼으므로 현재 테마 버전이 더 이상 존재하지 않습니다." + up_to_date: "테마가 최신입니다. 마지막 확인:" + has_overwritten_history: "강제 푸시로 Git 히스토리를 덮어 썼으므로 현재 테마 버전이 더 이상 존재하지 않습니다." add: "추가" theme_settings: "테마 설정" no_settings: "이 테마에는 설정이 없습니다." theme_translations: "테마 번역" empty: "항목이 없습니다" commits_behind: - other: "테마가 %{count} 개 커밋 뒤쳐졌습니다!" - compare_commits: "(새로운 커밋 참조)" - remote_theme_edits: "이 테마를 편집하려면 저장소에 변경 사항을 제출해야합니다." - repo_unreachable: "이 테마의 Git 저장소에 접속할 수 없습니다. 에러 메시지:" - imported_from_archive: "이 테마는 .zip 파일에서 가져 왔습니다." + other: "테마에 최신 커밋 %{count}개가 있습니다." + compare_commits: "(새 커밋 보기)" + remote_theme_edits: "이 테마를 편집하려면 저장소에 변경사항을 제출해야 합니다." + repo_unreachable: "이 테마의 Git 저장소에 접속할 수 없습니다. 오류 메시지:" + imported_from_archive: "이 테마는 .zip 파일에서 임포트했습니다." scss: text: "CSS" - title: "커스텀 CSS를 입력하세요. 형식에 맞는 CSS 와 SCSS 스타일을 지원합니다." + title: "커스텀 CSS를 입력하세요. 모든 유효한 CSS 및 SCSS 스타일을 지원합니다." header: text: "Header" - title: "사이트 Header에 표시될 HTML을 입력하세요" + title: "위 사이트 헤더에 표시할 HTML을 입력하세요" after_header: - text: "Header 다음" - title: "전체 페이지에서 Header다음에 표시될 HTML을 입력하세요" + text: "헤더 다음" + title: "전체 페이지에서 헤더 다음에 표시할 HTML을 입력하세요" footer: text: "Footer" - title: "페이지 Footer에 표시될 HTML을 입력하세요" + title: "페이지 바닥글에 표시할 HTML을 입력하세요" embedded_scss: text: "임베디드 CSS" - title: "임베디드 버전 코멘트를 보내기 위한 사용자 정의 CSS를 입력하세요" + title: "임베디드 버전 코멘트와 함께 전달하기 위해 사용자 지정 CSS를 입력하세요" color_definitions: text: "색상 정의" - title: "사용자 색상 정의 입력 (고급 사용자용)" + title: "사용자 지정 색상 정의 입력(고급 사용자용)" placeholder: |2- - 이 스타일시트를 사용하여 CSS 사용자 정의 속성 목록에 사용자 정의 색상을 추가합니다. + 이 스타일시트를 사용하여 CSS 사용자 지정 프로퍼티 목록에 사용자 지정 색상을 추가합니다. - 예: + 예시: %{example} - 플러그인 및/또는 코어와의 충돌을 피하기 위해 속성 이름 앞에 붙이는 것이 좋습니다. + 플러그인 및/또는 코어와의 충돌을 피하기 위해 프로퍼티 이름 앞에 붙이는 것이 좋습니다. head_tag: text: "헤드" title: "헤드 태그 앞에 삽입될 HTML" body_tag: - text: "바디" + text: "본문" title: "본문 태그 앞에 삽입될 HTML" yaml: text: "YAML" - title: "YAML 형식으로 테마 설정 정의" - scss_color_variables_warning: '테마에서 핵심 SCSS 색상 변수를 사용하는 것은 더 이상 사용되지 않습니다. 대신 CSS 사용자 정의 속성을 사용하십시오. 자세한 내용은 이 가이드 을 참조하십시오.' - scss_warning_inline: "테마에서 핵심 SCSS 색상 변수를 사용하는 것은 더 이상 사용되지 않습니다." + title: "YAML 포맷으로 테마 설정 정의" + scss_color_variables_warning: '테마에서 핵심 SCSS 색상 변수를 사용하는 기능은 지원 중단되었습니다. 대신 CSS 사용자 지정 프로퍼티를 사용하세요. 자세한 내용은 이 가이드를 참조하세요.' + scss_warning_inline: "테마에서 코어 SCSS 색상 변수를 사용하는 기능은 지원 중단되었습니다." colors: select_base: - title: "기본 색상 팔레트 선택" - description: "기본 팔레트 :" + title: "베이스 색상 팔레트 선택" + description: "베이스 팔레트:" title: "색상" edit: "색상 표 편집" long_title: "컬러 팔레트" - about: "테마에 사용되는 색상을 수정하십시오. 시작할 새 색상 팔레트를 만듭니다." - new_name: "새로운 컬러 팔레트" - copy_name_prefix: "복사본" - delete_confirm: "이 색상 표를 삭제 하시겠습니까?" + about: "테마에 사용되는 색상을 수정합니다. 시작하려면 새 색상 팔레트를 생성하세요." + new_name: "새 색상 팔레트" + copy_name_prefix: "다음의 사본" + delete_confirm: "이 색상 팔레트를 삭제할까요?" undo: "실행 복귀" - undo_title: "마지막 저장 상태로 색상 변경상태를 되돌리기" + undo_title: "마지막 저장 이후 색상 변경사항을 실행 취소합니다." revert: "되돌리기" - revert_title: "이 색상을 Discourse의 기본 색상 팔레트로 재설정합니다." + revert_title: "이 색상을 Discourse의 디폴트 색상 팔레트로 리셋합니다." primary: - name: "주요" - description: "대부분의 글, 아이콘 및 테두리" + name: "1차" + description: "대부분의 텍스트, 아이콘 및 테두리" primary-medium: name: "primary-medium" primary-low-mid: name: "primary-low-mid" secondary: name: "2차" - description: "메인 백그라운드 색상, 몇몇 버튼의 텍스트 색상" + description: "메인 배경 색상, 일부 버튼의 텍스트 색상" tertiary: name: "3차" - description: "링크, 버튼, 알림 및 강조를 위한 색" + description: "링크, 일부 버튼, 알림 및 강조 색상" quaternary: name: "4차" description: "네비게이션 링크" header_background: - name: "헤더 배경색" - description: "사이트 헤더의 배경 색상" + name: "헤더 배경 색상" + description: "사이트 헤더의 배경 색상입니다." header_primary: - name: "헤더 기본 색" - description: "사이트 헤더에 텍스트와 아이콘" + name: "헤더 기본" + description: "사이트 헤더의 텍스트와 아이콘입니다." highlight: name: "하이라이트" - description: "포스트나 토픽과 같은 페이지 내에서 강조된 요소의 배경색" + description: "게시물이나 주제와 같은 페이지 내 하이라이트된 요소의 배경 색상입니다." highlight-high: name: "highlight-high" highlight-medium: @@ -4153,26 +4172,26 @@ ko: name: "highlight-low" danger: name: "위험" - description: "글 삭제 등에 사용되는 강조색" + description: "게시물 및 주제 삭제와 같은 작업의 하이라이트 색상입니다." success: name: "성공" - description: "작업이 성공했음을 나타내는데 사용됩니다." + description: "작업이 성공했음을 나타내는 데 사용됩니다." love: - name: "사랑" - description: "좋아요 버튼 색" + name: "하트" + description: "좋아요 버튼 색입니다." robots: - title: "사이트의 robots.txt 파일을 재정의하십시오." - warning: "관련 사이트 설정이 영구적으로 무시됩니다." - overridden: 사이트의 기본 robots.txt 파일이 재정의되었습니다. + title: "사이트의 robots.txt 파일 오버라이드:" + warning: "관련된 모든 사이트 설정이 영구적으로 오버라이드됩니다." + overridden: 사이트의 디폴트 robots.txt 파일이 오버라이드되었습니다. email_style: title: "이메일 스타일" - heading: "이메일 스타일 사용자 정의" + heading: "이메일 스타일 사용자 지정" html: "HTML 템플릿" css: "CSS" - reset: "기본값으로 재설정" - reset_confirm: "기본 %{fieldName}으로 재설정하고 모든 변경 사항을 잃으시겠습니까?" - save_error_with_reason: "변경 사항이 저장되지 않았습니다. %{error}" - instructions: "모든 html 이메일이 렌더링되는 템플릿을 사용자 정의하고 CSS를 사용하여 스타일을 지정하십시오." + reset: "디폴트로 리셋" + reset_confirm: "디폴트 %{fieldName} 파일로 리셋하고 모든 변경사항을 버릴까요?" + save_error_with_reason: "변경사항이 저장되지 않았습니다. %{error}" + instructions: "모든 html 이메일이 렌더링되는 템플릿을 사용자 지정하고 CSS를 사용하여 스타일을 지정하세요." email: title: "이메일" settings: "설정" @@ -4180,50 +4199,50 @@ ko: preview_digest: "요약 미리보기" advanced_test: title: "고급 테스트" - desc: "Discourse가 수신 된 이메일을 처리하는 방법을 확인하십시오. 이메일을 올바르게 처리하려면 전체 원본 이메일 메시지 아래에 붙여 넣으십시오." + desc: "Discourse의 수신 이메일 처리 방법을 확인하세요. 이메일을 올바르게 처리하려면 전체 원본 이메일 메시지 아래에 붙여 넣으세요." email: "원본 메시지" run: "테스트 실행" text: "선택된 텍스트 본문" - elided: "생략 된 텍스트" - sending_test: "테스트 메일 발송중..." - error: "에러 - %{server_error}" - test_error: "테스트 메일을 전송하는데 문제가 있습니다. 메일 설정을 다시한번 체크해보고 메일 전송이 정상인지 다시 확인하고 시도해주세요." - sent: "보냄" - skipped: "생략됨" + elided: "생략된 텍스트" + sending_test: "테스트 메일 전송 중..." + error: "오류 - %{server_error}" + test_error: "테스트 메일을 전송하는 데 문제가 있습니다. 메일 설정을 다시 확인하여 호스트가 메일 연결을 차단하고 있지는 않은지 확인한 후 다시 시도하세요." + sent: "전송됨" + skipped: "건너뛰기됨" bounced: "반송됨" - received: "전송받음" + received: "수신됨" rejected: "거부됨" - sent_at: "보냄" + sent_at: "전송됨:" time: "시간" user: "사용자" - email_type: "이메일 타입" + email_type: "이메일 유형" to_address: "받는 주소" test_email_address: "테스트용 이메일 주소" send_test: "테스트 메일 전송" - sent_test: "전송됨!" + sent_test: "전송되었습니다!" delivery_method: "전달 방법" - preview_digest_desc: "초대 사용자들에게 보낼 요약 메일 내용 미리보기" + preview_digest_desc: "비활성 사용자에게 전송할 요약 메일 콘텐츠 미리보기" refresh: "새로고침" - send_digest_label: "이 결과를 여기로 전송합니다:" - send_digest: "보내기" - sending_email: "이메일을 보내고 있습니다..." - format: "형식" + send_digest_label: "이 결과를 다음에 전송:" + send_digest: "전송" + sending_email: "이메일 전송 중..." + format: "포맷" html: "html" - text: "문장" - html_preview: "이메일 내용 미리보기" - last_seen_user: "마지막으로 본 사용자" - no_result: "요약된 결과가 없습니다." - reply_key: "답글 단축키" - skipped_reason: "생략 이유" + text: "텍스트" + html_preview: "이메일 콘텐츠 미리보기" + last_seen_user: "마지막으로 본 사용자:" + no_result: "요약할 결과가 없습니다." + reply_key: "댓글 키" + skipped_reason: "건너뛰기 이유" incoming_emails: - from_address: "보내는사람" - to_addresses: "받는사람" + from_address: "보내는 사람" + to_addresses: "받는 사람" cc_addresses: "참조" subject: "제목" error: "에러" - none: "수신된 이메일이 없습니다." + none: "수신 이메일이 없습니다." modal: - title: "수신 이메일 세부사항" + title: "수신 이메일 상세 정보" error: "에러" headers: "헤더" subject: "제목" @@ -4242,54 +4261,54 @@ ko: user_placeholder: "아이디" address_placeholder: "name@example.com" type_placeholder: "다이제스트, 가입..." - reply_key_placeholder: "답글 키" + reply_key_placeholder: "댓글 키" smtp_transaction_response_placeholder: "SMTP 아이디" moderation_history: - performed_by: "수행자" - no_results: "사용 가능한 운영 기록이 없습니다." + performed_by: "수행자:" + no_results: "사용 가능한 관리 히스토리가 없습니다." actions: delete_user: "사용자 삭제됨" - suspend_user: "일시 중지 된 사용자" - silence_user: "쓰기 금지" - delete_post: "게시물 삭제" - delete_topic: "주제가 삭제되었습니다." - post_approved: "게시물 승인" + suspend_user: "사용자 정지됨" + silence_user: "사용자 차단됨" + delete_post: "게시물 삭제됨" + delete_topic: "주제 삭제됨" + post_approved: "게시물 승인됨" logs: title: "로그" - action: "허용여부" - created_at: "생성된" - last_match_at: "마지막 방문" - match_count: "방문" + action: "작업" + created_at: "생성일" + last_match_at: "마지막 일치" + match_count: "일치" ip_address: "IP" - topic_id: "토픽 ID" - post_id: "글 ID" + topic_id: "주제 ID" + post_id: "게시물 ID" category_id: "카테고리 ID" delete: "삭제" edit: "편집" save: "저장" screened_actions: - block: "블락" - do_nothing: "아무것도 하지 않음" + block: "차단" + do_nothing: "아무것도 안 함" staff_actions: - all: "전체" + all: "모두" filter: "필터:" - title: "스태프 기록" - clear_filters: "전체 보기" + title: "운영진 작업" + clear_filters: "전체 표시" staff_user: "사용자" - target_user: "타겟 사용자" + target_user: "대상 사용자" subject: "제목" - when: "언제" + when: "시기" context: "상황" - details: "상세" - previous_value: "이전값" - new_value: "새값" - show: "보기" - modal_title: "상세" + details: "상세 정보" + previous_value: "이전" + new_value: "신규" + show: "표시" + modal_title: "상세 정보" no_previous: "이전 값이 없습니다." - deleted: "새로운 값이 없습니다. 기록이 삭제되었습니다." + deleted: "새 값이 없습니다. 기록이 삭제되었습니다." actions: delete_user: "회원 삭제" - change_trust_level: "회원등급 변경" + change_trust_level: "신뢰 레벨 변경" change_username: "아이디 변경" change_site_setting: "사이트 설정 변경" change_theme: "테마 변경하기" @@ -4297,109 +4316,109 @@ ko: change_site_text: "site text 변경" suspend_user: "suspend user" unsuspend_user: "unsuspend user" - removed_suspend_user: "사용자 일시 중지 (삭제)" - removed_unsuspend_user: "일시 중지되지 않은 사용자 (제거됨)" + removed_suspend_user: "사용자 정지(제거됨)" + removed_unsuspend_user: "사용자 정지 해제(제거됨)" grant_badge: "배지 부여" revoke_badge: "배지 회수" check_email: "이메일 확인" - delete_topic: "글 삭제" + delete_topic: "주제 삭제" recover_topic: "주제 삭제 취소" - delete_post: "글 삭제" - impersonate: "대역" + delete_post: "게시물 삭제" + impersonate: "가장" anonymize_user: "anonymize user" roll_up: "roll up IP blocks" change_category_settings: "카테고리 설정 변경" - delete_category: "카테고리 지우기" - create_category: "카테고리 만들기" - silence_user: "쓰기 금지 사용자" - unsilence_user: "쓰기 금지 사용자" - removed_silence_user: "사용자 쓰기 금지 (제거됨)" - removed_unsilence_user: "쓰기 금지 해제 사용자 (제거됨)" - grant_admin: "관리자권한 부여" - revoke_admin: "관리자권한 회수" - grant_moderation: "운영자권한 부여" - revoke_moderation: "운영자권한 회수" + delete_category: "카테고리 삭제" + create_category: "카테고리 생성" + silence_user: "사용자 차단" + unsilence_user: "사용자 차단 해제" + removed_silence_user: "사용자 차단(제거됨)" + removed_unsilence_user: "사용자 차단 해제(제거됨)" + grant_admin: "관리자 권한 부여" + revoke_admin: "관리자 권한 취소" + grant_moderation: "관리 권한 부여" + revoke_moderation: "운영자 권한 취소" backup_create: "백업 생성" - deleted_tag: "태그 삭제하기" - deleted_unused_tags: "미사용 태그 삭제" - renamed_tag: "태그명 변경" - revoke_email: "이메일 회수" - lock_trust_level: "회원등급 고정" - unlock_trust_level: "회원등급 고정 해제" + deleted_tag: "태그 삭제됨" + deleted_unused_tags: "사용하지 않은 태그 삭제됨" + renamed_tag: "태그 이름 변경" + revoke_email: "이메일 취소" + lock_trust_level: "신뢰 레벨 잠금" + unlock_trust_level: "신뢰 레벨 잠금 해제" activate_user: "사용자 활성화" deactivate_user: "사용자 비활성화" - change_readonly_mode: "읽기 전용 모드 변경하기" + change_readonly_mode: "읽기 전용 모드 변경" backup_download: "백업 다운로드" - backup_destroy: "백업 삭제하기" - reviewed_post: "검토된 글" - custom_staff: "플러그인 커스텀 액션" + backup_destroy: "백업 제거" + reviewed_post: "검토한 게시물" + custom_staff: "플러그인 사용자 지정 작업" post_locked: "게시물 잠김" - post_edit: "편집 후" - post_unlocked: "게시물 잠금 해제" + post_edit: "게시물 편집" + post_unlocked: "게시물 잠금 해제됨" check_personal_message: "개인 메시지 확인" disabled_second_factor: "2단계 인증 비활성화" - topic_published: "주제가 출판 됨" - post_approved: "게시물 승인됨" + topic_published: "주제 게시됨" + post_approved: "승인된 게시물" post_rejected: "게시물 거부됨" - create_badge: "배지 만들기" + create_badge: "배지 생성" change_badge: "배지 변경" delete_badge: "배지 삭제" merge_user: "사용자 병합" - entity_export: "수출 실체" + entity_export: "엔티티 익스포트" change_name: "이름 변경" - topic_timestamps_changed: "주제 타임 스탬프가 변경됨" - approve_user: "승인 된 사용자" - web_hook_create: "웹훅 만들기" - web_hook_update: "웹 후크 업데이트" - web_hook_destroy: "웹훅 파괴" - web_hook_deactivate: "웹 후크 비활성화" + topic_timestamps_changed: "주제 타임스탬프 변경됨" + approve_user: "승인된 사용자" + web_hook_create: "Webhook 생성" + web_hook_update: "Webhook 업데이트" + web_hook_destroy: "Webhook 제거" + web_hook_deactivate: "Webhook 비활성화" embeddable_host_create: "임베디드 호스트 생성" embeddable_host_update: "임베디드 호스트 업데이트" - embeddable_host_destroy: "임베디드 호스트 파괴" + embeddable_host_destroy: "임베디드 호스트 제거" change_theme_setting: "테마 설정 변경" disable_theme_component: "테마 구성 요소 비활성화" - enable_theme_component: "테마 구성 요소 사용" - revoke_title: "제목 취소" - change_title: "제목 변경" + enable_theme_component: "테마 구성 요소 활성화" + revoke_title: "타이틀 취소" + change_title: "타이틀 변경" api_key_create: "API 키 만들기" api_key_update: "API 키 업데이트" - api_key_destroy: "API 키 삭제" - override_upload_secure_status: "업로드 보안 상태 무시" - page_published: "게시 된 페이지" - page_unpublished: "미공개 페이지" + api_key_destroy: "API 키 제거" + override_upload_secure_status: "업로드 보안 상태 오버라이드" + page_published: "게시된 페이지" + page_unpublished: "게시 취소된 페이지" add_email: "이메일 추가" update_email: "이메일 업데이트" - destroy_email: "이메일 삭제" - topic_closed: "글 닫힘" - topic_opened: "글 열림" - topic_archived: "아카이브된 글" - topic_unarchived: "아카이브 취소된 글" - post_staff_note_create: "관리자 메모 추가" - post_staff_note_destroy: "관리자 메모 삭제" + destroy_email: "이메일 제거" + topic_closed: "주제 종료됨" + topic_opened: "주제 열림" + topic_archived: "주제 보관됨" + topic_unarchived: "주제 보관 취소됨" + post_staff_note_create: "운영진 메모 추가" + post_staff_note_destroy: "관리자 메모 제거" delete_group: "그룹 삭제" watched_word_create: "검열 단어 추가" watched_word_destroy: "검열 단어 삭제" screened_emails: - title: "블락된 이메일들" - description: "누군가가 새로운 계정을 만들면 아래 이메일 주소는 체크되고 등록은 블락됩니다, 또는 다른 조치가 취해집니다." + title: "스크린된 이메일" + description: "누군가가 새 계정을 만들면 다음 이메일 주소를 확인하고 등록이 차단됩니다. 또는 다른 조치가 취해집니다." email: "이메일 주소" actions: allow: "허용" screened_urls: - title: "노출된 URL들" - description: "이 목록은 사용자에 의해 스팸으로 알려진 URL 목록입니다." + title: "스크린된 URL" + description: "이 URL 목록은 스팸 사용자로 알려진 사용자의 게시물에서 사용되었습니다." url: "URL" domain: "도메인" screened_ips: - title: "노출된 IP들" - description: '감시 중인 IP 주소입니다. IP 주소를 허용하려면 "허용"을 사용하십시오.' - delete_confirm: "%{ip_address}를 규칙에 의해 삭제할까요?" + title: "스크린된 IP" + description: '감시 중인 IP 주소입니다. IP 주소를 허용하려면 ''허용''을 사용하세요.' + delete_confirm: "%{ip_address} 규칙을 제거할까요?" actions: - block: "블락" + block: "차단" do_nothing: "허용" allow_admin: "관리자 허용하기" form: - label: "새 IP:" + label: "신규:" ip_address: "IP 주소" add: "추가" filter: "검색" @@ -4415,320 +4434,321 @@ ko: all_search_types: "모든 유형 검색" header: "헤더" full_page: "전체 페이지" - click_through_only: "모두 (클릭만)" - header_search_results: "검색 결과 헤더" + click_through_only: "모두(클릭만)" + header_search_results: "헤더 검색 결과" logster: - title: "에러 로그" + title: "오류 로그" watched_words: - title: "검열 단어" + title: "감시 단어" search: "검색" clear_filter: "지우기" show_words: - other: "%{count}개 단어 보기" + other: "%{count}개 단어 표시" case_sensitive: "(대소문자 구분)" download: 다운로드 clear_all: 모두 지우기 - clear_all_confirm: "%{action} 작업에 대한 모든 관심 단어를 지우시겠습니까?" - invalid_regex: '검열 단어 "%{word}"은 잘못된 정규식입니다.' - regex_warning: '검열 단어는 정규식 이며 단어 경계를 자동으로 포함하지 않습니다. 정규식이 전체 단어와 일치하도록하려면 정규식의 시작과 끝에 \b를 사용하세요.' + clear_all_confirm: "%{action} 작업에 대한 모든 감시 단어를 지울까요?" + invalid_regex: '''%{word}'' 감시 단어는 유효하지 않은 정규식입니다.' + regex_warning: '감시 단어는 정규식이며 단어 경계를 자동으로 포함하지 않습니다. 정규식을 단어 전체와 일치하도록 하려면 정규식의 시작과 끝에 \b를 포함하세요.' actions: block: "차단" - censor: "가리기" + censor: "검열" require_approval: "승인 필요" flag: "신고" - replace: "바꾸기" + replace: "대체" tag: "태그" - silence: "쓰기 금지" + silence: "차단" link: "링크" action_descriptions: - block: "이러한 단어가 포함된 게시물이 작성되지 않도록 합니다. 사용자가 게시물을 작성 완료 하면 오류 메시지가 표시됩니다." - censor: "이 단어가 포함된 게시물을 허용하되, 검열된 단어를 숨김 문자로 대체합니다." - require_approval: "이 단어를 포함한 포스트가 올라가려면 스탭의 허가가 필요합니다." - flag: "이러한 단어가 포함 된 게시물을 허용하지만 관리자가 검토 할 수 있도록 검토 대상 항목으로 표시합니다." - replace: "게시물의 단어를 다른 단어로 바꾸기" - tag: "첫 번째 게시물을 기반으로 글에 자동 태그 지정" - silence: "이러한 단어가 포함 된 사용자의 첫 게시물은 관리자의 승인을 받아야 볼 수 있으며 사용자는 자동으로 글쓰기가 금지됩니다." - link: "게시물의 단어를 링크로 바꾸기" + block: "이 단어가 포함된 게시물이 작성되지 않도록 합니다. 사용자가 게시물을 제출하려고 하면 오류 메시지가 표시됩니다." + censor: "이 단어가 포함된 게시물을 허용하되, 단어를 문자로 대체하여 검열된 단어를 숨깁니다." + require_approval: "이 단어가 포함된 게시물이 표시되려면 운영진의 승인이 필요합니다." + flag: "이 단어가 포함된 게시물을 허용하지만 운영자가 검토할 수 있도록 부적절 항목으로 신고합니다." + replace: "게시물의 단어를 다른 단어로 대체" + tag: "첫 게시물을 기반으로 주제에 자동으로 태그 지정" + silence: "이 단어가 포함된 사용자의 첫 게시물은 운영진의 승인을 받아야 표시될 수 있으며 해당 사용자는 자동으로 차단됩니다." + link: "게시물의 단어를 링크로 대체" form: - label: "단어 또는 구문" - placeholder: "단어 또는 구 입력 (*는 와일드카드)" - placeholder_regexp: "정규표현식" - replace_label: "교체" - replace_placeholder: "예" + label: "단어 또는 구문 포함" + placeholder: "단어 또는 구문 입력(*는 와일드카드)" + placeholder_regexp: "정규식" + replace_label: "대체" + replace_placeholder: "예시" tag_label: "태그" link_label: "링크" link_placeholder: "https://example.com" add: "추가" success: "성공" - exists: "이미 존재 함" + exists: "이미 존재함" upload: "파일에서 추가" - upload_successful: "성공적으로 업로드되었습니다. 단어가 추가되었습니다." + upload_successful: "업로드되었습니다. 단어가 추가되었습니다." case_sensitivity_label: "대소문자를 구분합니다" case_sensitivity_description: "대/소문자가 일치하는 단어만" test: button_label: "테스트" modal_title: "%{action}: 검열 단어 테스트" - description: "시청 한 단어와 일치하는지 확인하려면 아래에 텍스트를 입력하십시오" - found_matches: "일치하는 결과 :" - no_matches: "일치하는 결과가 없습니다" + description: "감시 단어와 일치하는지 확인하려면 아래에 텍스트를 입력하세요" + found_matches: "일치 결과:" + no_matches: "일치하는 항목이 없음" impersonate: - title: "이 사용자 행세하기" - help: "디버깅 목적으로 사용자 계정으로 로그인 할 수 있습니다. 사용이 끝나면 로그아웃하여야 합니다." - not_found: "해당 사용자를 찾을 수 없습니다." - invalid: "죄송합니다. 관리자만 접근할 수 있습니다." + title: "가장" + help: "이 툴을 사용하면 디버깅을 위해 사용자 계정으로 로그인할 수 있습니다. 사용이 끝나면 로그아웃해야 합니다." + not_found: "이 사용자를 찾을 수 없습니다." + invalid: "이 사용자를 가장할 수 없습니다." users: title: "사용자" create: "관리자 사용자 추가" - last_emailed: "마지막 이메일" - not_found: "죄송합니다, 그 이름은 시스템에 존재하지 않습니다." - id_not_found: "죄송합니다. 해당 사용자가 시스템에 없습니다." + last_emailed: "마지막으로 이메일 보냄" + not_found: "이 아이디는 시스템에 없습니다." + id_not_found: "이 사용자 아이디는 시스템에 없습니다." active: "활성화됨" - show_emails: "이메일 보기" + show_emails: "이메일 표시" hide_emails: "이메일 숨기기" nav: - new: "새로운 사용자" - active: "활성화 사용자" - staff: "스태프" - suspended: "차단됨" - silenced: "쓰기 금지" - staged: "격리됨" - approved: "승인?" + new: "신규" + active: "활성" + staff: "운영진" + suspended: "정지됨" + silenced: "차단됨" + staged: "스테이징됨" + approved: "승인되었나요?" titles: - active: "활동적인 회원" - new: "신규회원" - pending: "검토 대기중인 회원" - newuser: "0등급 회원 (신규가입 회원)" - basic: "1등급 회원 (초보 회원)" - member: "2등급 회원 (부회원)" - regular: "3등급 회원 (정회원)" - leader: "4등급 회원 (리더)" - staff: "스태프" - admins: "관리자" + active: "활성 사용자" + new: "신규 사용자" + pending: "검토 대기 중인 사용자" + newuser: "신뢰 레벨 0 사용자(신규 사용자)" + basic: "신뢰 레벨 1 사용자(기본 사용자)" + member: "신뢰 레벨 2 사용자(회원)" + regular: "신뢰 레벨 3 사용자(정회원)" + leader: "신뢰 레벨 4 사용자(리더)" + staff: "운영진" + admins: "관리자 사용자" moderators: "운영자" - silenced: "무음 사용자" - suspended: "차단된 사용자들" - staged: "단계적 사용자" - not_verified: "확인되지 않은" + silenced: "차단된 사용자" + suspended: "정지된 사용자" + staged: "스테이징된 사용자" + not_verified: "검증 안 됨" check_email: - title: "사용자의 이메일 주소 표시" - text: "보이기" + title: "이 사용자의 이메일 주소 표시" + text: "표시" check_sso: title: "SSO 페이로드 표시" - text: "보기" + text: "표시" user: - suspend_failed: "이 사용자를 차단 하는중 오류 발생 %{error}" - unsuspend_failed: "이 사용자를 접근 허용 하는데 오류 발생 %{error}" - suspend_duration: "사용자의 계정을 언제까지 차단 하시겠습니까?" + suspend_failed: "이 사용자를 정지하는 중에 오류 발생 %{error}" + unsuspend_failed: "이 사용자를 정지 해제하는 중에 오류 발생 %{error}" + suspend_duration: "이 사용자를 언제까지 정지할까요?" suspend_reason_label: "Why are you suspending? This text will be visible to everyone on this user's profile page, and will be shown to the user when they try to log in. Keep it short." - suspend_reason_hidden_label: "이 사용자를 일시정지하는 사유는 무엇인가요? 이 텍스트는 해당 사용자가 로그인할 때 보이게 됩니다. 짧게 적어주세요." + suspend_reason_hidden_label: "정지 이유는 무엇인가요? 이 텍스트는 해당 사용자가 로그인할 때 보입니다. 짧게 적어주세요." suspend_reason: "Reason" suspend_reason_title: "정지 이유" suspend_reasons: - not_listening_to_staff: "관리자의 조치를 따르지 않음" - consuming_staff_time: "스태프의 불균형 한 시간 사용" + not_listening_to_staff: "운영진의 피드백을 따르지 않음" + consuming_staff_time: "운영진의 시간을 과도하게 빼앗음" combative: "분란 조장" - in_wrong_place: "잘못된 곳에서" - no_constructive_purpose: "반대나 분란 조장의 목적 이외에는 다른 긍정적인 목적이 없습니다." + in_wrong_place: "이곳과 맞지 않음" + no_constructive_purpose: "커뮤니티 내에서 반대하는 것 외에는 건설적인 목적이 없음" custom: "사용자 지정..." - suspend_message: "이메일 메시지" - suspend_message_placeholder: "필요한 경우, 사용자에게 이메일을 통하여 일시정지에 대한 더 많은 정보를 제공할 수 있습니다." - suspended_by: "차단 처리자" + suspend_message: "메시지 이메일 전송" + suspend_message_placeholder: "(선택사항) 사용자에게 이메일을 보내 정지와 관련한 자세한 정보를 제공합니다." + suspended_by: "정지자:" silence_reason: "사유" - silenced_by: "사일런트" - silence_modal_title: "무음 사용자" - silence_duration: "사용자를 얼마나 오랫동안 쓰기 금지를 하시겠습니까?" - silence_reason_label: "이 사용자가 쓰기 금지된 이유는 무엇입니까?" - silence_reason_placeholder: "글쓰기 금지된 이유" - silence_message: "이메일 메시지" - silence_message_placeholder: "(기본 메시지를 보내려면 비워 두십시오)" - suspended_until: "(%{until} 까지)" - cant_suspend: "이 사용자는 일시정지할 수 없습니다." - delete_posts_failed: "글을 삭제하는 중 문제가 발생했습니다." - post_edits: "게시물 수정" - view_edits: "수정사항 보기" - penalty_post_actions: "관련 게시물에 대해 무엇을하고 싶습니까?" - penalty_post_delete: "글 삭제" - penalty_post_delete_replies: "게시물 + 답글 삭제" - penalty_post_edit: "글 수정" - penalty_post_none: "아무것도하지 않음" + silenced_by: "차단자:" + silence_modal_title: "사용자 차단" + silence_duration: "이 사용자를 언제까지 차단할까요?" + silence_reason_label: "이 사용자를 차단하는 이유가 무엇인가요?" + silence_reason_placeholder: "차단 이유" + silence_message: "메시지 이메일 전송" + silence_message_placeholder: "(디폴트 메시지를 보내려면 비워 두세요)" + suspended_until: "(%{until}까지)" + cant_suspend: "이 사용자는 정지할 수 없습니다." + delete_posts_failed: "게시물을 삭제하는 중에 문제가 발생했습니다." + post_edits: "게시물 편집" + view_edits: "편집 내용 보기" + penalty_post_actions: "관련 게시물에 어떤 작업을 하고 싶나요?" + penalty_post_delete: "게시물 삭제" + penalty_post_delete_replies: "게시물 + 모든 댓글 삭제" + penalty_post_edit: "게시물 편집" + penalty_post_none: "아무것도 안 함" penalty_count: "페널티 수" - penalty_history: "페널티 기록" + penalty_history: "페널티 히스토리" clear_penalty_history: - title: "명확한 페널티 기록" - description: "위약금이있는 사용자는 TL3에 도달 할 수 없습니다" - delete_all_posts_confirm_MF: "{POSTS, plural, one {# 댓글} other {# 댓글}} 그리고 {TOPICS, plural, one {# 글} other {# 글}} 을 삭제하려고 합니다. 확실합니까?" - silence: "쓰기 금지" - unsilence: "쓰기 금지 해제" - silenced: "쓰기 금지?" - moderator: "운영자?" - admin: "관리자?" - suspended: "차단되었나요?" - staged: "격리조치?" + title: "페널티 히스토리 지우기" + description: "페널티가 있는 사용자는 신뢰 레벨 3을 받을 수 없음" + delete_all_posts_confirm_MF: "{POSTS, plural, one {#개의 댓글} other {#개의 댓글}} 및 {TOPICS, plural, one {#개의 주제} other {#개의 주제}}를 삭제하려고 합니다. 계속할까요?" + silence: "차단" + unsilence: "차단 해제" + silenced: "차단되었나요?" + moderator: "운영자인가요?" + admin: "관리자인가요?" + suspended: "정지되었나요?" + staged: "스테이징되었나요?" show_admin_profile: "관리자" - show_public_profile: "공개 프로필 보기" - impersonate: "사용자로 로그인하기" - action_logs: "활동 로그" + show_public_profile: "공개 프로필 표시" + impersonate: "가장" + action_logs: "작업 로그" ip_lookup: "IP Lookup" log_out: "로그아웃" - logged_out: "사용자가 모든 디바이스에서 로그아웃 되었습니다." - revoke_admin: "관리자 권한 회수" + logged_out: "사용자가 모든 디바이스에서 로그아웃되었습니다." + revoke_admin: "관리자 권한 취소" grant_admin: "관리자 권한 부여" grant_admin_success: "새 관리자가 확인되었습니다." - grant_admin_confirm: "새로운 관리자를 인증하기 위해 메일을 보냈습니다. 메일을 열어서 메일에 적힌 지시에 따라 주세요." - revoke_moderation: "운영자 권한 회수" - grant_moderation: "운영자 권한 부여" - unsuspend: "접근 허용" - suspend: "차단됨" - show_flags_received: "받은 신고 보기" - flags_received_by: "%{username}님에 의해 신고 받음" - flags_received_none: "이 사용자는 신고를 받은것이 없습니다." + grant_admin_confirm: "새 관리자를 인증하기 위해 메일을 보냈습니다. 메일을 열어 지침을 따르세요." + revoke_moderation: "관리 권한 취소" + grant_moderation: "관리 권한 부여" + unsuspend: "정지 해제됨" + suspend: "정지" + show_flags_received: "받은 신고 표시" + flags_received_by: "%{username} 님에 의해 신고 받음" + flags_received_none: "이 사용자는 어떠한 신고도 받지 않았습니다." reputation: 평판 permissions: 권한 activity: 활동 - like_count: 준/받은 '좋아요' + like_count: 좋아요 보냄 / 받음 last_100_days: "지난 100일간" - private_topics_count: 비공개 토픽 - posts_read_count: 읽은 댓글 - post_count: 글 수 - second_factor_enabled: 2단계 인증 사용 - topics_entered: 읽은 글 + private_topics_count: 비공개 주제 + posts_read_count: 읽은 게시물 + post_count: 생성한 게시물 + second_factor_enabled: 2단계 인증 활성화됨 + topics_entered: 읽은 주제 flags_given_count: 작성한 신고 flags_received_count: 받은 신고 warnings_received_count: 받은 경고 warnings_list_warning: | - 중재자로서 이러한 글을 모두 보지 못할 수도 있습니다. 필요한 경우 관리자에게 @moderators 권한을 요청하십시오. - flags_given_received_count: "준/받은 신고" + 운영자로서 이러한 주제를 모두 보지 못할 수도 있습니다. 필요한 경우 관리자에게 메시지에 대한 @운영자 액세스를 요청하세요. + flags_given_received_count: "신고 보냄 / 받음" approve: "승인" approved_by: "승인자" - approve_success: "인증 이메일이 발송되었습니다." - approve_bulk_success: "성공! 모든 선택된 사용자는 인증되었고 통보되었습니다." + approve_success: "사용자가 승인되었으며 활성화 지침이 포함된 이메일이 전송되었습니다." + approve_bulk_success: "성공! 선택된 사용자가 모두 인증되었고 알림이 전송되었습니다." time_read: "읽은 시간" - post_edits_count: "게시물 수정" - anonymize: "익명 사용자" + post_edits_count: "게시물 편집" + anonymize: "사용자 익명화" anonymize_confirm: "Are you SURE you want to anonymize this account? This will change the username and email, and reset all profile information." anonymize_yes: "Yes, anonymize this account" anonymize_failed: "There was a problem anonymizing the account." delete: "사용자 삭제" delete_posts: - button: "모든 글을 삭제합니다" + button: "모든 게시물 삭제" progress: title: "게시물 삭제 진행률" - description: "글 삭제중..." + description: "게시물 삭제 중..." confirmation: - title: "%{username}님의 모든 게시물 삭제" + title: "%{username} 님의 모든 게시물 삭제" description: | -

    정말로 %{post_count}개의 @%{username}님 게시물을 삭제하시겠습니까? +

    @%{username} 님의 게시물 %{post_count}개를 삭제할까요? -

    이것은 취소할 수 없습니다!

    +

    이 작업은 취소할 수 없습니다!

    -

    계속 하려면 다음을 입력하세요: %{text}

    - text: "%{username}님의 게시물 삭제" - delete: "%{username}님의 게시물 삭제" + +

    계속하려면 다음을 입력하세요. %{text}

    + text: "%{username} 님의 게시물 삭제" + delete: "%{username} 님의 게시물 삭제" cancel: "취소" merge: button: "병합" prompt: - title: "전송 및 삭제 @ %{username}" + title: "@%{username} 이전 및 삭제" description: | -

    @%{username}의 콘텐츠에 대한 새 소유자를 선택하세요.

    +

    @%{username} 님의 콘텐츠에 대한 새 소유자를 선택하세요.

    -

    @%{username} 의해 생성 된 모든 게시물, 메시지 및 기타 콘텐츠가 변경 됩니다.

    - target_username_placeholder: "새로운 소유자의 사용자 이름" - transfer_and_delete: "전송 및 삭제 @ %{username}" +

    @%{username} 님이 생성한 모든 주제, 게시물, 메시지 및 기타 콘텐츠가 이전됩니다.

    + target_username_placeholder: "새 소유자의 아이디" + transfer_and_delete: "@%{username} 이전 및 삭제" cancel: "취소" progress: title: "병합 진행률" confirmation: - title: "전송 및 삭제 @ %{username}" + title: "@%{username} 이전 및 삭제" description: | -

    @%{username} 님의 모든 컨텐츠는 @%{targetUsername}님의 계정에 귀속됩니다. 컨텐츠 전송 후 @%{username} 계정은 삭제됩니다.

    +

    @%{username} 님의 모든 컨텐츠는 @%{targetUsername} 님에게 이전 및 귀속됩니다. 콘텐츠 이전 후 @%{username} 님의 계정은 삭제됩니다.

    -

    이것은 취소 할 수 없습니다!

    +

    이 작업은 취소할 수 없습니다!

    -

    계속하려면: %{text}

    - text: "@%{username} 에서 @%{targetUsername} 으로 옮기기" - transfer_and_delete: "전송 및 삭제 @ %{username}" +

    계속하려면 다음을 입력하세요. %{text}

    + text: "@%{username} 님에서 @%{targetUsername} 님으로 이전" + transfer_and_delete: "@%{username} 이전 및 삭제" cancel: "취소" - merging_user: "사용자 병합 중 ..." + merging_user: "사용자 병합 중..." merge_failed: "사용자를 병합하는 중에 오류가 발생했습니다." delete_forbidden_because_staff: "관리자 및 운영자 계정은 삭제할 수 없습니다." - delete_posts_forbidden_because_staff: "관리자와 운영자의 글은 삭제할 수 없습니다." + delete_posts_forbidden_because_staff: "관리자 및 운영자의 게시물은 모두 삭제할 수 없습니다." delete_forbidden: - other: "사용자가 작성한 글이 있으면 사용자를 삭제 할 수 없습니다. 사용자를 삭제 하기 전에 사용자가 작성한 글을 모두 삭제해야 합니다. (%{count}일 이전에 작성한 글은 삭제할 수 없습니다.)" + other: "게시물이 있는 사용자는 삭제할 수 없습니다. 사용자를 삭제하기 전에 게시물을 모두 삭제해야 합니다. (%{count}일 이전에 작성한 글은 삭제할 수 없습니다.)" cant_delete_all_posts: - other: "전체글을 삭제할 수 없습니다. 몇개의 글은 %{count}일 이전에 작성되었습니다. (The delete_user_max_post_age setting.)" + other: "모든 게시물을 삭제할 수 없습니다. 일부 게시물은 %{count}일 이전에 작성되었습니다. (delete_user_max_post_age 설정)" cant_delete_all_too_many_posts: - other: "이 사용자는 %{count}개 이상 글을 작성하였기 때문에 모든 글을 삭제 할 수 없습니다. (delete_all_posts_max 설정참고)" - delete_confirm: "기존 토론에서 컨텐츠를 제거하지 않으려면 사용자를 삭제하지 않고 익명화하는 것이 일반적으로 바람직합니다.

    이 사용자를 삭제 하시겠습니까? 이것은 영구적입니다!" - delete_and_block: "이 이메일과 IP주소를 삭제하고 차단하기" + other: "이 사용자는 %{count}개 이상의 게시물을 보유하고 있기 때문에 모든 게시물을 삭제할 수 없습니다. (delete_all_posts_max)" + delete_confirm_title: "정말로 이 사용자를 삭제하시겠습니까? 이는 영구적입니다!" + delete_and_block: "이 이메일과 IP 주소를 삭제하고 차단" delete_dont_block: "삭제만 하기" - deleting_user: "사용자 삭제중..." + deleting_user: "사용자 삭제 중..." deleted: "사용자가 삭제되었습니다." - delete_failed: "해당 사용자를 삭제하는 동안 오류가 발생했습니다. 모든 글은 사용자를 삭제하기 전에 삭제해야합니다." - send_activation_email: "인증 메일 보내기" - activation_email_sent: "인증 메일을 보냈습니다." - send_activation_email_failed: "인증 메일 전송중 오류 %{error}" + delete_failed: "이 사용자를 삭제하는 중에 오류가 발생했습니다. 사용자를 삭제하기 전에 모든 게시물을 삭제해야 합니다." + send_activation_email: "활성화 이메일 전송" + activation_email_sent: "활성화 이메일을 전송했습니다." + send_activation_email_failed: "추가 활성화 이메일 전송 중 문제가 발생했습니다. %{error}" activate: "계정 활성화" - activate_failed: "사용자 활성화에 문제가 있습니다." + activate_failed: "사용자를 활성화하는 중에 문제가 발생했습니다." deactivate_account: "계정 비활성화" - deactivate_failed: "사용자 비활성에 문제가 있습니다." - unsilence_failed: "사용자의 쓰기 금지를 해제하는 중에 문제가 발생했습니다." - silence_failed: "사용자를 쓰기 금지 설정하는중 문제가 발생했습니다." - silence_confirm: "이 사용자를 쓰기 금지 시키시겠습니까? 새 글이나 댓글을 작성할 수 없습니다." - silence_accept: "예, 이 사용자를 쓰기 금지 시킵니다." + deactivate_failed: "사용자를 비활성화하는 중에 문제가 발생했습니다." + unsilence_failed: "사용자를 차단 해제하는 중에 문제가 발생했습니다." + silence_failed: "사용자를 차단하는 중에 문제가 발생했습니다." + silence_confirm: "이 사용자를 차단할까요? 차단하면 새 주제나 게시물을 생성할 수 없게 됩니다." + silence_accept: "예, 이 사용자를 차단합니다" bounce_score: "반송 스코어" reset_bounce_score: label: "리셋" title: "반송 스코어 0으로 리셋" - visit_profile: "사용자 환경설정 페이지로 가서 프로필 수정하기" - deactivate_explanation: "비활성화 사용자는 이메일 인증을 다시 받아야합니다." - suspended_explanation: "일시적으로 차단된 사용자는 로그인 할 수 없습니다." - silence_explanation: "미활동 사용자는 글을 게시하거나 시작할 수 없습니다." - staged_explanation: "격리조치된 회원은 특정 글에 한해서 이메일로만 글을 쓸 수 있습니다." + visit_profile: "이 사용자의 환경설정 페이지로 이동하여 해당 프로필 편집" + deactivate_explanation: "비활성화된 사용자는 이메일 인증을 다시 받아야 합니다." + suspended_explanation: "정지된 사용자는 로그인할 수 없습니다." + silence_explanation: "차단된 사용자는 주제를 게시하거나 시작할 수 없습니다." + staged_explanation: "스테이징된 사용자는 특정 주제에서 이메일로만 게시할 수 있습니다." bounce_score_explanation: - none: "최근 해당 이메일로부터 반송메일을 받은 내역이 없습니다." - some: "최근 해당 이메일로부터 몇몇 반송메일을 받았습니다." - threshold_reached: "해당 이메일로부터 너무 많은 반송메일을 받았습니다." - trust_level_change_failed: "회원등급 변경에 실패했습니다." - suspend_modal_title: "거부된 사용자" - confirm_cancel_penalty: "패널티를 버리시겠습니까?" - trust_level_2_users: "2등급 회원들" - trust_level_3_requirements: "회원등급 3 이상이어야 합니다." - trust_level_locked_tip: "회원등급이 고정되었습니다. 시스템이 회원등급을 올리거나 내리지 않을 것입니다." - trust_level_unlocked_tip: "회원등급 고정이 풀렸습니다. 시스템이 회원등급을 자동적으로 올리거나 내릴 것입니다." - lock_trust_level: "회원등급 고정" - unlock_trust_level: "회원등급 고정 해제" - silenced_count: "쓰기 금지" - suspended_count: "차단됨" + none: "최근 해당 이메일로부터 반송 메일을 받지 않았습니다." + some: "최근 해당 이메일로부터 일부 반송 메일을 받았습니다." + threshold_reached: "해당 이메일로부터 너무 많은 반송 메일을 받았습니다." + trust_level_change_failed: "이 사용자의 신뢰 레벨 변경 중 문제가 발생했습니다." + suspend_modal_title: "사용자 정지" + confirm_cancel_penalty: "패널티를 취소할까요?" + trust_level_2_users: "신뢰 레벨 2 사용자" + trust_level_3_requirements: "신뢰 레벨 3 요구사항" + trust_level_locked_tip: "신뢰 레벨이 잠겼습니다. 시스템에서 사용자의 등급을 변경하지 않습니다" + trust_level_unlocked_tip: "신뢰 레벨이 잠금 해제되었습니다. 시스템에서 사용자의 등급을 변경할 수 있습니다" + lock_trust_level: "신뢰 레벨 잠금" + unlock_trust_level: "신뢰 레벨 잠금 해제" + silenced_count: "차단됨" + suspended_count: "정지됨" last_six_months: "지난 6개월" tl3_requirements: - title: "3등급 회원이 되기 위한 자격" + title: "신뢰 레벨 3의 요구사항" table_title: - other: "최근 %{count} 일 간:" + other: "최근 %{count}일간:" value_heading: "값" - requirement_heading: "자격요건" - visits: "방문횟수" + requirement_heading: "요구사항" + visits: "방문 횟수" days: "일" - topics_replied_to: "댓글을 단 토픽 수" - topics_viewed: "열어본 토픽 수" - topics_viewed_all_time: "열어본 토픽 수 (전체 기간)" - posts_read: "읽은 댓글" - posts_read_all_time: "글 읽음 (전체 기간)" - flagged_posts: "신고 된 게시물" - flagged_by_users: "신고한 회원수" - likes_given: "'좋아요' 선물한 횟수" - likes_received: "'좋아요' 받은 횟수" - likes_received_days: "한번이라도 '좋아요' 받아본 날짜횟수" - likes_received_users: "한번이라도 '좋아요' 선물해준 회원수" - suspended: "일시 중지됨 (지난 6 개월)" - silenced: "쓰기 금지 (지난 6개월)" - qualifies: "3등급회원 자격을 만족합니다" - does_not_qualify: "3등급회원 자격을 만족하지 않습니다" - will_be_promoted: "곧 승급 됩니다." + topics_replied_to: "댓글을 단 주제" + topics_viewed: "읽은 주제" + topics_viewed_all_time: "읽은 주제(전체 기간)" + posts_read: "읽은 게시물" + posts_read_all_time: "읽은 게시물(전체 기간)" + flagged_posts: "신고된 게시물" + flagged_by_users: "신고한 사용자" + likes_given: "좋아요 보냄" + likes_received: "좋아요 받음" + likes_received_days: "좋아요 받음: 고유 일 수" + likes_received_users: "좋아요 받음: 고유 사용자 수" + suspended: "정지됨(지난 6개월)" + silenced: "차단됨(지난 6개월)" + qualifies: "신뢰 레벨 3 자격을 만족합니다." + does_not_qualify: "신뢰 레벨 3 자격을 만족하지 않습니다." + will_be_promoted: "곧 승급됩니다." will_be_demoted: "곧 강등됩니다." on_grace_period: "현재 승급 유예 기간이므로 강등되지 않습니다." - locked_will_not_be_promoted: "회원등급이 고정되었습니다. 승급되지 않을 것입니다." - locked_will_not_be_demoted: "회원등급이 고정되었습니다. 강등되지 않을 것입니다." + locked_will_not_be_promoted: "신뢰 레벨이 잠겼습니다. 승급되지 않습니다." + locked_will_not_be_demoted: "신뢰 레벨이 잠겼습니다. 강등되지 않습니다." discourse_connect: title: "DiscourseConnect 단일 사인온" external_id: "외부 ID" @@ -4737,72 +4757,71 @@ ko: external_email: "이메일" external_avatar_url: "프로필 사진 URL" last_payload: "마지막 페이로드" - delete_sso_record: "SSO 레코드 삭제" - confirm_delete: "이 DiscourseConnect 레코드를 삭제 하시겠습니까?" + delete_sso_record: "SSO 기록 삭제" + confirm_delete: "이 DiscourseConnect 기록을 삭제할까요?" user_fields: title: "사용자 필드" - help: "사용자가 입력할 수 있는 필드를 추가" - create: "사용자 필드 생성하기" + help: "사용자가 입력할 수 있는 필드를 추가합니다." + create: "사용자 필드 생성" untitled: "무제" - name: "필드명" - type: "필드 속성" + name: "필드 이름" + type: "필드 유형" description: "필드 설명" save: "저장" edit: "편집" delete: "삭제" cancel: "취소" - delete_confirm: "사용자 필드를 삭제할까요?" + delete_confirm: "이 사용자 필드를 삭제할까요?" options: "옵션" required: - title: "회원가입시 필수항목?" + title: "가입 시 필수 항목인가요?" enabled: "필수" disabled: "필수 아님" editable: - title: "가입 후 편집 가능?" + title: "가입 후 편집 가능한가요?" enabled: "편집 가능" disabled: "편집 불가" show_on_profile: - title: "다른 사람이 프로필을 볼수 있게할까요?" + title: "공개 프로필에 표시할까요?" enabled: "프로필에 표시" disabled: "프로필에 표시하지 않기" show_on_user_card: title: "사용자 카드에 표시할까요?" - enabled: "사용자 카드에 표시하기" + enabled: "사용자 카드에 표시" disabled: "사용자 카드에 표시하지 않기" searchable: title: "검색 가능한가요?" enabled: "검색 가능" - disabled: "검색 할 수 없음" + disabled: "검색 불가" field_types: text: "텍스트 필드" confirm: "확인" dropdown: "드롭다운" multiselect: "다중 선택" site_text: - description: "포럼에 있는 그 어떤 텍스트도 수정이 가능합니다. 아래의 검색기능을 통해 시작하세요." - search: "편집하고 싶은 텍스트를 검색하세요." + description: "포럼에 있는 모든 텍스트를 사용자 지정할 수 있습니다. 아래의 검색 기능을 통해 시작하세요." + search: "편집하고 싶은 텍스트를 검색하세요" title: "텍스트" edit: "편집" - revert: "변경사항 취소" - revert_confirm: "정말로 변경사항을 되돌리시겠습니까?" + revert: "변경사항 되돌리기" + revert_confirm: "변경사항을 되돌릴까요?" go_back: "검색으로 돌아가기" - recommended: "다음의 텍스트를 요구에 맞게 편집하는 것을 권장:" - show_overriden: "Override 된 설정만 보여주기" + recommended: "다음 텍스트를 필요에 맞게 사용자 지정하는 것이 좋습니다." + show_overriden: "오버라이드된 항목만 표시" locale: "언어:" - fallback_locale_warning: "%{fallback}기반 언어를 편집하고 있습니다. 인터페이스 언어로 %{fallback}을 선택한 사용자는 변경 사항을 볼 수 없습니다." - more_than_50_results: "50개 이상의 결과가 있습니다. 검색 범위를 좁히십시오." + more_than_50_results: "50개 이상의 결과가 있습니다. 검색 범위를 좁혀보세요." settings: - show_overriden: "변경된 것들만 보기" - history: "변경 내역 보기" - reset: "초기화" + show_overriden: "오버라이드된 항목만 표시" + history: "변경 히스토리 보기" + reset: "리셋" none: "없음" site_settings: emoji_list: - invalid_input: "이모티콘 목록에는 유효한 이모티콘명만 포함되어야 합니다. 예: hugs" + invalid_input: "이모티콘 목록에는 유효한 이모티콘 이름만 포함되어야 합니다(예: 포옹)." add_emoji_button: label: "이모티콘 추가" title: "사이트 설정" - no_results: "검색된 결과가 없습니다." + no_results: "검색 결과가 없습니다." more_than_30_results: "30개 이상의 결과가 있습니다. 검색 범위를 좁히거나 카테고리를 선택하세요." clear_filter: "Clear" add_url: "URL 추가" @@ -4810,7 +4829,7 @@ ko: add_group: "그룹 추가" uploaded_image_list: label: "목록 수정" - empty: "아직 이미지가 없습니다. 업로드 해주세요." + empty: "아직 사진이 없습니다. 업로드하세요." upload: label: "업로드" title: "이미지 업로드" @@ -4820,42 +4839,42 @@ ko: all_results: "전체" required: "필수" branding: "브랜딩" - basic: "기본 설정" + basic: "기본 구성" users: "회원" - posting: "글" + posting: "게시" email: "이메일" files: "파일" - trust: "회원등급" + trust: "신뢰 레벨" security: "보안" onebox: "Onebox" - seo: "검색엔진최적화(SEO)" + seo: "검색 엔진 최적화(SEO)" spam: "스팸" - rate_limits: "제한" + rate_limits: "비율 제한" developer: "개발자" embedding: "Embedding" - legal: "법률조항" + legal: "법률" api: "API" user_api: "사용자 API" - uncategorized: "카테고리 없음" + uncategorized: "기타" backups: "백업" login: "로그인" plugins: "플러그인" - user_preferences: "회원 환경설정" + user_preferences: "사용자 환경설정" tags: "태그" search: "검색" groups: "그룹" dashboard: "대시보드" secret_list: - invalid_input: "입력 필드는 비어 있거나 수직 막대 문자를 포함 할 수 없습니다." + invalid_input: "입력 필드는 비워 두거나 수직 막대 문자를 포함할 수 없습니다." default_categories: - modal_description: "이 변경 사항을 역사적으로 적용 하시겠습니까? 기존 사용자 %{count}의 환경 설정이 변경됩니다." + modal_description: "이 변경사항을 기존 항목에도 일괄 적용할까요? 기존 사용자 %{count}명의 환경설정이 변경됩니다." modal_yes: "네" - modal_no: "아니요, 앞으로 만 변경 사항을 적용하십시오." + modal_no: "아니요, 지금부터 적용합니다" simple_list: add_item: "항목 추가..." json_schema: - edit: 편집기 실행 - modal_title: "%{name} 수정" + edit: 에디터 실행 + modal_title: "%{name} 편집" badges: title: 배지 new_badge: 새 배지 @@ -4868,59 +4887,59 @@ ko: badge_type: 배지 종류 badge_grouping: 그룹 badge_groupings: - modal_title: 배지 그룹으로 나누기 + modal_title: 배지 그룹화 granted_by: 배지 부여자 - granted_at: 배지 수여일 - reason_help: (토픽이나 포스트로 가는 링크) + granted_at: 배지 부여일 + reason_help: (주제 또는 게시물 링크) save: 저장 delete: 삭제 - delete_confirm: 정말로 이 배지를 삭제할까요? + delete_confirm: 이 배지를 삭제할까요? revoke: 회수 reason: 이유 - expand: 확장 … - revoke_confirm: 정말로 이 배지를 회수할까요? + expand: 펼치기… + revoke_confirm: 이 배지를 회수할까요? edit_badges: 배지 수정 grant_badge: 배지 부여 granted_badges: 부여된 배지 grant: 부여 - no_user_badges: "%{name}님은 배지가 없습니다." - no_badges: 받을 수 있는 배지가 없습니다. + no_user_badges: "%{name} 님은 배지가 없습니다." + no_badges: 부여할 배지가 없습니다. none_selected: "시작하려면 배지를 선택하세요" - allow_title: 배지를 칭호로 사용 가능하도록 허용 - multiple_grant: 중복 부여할 수 있도록 허용 - listable: 공개 배지 페이지에 표시되는 배지입니다. + allow_title: 배지를 타이틀로 사용하도록 허용 + multiple_grant: 중복 부여 가능 + listable: 공개 배지 페이지에 표시 enabled: 배지 기능 사용 icon: 아이콘 image: 이미지 graphic: 그래픽 - icon_help: "Font Awesome 아이콘 이름을 입력하십시오 (일반 아이콘에는 접두사 'far-', 브랜드 아이콘에는 'fab-'사용)" - image_help: "둘 다 설정된 경우 이미지 업로드가 아이콘 필드를 덮어씁니다." + icon_help: "Font Awesome 아이콘 이름을 입력하세요(일반 아이콘에는 접두사 'far-', 브랜드 아이콘에는 'fab-' 사용)" + image_help: "둘 다 설정된 경우 이미지 업로드가 아이콘 필드를 오버라이드합니다." select_an_icon: "아이콘 선택" upload_an_image: "이미지 업로드" - read_only_setting_help: "사용자 정의 텍스트" + read_only_setting_help: "사용자 지정 텍스트" query: 배지 쿼리(SQL) - target_posts: 글들을 대상으로 하는 쿼리 - auto_revoke: 회수 쿼리를 매일 실행 - show_posts: 배지 페이지에서 배지를 받게한 글을 보여줍니다. + target_posts: 게시물 대상 쿼리 + auto_revoke: 회수 쿼리 매일 실행 + show_posts: 배지 페이지에 배지 부여 게시물 표시 trigger: Trigger trigger_type: none: "매일 업데이트" - post_action: "회원이 글에 액션을 할 때" - post_revision: "회원이 새글을 쓰거나 글을 수정할 때" - trust_level_change: "회원등급이 바뀔 때" - user_change: "회원이 생성되거나 수정될 때" + post_action: "사용자가 게시물에 작업할 때" + post_revision: "사용자가 게시물을 편집 또는 생성할 때" + trust_level_change: "사용자가 신뢰 레벨을 변경할 때" + user_change: "사용자가 편집 또는 생성될 때" preview: - link_text: "수여된 배지 미리보기" - plan_text: "쿼리 플랜 미리보기" + link_text: "부여된 배지 미리보기" + plan_text: "쿼리 플랜과 함께 미리보기" modal_title: "배지 쿼리 미리보기" - sql_error_header: "질의 중 오류가 발생했습니다" + sql_error_header: "쿼리 중에 오류가 발생했습니다." error_help: "배지 쿼리 도움말을 보려면 다음 링크를 확인하세요." bad_count_warning: - header: "주의!" - text: "사라진 배지 샘플이 있습니다. 배지 query가 존재하지 않는 user ID나 post ID를 반환할 경우 발생합니다. 예상하지 못한 결과를 일으킬 수 있으니 query를 다시 한번 확인하세요." - no_grant_count: "할당된 배지가 없습니다." + header: "경고!" + text: "누락된 부여 샘플이 있습니다. 배지 쿼리가 존재하지 않는 사용자 ID나 게시물 ID를 반환할 경우 발생합니다. 나중에 예상하지 못한 결과를 일으킬 수 있으므로 쿼리를 다시 한번 확인하세요." + no_grant_count: "할당할 배지가 없습니다." grant_count: - other: "%{count}개의 배지가 할당됨." + other: "할당할 배지가 %{count}개 있습니다." sample: "샘플:" grant: with: %{username} @@ -4928,24 +4947,24 @@ ko: with_post_time: %{username} for post in %{link} at %{time} with_time: %{username} at %{time} badge_intro: - title: "시작하려면 기존 배지를 선택하거나 새 배지를 만드십시오" - emoji: "여자 학생 이모티콘" - what_are_badges_title: "배지란 무엇입니까?" - badge_query_examples_title: "배지 쿼리 예제" + title: "시작하려면 기존 배지를 선택하거나 새 배지를 생성하세요" + emoji: "여학생 이모티콘" + what_are_badges_title: "배지가 무엇인가요?" + badge_query_examples_title: "배지 쿼리 예시" mass_award: - title: 일괄 처리 - description: 한 번에 많은 사용자에게 동일한 배지를 수여하십시오. - no_badge_selected: 시작하려면 배지를 선택하십시오. - perform: "사용자에게 보너스 배지" - upload_csv: 사용자 이메일 또는 사용자 이름으로 CSV 업로드 - aborted: 사용자 이메일 또는 사용자 이름이 포함 된 CSV를 업로드하십시오 - success: CSV가 등록 되었으며 %{count}명의 사용자가 곧 배지를 받게 됩니다. - csv_has_unmatched_users: "다음 항목은 CSV 파일에 있지만 기존 사용자와 일치하지 않아 배지를 받지 못합니다." - replace_owners: 이전 소유자에서 배지를 제거합니다 + title: 일괄 수여 + description: 한 번에 많은 사용자에게 동일한 배지를 수여하세요. + no_badge_selected: 시작하려면 배지를 선택하세요. + perform: "사용자에게 배지 수여" + upload_csv: 사용자 이메일 또는 아이디 포함 CSV 업로드 + aborted: 사용자 이메일 또는 아이디가 포함된 CSV를 업로드하세요 + success: CSV가 업로드되었으며 %{count}명의 사용자가 곧 배지를 받게 됩니다. + csv_has_unmatched_users: "다음 엔트리는 CSV 파일에 있지만 기존 사용자와 일치하지 않아 배지를 받지 못합니다." + replace_owners: 이전 소유자에게서 배지 제거 grant_existing_holders: 기존 배지 소지자에게 추가 배지 부여 emoji: title: "이모티콘" - help: "모든 사람이 사용할 수 있는 새 그림 이모티콘을 추가하세요.이름을 입력하지 않고 여러 파일을 한 번에 드래그 앤 드롭하여 파일 이름으로 이모티콘을 만들 수 있습니다.선택한 그룹은 동시에 추가되는 모든 파일에 사용됩니다. '새 이모티콘 추가'를 클릭하여 파일 선택기를 열 수도 있습니다." + help: "모든 사람이 사용할 수 있는 새 이모티콘을 추가하세요. 파일명으로 이모티콘을 만들려면 이름을 입력하지 않고 여러 파일을 한 번에 드래그 앤 드롭하세요. 선택한 그룹은 동시에 추가되는 모든 파일에 사용됩니다. '새 이모티콘 추가'를 클릭하여 파일 선택기를 열 수도 있습니다." add: "새 이모티콘 추가" choose_files: "파일 선택" uploading: "업로드 중..." @@ -4953,79 +4972,80 @@ ko: group: "그룹" image: "이미지" alt: "맞춤 이모티콘 미리보기" - delete_confirm: "정말로 :%{name}: 이모티콘을 삭제 하시겠습니까?" + delete_confirm: ":%{name}: 이모티콘을 삭제할까요?" embedding: - get_started: "다른 웹사이트에 Discourse를 임베드하려면 호스트 추가부터 하세요" - confirm_delete: "정말로 host를 삭제할까요?" - title: "삽입(Embedding)" + get_started: "다른 웹사이트에 Discourse를 임베드하려면 먼저 호스트를 추가하세요." + confirm_delete: "호스트를 삭제할까요?" + title: "임베딩" host: "허용 Host" class_name: "클래스 이름" allowed_paths: "경로 허용 목록" edit: "편집" category: "카테고리에 게시" - add_host: "Host 추가" - settings: "삽입(Embedding) 설정" + add_host: "호스트 추가" + settings: "임베딩 설정" crawling_settings: "크롤러 설정" crawling_description: "When Discourse creates topics for your posts, if no RSS/ATOM feed is present it will attempt to parse your content out of your HTML. Sometimes it can be challenging to extract your content, so we provide the ability to specify CSS rules to make extraction easier." - embed_by_username: "토픽을 만들 때 사용할 아이디" - embed_post_limit: "포함할 게시물의 최대 수" - embed_title_scrubber: "게시글의 제목을 긁어오기 위해 정규표현식이 사용되었습니다" - embed_truncate: "임베드된 글 뒷부분 잘라내기" - embed_unlisted: "가져온 주제는 답변이있을 때까지 나열되지 않습니다." - allowed_embed_selectors: "임베드에서 허용되는 요소에 대한 CSS 선택기" - blocked_embed_selectors: "임베드에서 제거 된 요소에 대한 CSS 선택기" + embed_by_username: "주제 생성에 사용할 아이디" + embed_post_limit: "임베드할 최대 게시물 수" + embed_title_scrubber: "게시물의 제목을 스크럽하기 위해 사용된 정규식" + embed_truncate: "임베드된 게시물 자르기" + embed_unlisted: "임포트한 주제는 댓글이 있을 때까지 나열되지 않습니다." + allowed_embed_selectors: "임베드에서 허용한 요소에 대한 CSS 선택기" + blocked_embed_selectors: "임베드에서 제거한 요소에 대한 CSS 선택기" allowed_embed_classnames: "허용되는 CSS 클래스 이름" - save: "삽입(Embedding) 설정 저장하기" + save: "임베딩 설정 저장" permalink: - title: "고유링크" - description: "포럼에서 알려지지 않은 URL에 적용 할 리디렉션" + title: "고정 링크" + description: "포럼에서 알려지지 않은 URL에 적용할 리디렉션" url: "URL" - topic_id: "토픽 ID" - topic_title: "글" + topic_id: "주제 ID" + topic_title: "주제" post_id: "글 ID" post_title: "글" category_id: "카테고리 ID" category_title: "카테고리" - tag_name: "태그명" + tag_name: "태그 이름" external_url: "외부 또는 상대 URL" - destination: "목적지" - copy_to_clipboard: "퍼머링크를 클립보드에 복사" - delete_confirm: 정말로 이 고유 링크를 삭제하시겠습니까? + destination: "대상" + copy_to_clipboard: "고정 링크를 클립보드에 복사" + delete_confirm: 이 고정 링크를 삭제할까요? form: - label: "새로운:" + label: "신규:" add: "추가" - filter: "검색 (URL 혹은 외부 URL)" + filter: "검색(URL 또는 외부 URL)" reseed: action: - label: "글자 바꾸기..." - title: "카테고리 및 토픽의 글자를 번역본으로 대체하십시오" + label: "텍스트 대체..." + title: "카테고리 및 주제의 텍스트를 번역으로 대체합니다" modal: - title: "글자 바꾸기" - subtitle: "시스템 생성 카테고리 및 토픽의 글자를 최신 번역으로 바꿉니다" + title: "텍스트 대체" + subtitle: "시스템 생성 카테고리 및 주제의 텍스트를 최신 번역으로 대체합니다" categories: "카테고리" topics: "글" - replace: "바꾸기" + replace: "대체" wizard_js: wizard: - back: "이전" + finish: "종료" + back: "뒤로 가기" next: "다음" step-text: "단계" - step: "%{total} 중 %{current}" + step: "%{current} / %{total}" upload: "업로드" uploading: "업로드 중..." - upload_error: "죄송합니다. 해당 파일을 업로드하는 중에 오류가 발생했습니다. 다시 시도하십시오." + upload_error: "파일을 업로드하는 중에 오류가 발생했습니다. 다시 시도하세요." staff_count: - other: "커뮤니티에는 당신을 포함한 %{count}명의 스탭이 있습니다." + other: "커뮤니티에 나를 포함한 %{count}명의 운영진이 있습니다." invites: add_user: "추가" - none_added: "관리자에게 초대되지 않았습니다. 계속하시겠습니까?" + none_added: "운영진에게 초대되지 않았습니다. 계속할까요?" roles: admin: "관리자" moderator: "운영자" - regular: "일반 유저" + regular: "정회원" previews: - topic_title: "대화 글 제목" + topic_title: "토론 주제 제목" share_button: "공유" - reply_button: "댓글" - topic_preview: "글 미리보기" + reply_button: "댓글 달기" + topic_preview: "주제 미리보기" homepage_preview: "홈페이지 미리보기" diff --git a/config/locales/client.lt.yml b/config/locales/client.lt.yml index 3dd5d3d4ee..9ce8fe1442 100644 --- a/config/locales/client.lt.yml +++ b/config/locales/client.lt.yml @@ -199,7 +199,6 @@ lt: forwarded: "persiuntė minėtą el. laišką" topic_admin_menu: "temos veiksmai" skip_to_main_content: "Pereiti prie pagrindinio turinio" - wizard_required: "Sveiki, tai jūsų naujasis Discourse! Pradėkime nuoInstliacijos✨" emails_are_disabled: "Visos išeinančios elektroninės žinutės buvo uždraustos administratoriaus. Jokių papildų įspėjamųjų žinučių nebus išsiųsta" emails_are_disabled_non_staff: "Siunčiamas el. laiškas buvo išjungtas ne darbuotojams." software_update_prompt: @@ -211,6 +210,7 @@ lt: many: "Norėdami palengvinti naujos svetainės paleidimą, jūs esate paleidimo režime. Visiems naujiems vartotojams bus suteiktas 1 lygio pasitikėjimas ir bus įgalinti kasdieniniai elektroninio pašto santraukos atnaujinimai. Tai bus automatiškai išjungta, kai pasieksite %{count} vartotojų ribą." other: "Norėdami palengvinti naujos svetainės paleidimą, jūs esate paleidimo režime. Visiems naujiems vartotojams bus suteiktas 1 lygio pasitikėjimas ir bus įgalinti kasdieniniai elektroninio pašto santraukos atnaujinimai. Tai bus automatiškai išjungta, kai pasieksite %{count} vartotojų ribą." bootstrap_mode_disabled: "Paleidimo režimas bus išjungtas per 24 valandas." + bootstrap_invite_button_title: "Siųsti pakvietimą" themes: default_description: "Numatytasis" broken_theme_alert: "Jūsų svetainė gali neveikti, nes temoje / komponente yra klaidų." @@ -244,6 +244,8 @@ lt: not_implemented: "Ši funkcija dar neveikia, atsiprašome!" no_value: "Ne." yes_value: "Taip" + ok_value: "OK" + cancel_value: "Atšaukti" submit: "Pateikti" generic_error: "Atsiprašome, įvyko klaida." generic_error_with_reason: "Įvyko klaida: %{error}" @@ -2194,6 +2196,13 @@ lt: not_logged_in_user: "Vartotojo puslapis su veiksmų ir nustatymų aprašymu" current_user: "eitį i savo vartotojo puslapį" view_all: "peržiūrėti visus %{tab}" + user_menu: + tabs: + replies: "Atsakymai" + mentions: "Paminėjimai" + likes: "Patikimai" + bookmarks: "Žymės" + profile: "Profilis" topics: new_messages_marker: "paskutinis apsilankymas" bulk: @@ -3346,7 +3355,6 @@ lt: google: "„Google“ kalendorius" ics: "ICS" tagging: - all_tags: "Visos žymos" other_tags: "Kitos žymos" selector_all_tags: "visos žymos" selector_no_tags: "nėra žymų" @@ -3475,14 +3483,11 @@ lt: unsupported_file_picked: "Pasirinkote nepalaikomą failą. Palaikomi failų tipai - %{types}." user_activity: no_activity_title: "Dar nėra jokios veiklos" - no_activity_others: "Jokios veiklos." no_replies_title: "Jūs dar neatsakėte į jokias temas" - no_replies_others: "Jokių atsakymų." no_drafts_title: "Nepradėjote jokių juodraščių" no_drafts_body: "Ne visai pasiruošęs paskelbti? Mes automatiškai išsaugosime naują juodraštį ir pateiksime jį čia, kai tik pradėsite rašyti temą, atsakymą ar asmeninę žinutę. Pasirinkite atšaukimo mygtuką, kad atmestumėte juodraštį arba išsaugotumėte, kad galėtumėte tęsti vėliau." no_likes_title: "Jums dar nepatiko jokios temos" no_likes_body: "Puikus būdas prisidėti yra pradėti skaityti jau įvykusius pokalbius ir pasirinkti %{heartIcon} įrašus, kurie jums patinka!" - no_likes_others: "Patinkančių įrašų nėra." no_topics_title: "Dar nepradėjote jokių temų" no_read_topics_title: "Dar neskaitėte jokių temų" no_group_messages_title: "Grupės pranešimų nerasta" @@ -3505,7 +3510,10 @@ lt: many: "%{count} nauja" other: "%{count} nauja" more: "Daugiau..." + all_categories: "Visos kategorijos" sections: + about: + header_link_text: "Apie" messages: header_link_text: "Žinutės" links: @@ -3517,19 +3525,24 @@ lt: unread_with_count: "Neperskaitytas (%{count})" archive: "Archyvuoti" tags: - header_link_title: "visos žymos" header_link_text: "Žymos" categories: - header_link_title: "visos kategorijos" header_link_text: "Kategorijos" community: - header_link_title: "pradinis" header_link_text: "Bendruomenė" header_action_title: "sukurti naują temą" links: + about: + content: "Apie" + admin: + content: "Adminas" + badges: + content: "Trofėjai" everything: content: "Viskas" title: "Visos temos" + faq: + content: "DUK" tracked: content: "Sekami" title: "Visos stebimos temos" @@ -4713,7 +4726,6 @@ lt: recommended: "Mes rekomenduojame pakeisti sekančius tekstus, kad jie atitiktų tavo poreikius:" show_overriden: "Rodyti tik pakeistus" locale: "Kalba:" - fallback_locale_warning: "Jūs redaguojate kalbą pagal %{fallback}. Vartotojai, pasirinkę %{fallback} , nematys jūsų pakeitimų." more_than_50_results: "Yra daugiau nei 50 rezultatų. Prašome patikslinti paiešką." settings: show_overriden: "Rodyti tik pakeistus" diff --git a/config/locales/client.lv.yml b/config/locales/client.lv.yml index 40643f2e5b..95222f93a6 100644 --- a/config/locales/client.lv.yml +++ b/config/locales/client.lv.yml @@ -166,12 +166,12 @@ lv: disabled: "noņēma šo baneri %{when}. Tas vairs neparādīsies katras lapas augšā." forwarded: "pārsūtīja iepriekš minēto e -pastu" topic_admin_menu: "tēmas darbības" - wizard_required: "Laipni lūgti jūsu jaunajā Discourse! Sāksim ar uzstādīšanas palīgu ✨" emails_are_disabled: "Administrators ir globāli izslēdzis visus izejošos e-pastus. Netiks nosūtīti nekāda veida paziņojumi." software_update_prompt: message: "Mēs esam atjauninājuši šo vietni, lūdzu, atjaunojiet to, pretējā gadījumā var rasties kļūdas." dismiss: "Nerādīt" bootstrap_mode_disabled: "Bootstrap režīms tiks atspējots 24 stundu laikā." + bootstrap_invite_button_title: "Nosūtīt ielūgumus" themes: default_description: "Noklusējums" s3: @@ -203,6 +203,8 @@ lv: not_implemented: "Šī funkcionalitāte vēl nav ieviesta, atvainojiet!" no_value: "Nē" yes_value: "Jā" + ok_value: "Labi" + cancel_value: "Atcelt" submit: "Iesniegt" generic_error: "Atvainojiet, ir notikusi kļūda." generic_error_with_reason: "Notikusi kļūda: %{error}" @@ -1911,6 +1913,13 @@ lv: not_logged_in_user: "lietotāja lapa ar pēdējo aktivitāšu un iestatījumu vēsturi" current_user: "doties uz jūsu lietotāja lapu" view_all: "apskatīt visus %{tab}" + user_menu: + tabs: + replies: "Atbildes" + mentions: "Pieminēšanas" + likes: "Patīk" + bookmarks: "Grāmatzīmes" + profile: "Profils" topics: new_messages_marker: "pēdējais apmeklējums" bulk: @@ -2329,11 +2338,6 @@ lv: inappropriate: "Jūs ziņojāt par šo kā nepiedienīgu" notify_moderators: "Jūs ziņojāt par šo moderācijai" notify_user: "Jūs nosūtījāt ziņu šim lietotājam" - merge: - confirm: - zero: "Vai jūs esat drošs, ka vēlaties apvienot šos %{count} ierakstus?" - one: "Vai jūs esat drošs, ka vēlaties apvienot šos ierakstus?" - other: "Vai jūs esat drošs, ka vēlaties apvienot šos %{count} ierakstus?" revisions: controls: first: "Pirmā versija" @@ -2735,7 +2739,6 @@ lv: download_calendar: download: "Lejuplādēt" tagging: - all_tags: "Visi tagi" selector_all_tags: "visi tagi" selector_no_tags: "bez tagiem" changed: "mainītie tagi:" @@ -2813,7 +2816,10 @@ lv: one: "%{count} jauna" other: "%{count} jauna" more: "Vairāk..." + all_categories: "Visas sadaļas" sections: + about: + header_link_text: "Par" messages: header_link_text: "Ziņas" links: @@ -2825,15 +2831,20 @@ lv: unread_with_count: "Nelasīts (%{count})" archive: "Arhīvs" tags: - header_link_title: "visi tagi" header_link_text: "Birkas" categories: - header_link_title: "visas sadaļas" header_link_text: "Sadaļas" community: - header_link_title: "mājas" header_link_text: "Kopiena" links: + about: + content: "Par" + admin: + content: "Administrators" + badges: + content: "Žetoni" + faq: + content: "BUJ" tracked: content: "Sekots" groups: diff --git a/config/locales/client.nb_NO.yml b/config/locales/client.nb_NO.yml index 64564cf213..4a822cb4fe 100644 --- a/config/locales/client.nb_NO.yml +++ b/config/locales/client.nb_NO.yml @@ -160,12 +160,12 @@ nb_NO: forwarded: "videresendte e-posten voer" topic_admin_menu: "handlinger for tråd" skip_to_main_content: "Gå til hovedinnhold" - wizard_required: "Velkommen til ditt nye Discourse! Kom i gang med oppstartsveiviseren ✨" emails_are_disabled: "All utgående e-post har blitt deaktivert globalt av en administrator. Ingen e-postvarslinger vil bli sendt." software_update_prompt: message: "Vi har oppdatert dette nettstedet, Oppdater, eller du kan oppleve uventet oppførsel." dismiss: "Avslå" bootstrap_mode_disabled: "Oppstartsmodus vil bli deaktivert i løpet av 24 timer." + bootstrap_invite_button_title: "Send invitasjoner" themes: default_description: "Forvalg" s3: @@ -197,6 +197,8 @@ nb_NO: not_implemented: "Beklager, den funksjonen er ikke blitt implementert enda." no_value: "Nei" yes_value: "Ja" + ok_value: "OK" + cancel_value: "Avbryt" submit: "Utfør" generic_error: "Beklager, det har oppstått en feil." generic_error_with_reason: "Det oppstod et problem: %{error}" @@ -2143,6 +2145,13 @@ nb_NO: not_logged_in_user: "brukerside med oppsummering av nåværende aktivtet og preferanser." current_user: "gå til din brukerside" view_all: "se alle %{tab}" + user_menu: + tabs: + replies: "Svar" + mentions: "Omtalelser" + likes: "Likes tildelt" + bookmarks: "Bokmerker" + profile: "Profil" topics: new_messages_marker: "siste besøk" bulk: @@ -2733,10 +2742,6 @@ nb_NO: confirm: one: "Er du sikker på at du ønsker å slette dette innlegget?" other: "Er du sikker på at du ønsker å slette de %{count} innleggene?" - merge: - confirm: - one: "Er du sikker på at du vil flette disse postene?" - other: "Er du sikker på at du vil flette de %{count} innleggene?" revisions: controls: first: "Første versjon" @@ -3265,7 +3270,6 @@ nb_NO: download_calendar: download: "Last ned" tagging: - all_tags: "Alle stikkord" other_tags: "Andre stikkord" selector_all_tags: "alle stikkord" selector_no_tags: "ingen stikkord" @@ -3411,10 +3415,6 @@ nb_NO: detailed_name: "%{level}: %{name}" pick_files_button: unsupported_file_picked: "Du har plukket en ustøttet fil. Filtyper som støttes – %{types}." - user_activity: - no_activity_others: "Ingen aktivitet." - no_replies_others: "Ingen svar." - no_likes_others: "Ingen likte innlegg. " fullscreen_table: expand_btn: "Utvid tabell" sidebar: @@ -3425,7 +3425,10 @@ nb_NO: one: "%{count} ny" other: "%{count} nye" more: "Mer…" + all_categories: "Alle kategorier" sections: + about: + header_link_text: "Om" messages: header_link_text: "Meldinger" links: @@ -3437,15 +3440,20 @@ nb_NO: unread_with_count: "Ulest (%{count})" archive: "Arkiver" tags: - header_link_title: "alle stikkord" header_link_text: "Stikkord" categories: - header_link_title: "alle kategorier" header_link_text: "Kategorier" community: - header_link_title: "hjem" header_link_text: "Gemenskap" links: + about: + content: "Om" + admin: + content: "Administrator" + badges: + content: "Merker" + faq: + content: "O-S-S" tracked: content: "Overvåkes" groups: diff --git a/config/locales/client.nl.yml b/config/locales/client.nl.yml index 377520995a..130e176622 100644 --- a/config/locales/client.nl.yml +++ b/config/locales/client.nl.yml @@ -158,7 +158,6 @@ nl: disabled: "heeft deze banner verwijderd op %{when}. De banner zal niet meer bovenaan elke pagina verschijnen." forwarded: "heeft de bovenstaande e-mail doorgestuurd" topic_admin_menu: "topicacties" - wizard_required: "Welkom bij uw nieuwe Discourse! Laten we beginnen met de configuratiewizard ✨" emails_are_disabled: "Alle uitgaande e-mail is uitgeschakeld door een beheerder. Er wordt geen enkele e-mailmelding verstuurd." software_update_prompt: message: "We hebben deze site bijgewerkt, gelieve te vernieuwen, anders kan er onverwacht gedrag optreden." @@ -167,6 +166,7 @@ nl: one: "Om het opzetten van uw nieuwe website makkelijker te maken, bevindt u zich in bootstrapmodus. Aan alle nieuwe gebruikers wordt vertrouwensniveau 1 toegekend, en dagelijkse e-mailsamenvattingen zijn voor hen ingeschakeld. Dit wordt automatisch uitgeschakeld zodra %{count} gebruiker lid is geworden." other: "Om het opzetten van uw nieuwe website makkelijker te maken, bevindt u zich in bootstrapmodus. Aan alle nieuwe gebruikers wordt vertrouwensniveau 1 toegekend, en dagelijkse e-mailsamenvattingen zijn voor hen ingeschakeld. Dit wordt automatisch uitgeschakeld zodra %{count} gebruikers lid zijn geworden." bootstrap_mode_disabled: "De bootstrapmodus wordt binnen 24 uur uitgeschakeld." + bootstrap_invite_button_title: "Uitnodigingen versturen" themes: default_description: "Standaard" s3: @@ -199,6 +199,8 @@ nl: not_implemented: "Deze functie is helaas nog niet beschikbaar, sorry!" no_value: "Nee" yes_value: "Ja" + ok_value: "OK" + cancel_value: "Annuleren" submit: "Versturen" generic_error: "Sorry, er is iets fout gegaan." generic_error_with_reason: "Er is iets fout gegaan: %{error}" @@ -2196,6 +2198,13 @@ nl: not_logged_in_user: "gebruikerspagina met samenvatting van huidige activiteit en voorkeuren" current_user: "naar uw gebruikerspagina" view_all: "Alle %{tab} bekijken" + user_menu: + tabs: + replies: "Antwoorden" + mentions: "Vermeldingen" + likes: "Gegeven likes" + bookmarks: "Bladwijzers" + profile: "Profiel" topics: new_messages_marker: "laatste bezoek" bulk: @@ -2796,10 +2805,6 @@ nl: confirm: one: "Weet u zeker dat u dat bericht wilt verwijderen?" other: "Weet u zeker dat u die %{count} berichten wilt verwijderen?" - merge: - confirm: - one: "Weet u zeker dat u die berichten wilt samenvoegen?" - other: "Weet u zeker dat u die %{count} berichten wilt samenvoegen?" revisions: controls: first: "Eerste revisie" @@ -3330,7 +3335,6 @@ nl: download_calendar: download: "Downloaden" tagging: - all_tags: "Alle tags" other_tags: "Andere tags" selector_all_tags: "alle tags" selector_no_tags: "geen tags" @@ -3484,9 +3488,6 @@ nl: leader: "leider" user_activity: no_activity_title: "Nog geen activiteit" - no_activity_others: "Geen activiteit." - no_replies_others: "Geen antwoorden." - no_likes_others: "Geen gelikete berichten." no_read_topics_body: "Zodra u discussies gaat lezen, ziet u hier een lijst. Om te beginnen met lezen, zoek naar interessante topics onder Top of Categorieën of zoek op trefwoord %{searchIcon}" sidebar: unread_count: @@ -3496,7 +3497,10 @@ nl: one: "%{count} nieuw" other: "%{count} nieuw" more: "Meer..." + all_categories: "Alle categorieën" sections: + about: + header_link_text: "Over" messages: header_link_text: "Berichten" links: @@ -3508,15 +3512,20 @@ nl: unread_with_count: "Ongelezen (%{count})" archive: "Archief" tags: - header_link_title: "alle tags" header_link_text: "Tags" categories: - header_link_title: "alle categorieën" header_link_text: "Categorieën" community: - header_link_title: "hoofdpagina" header_link_text: "Gemeenschap" links: + about: + content: "Over" + admin: + content: "Beheer" + badges: + content: "Badges" + faq: + content: "FAQ" tracked: content: "Gevolgd" groups: @@ -4654,7 +4663,6 @@ nl: cant_delete_all_too_many_posts: one: "Kan niet alle berichten verwijderen, omdat de gebruiker meer dan %{count} bericht heeft geplaatst. (delete_all_posts_max)" other: "Kan niet alle berichten verwijderen, omdat de gebruiker meer dan %{count} berichten heeft geplaatst. (delete_all_posts_max)" - delete_confirm: "Om te voorkomen dat inhoud uit bestaande discussies wordt verwijderd, is het doorgaans beter om gebruikers te anonimiseren dan ze te verwijderen.

    Weet u ZEKER dat u deze gebruiker wilt verwijderen? Dit is blijvend!" delete_and_block: "Dit e-mail- en IP-adres verwijderen en blokkeren" delete_dont_block: "Alleen verwijderen" deleting_user: "Gebruiker verwijderen..." @@ -4783,7 +4791,6 @@ nl: recommended: "We raden aan de volgende tekst naar wens aan te passen:" show_overriden: "Alleen aangepaste tonen" locale: "Taal:" - fallback_locale_warning: "U bent een taal gebaseerd op %{fallback} aan het bewerken. Gebruikers die %{fallback} als taal van hun interface kiezen zien uw wijzigingen niet." more_than_50_results: "Er zijn meer dan 50 resultaten. Verfijn uw zoekopdracht." settings: show_overriden: "Alleen aangepaste tonen" diff --git a/config/locales/client.pl_PL.yml b/config/locales/client.pl_PL.yml index 9f9b1ec4b4..63088c9ec2 100644 --- a/config/locales/client.pl_PL.yml +++ b/config/locales/client.pl_PL.yml @@ -235,7 +235,6 @@ pl_PL: forwarded: "przekazano powyższy email" topic_admin_menu: "akcje tematu" skip_to_main_content: "Przejdź do głównej zawartości" - wizard_required: "Witaj na Twoim na nowym forum Discourse! Zacznijmy od kreatora ustawień ✨" emails_are_disabled: "Wszystkie wychodzące wiadomości e-mail zostały globalnie wyłączone przez administratora. Żadne powiadomienia e-mail nie będą wysyłane." emails_are_disabled_non_staff: "Poczta wychodząca została wyłączona dla użytkowników niebędących pracownikami." software_update_prompt: @@ -247,6 +246,8 @@ pl_PL: many: "Aby ułatwić uruchomienie Twojej strony, jesteś w trybie bootstrap. Wszyscy nowi użytkownicy otrzymają poziom zaufania 1 i będą otrzymywać codzienne wiadomości e-mail z podsumowaniem aktywności na forum. To zostanie automatycznie wyłączone, kiedy %{count} osób dołączy." other: "Aby ułatwić uruchomienie Twojej strony, jesteś w trybie bootstrap. Wszyscy nowi użytkownicy otrzymają poziom zaufania 1 i będą otrzymywać codzienne wiadomości e-mail z podsumowaniem aktywności na forum. To zostanie automatycznie wyłączone, kiedy %{count} osób dołączy." bootstrap_mode_disabled: "Tryb bootstrap zostanie wyłączony w ciągu 24 godzin." + bootstrap_invite_button_title: "Wyślij zaproszenia" + bootstrap_wizard_link_title: "Zakończ kreator konfiguracji" themes: default_description: "Domyślny" broken_theme_alert: "Twoja strona może nie działać, ponieważ motyw / komponent ma błędy." @@ -283,6 +284,8 @@ pl_PL: not_implemented: "Bardzo nam przykro, ale ta funkcja nie została jeszcze zaimplementowana." no_value: "Nie" yes_value: "Tak" + ok_value: "OK" + cancel_value: "Anuluj" submit: "Prześlij" generic_error: "Przepraszamy, wystąpił błąd." generic_error_with_reason: "Wystąpił błąd: %{error}" @@ -1788,7 +1791,6 @@ pl_PL: set_custom_status: "Ustaw własny status" what_are_you_doing: "Co robisz?" remove_status: "Usuń status" - until: "Aż do:" loading: "Wczytuję…" errors: prev_page: "podczas próby wczytania" @@ -1854,7 +1856,6 @@ pl_PL: hide_forever: "nie, dziękuję" hidden_for_session: "OK, zapytamy Cię jutro. Zawsze możesz też użyć opcji „Zaloguj się”, aby utworzyć konto." intro: "Hej! Wygląda na to, że zainteresowała Cię ta dyskusja, ale nie posiadasz jeszcze konta." - value_prop: "Masz dość przewijania tych samych postów? Zakładając konto, zawsze będziesz mógł wrócić do miejsca, w którym skończyłeś. Mając konto, możesz również otrzymywać powiadomienia o nowych odpowiedziach, zapisywać zakładki i używać polubień, aby podziękować innym. Wszyscy razem możemy uczynić tę społeczność wspaniałą. :heart:" summary: enabled_description: "Przeglądasz podsumowanie tego tematu: widoczne są jedynie najbardziej wartościowe wpisy zdaniem uczestników. " description: @@ -2531,14 +2532,20 @@ pl_PL: view_all: "zobacz wszystkie %{tab}" user_menu: generic_no_items: "Na tej liście nie ma żadnych pozycji." - sr_menu_tabs: "Zakładki menu" view_all_notifications: "zobacz wszystkie powiadomienia" + view_all_bookmarks: "zobacz wszystkie zakładki" + view_all_messages: "wyświetl wszystkie wiadomości osobiste" + tabs: + replies: "Odpowiedzi" + mentions: "Wzmianki" + likes: "Otrzymane polubienia" + bookmarks: "Zakładki" + profile: "Profil" reviewable: queue: "Kolejka" deleted_user: "(usunięty użytkownik)" post_number_with_topic_title: "post #%{post_number} - %{title}" new_post_in_topic: "nowy post w %{title}" - suspicious_user: "podejrzany użytkownik %{username}" default_item: "pozycja do sprawdzenia #%{reviewable_id}" topics: new_messages_marker: "ostatnia wizyta" @@ -3272,12 +3279,6 @@ pl_PL: few: "Czy na pewno chcesz usunąć te %{count} posty?" many: "Czy na pewno chcesz usunąć te %{count} postów?" other: "Czy na pewno chcesz usunąć te %{count} postów?" - merge: - confirm: - one: "Czy na pewno chcesz połączyć te posty?" - few: "Czy na pewno chcesz połączyć te %{count} posty?" - many: "Czy na pewno chcesz połączyć te %{count} postów?" - other: "Czy na pewno chcesz połączyć te %{count} postów?" revisions: controls: first: "Pierwsza wersja" @@ -3815,6 +3816,7 @@ pl_PL: edit: "%{shortcut} Edytuj wpis" delete: "%{shortcut} Usuń wpis" mark_muted: "%{shortcut} Wycisz temat" + mark_regular: "%{shortcut} Normalny (domyślny) temat" mark_tracking: "%{shortcut} śledź temat" mark_watching: "%{shortcut} Obserwuj temat" print: "%{shortcut} Drukuj temat" @@ -3881,7 +3883,6 @@ pl_PL: google: "Kalendarz Google" ics: "ICS" tagging: - all_tags: "Wszystkie tagi" other_tags: "Inne tagi" selector_all_tags: "wszystkie tagi" selector_no_tags: "brak tagów" @@ -4061,14 +4062,11 @@ pl_PL: user_activity: no_activity_title: "Brak aktywności" no_activity_body: "Witaj w naszej społeczności! Jesteś tu zupełnie nowy(-a) i nie uczestniczyłeś(-aś) jeszcze w żadnych dyskusjach. Jako pierwszy krok, odwiedź Popularne lub Kategorie i po prostu zacznij czytać! Kliknij w %{heartIcon} przy postach, które lubisz lub chcesz dowiedzieć się więcej. Gdy bierzesz udział w dyskusji, Twoja aktywność zostanie wymieniona tutaj." - no_activity_others: "Brak aktywności" no_replies_title: "Nie odpowiedziałeś jeszcze na żadne tematy" - no_replies_others: "Brak odpowiedzi." no_drafts_title: "Nie rozpocząłeś żadnych szkiców" no_drafts_body: "Nie jesteś gotowy do opublikowania? Automatycznie zapiszemy nową wersję roboczą i wyświetlimy ją tutaj za każdym razem, gdy zaczniesz pisać temat, odpowiedź lub wiadomość osobistą. Wybierz przycisk anulowania, aby odrzucić lub zapisać wersję roboczą, aby kontynuować później." no_likes_title: "Nie polubiłeś jeszcze żadnych tematów" no_likes_body: "Świetnym sposobem na włączenie się do dyskusji i rozpoczęcie współtworzenia jest rozpoczęcie czytania rozmów, które już miały miejsce, i kliknięcie %{heartIcon} przy postach, które Ci się podobają!" - no_likes_others: "Brak polubionych wpisów." no_topics_title: "Nie rozpocząłeś jeszcze żadnych tematów" no_topics_body: "Zawsze najlepiej jest przeszukać stronę w poszukiwaniu istniejących tematów konwersacji przed rozpoczęciem nowej, ale jeśli masz pewność, że temat, którego szukasz nie istnieje, śmiało rozpocznij nowy temat. Poszukaj przycisku + Nowy temat w prawym górnym rogu listy tematów, kategorii lub tagu, aby rozpocząć tworzenie nowego tematu w tym obszarze." no_topics_title_others: "%{username} nie utworzył jeszcze żadnego tematu" @@ -4095,9 +4093,11 @@ pl_PL: other: "%{count} nowy" toggle_section: "przełącz sekcję" more: "Więcej…" + all_categories: "Wszystkie kategorie" sections: + about: + header_link_text: "O stronie" messages: - header_link_title: "osobiste wiadomości" header_link_text: "Wiadomości" header_action_title: "utwórz osobistą wiadomość" links: @@ -4111,23 +4111,28 @@ pl_PL: tags: none: "Nie dodałeś żadnych tagów." click_to_get_started: "Kliknij tutaj, aby rozpocząć." - header_link_title: "wszystkie tagi" header_link_text: "Etykiety" header_action_title: "edytuj tagi paska bocznego" categories: none: "Nie dodałeś żadnych kategorii." click_to_get_started: "Kliknij tutaj, aby rozpocząć." - header_link_title: "wszystkie kategorie" header_link_text: "Kategorie" header_action_title: "edytuj kategorie paska bocznego" community: - header_link_title: "strona główna" header_link_text: "Społeczność" header_action_title: "utwórz nowy temat" links: + about: + content: "O stronie" + admin: + content: "Administratorzy" + badges: + content: "Odznaki" everything: content: "Wszystko" title: "Wszystkie tematy" + faq: + content: "FAQ" tracked: content: "Śledzone" title: "Wszystkie śledzone tematy" @@ -4145,6 +4150,11 @@ pl_PL: few: "%{count} szkice" many: "%{count} szkice" other: "%{count} szkice" + welcome_topic_banner: + title: "Stwórz swój temat powitalny" + description: 'Twój temat powitalny jest pierwszą rzeczą, którą przeczytają nowicjusze. Postaraj się w jednym akapicie wyrazić najważniejsze informacje, jakie chcesz przekazać nowym użytkownikom forum.' + button_title: "Rozpocznij edycję" + until: "Aż do:" admin_js: type_to_filter: "pisz, aby filtrować…" admin: @@ -4711,6 +4721,8 @@ pl_PL: import_web_advanced: "Zaawansowane..." import_file_tip: "plik .tar.gz, .zip, lub .dcstyle.json zawierający motyw" is_private: "Motyw jest w prywatnym repozytorium git" + finish_install: "Zakończ instalację motywu" + last_attempt: "Proces instalacji nie został zakończony, ostatnia próba:" remote_branch: "Nazwa oddziału (opcjonalnie)" public_key: "Podaj następujący klucz publiczny pozwalający na dostęp do repozytorium:" public_key_note: "Po wprowadzeniu powyżej poprawnego adresu URL prywatnego repozytorium klucz SSH zostanie wygenerowany i wyświetlony tutaj." @@ -4721,6 +4733,8 @@ pl_PL: install_git_repo: "Z repozytorium git" install_create: "Stwórz nowy" duplicate_remote_theme: "Komponent motywu ”%{name}” jest już zainstalowany. Czy na pewno chcesz zainstalować inną kopię?" + force_install: "Nie można zainstalować motywu, ponieważ repozytorium Git jest niedostępne. Czy na pewno chcesz kontynuować instalację?" + create_placeholder: "Utwórz symbol zastępczy" about_theme: "O stronie" license: "Licencja" version: "Wersja:" @@ -5357,7 +5371,6 @@ pl_PL: few: "Nie można usunąć wszystkich postów, ponieważ użytkownik ma ich więcej niż %{count}. (delete_all_posts_max)" many: "Nie można usunąć wszystkich wpisów, ponieważ użytkownik ma ich więcej niż %{count}. (delete_all_posts_max)" other: "Nie można usunąć wszystkich wpisów, ponieważ użytkownik ma ich więcej niż %{count}. (delete_all_posts_max)" - delete_confirm: "Generalnie lepiej jest anonimizować użytkowników niż ich usuwać, aby uniknąć usuwania treści z istniejących dyskusji.

    Czy NA PEWNO chcesz usunąć tego użytkownika? Nie można tego cofnąć!" delete_and_block: "Usuń i zablokuj ten email oraz adres IP" delete_dont_block: "Tylko usuń" deleting_user: "Usuwanie użytkownika…" @@ -5490,7 +5503,6 @@ pl_PL: recommended: "Zalecamy zmianę poniższego tekstu, aby lepiej odpowiadał Twoim potrzebom:" show_overriden: "Pokaż tylko nadpisane" locale: "Język:" - fallback_locale_warning: "Edytujesz język oparty na %{fallback}. Użytkownicy, którzy wybiorą %{fallback} jako język interfejsu, nie zobaczą Twoich zmian." more_than_50_results: "Istnieje ponad 50 wyników. Zawęź wyszukiwanie." settings: show_overriden: "Pokaż tylko nadpisane" diff --git a/config/locales/client.pt.yml b/config/locales/client.pt.yml index 17ee60e99c..59358c59e8 100644 --- a/config/locales/client.pt.yml +++ b/config/locales/client.pt.yml @@ -160,7 +160,6 @@ pt: forwarded: "encaminhou o e-mail acima" topic_admin_menu: "ações do tópico" skip_to_main_content: "Saltar para o conteúdo principal" - wizard_required: "Bem-vindo ao seu novo Discourse! Vamos começar com o assistente de configuração ✨" emails_are_disabled: "Todos os envios de e-mail foram globalmente desativados por um administrador. Nenhum e-mail de notificação será enviado." software_update_prompt: message: "Atualizámos este site, por favor recarregue a página ou poderá experienciar um comportamento inesperado." @@ -169,6 +168,7 @@ pt: one: "Para que o início do teu Site seja o mais simples possível, estás agora em modo de inicialização simples. A todos os novos utilizadores será concedido o Nível de Confiança 1 e o resumo por e-mail enviado diariamente estará ativado. Isto será automaticamente desligado quando %{count} utilizador se tiver juntado ao fórum." other: "Para que o início do teu Site seja o mais simples possível, estás agora em modo de inicialização simples. A todos os novos utilizadores será concedido o Nível de Confiança 1 e o resumo por e-mail enviado diariamente estará ativado. Isto será automaticamente desligado quando %{count} utilizadores se tiverem juntado ao fórum." bootstrap_mode_disabled: "O modo de inicialização simples será desactivado em 24 horas." + bootstrap_invite_button_title: "Enviar Convites" themes: default_description: "Predefinição" broken_theme_alert: "Seu site pode não funcionar porque um tema ou componente têm erros." @@ -203,6 +203,8 @@ pt: not_implemented: "Essa funcionalidade ainda não foi implementada, pedimos desculpa!" no_value: "Não" yes_value: "Sim" + ok_value: "CONFIRMAR" + cancel_value: "Cancelar" submit: "Submeter" generic_error: "Pedimos desculpa, ocorreu um erro." generic_error_with_reason: "Ocorreu um erro: %{error}" @@ -2187,6 +2189,13 @@ pt: not_logged_in_user: "página de utilizador com resumo da atividade atual e preferências " current_user: "ir para a sua página de utilizador" view_all: "ver todos %{tab}" + user_menu: + tabs: + replies: "Respostas" + mentions: "Menções" + likes: "Gostos Dados" + bookmarks: "Marcadores" + profile: "Perfil" topics: new_messages_marker: "última visita" bulk: @@ -3282,7 +3291,6 @@ pt: download: "Transferir" add_to_calendar: "Adicionar ao calendário" tagging: - all_tags: "Todas as Etiquetas" other_tags: "Outras Tags" selector_all_tags: "todas as etiquetas" selector_no_tags: "sem etiquetas" @@ -3418,8 +3426,6 @@ pt: regular: "habitual" leader: "líder" detailed_name: "%{level}: %{name}" - user_activity: - no_likes_others: "Sem publicações gostadas." sidebar: unread_count: one: "%{count} não lido" @@ -3428,7 +3434,10 @@ pt: one: "%{count} novo" other: "%{count} novos" more: "Mais..." + all_categories: "Todas as categorias" sections: + about: + header_link_text: "Sobre" messages: header_link_text: "Mensagens" links: @@ -3440,15 +3449,20 @@ pt: unread_with_count: "Não Lido (%{count})" archive: "Arquivo" tags: - header_link_title: "todas as etiquetas" header_link_text: "Etiquetas" categories: - header_link_title: "todas as categorias" header_link_text: "Categorias" community: - header_link_title: "início" header_link_text: "Comunidade" links: + about: + content: "Sobre" + admin: + content: "Administrador" + badges: + content: "Crachás" + faq: + content: "FAQ" tracked: content: "Seguido" groups: diff --git a/config/locales/client.pt_BR.yml b/config/locales/client.pt_BR.yml index 48aa3328a3..a90849d4ca 100644 --- a/config/locales/client.pt_BR.yml +++ b/config/locales/client.pt_BR.yml @@ -77,6 +77,9 @@ pt_BR: date_month: "D MMM" date_year: "MMM 'YY" medium: + less_than_x_minutes: + one: "menos de %{count} min" + other: "menos de %{count} mins" x_minutes: one: "%{count} minuto" other: "%{count} minutos" @@ -95,6 +98,12 @@ pt_BR: about_x_years: one: "cerca de %{count} ano" other: "cerca de %{count} anos" + over_x_years: + one: "mais de %{count} ano" + other: "mais de %{count} anos" + almost_x_years: + one: "há quase %{count} ano" + other: "há quase %{count} anos" date_year: "D MMM, 'YY" medium_with_ago: x_minutes: @@ -129,6 +138,7 @@ pt_BR: to_placeholder: "até agora" share: topic_html: 'Tópico: %{topicTitle}' + post: "publicação #%{postNumber} de @%{username}" close: "fechar" twitter: "Compartilhar no Twitter" facebook: "Compartilhar no Facebook" @@ -169,8 +179,8 @@ pt_BR: forwarded: "encaminhou o e-mail acima" topic_admin_menu: "ações de tópico" skip_to_main_content: "Ir para o conteúdo principal" - wizard_required: "Boas-vindas ao seu novo Discourse! Vamos começar com o assistente de configuração ✨" emails_are_disabled: "Todos os envios de e-mail foram desabilitados globalmente por um administrador. Nenhuma notificação por e-mail de qualquer tipo será enviada." + emails_are_disabled_non_staff: "O e-mail de saída foi desabilitado para usuários que não são da equipe." software_update_prompt: message: "Nós atualizamos este site, atualize a página, ou você poderá enfrentar uma situação inesperada." dismiss: "Descartar" @@ -178,8 +188,13 @@ pt_BR: one: "Para facilitar o lançamento do seu novo site, você está no modo de inicialização. Todos os usuários novos receberão o nível de confiança 1 e terão os e-mails diários do resumo de e-mails ativados. Isso será desativado automaticamente quando %{count} usuários se registrarem." other: "Para facilitar o lançamento do seu novo site, você está no modo de inicialização. Todos os usuários novos receberão o nível de confiança 1 e terão os e-mails diários do resumo de e-mails ativados. Isso será desativado automaticamente quando %{count} usuários se registrarem." bootstrap_mode_disabled: "O modo de inicialização será desativado em 24 horas." + bootstrap_invite_button_title: "Enviar convites" + bootstrap_wizard_link_title: "Concluir o assistente de configuração" themes: default_description: "Padrão" + broken_theme_alert: "Seu site pode não funcionar porque o tema/componente tem erros." + error_caused_by: "Causado por '%{name}'. Clique aqui para atualizar, reconfigurar ou desabilitar." + only_admins: "(esta mensagem é mostrada somente aos administradores do site)" s3: regions: ap_northeast_1: "Ásia Pacífico (Tóquio)" @@ -210,6 +225,8 @@ pt_BR: not_implemented: "Este recurso ainda não foi implementado, desculpe!" no_value: "Não" yes_value: "Sim" + ok_value: "Ok" + cancel_value: "Cancelar" submit: "Enviar" generic_error: "Desculpe, ocorreu um erro." generic_error_with_reason: "Ocorreu um erro: %{error}" @@ -315,6 +332,8 @@ pt_BR: existing_reminder: "Você tem um lembrete definido para este favorito que será enviado em %{at_date_time}" copy_codeblock: copied: "copiado!" + copy: "copiar código para a área de transferência" + fullscreen: "exibir código em tela cheia" drafts: label: "Rascunhos" label_with_count: "Rascunhos (%{count})" @@ -351,6 +370,7 @@ pt_BR: saved: "Salvo!" upload: "Enviar" uploading: "Enviando..." + processing: "Processando..." uploading_filename: "Enviando: %{filename}..." processing_filename: "Processando: %{filename}..." clipboard: "área de transferência" @@ -562,7 +582,10 @@ pt_BR: relative: "Relativo" time_shortcut: now: "Agora" + in_one_hour: "Em uma hora" + in_two_hours: "Em duas horas" later_today: "Hoje mais tarde" + two_days: "Dois dias" next_business_day: "Próximo dia útil" tomorrow: "Amanhã" post_local_date: "Data na postagem" @@ -704,6 +727,7 @@ pt_BR: title: "Configurações" allow_unknown_sender_topic_replies: "Permita que remetentes desconhecidos respondam a tópicos." allow_unknown_sender_topic_replies_hint: "Permite que remetentes desconhecidos(as) respondam a tópicos de grupo. Se não estiver ativado, será criado um novo tópico para respostas de endereços de e-mail de usuários(as) não convidados para o tópico." + from_alias: "De Alias" mailboxes: synchronized: "Caixa de mensagens sincronizada" none_found: "Nenhuma caixa de mensagens foi encontrada nesta conta de e-mail." @@ -1063,6 +1087,10 @@ pt_BR: enable_defer: "Ativar adiamento para marcar tópicos como não lidos" experimental_sidebar: options: "Opções" + categories_section: "Seção de Categorias" + categories_section_instruction: "As categorias selecionadas serão exibidas na seção de categorias do painel lateral." + tags_section: "Seção de Etiquetas" + tags_section_instruction: "As etiquetas selecionadas serão exibidas na seção de etiquetas da barra lateral." change: "alterar" featured_topic: "Tópico em destaque" moderator: "%{user} é moderador(a)" @@ -1175,6 +1203,7 @@ pt_BR: tags: "Etiquetas" interface: "Interface" apps: "Aplicativos" + sidebar: "Barra Lateral" change_password: success: "(e-mail enviado)" in_progress: "(enviando e-mail)" @@ -1279,6 +1308,7 @@ pt_BR: upload_title: "Enviar sua imagem" image_is_not_a_square: "Aviso: cortamos a sua imagem. A largura e a altura não eram iguais." logo_small: "Logotipo pequeno do site. Usado por padrão." + use_custom: "Ou envie um avatar customizado:" change_profile_background: title: "Cabeçalho do perfil" instructions: "Os cabeçalhos do perfil serão centralizados e terão largura padrão de 1110px." @@ -1785,19 +1815,32 @@ pt_BR: not_approved: "Sua conta ainda não foi aprovada. Você será notificado(a) por e-mail quando tudo estiver pronto para entrar." google_oauth2: name: "Google" + title: "Conectar com o Google" + sr_title: "Conectar com o Google" twitter: name: "Twitter" + title: "Conectar com o Twitter" + sr_title: "Conectar com o Twitter" instagram: name: "Instagram" + title: "Entrar com o Instagram" + sr_title: "Entrar com o Instagram" facebook: name: "Facebook" + title: "Entrar com o Facebook" + sr_title: "Entrar com o Facebook" github: name: "GitHub" + title: "Entrar com o GitHub" + sr_title: "Entrar com o GitHub" discord: name: "Discord" + title: "Entrar com o Discord" + sr_title: "Entrar com o Discord" second_factor_toggle: totp: "Use um aplicativo autenticador" backup_code: "Use um código de backup" + security_key: "Em vez disso, utilizar uma chave de segurança" invites: accept_title: "Convite" emoji: "emoji de envelope" @@ -1954,6 +1997,7 @@ pt_BR: create_shared_draft: "Criar rascunho compartilhado" edit_shared_draft: "Editar rascunho compartilhado" title: "Ou aperte %{modifier}Enter" + users_placeholder: "Adicionar usuários ou grupos" title_placeholder: "Em algumas palavras, sobre o que é esta discussão?" title_or_link_placeholder: "Digite um título, ou cole um link aqui" edit_reason_placeholder: "por que você está editando?" @@ -2275,6 +2319,13 @@ pt_BR: not_logged_in_user: "página do(a) usuário(a) com resumo de atividades e preferências atuais" current_user: "ir para a sua página do(a) usuário(a)" view_all: "exibir tudo %{tab}" + user_menu: + tabs: + replies: "Respostas" + mentions: "Menções" + likes: "Curtidas" + bookmarks: "Favoritos" + profile: "Perfil" topics: new_messages_marker: "último acesso" bulk: @@ -2898,10 +2949,6 @@ pt_BR: confirm: one: "Tem certeza de que deseja excluir esta postagem?" other: "Tem certeza de que deseja excluir estas %{count} postagens?" - merge: - confirm: - one: "Tem certeza de que deseja mesclar estas postagens?" - other: "Tem certeza de que deseja mesclar estas %{count} postagens?" revisions: controls: first: "Primeira revisão" @@ -3310,6 +3357,7 @@ pt_BR: preloader_text: "Carregando" lightbox: download: "download" + open: "imagem original" previous: "Anterior (seta para a esquerda)" next: "Próximo (seta para a direita)" counter: "%curr% de %total%" @@ -3324,6 +3372,7 @@ pt_BR: shortcut_delimiter_slash: "%{shortcut1}/%{shortcut2}" shortcut_delimiter_space: "%{shortcut1} %{shortcut2}" title: "Atalhos do teclado" + short_title: "Atalhos" jump_to: title: "Pular para" home: "%{shortcut} Início" @@ -3606,14 +3655,11 @@ pt_BR: unsupported_file_picked: "Você escolheu um arquivo incompatível. Tipos de arquivos compatíveis: %{types}." user_activity: no_activity_title: "Nenhuma atividade ainda." - no_activity_others: "Nenhuma atividade." no_replies_title: "Você ainda não respondeu a nenhum tópico." - no_replies_others: "Sem respostas." no_drafts_title: "Você ainda não iniciou nenhum rascunho" no_drafts_body: "Ainda não está pronto(a) para postar? Salvaremos automaticamente um novo rascunho e o listaremos aqui sempre que você começar a escrever um tópico, resposta ou mensagem pessoal. Selecione o botão de cancelamento para descartar ou salvar seu rascunho para continuar mais tarde." no_likes_title: "Você ainda não curtiu nenhum tópico" no_likes_body: "Uma ótima maneira de participar e começar a contribuir é iniciar a leitura das conversas que já aconteceram e selecionar %{heartIcon} nas postagens de que você gostou!" - no_likes_others: "Nenhuma postagem curtida." no_topics_title: "Você ainda não iniciou nenhum tópico" no_read_topics_title: "Você ainda não leu nenhum tópico" no_read_topics_body: "Quando começar a ler as discussões, uma lista será exibida aqui. Para começar a ler, procure tópicos do seu interesse em Melhores ou Categorias, ou pesquise por palavra-chave %{searchIcon}" @@ -3628,7 +3674,11 @@ pt_BR: one: "%{count} nova" other: "%{count} novas" more: "Mais..." + all_categories: "Todas as categorias" + all_tags: "Todas as etiquetas" sections: + about: + header_link_text: "Sobre" messages: header_link_text: "Mensagens" links: @@ -3640,24 +3690,44 @@ pt_BR: unread_with_count: "Não lido (%{count})" archive: "Arquivo" tags: - header_link_title: "todas as etiquetas" + none: "Você não adicionou nenhuma etiqueta." + click_to_get_started: "Clique aqui para começar." header_link_text: "Etiquetas" + header_action_title: "editar as suas etiquetas da barra lateral" categories: - header_link_title: "todas as categorias" + none: "Você não adicionou nenhuma categoria." + click_to_get_started: "Clique aqui para começar." header_link_text: "Categorias" community: - header_link_title: "início" header_link_text: "Comunidade" links: + about: + content: "Sobre" + admin: + content: "Administrador(a)" + badges: + content: "Emblemas" + everything: + content: "Tudo" + title: "Todos os Tópicos" + faq: + content: "FAQ" tracked: content: "Monitorados(as)" + title: "Todos os Tópicos Rastreados" groups: content: "Grupos" title: "Todos os grupos" users: content: "Usuários(as)" + title: "Todos(as) os(as) usuários(as)" my_posts: content: "Minhas postagens" + title: "Minhas publicações" + welcome_topic_banner: + title: "Crie seu tópico de Boas-Vindas" + button_title: "Começar a Editar" + until: "Até:" admin_js: type_to_filter: "Digite para filtrar..." admin: @@ -4103,6 +4173,7 @@ pt_BR: delete_confirm: 'Você tem certeza de que deseja excluir "%{theme_name}"?' color: "Cor" opacity: "Opacidade" + copy: "Duplicado" copy_to_clipboard: "Copiar para área de transferência" copied_to_clipboard: "Copiou para área de transferência" copy_to_clipboard_error: "Erro ao copiar dados para a área de transferência" @@ -4202,6 +4273,7 @@ pt_BR: import_web_advanced: "Avançado…" import_file_tip: "Arquivo .tar.gz, .zip ou .dcstyle.json com o tema" is_private: "O tema está em um repositório git privado" + finish_install: "Concluir a instalação do tema" remote_branch: "Nome da unidade (opcional)" public_key: "Conceder o seguinte acesso da chave pública ao repo:" public_key_note: "Após digitar uma URL do repositório privada válida, uma chave SSH será gerada e exibida aqui." @@ -4374,6 +4446,7 @@ pt_BR: time: "Hora" user: "Usuário(a)" email_type: "Tipo de e-mail" + details_title: "Exibir detalhes do e-mail" to_address: "Para o endereço" test_email_address: "endereço de e-mail para testar" send_test: "Enviar e-mail de teste" @@ -4420,6 +4493,7 @@ pt_BR: address_placeholder: "nome@exemplo.com" type_placeholder: "compilação, cadastro..." reply_key_placeholder: "tecla de resposta" + smtp_transaction_response_placeholder: "ID do SMTP" moderation_history: performed_by: "Executado por" no_results: "Não há histórico de moderação disponível." @@ -4602,6 +4676,7 @@ pt_BR: show_words: one: "exibir %{count} palavra" other: "exibir %{count} palavras" + case_sensitive: "(diferencia maiúsculas)" download: Download clear_all: Limpar tudo clear_all_confirm: "Tem certeza de que deseja remover todas as palavras acompanhadas para a ação %{action}?" @@ -4639,6 +4714,7 @@ pt_BR: exists: "Já existe" upload: "Adicionar do arquivo" upload_successful: "Envio bem-sucedido. As palavras foram adicionadas." + case_sensitivity_label: "É sensível a maiúsculas" test: button_label: "Testar" modal_title: "%{action}: testar palavras acompanhadas" @@ -4836,7 +4912,8 @@ pt_BR: cant_delete_all_too_many_posts: one: "Não é possível remover todas as postagens porque o usuário(a) tem mais de %{count} postagem (delete_all_posts_max)" other: "Não é possível remover todas as postagens porque o usuário(a) tem mais de %{count} postagens. (delete_all_posts_max)" - delete_confirm: "Geralmente é preferível tornar anônimos(as) os(as) usuários(as) em vez de excluí-los(as), para evitar remover conteúdo de discussões existentes.

    Você tem CERTEZA de que deseja excluir este(a) usuário(a)? Essa ação é permanente!" + delete_confirm_title: "Você TEM CERTEZA que deseja excluir este usuário? Essa é uma ação permanente!" + delete_confirm: "Geralmente, é preferível anonimizar os usuários em vez de excluí-los, evitando assim a remoção de conteúdo das discussões existentes." delete_and_block: "Excluir e bloquear este e-mail e endereço IP" delete_dont_block: "Excluir apenas" deleting_user: "Excluindo usuário(a)..." @@ -4967,7 +5044,6 @@ pt_BR: recommended: "Recomendamos personalizar o texto a seguir para atender às suas necessidades:" show_overriden: "Exibir apenas substituídos" locale: "Idioma:" - fallback_locale_warning: "Você está editando um idioma com base em %{fallback}. Os(as) usuários(as) que escolherem %{fallback} como idioma de interface não visualizarão suas alterações." more_than_50_results: "Existem mais de 50 resultados. Refine sua pesquisa." settings: show_overriden: "Exibir apenas substituídos" @@ -5188,8 +5264,11 @@ pt_BR: replace: "Substituir" wizard_js: wizard: + jump_in: "Pular dentro!" + finish: "Sair da configuração" back: "Voltar" next: "Próximo" + configure_more: "Configurar Mais..." step-text: "Intervalo" step: "%{current} de %{total}" upload: "Enviar" diff --git a/config/locales/client.ro.yml b/config/locales/client.ro.yml index 08a0a533a8..9c40386aeb 100644 --- a/config/locales/client.ro.yml +++ b/config/locales/client.ro.yml @@ -184,7 +184,6 @@ ro: forwarded: "a redirecționat e-mailul de mai sus" topic_admin_menu: "acțiuni subiect" skip_to_main_content: "Treci la conținutul principal" - wizard_required: "Bine ai venit la noul tău Discourse! Să începem cu expertul de configurare ✨" emails_are_disabled: "Trimiterea de emailuri a fost dezactivată global de către un administrator. Nu vor fi trimise notificări email de nici un fel." software_update_prompt: message: "Site-ul a fost actualizat! Reîmprospătează pagina." @@ -194,6 +193,7 @@ ro: few: "Pentru a simplifica lansarea noului dv. site, sunteți în modul bootstrap. Toți utilizatorii noi vor primi nivelul 1 de încredere și vor avea activată primirea zilnică de e-mail-uri rezumat. Această funcționalitate va fi oprită automat după ce se înregistrează primii %{count} membri." other: "Pentru a simplifica lansarea noului dv. site, sunteți în modul bootstrap. Toți utilizatorii noi vor primi nivelul 1 de încredere și vor avea activată primirea zilnică de e-mail-uri rezumat. Această funcționalitate va fi oprită automat după ce se înregistrează primii %{count} membri." bootstrap_mode_disabled: "Modul bootstrap va fi dezactivat în următoarele 24 de ore" + bootstrap_invite_button_title: "Trimite invitații" themes: default_description: "Implicit" s3: @@ -224,6 +224,8 @@ ro: not_implemented: "Această funcționalitate nu a fost implementată încă." no_value: "Nu" yes_value: "Da" + ok_value: "Ok" + cancel_value: "Anulare" submit: "Trimite" generic_error: "A apărut o eroare." generic_error_with_reason: "A apărut o eroare: %{error}" @@ -337,6 +339,7 @@ ro: fullscreen: "afișați codul în ecran complet" drafts: label: "Ciorne" + label_with_count: "Schițe (%{count})" resume: "Reluați" remove: "Eliminați" remove_confirmation: "Ești sigur că vrei să ștergi această ciornă?" @@ -605,6 +608,7 @@ ro: six_months: "Șase luni" one_year: "Un an" forever: "Pentru totdeanua" + none: "Nici unul necesar" never: "Niciodată" last_custom: "Ultima dată personalizată" custom: "Data și ora personalizată" @@ -877,6 +881,7 @@ ro: topic_stat_unit: week: "săptămană" month: "lună" + n_more: "Categorii (%{count} mai multe)..." ip_lookup: title: Căutare adresă IP hostname: Nume gazdă @@ -1363,6 +1368,7 @@ ro: same_as_email: "Parolă identică cu adresa de email" ok: "Parola dumneavoastră este OK." instructions: "minimum %{count} caractere" + required: "Vă rugăm să introduceți o parolă" summary: title: "Sumar" stats: "Statistici" @@ -1488,6 +1494,7 @@ ro: other: de răspunsuri signup_cta: sign_up: "Înregistrare" + hide_session: "Poate mai târziu" hide_forever: "Nu, mulțumesc" intro: "Salut! Se pare că îți place discuția, dar încă nu te-ai înscris pentru un cont." summary: @@ -1519,6 +1526,7 @@ ro: disclaimer: "Prin înregistrare, ești de acord cu politica de confidențialitate și termenii de utilizare." title: "Creează-ți contul" failed: "Ceva s-a întâmplat, poate că acest email este deja înregistrat, încearcă să-ți resetezi parola la link-ul respectiv." + associate: "Ai deja un cont? Loghează-te pentru a conecta contul tău %{provider}." forgot_password: title: "Resetare parolă" action: "Mi-am uitat parola" @@ -1688,6 +1696,7 @@ ro: create_pm: "Mesaj" create_whisper: "Șoaptă" create_shared_draft: "Creează ciornă partajată" + users_placeholder: "Adaugă utilizatori sau grupuri" title_placeholder: "Despre ce e vorba în acest subiect - pe scurt?" title_or_link_placeholder: "Introdu titlul, sau copiază aici un link" edit_reason_placeholder: "de ce editezi?" @@ -1710,6 +1719,7 @@ ro: link_description: "adaugă aici descrierea link-ului" link_dialog_title: "Introdu link" link_optional_text: "titlu opțional" + link_url_placeholder: "Lipește un URL sau tastează pentru a căuta subiecte" blockquote_title: "Bloc citat" blockquote_text: "Bloc citat" code_title: "Text preformatat" @@ -1906,6 +1916,13 @@ ro: go_back: "înapoi" not_logged_in_user: "pagina utilizatorului cu rezumatul activităților și preferințelor" current_user: "mergi la pagina ta de utilizator" + user_menu: + tabs: + replies: "Răspunsuri" + mentions: "Mențiuni" + likes: "Aprecieri date" + bookmarks: "Semne de carte" + profile: "Profil" topics: new_messages_marker: "ultima vizită" bulk: @@ -1944,6 +1961,7 @@ ro: category: "Nu există niciun subiect din categoria %{category}." top: "Nu exită niciun subiect de top." educate: + new: '

    Subiectele noi vor apărea aici.Implicit, subiectele vor fi considerate noi și vor afișa un indicator dacă au fost create în ultimele 2 zile.

    Mergi la preferințe pentru a schimba această setare.

    ' unread: '

    Subiectele necitite vor apărea aici

    Implicit, subiectele sunt considerate necitite și se va afișa numărul celor necitite 1dacă ai:

    • Creat subiectul
    • Răspuns la subiect
    • Citit subiectul de mai mult de 4 minute

    Sau dacă ai setat în mod explicit subiectul pe Urmărire sau Urmărire activă prin intermediul contorului de notificare de la sfârșitul fiecărui subiect.

    Mergi la preferințe pentru a schimba această setare.

    ' bottom: latest: "Nu mai există niciun subiect recent." @@ -1962,6 +1980,7 @@ ro: other: "%{count} de postări în subiect" create: "Subiect nou" create_long: "Creează un subiect nou" + open_draft: "Deschide schiță" private_message: "Scrie un mesaj." archive_message: help: "Mută mesajul în arhivă" @@ -2078,9 +2097,10 @@ ro: "3_2": "Vei primi notificări deoarece urmărești activ acest subiect." "3_1": "Vei primi notificări deoarece ai creat acest subiect." "3": "Vei primi notificări deoarece urmărești activ acest subiect." + "2_8": "Vei vedea numărul răspunsurilor noi deoarece urmărești această categorie." "2_4": "Vei vedea numărul răspunsurilor noi deoarece ai adăugat un comentariu în acest subiect." "2_2": "Vei vedea numărul răspunsurilor noi deoarece urmărești acest subiect." - "2": 'You will see a count of new replies because you read this topic.' + "2": 'Vei vedea numărul răspunsurilor noi deoarece citești acest subiect.' "1_2": "Vei fi notificat dacă cineva îți menționează @numele sau îți scrie un răspuns." "1": "Vei fi notificat dacă cineva îți menționează @numele sau îți scrie un răspuns." "0_7": "Ignori toate notificările din această categorie." @@ -2370,11 +2390,6 @@ ro: one: "Ești sigur că vrei să ștergi aca postare?" few: "Ești sigur că vrei să ștergi acele %{count} postări?" other: "Ești sigur că vrei să ștergi acele %{count} postări?" - merge: - confirm: - one: "Ești sigur că vrei să comasezi acele postări?" - few: "Ești sigur că vrei să comasezi acele %{count} postări?" - other: "Ești sigur că vrei să comasezi acele %{count} postări?" revisions: controls: first: "Prima revizie" @@ -2818,7 +2833,6 @@ ro: download_calendar: download: "Descărcare" tagging: - all_tags: "Toate etichetele" other_tags: "Alte etichete" selector_all_tags: "toate etichetele" selector_no_tags: "fără etichete" @@ -2911,11 +2925,10 @@ ro: no_activity_title: "Nicio activitate încă" no_activity_body: "Bun venit în comunitatea noastră! Ești nou-nouț aici și nu ai contribuit încă la discuții. Ca prim pas, vizitează Top sau Categorii și începe să citești! Selectează %{heartIcon} pentru postările care iți plac sau despre care dorești să afli mai multe. Pe măsură ce partici, activitatea ta va fi listată aici." no_replies_title: "Nu ai citit nici un subiect până acum" - no_drafts_title: "Nu ai început nicio ciornă" + no_drafts_title: "Nu ai început nicio schiță" no_drafts_body: "Nu ești gata să postezi? Vom salva automat o schiță nouă și o vom afișa aici ori de câte ori începi să compui un subiect, un răspuns sau un mesaj personal. Selectați butonul de anulare pentru a renunța sau a salva ciorna pentru a continua mai târziu." no_likes_title: "Încă nu ți-a plăcut niciun subiect" no_likes_body: "O modalitate excelentă de a intra și de a începe să contribui este să începi să citești conversațiile care au avut deja loc și să selectezi %{heartIcon} din postările care îți plac!" - no_likes_others: "Nu există postări apreciate." no_topics_title: "Încă nu aţi început niciun subiect" sidebar: unread_count: @@ -2927,7 +2940,10 @@ ro: few: "%{count} noi" other: "%{count} nou" more: "Mai multe..." + all_categories: "Toate categoriile" sections: + about: + header_link_text: "Despre" messages: header_link_text: "Mesaje" links: @@ -2939,15 +2955,20 @@ ro: unread_with_count: "Necitit (%{count})" archive: "Arhivă" tags: - header_link_title: "toate etichetele" header_link_text: "Etichete" categories: - header_link_title: "Toate categoriile" header_link_text: "Categorii" community: - header_link_title: "acasă" header_link_text: "Comunitate" links: + about: + content: "Despre" + admin: + content: "Administrator" + badges: + content: "Ecusoane" + faq: + content: "Întrebări frecvente" tracked: content: "Urmărite" groups: diff --git a/config/locales/client.ru.yml b/config/locales/client.ru.yml index 996b222622..392a60eb4d 100644 --- a/config/locales/client.ru.yml +++ b/config/locales/client.ru.yml @@ -230,12 +230,11 @@ ru: enabled: "Включил отображение темы %{when}" disabled: "Выключил отображение темы %{when}" banner: - enabled: "Создал объявление %{when}. Оно будет отображаться в верхней части каждой страницы пока пользователь не закроет его." - disabled: "Удалил объявление %{when}. Оно больше не будет отображаться в верхней части каждой страницы." + enabled: "Создал объявление %{when} Оно будет отображаться в верхней части каждой страницы пока пользователь не закроет его." + disabled: "Удалил объявление %{when} Оно больше не будет отображаться в верхней части каждой страницы." forwarded: "Переадресовал вышеуказанное письмо" topic_admin_menu: "Действия администратора над темой" skip_to_main_content: "Перейти к основному контенту" - wizard_required: "Добро пожаловать в ваш новый Discourse! Начните с мастера настройки ✨" emails_are_disabled: "Все исходящие письма были глобально отключены администратором. Уведомления любого вида не будут отправляться на почту." emails_are_disabled_non_staff: "Возможность отправки электронной почты отключена для пользователей, не являющихся сотрудниками." software_update_prompt: @@ -247,6 +246,8 @@ ru: many: "Для скорейшего развития вашего нового сайта был включен специальный режим работы. В этом режиме всем новым пользователям при регистрации автоматически присваивается 1-й уровень доверия и включается ежедневная почтовая рассылка сводки новостей. Этот режим будет автоматически выключен, как только количество зарегистрированных пользователей достигнет %{count}." other: "Для скорейшего развития вашего нового сайта был включен специальный режим работы. В этом режиме всем новым пользователям при регистрации автоматически присваивается 1-й уровень доверия и включается ежедневная почтовая рассылка сводки новостей. Этот режим будет автоматически выключен, как только количество зарегистрированных пользователей достигнет %{count}." bootstrap_mode_disabled: "Специальный режим будет отключён в течение 24 часов." + bootstrap_invite_button_title: "Отправить приглашения" + bootstrap_wizard_link_title: "Завершить работу мастера настройки" themes: default_description: "По умолчанию" broken_theme_alert: "Ваш сайт может не работать, потому что в теме / компоненте есть ошибки." @@ -283,6 +284,8 @@ ru: not_implemented: "Извините, эта функция ещё не реализована!" no_value: "Нет" yes_value: "Да" + ok_value: "ОК" + cancel_value: "Нет" submit: "Отправить" generic_error: "Извините, произошла ошибка." generic_error_with_reason: "Произошла ошибка: %{error}" @@ -637,9 +640,9 @@ ru: title: "На это сообщение поступила жалоба" flagged_by: "Кто пожаловался" reviewable_queued_topic: - title: "Тема в очереди" + title: "Тема на премодерации" reviewable_queued_post: - title: "Сообщение в очереди" + title: "Сообщение на премодерации" reviewable_user: title: "Пользователь" reviewable_post: @@ -1167,9 +1170,10 @@ ru: dismiss_notifications: "Отклонить всё" dismiss_notifications_tooltip: "Пометить все непрочитанные уведомления прочитанными" dismiss_bookmarks_tooltip: "Пометить все непрочитанные напоминания о закладках как прочитанные" + dismiss_messages_tooltip: "Отметить все уведомления о непрочитанных личных сообщениях как прочитанные" no_messages_title: "У вас нет личных сообщений" no_messages_body: > - Необходимо непубличное общение с кем-то из участников форума? Напишите личное сообщение, кликнув на аватар участника и нажав на кнопку %{icon}.

    . Если вам необходима помощь, вы можете написать нам на адрес, указанный на этой странице. + Необходимо непубличное общение с кем-то из участников форума? Напишите личное сообщение, кликнув на аватар участника и нажав на кнопку %{icon}.

    Если вам необходима помощь, вы можете написать нам на адрес, указанный на этой странице. no_bookmarks_title: "Вы ещё ничего не добавили в закладки" no_bookmarks_body: > Начните добавлять сообщения в закладки с помощью кнопки %{icon} , и они будут перечислены здесь для быстрого доступа. Вы также можете настроить напоминание о закладке! @@ -1792,7 +1796,6 @@ ru: set_custom_status: "Поменять статус" what_are_you_doing: "Что вы сейчас делаете?" remove_status: "Удалить статус" - until: "До:" loading: "Загрузка..." errors: prev_page: "при попытке загрузки" @@ -1825,6 +1828,8 @@ ru: enabled: "Сайт работает в режиме \"только для чтения\". Сейчас вы можете продолжать просматривать сайт, но другие действия будут недоступны." login_disabled: "Вход отключён, пока сайт находится в режиме «только для чтения»" logout_disabled: "Выход отключён, пока сайт находится в режиме «только для чтения»" + staff_writes_only_mode: + enabled: "Сайт находится в режиме 'только для персонала'. Пожалуйста, продолжайте просмотр, но отвечать, выражать симпатии и выполнять другие действия, влияющие на контент, могут только сотрудники." too_few_topics_and_posts_notice_MF: >- Давайте приступим к обсуждению! Есть {currentTopics, plural, one {# тема} few {# темы} other {# тем}} и {currentPosts, plural, one {# сообщение} few {# сообщения} other {# сообщений}}. Пользователи должны больше читать и отвечать – мы рекомендуем по крайней мере {requiredTopics, plural, one {# тему} few {# темы} other {# тем}} и {requiredPosts, plural, one {# сообщение} few {# сообщения} other {# сообщений}}. Только сотрудники могут видеть это сообщение. too_few_topics_notice_MF: >- @@ -2231,6 +2236,7 @@ ru: abandon: "Закрыть редактор и отменить черновик" enter_fullscreen: "Включить полноэкранный режим редактора" exit_fullscreen: "Выключить полноэкранный режима редактора" + exit_fullscreen_prompt: "Нажмите ESC для выхода из полноэкранного режима" show_toolbar: "Отобразить панель инструментов редактора" hide_toolbar: "Скрыть панель инструментов редактора" modal_ok: "OK" @@ -2298,6 +2304,7 @@ ru: post_approved: "Ваше сообщение было одобрено" reviewable_items: "Сообщения, требующие рассмотрения" watching_first_post_label: "Новая тема" + user_moved_post: "%{username} - перемещено" mentioned: "%{username} %{description}" group_mentioned: "%{username} %{description}" quoted: "%{username} %{description}" @@ -2355,6 +2362,11 @@ ru: few: "Вы уверены? У вас %{count} непрочитанных напоминания о закладках." many: "Вы уверены? У вас %{count} непрочитанных напоминаний о закладках." other: "Вы уверены? У вас %{count} непрочитанных напоминаний о закладках." + messages: + one: "Вы уверены? У вас %{count} непрочитанное личное сообщение." + few: "Вы уверены? У вас %{count} непрочитанных личных сообщения." + many: "Вы уверены? У вас %{count} непрочитанных личных сообщений." + other: "Вы уверены? У вас %{count} непрочитанных личных сообщений." dismiss: "Пометить прочитанными" cancel: "Нет" group_message_summary: @@ -2375,30 +2387,30 @@ ru: confirm_body: "Уведомления были успешно включены." custom: "Уведомления от пользователя %{username} на сайте %{site_title}" titles: - mentioned: "Упомянутый" + mentioned: "Упомянут" replied: "Новый ответ" - quoted: "цитируемый" - edited: "отредактированный" + quoted: "Процитировано" + edited: "Отредактировано" liked: "Новая симпатия" private_message: "Новое личное сообщение" invited_to_private_message: "Приглашён в личное сообщение" invitee_accepted: "Приглашение принято" posted: "Новое сообщение" moved_post: "Сообщение перемещено" - linked: "связанный" + linked: "Связано" bookmark_reminder: "Напоминание о закладке" bookmark_reminder_with_name: "Напоминание о закладке - %{name}" - granted_badge: "награда получена" - invited_to_topic: "приглашён в тему" - group_mentioned: "упомянутая группа" - group_message_summary: "новые групповые сообщения" + granted_badge: "Получена награда" + invited_to_topic: "Приглашён в тему" + group_mentioned: "Упомянута группа" + group_message_summary: "Новые групповые сообщения" watching_first_post: "Новая тема" topic_reminder: "Напоминание о теме" - liked_consolidated: "новые симпатии" + liked_consolidated: "Новые симпатии" post_approved: "Сообщение утверждено" - membership_request_consolidated: "новые запросы на вступление" - reaction: "новая реакция" - votes_released: "Голосование было опубликовано" + membership_request_consolidated: "Новые запросы на членство" + reaction: "Новая реакция" + votes_released: "Голосование опубликовано" upload_selector: uploading: "Загрузка" processing: "Обработка загружаемого контента" @@ -2531,7 +2543,7 @@ ru: aria_label: Фильтр по максимальному количеству просмотров additional_options: label: "Фильтр по количеству сообщений и просмотров тем" - hamburger_menu: "системное меню" + hamburger_menu: "Меню" new_item: "новый" go_back: "вернуться" not_logged_in_user: "страница пользователя с историей его последней активности и настроек" @@ -2539,16 +2551,69 @@ ru: view_all: "Просмотреть все %{tab}" user_menu: generic_no_items: "Нет элементов в списке." - sr_menu_tabs: "Вкладки меню" + sr_menu_tabs: "Вкладки меню пользователя" view_all_notifications: "Просмотреть все уведомления" view_all_bookmarks: "Просмотреть все закладки" + view_all_messages: "Просмотреть все личные сообщения" + tabs: + all_notifications: "Все уведомления" + replies: "Ответы" + replies_with_unread: + one: "Ответы - %{count} непрочитанный ответ" + few: "Ответы - %{count} непрочитанных ответа" + many: "Ответы - %{count} непрочитанных ответов" + other: "Ответы - %{count} непрочитанных ответов" + mentions: "Упоминания" + mentions_with_unread: + one: "Упоминания - %{count} непрочитанное упоминание" + few: "Упоминания - %{count} непрочитанных упоминания" + many: "Упоминания - %{count} непрочитанных упоминаний" + other: "Упоминания - %{count} непрочитанных упоминаний" + likes: "Симпатии" + likes_with_unread: + one: "Симпатии - %{count} непрочитанное сообщение" + few: "Симпатии - %{count} непрочитанных сообщения" + many: "Симпатии - %{count} непрочитанных сообщений" + other: "Симпатии - %{count} непрочитанных сообщений" + watching: "Наблюдаемые темы" + watching_with_unread: + one: "Наблюдаемые темы - %{count} непрочитанная тема" + few: "Наблюдаемые темы - %{count} непрочитанных темы" + many: "Наблюдаемые темы - %{count} непрочитанных тем" + other: "Наблюдаемые темы - %{count} непрочитанных тем" + messages: "Личные сообщения" + messages_with_unread: + one: "Личные сообщения - %{count} непрочитанное сообщение" + few: "Личные сообщения - %{count} непрочитанных сообщения" + many: "Личные сообщения - %{count} непрочитанных сообщений" + other: "Личные сообщения - %{count} непрочитанных сообщений" + bookmarks: "Закладки" + bookmarks_with_unread: + one: "Закладки - %{count} непрочитанная закладка" + few: "Закладки - %{count} непрочитанных закладки" + many: "Закладки - %{count} непрочитанных закладок" + other: "Закладки - %{count} непрочитанных закладок" + review_queue: "Премодерация" + review_queue_with_unread: + one: "Премодерация – %{count} элемент требует проверки" + few: "Премодерация – %{count} элемента требуют проверки" + many: "Премодерация – %{count} элементов требуют проверки" + other: "Премодерация – %{count} элементов требуют проверки" + other_notifications: "Другие уведомления" + other_notifications_with_unread: + one: "Другие уведомления - %{count} непрочитанное уведомление" + few: "Другие уведомления - %{count} непрочитанных уведомления" + many: "Другие уведомления - %{count} непрочитанных уведомлений" + other: "Другие уведомления - %{count} непрочитанных уведомлений" + profile: "Профиль" reviewable: view_all: "Просмотреть все сообщения, находящиеся на премодерации" queue: "Очередь" deleted_user: "(удалённый пользователь)" + deleted_post: "(удалённое сообщение)" post_number_with_topic_title: "Cообщение #%{post_number} - %{title}" new_post_in_topic: "Новое сообщение в теме %{title}" - suspicious_user: "Подозрительный пользователь: %{username}" + user_requires_approval: "Пользователь %{username} требует одобрения" default_item: "Премодерируемый элемент #%{reviewable_id}" topics: new_messages_marker: "последний визит" @@ -3284,7 +3349,7 @@ ru: other: "Вы действительно хотите удалить %{count} сообщений?" merge: confirm: - one: "Вы действительно хотите объединить эти сообщения?" + one: "Вы действительно хотите объединить это %{count} сообщение?" few: "Вы действительно хотите объединить эти %{count} сообщения?" many: "Вы действительно хотите объединить эти %{count} сообщений?" other: "Вы действительно хотите объединить эти %{count} сообщений?" @@ -3735,6 +3800,7 @@ ru: today: "За сегодня" other_periods: "Просмотреть самые обсуждаемые:" browser_update: 'К сожалению, ваш браузер безнадёжно устарел . Пожалуйста, обновите его для полноценной работы с сайтом.' + safari_13_warning: Этот сайт скоро прекратит поддержку iOS и Safari версии 13 и ниже. Упрощённая версия только для чтения останется доступной. (больше информации) permission_types: full: "Создавать / Отвечать / Просматривать" create_post: "Отвечать / Просматривать" @@ -3784,7 +3850,7 @@ ru: title: "Форум" create: "%{shortcut} Создать тему" notifications: "%{shortcut} Открыть уведомления" - hamburger_menu: "%{shortcut} Открыть системное меню" + hamburger_menu: "%{shortcut} Открыть меню" user_profile_menu: "%{shortcut} Открыть меню профиля" show_incoming_updated_topics: "%{shortcut} Показать обновлённые темы" search: "%{shortcut} Поиск" @@ -4072,14 +4138,14 @@ ru: user_activity: no_activity_title: "Пока нет активности" no_activity_body: "Добро пожаловать в наше сообщество! Вы здесь пока новичок и ещё не участвовали в обсуждениях. Для начала посмотрите самые обсуждаемые темы или ознакомьтесь с разделами форума! Отметьте наиболее полезные или понравившиеся сообщения значком %{heartIcon}. Статистика Вашей активности будет отображаться на этой странице." - no_activity_others: "Нет активности." no_replies_title: "Вы пока не ответили ни на какие сообщения" - no_replies_others: "Нет ответов." + no_replies_title_others: "Пользователь %{username} ещё не ответил ни в одной теме" + no_replies_body: "Когда вы обнаружите интересную дискуссию, в которую хотите внести свой вклад, нажмите кнопку Ответить прямо под интересующим вас сообщением, чтобы ответить непосредственно на это сообщение. Или, если вы предпочитаете ответить на тему в целом, а не на отдельное сообщение или конкретному пользователю - нажмите на кнопку Ответить, расположенную в нижней части темы или справа, под шкалой времени." no_drafts_title: "У вас нет черновиков" no_drafts_body: "Не готовы опубликовать сообщение? При создании темы, ответа или личного сообщения мы автоматически сохраним текст как черновик и отобразим его здесь. Нажмите кнопку отмены, если необходимо отменить сохранение текста, или вернитесь к сохранённому черновику позже, чтобы продолжить создание сообщения." no_likes_title: "Вы пока ещё не выражали симпатий на этом форуме." + no_likes_title_others: "Пользователь %{username} ещё не выразил ни одной симпатии" no_likes_body: "Отличный способ принять участие и внести свой вклад - это начать читать обсуждения, и отмечать значком %{heartIcon} сообщения, которые вам понравились!" - no_likes_others: "Симпатий пока нет." no_topics_title: "Вы пока ещё не начали ни одной темы" no_topics_body: "Всегда лучше поискать интересующий вас ответ в уже существующих темах, прежде чем начинать новую, но если вы уверены, что нужной вам темы всё же нет - создайте новую. Нажмите кнопку + Создать тему, расположенную в правом верхнем углу списка тем, разделов или тегов, чтобы начать создание новой темы." no_topics_title_others: "Пользователь %{username} ещё не создал ни одной темы" @@ -4106,9 +4172,12 @@ ru: other: "%{count} непрочитанных" toggle_section: "Переключить секцию" more: "Ещё..." + all_categories: "Все разделы" + all_tags: "Все теги" sections: + about: + header_link_text: "О форуме" messages: - header_link_title: "Личные сообщения" header_link_text: "Личные сообщения" header_action_title: "Создать личное сообщение" links: @@ -4122,25 +4191,30 @@ ru: tags: none: "Вы не добавили ни одного тега." click_to_get_started: "Нажмите здесь, чтобы начать." - header_link_title: "Все теги" header_link_text: "Теги" header_action_title: "Редактировать теги боковой панели" categories: none: "Вы не добавили ни одного раздела." click_to_get_started: "Нажмите здесь, чтобы начать." - header_link_title: "Все разделы" header_link_text: "Разделы" header_action_title: "Редактировать разделы боковой панели" community: - header_link_title: "Темы" header_link_text: "Сообщество" header_action_title: "Cоздать новую тему" links: + about: + content: "О форуме" + admin: + content: "Админка" + badges: + content: "Награды" everything: content: "Все" title: "Все темы" + faq: + content: "Правила" tracked: - content: "Следящие" + content: "Отслеживаемые" title: "Все отслеживаемые темы" groups: content: "Группы" @@ -4156,6 +4230,11 @@ ru: few: "%{count} черновика" many: "%{count} черновиков" other: "%{count} черновиков" + welcome_topic_banner: + title: "Создать приветственную тему" + description: 'Ваша приветственная тема — это первое, что прочитают новички. Постарайтесь одним абзацем выразить наиболее важную информацию, которую вы хотите донести до новых пользователей форума.' + button_title: "Начать редактирование" + until: "До:" admin_js: type_to_filter: "Фильтрация настроек..." admin: @@ -4723,6 +4802,8 @@ ru: import_web_advanced: "Дополнительно..." import_file_tip: "Файл с расширением .tar.gz, .zip, или .dcstyle.json, содержащий тему" is_private: "Тема находится в приватном git-репозитории" + finish_install: "Завершить установку темы" + last_attempt: "Процесс установки не завершен, последняя попытка:" remote_branch: "Имя ветки (необязательно)" public_key: "Предоставьте доступ к репозиторию со следующим открытым ключом:" public_key_note: "После ввода корректного URL-адреса приватного репозитория, будет сгенерирован ключ SSH, который будет отображаться здесь." @@ -4733,6 +4814,8 @@ ru: install_git_repo: "Из git-репозитория" install_create: "Создать новую" duplicate_remote_theme: "Компонент темы «%{name}» уже установлен. Вы действительно хотите установить ещё одну копию?" + force_install: "Невозможно установить тему, так как репозиторий Git недоступен. Вы действительно хотите продолжить установку?" + create_placeholder: "Создать заполнитель" about_theme: "О теме" license: "Лицензия" version: "Версия:" @@ -5262,6 +5345,7 @@ ru: suspended: "Заморожен?" staged: "Имитация?" show_admin_profile: "Администратор" + manage_user: "Управление пользователем" show_public_profile: "Показать публичный профиль" impersonate: "Представиться как пользователь" action_logs: "Журнал действий" @@ -5365,7 +5449,8 @@ ru: few: "Не удаётся удалить все сообщения, потому что у пользователя более %{count} сообщений. (Настройка delete_all_posts_max.)" many: "Не удаётся удалить все сообщения, потому что у пользователя более %{count} сообщений. (Настройка delete_all_posts_max.)" other: "Не удаётся удалить все сообщения, потому что у пользователя более %{count} сообщений. (Настройка delete_all_posts_max.)" - delete_confirm: "Обычно предпочтительнее анонимизировать пользователей, чем удалять их, чтобы избежать удаления контента из существующих обсуждений.

    Вы действительно хотите удалить этого пользователя? Это навсегда!" + delete_confirm_title: "Вы ДЕЙСТВИТЕЛЬНО хотите удалить этого пользователя? Этот пользователь будет удалён безвозвратно!" + delete_confirm: "Как правило, предпочтительнее анонимизировать пользователей, а не удалять их, чтобы избежать удаления контента из существующих обсуждений." delete_and_block: "Удалить и заблокировать этот Email и IP-адрес" delete_dont_block: "Только удалить" deleting_user: "Удаление пользователя ..." @@ -5498,7 +5583,6 @@ ru: recommended: "Мы рекомендуем изменить текст этих шаблонов под ваши требования:" show_overriden: "Показывать только изменённые значения" locale: "Язык:" - fallback_locale_warning: "Вы редактируете язык на основе %{fallback}. Пользователи, выбравшие %{fallback} в качестве языка интерфейса, не увидят ваши изменения." more_than_50_results: "Найдено более 50 результатов. Пожалуйста, уточните параметры поиска." settings: show_overriden: "Показывать только изменённые значения" diff --git a/config/locales/client.sk.yml b/config/locales/client.sk.yml index b9fe03ff1e..c425e3d007 100644 --- a/config/locales/client.sk.yml +++ b/config/locales/client.sk.yml @@ -184,11 +184,11 @@ sk: banner: enabled: "Téma je odteraz baner %{when} Bude sa zobrazovať navrchu každej stránky, pokiaľ ju používateľ nezavrie." disabled: "odstránil(a) tento oznam %{when}. Už sa viac nebude zobrazovať navrchu každej stránky." - wizard_required: "Vitajte vo vašom novom Discourse! Začnime so sprievodcom nastavením✨ " emails_are_disabled: "Odosielanie emailov bolo globálne vypnuté administrátorom. Žiadne emailové notifikácie nebudú odoslané." software_update_prompt: dismiss: "Zahodiť" bootstrap_mode_disabled: "Zavádzací režim bude zrušený v priebehu nasledujúcich 24 hodín." + bootstrap_invite_button_title: "Poslať pozvánky" themes: default_description: "Predvolené" s3: @@ -213,6 +213,8 @@ sk: not_implemented: "Ľutujeme, táto funkcia ešte nie je implementovaná." no_value: "Nie" yes_value: "Áno" + ok_value: "OK" + cancel_value: "Zrušiť" submit: "Odoslať" generic_error: "Ľutujeme, nastala chyba." generic_error_with_reason: "Nastala chyba: %{error}" @@ -1411,6 +1413,13 @@ sk: go_back: "späť" not_logged_in_user: "používateľská stránka so súhrnom aktivít a nastavení" current_user: "prejsť na Vašu používateľskú stránku" + user_menu: + tabs: + replies: "Odpovede" + mentions: "Zmienky" + likes: "Rozdaných 'páči sa mi'" + bookmarks: "Záložky" + profile: "Profil" topics: new_messages_marker: "posledná návševa" bulk: @@ -2203,7 +2212,6 @@ sk: download_calendar: download: "Stiahnuť" tagging: - all_tags: "Všetky štítky" selector_all_tags: "všetky štítky" selector_no_tags: "žiadne štítky" changed: "zmenené štítky:" @@ -2267,8 +2275,6 @@ sk: member: "člen" regular: "bežný" leader: "vodca" - user_activity: - no_activity_others: "Žiadna aktivita" sidebar: unread_count: one: "%{count} neprečítaná" @@ -2281,7 +2287,10 @@ sk: many: "%{count} nových" other: "%{count} nových" more: "Viac ..." + all_categories: "Všetky kategórie" sections: + about: + header_link_text: "O stránke" messages: header_link_text: "Správy" links: @@ -2293,15 +2302,20 @@ sk: unread_with_count: "Neprečítaná (%{count})" archive: "Archív" tags: - header_link_title: "všetky štítky" header_link_text: "Štítky" categories: - header_link_title: "všetky kategórie" header_link_text: "Kategórie" community: - header_link_title: "domov" header_link_text: "Komunita" links: + about: + content: "O stránke" + admin: + content: "Administrátor" + badges: + content: "Odznaky" + faq: + content: "Časté otázky" tracked: content: "Pozorované" groups: diff --git a/config/locales/client.sl.yml b/config/locales/client.sl.yml index 0dac944313..3fa7687027 100644 --- a/config/locales/client.sl.yml +++ b/config/locales/client.sl.yml @@ -200,11 +200,11 @@ sl: disabled: "je odstranil ta oglasni trak %{when}. Ne bo se več pojavljal na vrhu vsake strani." forwarded: "zgoraj navedeno sporočilo je bilo posredovano" topic_admin_menu: "dejanja teme" - wizard_required: "Dobrodošli v vašem novem Discoursu! Začnimo s čarovnikom za nastavitve ✨" emails_are_disabled: "Vsa odhodna e-pošta je bila globalno onemogočena iz strani administratorja. E-poštna obvestila ne bodo poslana." software_update_prompt: dismiss: "Opusti" bootstrap_mode_disabled: "Zagonski način bo onemogočen v 24 urah." + bootstrap_invite_button_title: "Pošlji povabila" themes: default_description: "Privzeto" s3: @@ -235,6 +235,8 @@ sl: not_implemented: "Oprosti, ta funkcija še ni bila implementirana!" no_value: "Ne" yes_value: "Da" + ok_value: "V redu" + cancel_value: "Prekliči" submit: "Išči" generic_error: "Ups, prišlo je do napake." generic_error_with_reason: "Napaka: %{error}" @@ -2111,6 +2113,13 @@ sl: go_back: "pojdi nazaj" not_logged_in_user: "stran uporabnika s povzetkom trenutnih aktivnosti in nastavitev" current_user: "pojdi na svojo uporabniško stran" + user_menu: + tabs: + replies: "Odgovori" + mentions: "Omembe" + likes: "Dani všečki" + bookmarks: "Zaznamki" + profile: "Profil" topics: new_messages_marker: "zadnji obisk" bulk: @@ -2709,12 +2718,6 @@ sl: two: "Ali ste prepričani da hočete izbrisati ta %{count} prispevka?" few: "Ali ste prepričani da hočete izbrisati te %{count} prispevke?" other: "Ali ste prepričani da hočete izbrisati teh %{count} prispevkov?" - merge: - confirm: - one: "Ali ste prepričani da hočete združiti ta %{count} prispevek?" - two: "Ali ste prepričani da hočete združiti ta %{count} prispevka?" - few: "Ali ste prepričani da hočete združiti te %{count} prispevke?" - other: "Ali ste prepričani da hočete združiti teh %{count} prispevkov?" revisions: controls: first: "Prva verzija" @@ -3231,7 +3234,6 @@ sl: download_calendar: download: "Naloži" tagging: - all_tags: "Vse oznake" other_tags: "Druge oznake" selector_all_tags: "vse oznake" selector_no_tags: "brez oznak" @@ -3388,7 +3390,10 @@ sl: few: "%{count} nove" other: "%{count} novih" more: "Več..." + all_categories: "Vse kategorije" sections: + about: + header_link_text: "O nas" messages: header_link_text: "Sporočila" links: @@ -3400,15 +3405,20 @@ sl: unread_with_count: "Neprebrana (%{count})" archive: "Arhiv" tags: - header_link_title: "vse oznake" header_link_text: "Oznake" categories: - header_link_title: "vse kategorije" header_link_text: "Kategorije" community: - header_link_title: "domov" header_link_text: "Skupnost" links: + about: + content: "O nas" + admin: + content: "Admin" + badges: + content: "Značke" + faq: + content: "Pravila skupnosti" tracked: content: "Sledim" groups: @@ -4062,7 +4072,6 @@ sl: two: "Uporabnik ne more biti izbrisan, če ima prispevke. Izbrišite vse prispevke preden izbrišete uporabnika. (Prispevki starejši od %{count} dni ne morejo biti izbrisani.)" few: "Uporabnik ne more biti izbrisan, če ima prispevke. Izbrišite vse prispevke preden izbrišete uporabnika. (Prispevki starejši od %{count} dni ne morejo biti izbrisani.)" other: "Uporabnik ne more biti izbrisan, če ima prispevke. Izbrišite vse prispevke preden izbrišete uporabnika. (Prispevki starejši od %{count} dni ne morejo biti izbrisani.)" - delete_confirm: "Navadno je bolj primerno da se uporabnike anonimizira in ne izbriše, ker se z brisanjem odstrani tudi vsebina iz obstoječih razprav.

    Ali ste PREPRIČANI da hočete odstraniti tega uporabnika? To dejanje je trajno!" delete_and_block: "Izbriši in blokiraj ta e-naslov in IP naslov" delete_dont_block: "Samo izbriši" deleted: "Ta uporabnik je bil izbrisan" @@ -4170,7 +4179,6 @@ sl: go_back: "Nazaj na iskalnik" show_overriden: "Prikaži samo preglašene/spremenjene" locale: "Jezik:" - fallback_locale_warning: "Urejate jezik ki temelji na %{fallback}. Uporabniki, ki za jezik vmesnika izberejo %{fallback} ne bodo videli sprememb." more_than_50_results: "Našli smo več kot 50 zadetkov. Določite bolj natančno iskalne kriterije." settings: show_overriden: "Prikaži samo preglašene/spremenjene" diff --git a/config/locales/client.sq.yml b/config/locales/client.sq.yml index df143dee42..4d3bfedd9d 100644 --- a/config/locales/client.sq.yml +++ b/config/locales/client.sq.yml @@ -136,10 +136,10 @@ sq: visible: enabled: "listuar %{when}" disabled: "çlistuar %{when}" - wizard_required: "Mirseerdhët tek faqja juaj e re Discourse! Le t'ia nisim me \"setup wizard\" ✨" emails_are_disabled: "Emailat janë çaktivizuar globalisht nga administratori i faqes. Asnjë njoftim me email nuk do të dërgohet. " software_update_prompt: dismiss: "Hiqe" + bootstrap_invite_button_title: "Dërgo ftesa" themes: default_description: "Paracaktuar" s3: @@ -161,6 +161,8 @@ sq: not_implemented: "Kjo veçori nuk është implementuar akoma, na vjen keq!" no_value: "Jo" yes_value: "Po" + ok_value: "OK" + cancel_value: "Anulo" generic_error: "Na vjen keq, por sapo ndodhi një gabim." generic_error_with_reason: "Pati një gabim: %{error}" sign_up: "Regjistrohu" @@ -1141,6 +1143,13 @@ sq: go_back: "kthehu mbrapa" not_logged_in_user: "faqja e përdoruesit me një përmbledhje të aktivitetit dhe preferencave" current_user: "shko tek profili yt" + user_menu: + tabs: + replies: "Përgjigjet" + mentions: "Përmendje" + likes: "Pëlqimet" + bookmarks: "Të preferuarat" + profile: "Profili" topics: new_messages_marker: "vizita e fundit" bulk: @@ -1862,7 +1871,6 @@ sq: download_calendar: download: "Shkarko" tagging: - all_tags: "Të gjitha etiketat" selector_all_tags: "të gjitha etiketat" selector_no_tags: "asnjë etiketë" changed: "etiketat e ndryshuara:" @@ -1938,7 +1946,10 @@ sq: one: "%{count} e re" other: "%{count} të reja" more: "Më shuMë..." + all_categories: "Të gjitha kategoritë" sections: + about: + header_link_text: "Rreth" messages: header_link_text: "Mesazhet" links: @@ -1950,15 +1961,20 @@ sq: unread_with_count: "Të palexuara (%{count})" archive: "Arkivi" tags: - header_link_title: "të gjitha etiketat" header_link_text: "Etiketat" categories: - header_link_title: "kategoritë" header_link_text: "Categories" community: - header_link_title: "kryefaqja" header_link_text: "Komuniteti" links: + about: + content: "Rreth" + admin: + content: "Admin" + badges: + content: "Stemat" + faq: + content: "Pyetje të shpeshta" tracked: content: "Gjurmuar" groups: diff --git a/config/locales/client.sr.yml b/config/locales/client.sr.yml index dfe7162837..516b0b9261 100644 --- a/config/locales/client.sr.yml +++ b/config/locales/client.sr.yml @@ -188,7 +188,6 @@ sr: disabled: "je uklonio ovaj baner%{when}. Više se neće pojavljivati na vrhu svake stranice." forwarded: "je prosledio/la navedenu e-poštu" topic_admin_menu: "opcije teme" - wizard_required: "Dobrodošli na Vaš novi Discourse! Počnimo sa instalacijom" emails_are_disabled: "Sva odlazeća epošta je onemogućena globalno od strane administratora. Ni jedna notifikacija neće biti poslata." software_update_prompt: message: "Ažurirali smo ovaj sajt, molimo vas rifrešujte, u suprotnom može doći do nepredviđenih rezultata." @@ -225,6 +224,8 @@ sr: not_implemented: "Ova stavka nije jos omogućena za sad, izvinjavamo se." no_value: "Ne" yes_value: "Da" + ok_value: "U redu" + cancel_value: "Odustani" submit: "Potvrdi" generic_error: "Izvinite, pojavila se greška." generic_error_with_reason: "Došlo je do greške: %{error}" @@ -1182,6 +1183,13 @@ sr: go_back: "idi nazad" not_logged_in_user: "stranica korisnika sa sažetkom trenutnih aktivnosti i postavki" current_user: "idi na korisničku stranicu" + user_menu: + tabs: + replies: "Odgovori" + mentions: "Spominjanja" + likes: "Lajkova" + bookmarks: "Markiraj" + profile: "Profil" topics: new_messages_marker: "poslednja poseta" bulk: @@ -1811,6 +1819,8 @@ sr: other: "%{count} nova" more: "Više..." sections: + about: + header_link_text: "O nama" messages: header_link_text: "Poruke" links: @@ -1822,12 +1832,18 @@ sr: unread_with_count: "Nepročitane (%{count})" archive: "Arhiviraj" categories: - header_link_title: "sve kategorije" header_link_text: "Kategorije" community: - header_link_title: "home" header_link_text: "Zajednica" links: + about: + content: "O nama" + admin: + content: "Admin" + badges: + content: "Značke" + faq: + content: "FAQ (često postavljana pitanja)" tracked: content: "Praćeno" groups: diff --git a/config/locales/client.sv.yml b/config/locales/client.sv.yml index f52ba93c0b..d6b2d23e57 100644 --- a/config/locales/client.sv.yml +++ b/config/locales/client.sv.yml @@ -179,7 +179,6 @@ sv: forwarded: "vidarebefordrade ovanstående e-post" topic_admin_menu: "ämnesåtgärder" skip_to_main_content: "Hoppa till huvudinnehållet" - wizard_required: "Välkommen till din nya Discourse! Låt oss komma igång med hjälp av konfigureringsguiden ✨" emails_are_disabled: "All utgående e-post har blivit globalt inaktiverad av en administratör. Inga e-postaviseringar av något slag kommer att skickas ut." emails_are_disabled_non_staff: "Utgående e-post har inaktiverats för användare som inte är anställda." software_update_prompt: @@ -189,6 +188,8 @@ sv: one: "Du är i bootstrap-läge för att göra lanseringen av din nya webbplats enklare. Alla nya användare kommer att beviljas förtroendenivå 1 och få dagliga sammanfattningar skickade via e-post. Det här stängs automatiskt av när antalet användare når %{count}." other: "Du är i bootstrap-läge för att göra lanseringen av din nya webbplats enklare. Alla nya användare kommer att beviljas förtroendenivå 1 och få dagliga sammanfattningar skickade via e-post. Det här stängs automatiskt av när antalet användare når %{count}." bootstrap_mode_disabled: "Bootstrap-läge stängs av om 24 timmar." + bootstrap_invite_button_title: "Skicka inbjudningar" + bootstrap_wizard_link_title: "Slutför installationsguiden" themes: default_description: "Standard" broken_theme_alert: "Din webbplats kanske inte fungerar eftersom ett tema / komponent har fel." @@ -225,6 +226,8 @@ sv: not_implemented: "Denna funktion har tyvärr inte implementerats än!" no_value: "Nej" yes_value: "Ja" + ok_value: "OK" + cancel_value: "Avbryt" submit: "Skicka" generic_error: "Tyvärr, ett fel har inträffat." generic_error_with_reason: "Ett fel inträffade: %{error}" @@ -1052,6 +1055,8 @@ sv: dismiss: "Avfärda" dismiss_notifications: "Avfärda alla" dismiss_notifications_tooltip: "Markera alla olästa aviseringar som lästa" + dismiss_bookmarks_tooltip: "Markera alla olästa bokmärkespåminnelser som lästa" + dismiss_messages_tooltip: "Markera alla olästa personliga meddelanden som lästa" no_messages_title: "Du har inga meddelanden" no_messages_body: > Behöver du ha en direkt personlig konversation med någon, utanför det normala konversationsflödet? Meddela dem genom att klicka på deras avatar och använd %{icon} meddelandeknappen.

    Om du behöver hjälp kan du meddela någon ur personalen. @@ -1649,7 +1654,6 @@ sv: set_custom_status: "Ställ in anpassad status" what_are_you_doing: "Vad gör du?" remove_status: "Ta bort status" - until: "T.o.m.:" loading: "Laddar..." errors: prev_page: "medan vi försökte ladda" @@ -1713,7 +1717,6 @@ sv: hide_forever: "nej tack" hidden_for_session: "Ok, vi frågar dig imorgon. Du kan alltid använda 'Logga in' för att skapa ett konto, också." intro: "Hejsan! Det verkar som du gillar diskussionen, men du har ännu inte registrerat dig för ett konto." - value_prop: "Trött på att bläddra igenom samma inlägg? när du skapar ett konto kommer du alltid tillbaka där du slutade. Med ett konto kan du också bli notifierad om nya svar, spara bokmärken och använda gillningar för att tacka andra. Vi kan alla arbeta tillsammans för att göra denna gemenskap fantastisk. :heart:" summary: enabled_description: "Sammanfattning över de inlägg som användarna tycker är mest intressanta." description: @@ -2058,6 +2061,7 @@ sv: abandon: "stäng skaparen och kasta utkast" enter_fullscreen: "skaparen i helskärm" exit_fullscreen: "avsluta helskärmsläge för skaparen" + exit_fullscreen_prompt: "Tryck på ESC för att lämna helskärmsläget" show_toolbar: "visa redigerarens verktygsfält" hide_toolbar: "dölj redigerarens verktygsfält" modal_ok: "OK" @@ -2162,6 +2166,12 @@ sv: default: one: "Är du säker? Du har %{count} viktig avisering." other: "Är du säker? Du har %{count} viktiga aviseringar." + bookmarks: + one: "Är du säker? Du har %{count} oläst bokmärkespåminnelse." + other: "Är du säker? Du har %{count} olästa bokmärkespåminnelser." + messages: + one: "Är du säker? Du har %{count} oläst personligy meddelande." + other: "Är du säker? Du har %{count} olästa personliga meddelanden." dismiss: "Avfärda" cancel: "Avbryt" group_message_summary: @@ -2342,15 +2352,53 @@ sv: view_all: "visa alla %{tab}" user_menu: generic_no_items: "Det finns inga objekt i den här listan." - sr_menu_tabs: "Menyflikar" + sr_menu_tabs: "Flikar i användarmenyn" view_all_notifications: "visa alla aviseringar" + view_all_bookmarks: "visa alla bokmärken" + view_all_messages: "visa alla personliga meddelanden" + tabs: + all_notifications: "Alla aviseringar" + replies: "Svar" + replies_with_unread: + one: "Svar - %{count} oläst svar" + other: "Svar - %{count} olästa svar" + mentions: "Omnämnanden" + mentions_with_unread: + one: "Omnämnanden - %{count} oläst omnämnande" + other: "Omnämnanden - %{count} olästa omnämnanden" + likes: "Gillar" + likes_with_unread: + one: "Gillningar - %{count} oläst gillning" + other: "Gillningar - %{count} olästa gillningar" + watching: "Bevakade ämnen" + watching_with_unread: + one: "Bevakade ämnen - %{count} oläst bevakat ämne" + other: "Bevakade ämnen - %{count} olästa bevakade ämnen" + messages: "Personliga meddelanden" + messages_with_unread: + one: "Personliga meddelanden - %{count} oläst meddelande" + other: "Personliga meddelanden - %{count} olästa meddelanden" + bookmarks: "Bokmärken" + bookmarks_with_unread: + one: "Bokmärken - %{count} oläst bokmärke" + other: "Bokmärken - %{count} olästa bokmärken" + review_queue: "Granskningskö" + review_queue_with_unread: + one: "Granskningskö - %{count} objekt behöver granskas" + other: "Granskningskö - %{count} objekt behöver granskas" + other_notifications: "Andra aviseringar" + other_notifications_with_unread: + one: "Andra aviseringar - %{count} oläst avisering" + other: "Andra aviseringar - %{count} olästa aviseringar" + profile: "Profil" reviewable: view_all: "visa alla granskningsobjekt" queue: "Kö" deleted_user: "(raderad användare)" + deleted_post: "(raderat inlägg)" post_number_with_topic_title: "inlägg nr %{post_number} - %{title}" new_post_in_topic: "nytt inlägg i %{title}" - suspicious_user: "misstänkt användare %{username}" + user_requires_approval: "%{username} kräver godkännande" default_item: "granskningsbart objekt nr %{reviewable_id}" topics: new_messages_marker: "senaste besök" @@ -2999,7 +3047,7 @@ sv: merge: confirm: one: "Är du säker på att du vill slå ihop dessa inlägg?" - other: "Är du säker på att du vill sammanfoga de %{count} inläggen?" + other: "Är du säker på att du vill slå ihop dessa %{count} inlägg?" revisions: controls: first: "Första version" @@ -3417,6 +3465,7 @@ sv: today: "Idag" other_periods: "se toppen för:" browser_update: 'Tyvärr stöds inte din webbläsare. Vänligen byt till en webbläsare som stöds för att se innehåll, logga in och svara.' + safari_13_warning: Den här webbplatsens stöd för iOS och Safari i version 13 och äldre avlägsnas inom kort. En förenklad skrivskyddad version kommer att förbli tillgänglig. (mer information) permission_types: full: "Skapa / svara / se" create_post: "Svara / se" @@ -3728,14 +3777,14 @@ sv: user_activity: no_activity_title: "Ingen aktivitet än" no_activity_body: "Välkommen till vårt forum! Du är helt ny här och har ännu inte bidragit i diskussioner. Du kan börja med att gå till Topp eller Kategorier och sätta igång att läsa! Välj %{heartIcon} på inlägg som du gillar eller vill lära dig mer om. I takt med att du deltar kommer din aktivitet att visas här." - no_activity_others: "Ingen aktivitet." no_replies_title: "Du har inte svarat på några ämnen än" - no_replies_others: "Inga svar." + no_replies_title_others: "%{username} har inte svarat på några ämnen ännu" + no_replies_body: "När du upptäcker en intressant konversation som du vill bidra till trycker du på knappen Svara direkt under ett inlägg för att börja svara på det specifika inlägget. Om du föredrar att svara på det allmänna ämnet snarare än på ett enskilt inlägg eller en enskild person, kan du leta efter knappen Svara längst ner i ämnet eller under ämnets tidslinje." no_drafts_title: "Du har inte startat några utkast" no_drafts_body: "Inte riktigt redo att göra ett inlägg? Vi sparar automatiskt ett nytt utkast och visar det i listan här när du börjar skriva ett ämne, svar eller personligt meddelande. Välj avbryt-knappen för att ta bort eller spara ditt utkast för att fortsätta senare." no_likes_title: "Du har inte gillat några ämnen än" + no_likes_title_others: "%{username} har inte gillat några ämnen ännu" no_likes_body: "Ett bra sätt att hoppa in och börja bidra är att börja läsa samtal som redan har ägt rum, och välja %{heartIcon} på inlägg som du gillar!" - no_likes_others: "Inga gillade inlägg." no_topics_title: "Du har inte startat några ämnen än" no_topics_body: "Det är alltid bäst att söka efter befintliga samtalsämnen innan du startar ett nytt, men om du är säker på att ämnet du vill ha inte redan finns där, var så god och starta ett nytt eget ämne. Leta efter knappen + Nytt ämne längst upp till höger i ämneslistan, kategorin eller taggen för att börja skapa ett nytt ämne inom det området." no_topics_title_others: "%{username} har inte startat några ämnen än" @@ -3758,9 +3807,12 @@ sv: other: "%{count} nya" toggle_section: "växla avsnitt" more: "Mer..." + all_categories: "Alla kategorier" + all_tags: "Alla taggar" sections: + about: + header_link_text: "Om" messages: - header_link_title: "personliga meddelanden" header_link_text: "Meddelanden" header_action_title: "skapa ett personligt meddelande" links: @@ -3774,23 +3826,28 @@ sv: tags: none: "Du har inte lagt till några taggar." click_to_get_started: "Klicka här för att komma igång." - header_link_title: "alla taggar" header_link_text: "Taggar" header_action_title: "redigera sidofältets taggar" categories: none: "Du har inte lagt till några kategorier." click_to_get_started: "Klicka här för att komma igång." - header_link_title: "alla kategorier" header_link_text: "Kategorier" header_action_title: "redigera sidofältets kategorier" community: - header_link_title: "start" header_link_text: "Community" header_action_title: "skapa ett nytt ämne" links: + about: + content: "Om" + admin: + content: "Admin" + badges: + content: "Utmärkelser" everything: content: "Allting" title: "Alla ämnen" + faq: + content: "FAQ" tracked: content: "Följda" title: "Alla följda ämnen" @@ -3806,6 +3863,11 @@ sv: draft_count: one: "%{count} utkast" other: "%{count} utkast" + welcome_topic_banner: + title: "Skapa ditt välkomstämne" + description: 'Ditt välkomstämne är det första som nykomlingar läser. Tänk på det som din "snabbpresentation" eller "målbeskrivning" i ett enda stycke.' + button_title: "Börja redigera" + until: "T.o.m.:" admin_js: type_to_filter: "skriv för att filtrera..." admin: @@ -4363,6 +4425,8 @@ sv: import_web_advanced: "Avancerat..." import_file_tip: ".tar.gz-, .zip- eller .dcstyle.json-fil innehåller tema" is_private: "Temat är i en privat git-lagringsplats" + finish_install: "Slutför temainstallationen" + last_attempt: "Installationsprocessen slutfördes inte, det senaste försöket:" remote_branch: "Filialnamn (valfritt)" public_key: "Ge följande offentliga nyckel tillträde till lagringsplatsen:" public_key_note: "När du har angett en giltig privat lagringsplats URL ovan genereras det en SSH-nyckel som visas här." @@ -4373,6 +4437,8 @@ sv: install_git_repo: "Från en git-lagringsplats" install_create: "Skapa ny" duplicate_remote_theme: "Temakomponenten \"%{name}\" har redan installerats. Är du säker på att du vill installera ytterligare en kopia?" + force_install: "Temat kan inte installeras eftersom Git-arkivet är otillgängligt. Är du säker på att du vill fortsätta installera det?" + create_placeholder: "Skapa platshållare" about_theme: "Om" license: "Licens" version: "Version:" @@ -4906,6 +4972,7 @@ sv: suspended: "Avstängd?" staged: "Arrangerad?" show_admin_profile: "Administratör" + manage_user: "Hantera användare" show_public_profile: "Visa offentlig profil" impersonate: "Imitera" action_logs: "Åtgärdslogg" @@ -5003,7 +5070,8 @@ sv: cant_delete_all_too_many_posts: one: "Kan inte radera alla inlägg, då användaren har fler än %{count} inlägg. (delete_all_posts_max)" other: "Kan inte radera alla inlägg, då användaren har fler än %{count} inlägg. (delete_all_posts_max)" - delete_confirm: "Det är generellt att föredra att anonymisera användare snarare än att ta bort dem för att undvika att ta bort innehåll från befintliga diskussioner.

    Är du säker på att du vill ta bort den här användaren? Detta görs permanent!" + delete_confirm_title: "Är du SÄKER på att du vill radera den här användaren? Detta är permanent!" + delete_confirm: "I allmänhet är det att föredra att anonymisera användare istället för att radera dem, för att undvika att innehåll från befintliga diskussioner tas bort." delete_and_block: "Radera och blockera denna e-postadress och IP-adress" delete_dont_block: "Radera enbart" deleting_user: "Raderar användaren..." @@ -5134,7 +5202,6 @@ sv: recommended: "Vi rekommenderar att du anpassar följande texter:" show_overriden: "Visa bara överskrivna" locale: "Språk:" - fallback_locale_warning: "Du redigerar ett språk baserat på %{fallback}. Användare som väljer %{fallback} som sitt gränssnittsspråk kommer inte att se dina ändringar." more_than_50_results: "Det blev fler än 50 resultat. Förfina din sökning." settings: show_overriden: "Visa bara överskrivna" diff --git a/config/locales/client.sw.yml b/config/locales/client.sw.yml index e90cd198b5..bed55f4098 100644 --- a/config/locales/client.sw.yml +++ b/config/locales/client.sw.yml @@ -138,11 +138,11 @@ sw: banner: enabled: "aligeuza hili kuwa bango %{when}. Itaonekana juu ya kila ukurasa mpaka itakapo ondolewa na mtumiaji." disabled: "aliondoa hili bango %{when}. Halitaonekana tena juu ya kila ukurasa." - wizard_required: "Karibu Discourse! Tuanze na the setup wizard ✨" emails_are_disabled: "Utumaji wa barua pepe umezuiliwa na msimamizi. Hakuna taarifa za utumwaji wa barua pepe zitakazotumwa." software_update_prompt: dismiss: "Ondosha" bootstrap_mode_disabled: "Halitumizi ya Bootstrap itasitishwa baada ya masaa 24." + bootstrap_invite_button_title: "Tuma Mialiko" themes: default_description: "Halisi" s3: @@ -166,6 +166,8 @@ sw: not_implemented: "Samahani, kipengele hicho hakijatekelezwa bado." no_value: "Hapana" yes_value: "Ndiyo" + ok_value: "Vema" + cancel_value: "Ghairi" submit: "Wasilisha" generic_error: "Samahani, hitilafu imetokea." generic_error_with_reason: "Hitilafu imetokea: %{error}" @@ -1423,6 +1425,13 @@ sw: go_back: "rudi nyuma" not_logged_in_user: "karatasi ya kwanza yenye muhtasari wa shughuli na mapendekezo ya sasa" current_user: "nenda kwenye ukurasa wako" + user_menu: + tabs: + replies: "Majibu" + mentions: "Kutajwa" + likes: "Upendo Uliotolewa" + bookmarks: "Mialamisho" + profile: "Maelezo mafupi" topics: new_messages_marker: "Mara ya mwisho imetembelewa" bulk: @@ -2175,7 +2184,6 @@ sw: download_calendar: download: "Pakua" tagging: - all_tags: "Lebo Zote" other_tags: "Lebo Zingine" selector_all_tags: "lebo zote" selector_no_tags: "hakuna lebo" @@ -2249,10 +2257,6 @@ sw: member: "mwanachama" regular: "kawaida" leader: "kiongozi" - user_activity: - no_activity_others: "Hakuna shughuli." - no_replies_others: "Hakuna majibu." - no_likes_others: "Hakuna machapisho yaliyopendwa." sidebar: unread_count: one: "%{count} haijasomwa" @@ -2261,7 +2265,10 @@ sw: one: "Mada mpya %{count}" other: "Mada mpya %{count} " more: "Zaidi" + all_categories: "Kategoria Zote" sections: + about: + header_link_text: "Kuhusu" messages: header_link_text: "Ujumbe" links: @@ -2272,15 +2279,20 @@ sw: unread_with_count: "Haijasomwa (%{count})" archive: "Hifadhi" tags: - header_link_title: "lebo zote" header_link_text: "Lebo" categories: - header_link_title: "kategoria zote" header_link_text: "Kategoria" community: - header_link_title: "nyumbani" header_link_text: "Jumuiya" links: + about: + content: "Kuhusu" + admin: + content: "Msimamizi" + badges: + content: "Beji" + faq: + content: "FAQ" tracked: content: "Imefuatiliwa" groups: diff --git a/config/locales/client.te.yml b/config/locales/client.te.yml index 100c06a177..f1f1546cd8 100644 --- a/config/locales/client.te.yml +++ b/config/locales/client.te.yml @@ -100,12 +100,15 @@ te: share: close: "మూసివేయి" emails_are_disabled: "బయటకు వెళ్లే అన్ని ఈమెయిల్లూ అధికారి నిశేధించాడు. ఇప్పుడు ఎటువంటి ఈమెయిల్ ప్రకటనలూ పంపవీలవదు." + bootstrap_invite_button_title: "ఆహ్వానాలు పంపు" themes: default_description: "అప్రమేయ" edit: "ఈ విషయపు శీర్షిక మరియు వర్గం సవరించు" not_implemented: "ఈ ఫీచరు ఇంకా ఇంప్లిమెటు చేయలేదు. క్షమాపణలు!" no_value: "లేదు" yes_value: "అవును" + ok_value: "సరే" + cancel_value: "రద్దుచేయి" generic_error: "క్షమించాలి, ఒక దోషం తలెత్తింది" generic_error_with_reason: "ఒక దోషం జరిగింది: %{error}" sign_up: "సైన్ అప్" @@ -803,6 +806,13 @@ te: go_back: "వెనక్కు మరలు" not_logged_in_user: "సభ్యుని ప్రస్తుత కలాపాల మరియు అభిరూపాల సారాంశ పుట" current_user: "మీ సభ్యపుటకు వెళ్లు" + user_menu: + tabs: + replies: "జవాబులు" + mentions: "ప్రస్తావనలు" + likes: "ఇచ్చిన ఇష్టాలు " + bookmarks: "పేజీకలు" + profile: "ప్రవర" topics: bulk: defer: "వాయిదావేయి" @@ -1356,6 +1366,8 @@ te: one: "%{count} కొత్త" other: "%{count} కొత్త" sections: + about: + header_link_text: "గురించి" messages: header_link_text: "సందేశాలు" links: @@ -1366,11 +1378,18 @@ te: tags: header_link_text: "ట్యాగులు" categories: - header_link_title: "అన్ని వర్గాలు" header_link_text: "వర్గాలు" community: header_link_text: "కమ్యునిటీ" links: + about: + content: "గురించి" + admin: + content: "అధికారి" + badges: + content: "బ్యాడ్జీలు" + faq: + content: "తవసం" tracked: content: "గమనించారు" groups: diff --git a/config/locales/client.th.yml b/config/locales/client.th.yml index 52365ae5f8..8b116e0d02 100644 --- a/config/locales/client.th.yml +++ b/config/locales/client.th.yml @@ -150,18 +150,20 @@ th: forwarded: "ส่งต่ออีเมลข้างต้นแล้ว" topic_admin_menu: "การดำเนินการสำหรับหัวเรื่อง" skip_to_main_content: "ข้ามไปยังเนื้อหา" - wizard_required: "ยินดีต้อนรับเข้าสู่ Discourse! เริ่มต้นด้วยการไปที่เครื่องมือเปิดใช้งาน✨" emails_are_disabled: "อีเมลขาออกทั้งหมดถูกปิดโดยผู้ดูแลระบบ จะไม่มีอีเมลแจ้งเตือนใดๆถูกส่งออกไป" emails_are_disabled_non_staff: "การส่งอีเมลออกถูกปิดใช้งานสำหรับผู้ใช้ที่ไม่ใช่เจ้าหน้าที่" software_update_prompt: message: "เราอัปเดตไซต์นี้เมื่อสักครู่ โปรดรีเฟรชหน้านี้ หรือคุณอาจเกิดเหตุการณ์ที่ไม่ตรงตามต้องการ" dismiss: "ซ่อน" + bootstrap_invite_button_title: "ส่งคำเชิญ" themes: default_description: "ค่าเริ่มต้น" + only_admins: "(ข้อความนี้จะแสดงเฉพาะผู้ดูแลไซต์เท่านั้น)" s3: regions: ap_northeast_1: "เอเชียแปซิฟิก (โตเกียว)" ap_northeast_2: "เอเชียแปซิฟิก (โซล)" + ap_east_1: "เอเชียแปซิฟิก (ฮ่องกง)" ap_south_1: "เอเชียแปซิฟิก (มุมไบ)" ap_southeast_1: "เอเชียแปซิฟิก (สิงคโปร์)" ap_southeast_2: "เอเชียแปซิฟิก (ซิดนีย์)" @@ -170,6 +172,7 @@ th: cn_northwest_1: "จีน (หนิงเซี่ย)" eu_central_1: "อียู (แฟรงก์เฟิร์ต)" eu_north_1: "อียู (สต็อกโฮล์ม)" + eu_south_1: "สหภาพยุโรป (มิลาน)" eu_west_1: "อียู (ไอร์แลนด์)" eu_west_2: "อียู (ลอนดอน)" eu_west_3: "อียู (ปารีส)" @@ -185,6 +188,8 @@ th: not_implemented: "ขออภัย! คุณสมบัตินั้นยังไม่เสร็จสมบูรณ์" no_value: "ไม่ใช่" yes_value: "ใช่" + ok_value: "ตกลง" + cancel_value: "ยกเลิก" submit: "ตกลง" generic_error: "ขออภัย เกิดข้อผิดพลาดขึ้น" generic_error_with_reason: "เกิดข้อผิดพลาดขึ้น: %{error}" @@ -223,6 +228,8 @@ th: max_of_count: "สูงสุดของ %{count}" character_count: other: "%{count} ตัวอักษร" + period_chooser: + aria_label: "กรองตามช่วงเวลา" related_messages: title: "ข้อความที่เกี่ยวข้อง" see_all: 'ดูข้อความทั้งหมดจาก @%{username}' @@ -238,6 +245,9 @@ th: moderators: "ผู้ดูแล" stat: all_time: "ตลอดเวลา" + last_day: "24 ชั่วโมงที่ผ่านมา" + last_7_days: "7 วันที่ผ่านมา" + last_30_days: "30 วันที่ผ่านมา" like_count: "ถูกใจ" topic_count: "กระทู้" post_count: "โพสต์" @@ -247,21 +257,26 @@ th: contact_info: "ในกรณีที่เกิดเหตุฉุกเฉินหรือประเด็นสำคัญที่ส่งผลต่อเว็บไซต์นี้ กรุณาติดต่อเราที่ %{contact_info}" bookmarked: title: "บุ๊กมาร์ก" + edit_bookmark: "แก้ไขบุ๊กมาร์ก" clear_bookmarks: "ล้างบุ๊กมาร์ก" help: bookmark: "คลิกเพื่อ บุ๊คมาร์ค ที่โพสแรกของกระทู้นี้" unbookmark: "คลิกเพื่อลบบุ๊กมาร์กทั้งหมดในกระทู้นี้" bookmarks: + created: "คุณได้บุ๊กมาร์กโพสต์นี้ %{name}" + created_generic: "คุณได้บุ๊กมาร์กสิ่งนี้ %{name}" create: "สร้างบุ๊กมาร์ก" edit: "แก้ไขบุ๊กมาร์ก" not_bookmarked: "บุ๊กมาร์กโพสต์นี้" remove: "ลบบุ๊กมาร์ก" delete: "ลบบุ๊กมาร์ก" + confirm_delete: "คุณแน่ใจหรือไม่ว่าต้องการลบบุ๊กมาร์กนี้ การเตือนความจำจะถูกลบออกด้วย" confirm_clear: "คุณแน่ใจหรือว่าต้องการล้างบุ๊กมาร์กทั้งหมดจากกระทู้นี้" save: "บันทึก" invalid_custom_datetime: "วันและเวลาที่คุณกรอกไม่ถูกต้อง กรุณาลองอีกครั้ง" list_permission_denied: "คุณไม่ได้รับอนุญาตให้ดูบุ๊กมาร์กของผู้ใช้งานนี้" auto_delete_preference: + label: "หลังจากที่คุณได้รับแจ้ง" when_reminder_sent: "ลบบุ๊กมาร์ก" search: "ค้นหา" reminders: @@ -1587,6 +1602,13 @@ th: go_back: "ย้อนกลับ" not_logged_in_user: "หน้าผู้ใช้พร้อมสรุปกิจกรรมล่าสุดและการตั้งค่า" current_user: "ไปยังหน้าผู้ใช้ของคุณ" + user_menu: + tabs: + replies: "ตอบ" + mentions: "กล่าวถึง" + likes: "ถูกใจ" + bookmarks: "บุ๊คมาร์ค" + profile: "โปรไฟล์" topics: new_messages_marker: "เยี่ยมชมครั้งล่าสุด" bulk: @@ -2353,7 +2375,6 @@ th: download_calendar: download: "ดาวน์โหลด" tagging: - all_tags: "แท็กทั้งหมด" other_tags: "แท็กอื่น" selector_all_tags: "แท็กทั้งหมด" selector_no_tags: "ไม่มีแท็ก" @@ -2430,7 +2451,10 @@ th: new_count: other: "%{count} ใหม่" more: "อื่นๆ..." + all_categories: "หมวดหมู่ทั้งหมด" sections: + about: + header_link_text: "เกี่ยวกับ" messages: header_link_text: "ข้อความ" links: @@ -2442,15 +2466,20 @@ th: unread_with_count: "ยังไม่อ่าน (%{count})" archive: "คลัง" tags: - header_link_title: "แท็กทั้งหมด" header_link_text: "ป้าย" categories: - header_link_title: "ทุกหมวดหมู่" header_link_text: "หมวดหมู่" community: - header_link_title: "หน้าแรก" header_link_text: "ชุมชน" links: + about: + content: "เกี่ยวกับ" + admin: + content: "แอดมิน" + badges: + content: "เหรียญ" + faq: + content: "คำถามที่พบบ่อย" tracked: content: "ติดตาม" groups: diff --git a/config/locales/client.tr_TR.yml b/config/locales/client.tr_TR.yml index fdcc51fb0f..3a8ac69170 100644 --- a/config/locales/client.tr_TR.yml +++ b/config/locales/client.tr_TR.yml @@ -141,10 +141,10 @@ tr_TR: removed_group: "%{who} %{when} kaldırıldı" autobumped: "%{when} tarihinde otomatik olarak yükseltti" autoclosed: - enabled: "%{when} tarihinde kapatıldı" + enabled: "%{when} kapatıldı" disabled: "%{when} tarihinde açıldı" closed: - enabled: "%{when} tarihinde kapatıldı" + enabled: "%{when} kapatıldı" disabled: "%{when} tarihinde açıldı" archived: enabled: "%{when} tarihinde arşivlendi" @@ -164,8 +164,8 @@ tr_TR: forwarded: "yukarıdaki e-postayı iletti" topic_admin_menu: "konu eylemleri" skip_to_main_content: "Ana içeriğe atla" - wizard_required: "Yeni Discourse'una hoşgeldin! Haydi kuruluma başlayalım! Kurulum Sihirbazı ✨" emails_are_disabled: "Giden tüm e-postalar yönetici tarafından devre dışı bırakıldı. Herhangi bir e-posta bildirimi gönderilmeyecek." + emails_are_disabled_non_staff: "Giden e-posta, personel olmayan kullanıcılar için devre dışı bırakıldı." software_update_prompt: message: "Siteyi güncelledik, lütfen sayfayı yenileyin, aksi takdirde beklenmedik durumlarla karşılaşabilirsiniz." dismiss: "Kapat" @@ -173,6 +173,8 @@ tr_TR: one: "Yeni sitenizi başlatmayı kolaylaştırmak için önyükleme modundasınız. Tüm yeni kullanıcılara güven düzeyi 1 verilir ve günlük e-posta özeti e-postaları etkinleştirilir. Bu, %{count} kullanıcı katıldığında otomatik olarak kapatılacaktır." other: "Yeni sitenizi başlatmayı kolaylaştırmak için önyükleme modundasınız. Tüm yeni kullanıcılara güven düzeyi 1 verilir ve günlük e-posta özeti e-postaları etkinleştirilir. Bu, %{count} kullanıcı katıldığında otomatik olarak kapatılacaktır." bootstrap_mode_disabled: "Önyükleme modu 24 saat içinde devre dışı bırakılacak." + bootstrap_invite_button_title: "Davetleri Gönder" + bootstrap_wizard_link_title: "Kurulum sihirbazını bitir" themes: default_description: "Varsayılan" broken_theme_alert: "Bir tema veya bileşende hata olduğu için siteniz çalışmayabilir." @@ -208,6 +210,8 @@ tr_TR: not_implemented: "Bu özellik henüz geliştirilmedi, üzgünüz!" no_value: "Hayır" yes_value: "Evet" + ok_value: "Tamam" + cancel_value: "İptal et" submit: "Gönder" generic_error: "Üzgünüz, bir hata oluştu." generic_error_with_reason: "Bir hata oluştu: %{error}" @@ -1619,7 +1623,6 @@ tr_TR: set_custom_status: "Özel bir durum ayarla" what_are_you_doing: "Ne yapıyorsun?" remove_status: "Durumu kaldır" - until: "Şuna kadar:" loading: "Yükleniyor..." errors: prev_page: "şu adresi yüklemeye çalışırken:" @@ -1683,7 +1686,6 @@ tr_TR: hide_forever: "hayır teşekkürler" hidden_for_session: "Tamam, sana yarın yeniden soracağız. \"Giriş Yap\" bağlantısını kullanarak da hesap oluşturabilirsin." intro: "Merhaba! Tartışmanın tadını çıkarıyor gibisiniz, ancak henüz bir hesap için kaydolmadınız." - value_prop: "Aynı gönderiler arasında gezinmekten bıktınız mı? Bir hesap oluşturursanız, kaldığınız yere geri dönebilirsiniz. Ayrıca bir hesabınız olursa yeni yanıtlardan haberdar olabilir, yer imlerini kaydedebilir ve başkalarına teşekkür etmek için beğenileri kullanabilirsiniz. Bu topluluğu harika kılmak için hep birlikte çalışabiliriz. :heart:" summary: enabled_description: "Bu konunun özetini görüntülüyorsun: Okuyucularımızın en çok ilgisini çeken gönderiler" description: @@ -2017,6 +2019,7 @@ tr_TR: abandon: "yazım alanını kapat ve taslağı sil" enter_fullscreen: "tam ekran yaratıcıya gir" exit_fullscreen: "tam ekran yaratıcıdan çık" + exit_fullscreen_prompt: "Tam ekrandan çıkmak için ESC tuşuna basın" show_toolbar: "editör araç çubuğunu göster" hide_toolbar: "editör araç çubuğunu gizle" modal_ok: "Tamam" @@ -2304,16 +2307,21 @@ tr_TR: view_all: "tümünü görüntüle %{tab}" user_menu: generic_no_items: "Bu listede hiç öğe yok." - sr_menu_tabs: "Menü sekmeleri" view_all_notifications: "tüm bildirimleri görüntüle" view_all_bookmarks: "tüm yer imlerini görüntüle" + tabs: + replies: "Yanıtlar" + mentions: "Bahsedilenler" + likes: "Beğeni" + bookmarks: "İmlenenler" + profile: "Profil" reviewable: view_all: "tüm gözden geçirme öğeleri" queue: "Kuyruk" deleted_user: "(silinmiş kullanıcı)" post_number_with_topic_title: "gönderi #%{post_number} - %{title}" new_post_in_topic: "%{title} başlığıyla yeni gönderi" - suspicious_user: "şüpheli kullanıcı %{username}" + user_requires_approval: "%{username} onay bekliyor" default_item: "gözden geçirme öğesi #%{reviewable_id}" topics: new_messages_marker: "son ziyaret" @@ -2956,8 +2964,8 @@ tr_TR: other: "%{count} tane gönderiyi silmek istediğinize emin misiniz?" merge: confirm: - one: "Bu yayınları birleştirmek istediğinize emin misiniz?" - other: "%{count} gönderiyi birleştirmek istediğinizden emin misiniz?" + one: "Bu %{count} gönderiyi birleştirmek istediğinizden emin misiniz?" + other: "Bu %{count} gönderiyi birleştirmek istediğinizden emin misiniz?" revisions: controls: first: "İlk revizyon" @@ -3371,6 +3379,7 @@ tr_TR: this_week: "Hafta" today: "Bugün" other_periods: "en çok ilgi görenlere bak:" + safari_13_warning: Bu site yakında iOS ve Safari sürüm 13 ve altını desteklemeyecek. Basitleştirilmiş ve salt okunur bir sürüm var olmaya devam edecek. (detaylı bilgi) permission_types: full: "Oluştur / Yanıtla / Bak" create_post: "Yanıtla / Bak" @@ -3520,7 +3529,7 @@ tr_TR: google: "Google Takvim" ics: "ICS" tagging: - all_tags: "Tüm Etiketler" + all_tags: "Tüm etiketler" other_tags: "Diğer Etiketler" selector_all_tags: "tüm etiketler" selector_no_tags: "etiket yok" @@ -3675,12 +3684,11 @@ tr_TR: user_activity: no_activity_title: "Henüz etkinlik yok" no_activity_body: "Topluluğumuza hoş geldiniz! Burada çok yenisiniz ve tartışmalara henüz katkıda bulunmadınız. İlk adım olarak en çok okunanları veya kategorileri ziyaret edebilir ve okumaya başlayabilirsiniz! Beğendiğiniz veya hakkında daha fazla bilgi edinmek istediğiniz gönderilerde lütfen %{heartIcon} kullanarak beğeninizi belirtin. Paylaşımlara katıldıkça, etkinliğiniz burada listelenecek." - no_activity_others: "Etkinlik yok." no_replies_title: "Henüz hiçbir konuyu yanıtlamadınız." - no_replies_others: "Yanıt yok." + no_replies_title_others: "%{username} henüz hiçbir konuya cevap vermedi" no_drafts_title: "Hiç taslak başlatmadınız" no_likes_title: "Henüz hiçbir konuyu beğenmedin" - no_likes_others: "Beğenilen gönderi yok." + no_likes_title_others: "%{username} henüz hiçbir konuyu beğenmedi" no_topics_title: "Henüz herhangi bir konu başlatmadın" no_topics_title_others: "%{username} kullanıcısı henüz herhangi bir konu başlatmadı" no_read_topics_title: "Henüz herhangi bir konu okumadın" @@ -3699,9 +3707,12 @@ tr_TR: other: "%{count} yeni" toggle_section: "bölümü değiştir" more: "Daha..." + all_categories: "Tüm kategoriler" + all_tags: "Tüm etiketler" sections: + about: + header_link_text: "Hakkında" messages: - header_link_title: "kişisel mesajlar" header_link_text: "İletiler" header_action_title: "kişisel bir mesaj oluştur" links: @@ -3713,19 +3724,24 @@ tr_TR: unread_with_count: "Okunmamış (%{count})" archive: "Arşiv" tags: - header_link_title: "tüm etiketler" header_link_text: "Etiketler" categories: - header_link_title: "tüm kategoriler" header_link_text: "Kategoriler" community: - header_link_title: "anasayfa" header_link_text: "Topluluk" header_action_title: "yeni konu oluştur" links: + about: + content: "Hakkında" + admin: + content: "Yönetici" + badges: + content: "Rozetler" everything: content: "Her şey" title: "Tüm konular" + faq: + content: "SSS" tracked: content: "Takipte" title: "Tüm izlenen konular" @@ -3741,6 +3757,11 @@ tr_TR: draft_count: one: "%{count} taslak" other: "%{count} taslak" + welcome_topic_banner: + title: "Hoş Geldiniz konulu gönderinizi oluşturun" + description: 'Hoş geldiniz konulu gönderiniz, yeni katılanların okuyacağı ilk şeydir. Bunu bir paragraf “kısa bir sunum” veya “misyon anlatımınız” olarak düşünün' + button_title: "Düzenlemeye Başla" + until: "Şuna kadar:" admin_js: type_to_filter: "filtrelemek için yaz..." admin: @@ -4925,7 +4946,8 @@ tr_TR: cant_delete_all_too_many_posts: one: "Tüm gönderileri silemezsiniz çünkü kullanıcının %{count} 'ten daha fazla gönderisi var. (delete_all_posts_max)" other: "Tüm gönderileri silemezsin çünkü kullanıcının %{count} 'ten fazla gönderisi var. (delete_all_posts_max)" - delete_confirm: "İçeriği mevcut tartışmalardan kaldırmaktan kaçınmak veya kullanıcıları silmek yerine genellikle anonimleştirmek tercih edilir.

    Bu kullanıcıyı silmek istediğinizden emin misiniz? Bu geri alınamaz!" + delete_confirm_title: "Bu kullanıcıyı silmek istediğinizden emin misiniz? Bu kalıcıdır!" + delete_confirm: "Mevcut tartışmalardan içerik kaldırmamak için kullanıcıları silmek yerine anonimleştirmek genellikle tercih edilir." delete_and_block: "Sil ve bu e-posta ve IP adresini engelle" delete_dont_block: "Yalnızca sil" deleting_user: "Kullanıcı siliniyor..." @@ -5056,7 +5078,6 @@ tr_TR: recommended: "Sıradaki metni isteğine göre uyarlamanı öneririz:" show_overriden: "Yalnızca iptal edilenleri göster" locale: "Dil:" - fallback_locale_warning: "%{fallback} diline dayalı bir dili düzenliyorsunuz. Arayüz dili olarak %{fallback} seçen kullanıcılar değişikliklerinizi görmez." more_than_50_results: "50 den fazla sonuç var. Lütfen aramanızı daraltın." settings: show_overriden: "Yalnızca geçersiz kılınanları göster" diff --git a/config/locales/client.uk.yml b/config/locales/client.uk.yml index d4fe4b33cf..f9bcf6d379 100644 --- a/config/locales/client.uk.yml +++ b/config/locales/client.uk.yml @@ -235,7 +235,6 @@ uk: forwarded: "переслано вищевказаний електронний лист" topic_admin_menu: "дії теми" skip_to_main_content: "Перейти до основного вмісту" - wizard_required: "Запрошуємо до вашого нового Discourse! Давайте розпочнемо з майстра налаштування ✨" emails_are_disabled: "Надсилання повідомлень електронною поштою було глобально вимкнено адміністратором. Жодне сповіщення електронною поштою не буде надіслано." emails_are_disabled_non_staff: "Вихідну електронну пошту було вимкнено для користувачів, які не є персоналом." software_update_prompt: @@ -247,6 +246,8 @@ uk: many: "Задля спрощення запуску вашого нового сайту, сайт зараз у режимі початкового спеціального режиму. Усі нові користувачі отримають рівень довіри 1 та увімкнена щоденна розсилка підсумків електронною поштою. Цей режим буде автоматично вимкнено, коли буде мінімально потрібна кількість зареєстрованих користувачів — %{count}." other: "Задля спрощення запуску вашого нового сайту, сайт зараз у режимі початкового спеціального режиму. Усі нові користувачі отримають рівень довіри 1 та увімкнена щоденна розсилка підсумків електронною поштою. Цей режим буде автоматично вимкнено, коли буде мінімально потрібна кількість зареєстрованих користувачів — %{count}." bootstrap_mode_disabled: "Режим Bootstrap буде вимкнено через 24 години." + bootstrap_invite_button_title: "Надіслати запрошення" + bootstrap_wizard_link_title: "Завершити роботу майстра налаштування" themes: default_description: "Промовчання" broken_theme_alert: "Ваш сайт не може працювати, оскільки тема / компонент має помилки." @@ -283,6 +284,8 @@ uk: not_implemented: "Цей функціонал ще не реалізовано, даруйте!" no_value: "Ні" yes_value: "Так" + ok_value: "OK" + cancel_value: "Скасувати" submit: "Надіслати" generic_error: "Даруйте, виникла помилка." generic_error_with_reason: "Виникла помилка: %{error}" @@ -1166,6 +1169,8 @@ uk: dismiss: "Відкинути" dismiss_notifications: "Відкинути все" dismiss_notifications_tooltip: "Позначити всі сповіщення як прочитані" + dismiss_bookmarks_tooltip: "Позначити всі непрочитані нагадування про закладки як прочитані" + dismiss_messages_tooltip: "Позначати всі сповіщення про непрочитані особисті повідомлення як прочитані" no_messages_title: "У вас немає повідомлень" no_messages_body: > Потрібна особиста розмова з кимось, поза звичайним спілкуванням? Надішліть їм повідомлення, вибравши їх аватар і натиснувши кнопку повідомлення %{icon}

    Якщо вам потрібна допомога, ви можете надіслати повідомлення співробітнику. @@ -1791,7 +1796,6 @@ uk: set_custom_status: "Встановити власний статус" what_are_you_doing: "Що ви робите?" remove_status: "Видалити статус" - until: "До:" loading: "Завантаження..." errors: prev_page: "при спробі завантаження" @@ -1853,9 +1857,11 @@ uk: other: відповідь signup_cta: sign_up: "Зареєструватись" + hide_session: "Можливо пізніше" hide_forever: "ні дякую" hidden_for_session: "Гаразд, ми запитаємо вас завтра. Ви завжди можете використати 'Увійти', щоб створити обліковий запис теж." intro: "Вітаємо! Схоже, вам подобається обговорення, але ви ще не зареєстрували акаунт." + value_prop: "Втомились від прокручування тих самих повідомлень? Якщо ви створите акаунт, ви завжди будете повертатися до тих записів, на яких зупинилися. За допомогою облікового запису ви також зможете отримувати повідомлення про нові відповіді, зберігати закладки і використовувати вподобайки для подяки іншим. Ми можемо працювати разом, щоб зробити цю спільноту цікавою. :heart:" summary: enabled_description: "Ви переглядаєте витяг з теми - тільки найцікавіші повідомлення на думку спільноти." description: @@ -2023,6 +2029,7 @@ uk: categories_only: "Тільки розділи" categories_with_featured_topics: "Розділи та їх найкращі теми" categories_and_latest_topics: "Розділи та список останніх тем форуму" + categories_and_latest_topics_created_date: "Категорії та останні теми (сортувати за датою створення теми)" categories_and_top_topics: "Категорії та головні теми" categories_boxes: "Коробки з підкатегорій" categories_boxes_with_topics: "Коробки з Обраними Темами" @@ -2227,6 +2234,7 @@ uk: abandon: "закрити композитор та скасувати чернетку" enter_fullscreen: "введіть повноекранний композитор" exit_fullscreen: "вийти з повноекранного режиму композитора" + exit_fullscreen_prompt: "Натисніть ESC, щоб вийти з повноекранного режиму" show_toolbar: "Показати панель редактора" hide_toolbar: "приховати панель редактора" modal_ok: "OK" @@ -2270,6 +2278,7 @@ uk: ignore: "Ігнорувати" image_alt_text: aria_label: Альтернативний текст для зображення + delete_image_button: Видалити зображення notifications: tooltip: regular: @@ -2346,6 +2355,16 @@ uk: few: "Ви впевнені? У вас є %{count} важливих повідомлення." many: "Ви впевнені? У вас є %{count} важливих повідомлень." other: "Ви впевнені? У вас є %{count} важливих повідомлень." + bookmarks: + one: "Ти впевнений? У вас %{count} непрочитане нагадування про закладки." + few: "Ти впевнений? У вас %{count} непрочитані нагадування про закладки." + many: "Ти впевнений? У вас %{count} непрочитаних нагадувань про закладки." + other: "Ти впевнений? У вас %{count} непрочитаних нагадувань про закладки." + messages: + one: "Ви впевнені? У вас є %{count} непрочитане особисте повідомлення." + few: "Ви впевнені? У вас є %{count} непрочитані особисті повідомлення." + many: "Ви впевнені? У вас є %{count} непрочитаних особистих повідомлень." + other: "Ви впевнені? У вас є %{count} непрочитаних особистих повідомлень." dismiss: "Відкинути" cancel: "Скасувати" group_message_summary: @@ -2530,8 +2549,70 @@ uk: view_all: "Переглянути всі %{tab}" user_menu: generic_no_items: "Немає записів у цьому списку." - sr_menu_tabs: "Вкладки меню" + sr_menu_tabs: "Вкладки меню користувача" view_all_notifications: "Переглянути всі сповіщення" + view_all_bookmarks: "переглянути всі закладки" + view_all_messages: "переглянути всі особисті повідомлення" + tabs: + all_notifications: "Всі сповіщення" + replies: "Відповіді" + replies_with_unread: + one: "Відповіді - %{count} непрочитане" + few: "Відповіді - %{count} непрочитані" + many: "Відповіді - %{count} непрочитаних" + other: "Відповіді - %{count} непрочитаних" + mentions: "Згадки" + mentions_with_unread: + one: "Згадки - %{count} непрочитана згадка" + few: "Згадки - %{count} непрочитані згадки" + many: "Згадки - %{count} непрочитаних згадок" + other: "Згадки - %{count} непрочитаних згадок" + likes: "Вподобані" + likes_with_unread: + one: "Вподобайки - %{count} непрочитане" + few: "Вподобайки - %{count} непрочитані" + many: "Вподобайки - %{count} непрочитаних" + other: "Вподобайки - %{count} непрочитаних" + watching: "Теми які ви відстежуєте" + watching_with_unread: + one: "Теми які відстежуються - %{count} непрочитана" + few: "Теми які відстежуються - %{count} непрочитані теми" + many: "Теми які відстежуються - %{count} непрочитаних тем" + other: "Теми які відстежуються - %{count} непрочитаних тем" + messages: "Особисті повідомлення" + messages_with_unread: + one: "Особисті повідомлення – %{count} непрочитане повідомлення" + few: "Особисті повідомлення – %{count} непрочитані повідомлення" + many: "Особисті повідомлення – %{count} непрочитаних повідомлень" + other: "Особисті повідомлення – %{count} непрочитаних повідомлень" + bookmarks: "Закладки" + bookmarks_with_unread: + one: "Закладки — %{count} непрочитана закладка" + few: "Закладки — %{count} непрочитані закладки" + many: "Закладки — %{count} непрочитаних закладок" + other: "Закладки — %{count} непрочитаних закладок" + review_queue: "Премодерація" + review_queue_with_unread: + one: "Черга премодерації- %{count} елемент потребує рецензування" + few: "Черга премодерації- %{count} елементи потребують рецензування" + many: "Черга премодерації - %{count} елементів потребують рецензування" + other: "Черга премодерації – %{count} елементи потребують рецензування" + other_notifications: "Інші сповіщення" + other_notifications_with_unread: + one: "Інші сповіщення – %{count} непрочитане повідомлення" + few: "Інші сповіщення – %{count} непрочитані повідомлення" + many: "Інші сповіщення – %{count} непрочитаних повідомлень" + other: "Інші сповіщення – %{count} непрочитаних повідомлень" + profile: "Профіль" + reviewable: + view_all: "переглянути всі дописи, що знаходяться на премодерації" + queue: "Черга" + deleted_user: "(видалений користувач)" + deleted_post: "(видалений запис)" + post_number_with_topic_title: "допис #%{post_number} - %{title}" + new_post_in_topic: "новий допис в темі %{title}" + user_requires_approval: "Користувач %{username} вимагає схвалення" + default_item: "премодерований елемент #%{reviewable_id}" topics: new_messages_marker: "останнє відвідування" bulk: @@ -3266,10 +3347,10 @@ uk: other: "Ви впевнені, що хочете видалити %{count} повідомлень?" merge: confirm: - one: "Ви впевнені, що хочете об’єднати ці повідомлення?" - few: "Are you sure you want to merge those %{count} posts?" - many: "Are you sure you want to merge those %{count} posts?" - other: "Are you sure you want to merge those %{count} posts?" + one: "Ви впевнені, що хочете об’єднати це повідомлення?" + few: "Ви впевнені, що хочете об’єднати ці %{count} повідомлення?" + many: "Ви впевнені, що хочете об’єднати ці %{count} повідомлень?" + other: "Ви впевнені, що хочете об’єднати ці %{count} повідомлень?" revisions: controls: first: "Перша версія" @@ -3717,6 +3798,7 @@ uk: today: "Today" other_periods: "дивитися TOP:" browser_update: 'На жаль, ваш браузер не підтримується. Будь ласка, перейдіть на підтримуваний браузер , щоб повноцінно переглянути вміст, увійти та відповісти.' + safari_13_warning: Цей сайт незабаром перестане підтримувати версії iOS і Safari 13 і нижче. Спрощена версія "тільки для читання" залишиться доступною. (більше інформації) permission_types: full: "Створювати / Відповідати / Бачити" create_post: "Відповідати / Бачити" @@ -3874,7 +3956,7 @@ uk: google: "Календар Google" ics: "ICS" tagging: - all_tags: "Усі мітки" + all_tags: "Всі теги" other_tags: "Інші мітки" selector_all_tags: "усі мітки" selector_no_tags: "без міток" @@ -4054,15 +4136,16 @@ uk: user_activity: no_activity_title: "Ще немає активності" no_activity_body: "Ласкаво просимо до нашої спільноти! Ви тут зовсім новачок і ще не долучилися до обговорень. Як перший крок, відвідайте Топ або Категорії і просто почніть читати! Позначте %{heartIcon} публікації, які вам подобаються або про які потрібно дізнатися більше. Якщо ви цього ще не зробили, допоможіть іншим познайомитися з вами, додавши зображення та коротку інформацію про себе у профілі користувача." - no_activity_others: "Немає активностей." no_replies_title: "Ви ще не відповіли на жодну тему" - no_replies_others: "Немає відповідей" + no_replies_title_others: "%{username} ще не відповів у жодній темі" + no_replies_body: "Коли ви відкрити цікаву розмову, до якої хочете зробити внесок, натисніть кнопку Відповісти безпосередньо в будь-якому повідомленні, щоб почати відповідати на це повідомлення. Або, якщо ви волієте відповідати на тему загалом, а не на конкретне повідомлення чи конкретній особі, шукайте кнопку Відповідь в самій нижній частині теми, або в списку шкали часу теми праворуч." no_drafts_title: "Ви не маєте чернеток" no_drafts_body: "Не готові до публікації? Ми автоматично збережемо нову чернетку та покажемо її тут при створенні Вами нового допису. Натисніть кнопку для скасування, щоб відхилити збереження тексту, або зберегти чернетку, щоб продовжити роботу з нею пізніше." no_likes_title: "Ви ще не вподобали жодної теми" + no_likes_title_others: "%{username} ще не вподобав жодної теми" no_likes_body: "Чудовий спосіб долучитись та почати робити внесок – це почати читати обговорення, та позначати %{heartIcon} публікації, які вам подобаються!" - no_likes_others: "Вподобаних повідомлень немає." no_topics_title: "Ви ще не розпочали жодної теми" + no_topics_body: "Завжди краще шукати існуючі теми перед початком нової теми, але якщо ви впевнені, що така тема ще не почата, то розпочніть нову тему. Знайдіть кнопку + Нова тема у верхньому правому куті списку тем, категорій, або тегів для створення нової теми в цій області." no_topics_title_others: "Користувач %{username} ще не розпочав жодної теми" no_read_topics_title: "Ви ще не читали жодної теми" no_read_topics_body: "Коли ви почнете читати обговорення, ви побачите тут список тем. Щоб почати читати, шукайте теми, які вас зацікавлять в Топ або у Категорії або шукайте за ключовим словом %{searchIcon}" @@ -4087,9 +4170,12 @@ uk: other: "%{count} нова" toggle_section: "Переключити розділ" more: "Ще..." + all_categories: "Всі категорії" + all_tags: "Всі теги" sections: + about: + header_link_text: "Про" messages: - header_link_title: "особисті повідомлення" header_link_text: "Повідомлення" header_action_title: "створити особисте повідомлення" links: @@ -4103,23 +4189,28 @@ uk: tags: none: "Ви не додали жодного тегу." click_to_get_started: "Натисніть тут, щоб почати." - header_link_title: "усі мітки" header_link_text: "Теги" header_action_title: "Редагувати теги бічної панелі" categories: none: "Ви не додали жодної категорії." click_to_get_started: "Натисніть тут, щоб почати." - header_link_title: "усі розділи" header_link_text: "Категорії" header_action_title: "редагувати категорії бічної панелі" community: - header_link_title: "головна" header_link_text: "Спільнота" header_action_title: "створити нову тему" links: + about: + content: "Про" + admin: + content: "Адмін" + badges: + content: "Нагороди" everything: content: "Усе" title: "Всі теми" + faq: + content: "Часті запитання" tracked: content: "Відстежувані" title: "Усі відстежувані теми" @@ -4128,6 +4219,7 @@ uk: title: "Усі групи" users: content: "Користувачі" + title: "Всі користувачі" my_posts: content: "Мої дописи" title: "Мої дописи" @@ -4136,6 +4228,11 @@ uk: few: "%{count} чернетки" many: "%{count} чернетки" other: "%{count} чернетки" + welcome_topic_banner: + title: "Створіть тему привітання" + description: 'Ваша привітальна тема – це перше, що прочитають новачки. Думайте про це як про «початкову презентацію» або «заяву про місію» з одного абзацу.' + button_title: "Почати редагування" + until: "До:" admin_js: type_to_filter: "введіть, щоб фільтрувати..." admin: @@ -4703,6 +4800,8 @@ uk: import_web_advanced: "Додатково..." import_file_tip: ".tar.gz, .zip, або .dcstyle .json файл, який містить тему" is_private: "Тема знаходиться в приватному репозиторії git" + finish_install: "Завершити встановлення теми" + last_attempt: "Процес встановлення не завершено, остання спроба:" remote_branch: "Назва гілки (не обов’язково)" public_key: "Надайте доступ до сховища з наступним відкритим ключем:" public_key_note: "Після введення коректної адреси приватного сховища вище, тут буде згенеровано і показано SSH ключ." @@ -4713,6 +4812,8 @@ uk: install_git_repo: "Зі сховища git" install_create: "Створити новий" duplicate_remote_theme: "Компонент теми «%{name}» уже встановлений. Ви впевнені, що хочете встановити іншу копію?" + force_install: "Тему неможливо встановити, тому що не доступний репозиторій Git. Ви впевнені, що хочете продовжити установку?" + create_placeholder: "Створити заповнювач" about_theme: "Про" license: "Ліцензія" version: "Версія:" @@ -4895,6 +4996,7 @@ uk: last_seen_user: "Востаннє помічено користувача:" no_result: "Нічого не знайдено для зведення новин." reply_key: "Ключ відповіді" + post_link_with_smtp: "Пошта & SMTP Подробиці" skipped_reason: "Причина пропуску" incoming_emails: from_address: "Від" @@ -4924,6 +5026,7 @@ uk: address_placeholder: "name@example.com" type_placeholder: "дайджест, підписка..." reply_key_placeholder: "Ключ відповіді" + smtp_transaction_response_placeholder: "SMTP ID" moderation_history: performed_by: "Виконано користувачем " no_results: "Історія модерації недоступна." @@ -5108,6 +5211,7 @@ uk: few: "показати %{count} слів" many: "показати %{count} слів" other: "показати %{count} слів" + case_sensitive: "(з урахуванням регістру)" download: Завантажити clear_all: Скинути все clear_all_confirm: "Ви впевнені, що хочете видалити всі контрольні слова на %{action}?" @@ -5145,6 +5249,8 @@ uk: exists: "Вже існує" upload: "Додати з файлу" upload_successful: "Завантаження пройшло успішно. Слова додані." + case_sensitivity_label: "З урахуванням регістру" + case_sensitivity_description: "Тільки слова з відповідним регістром" test: button_label: "Тест" modal_title: "%{action}: Тест контрольованих слів" @@ -5245,6 +5351,7 @@ uk: suspended: "Призупинено?" staged: "Недокористувач?" show_admin_profile: "Адмін" + manage_user: "Керування користувачем" show_public_profile: "Показати публічний профіль" impersonate: "Втілитися" action_logs: "Журнал дій" @@ -5348,7 +5455,8 @@ uk: few: "Не вдалось визначити видалити всі повідомлення, тому що у користувача більш %{count} повідомлень. (Налаштування delete_all_posts_max.)" many: "Не вдалось визначити видалити всі повідомлення, тому що у користувача більш %{count} повідомлень. (Налаштування delete_all_posts_max.)" other: "Не вдалось визначити видалити всі повідомлення, тому що у користувача більш %{count} повідомлень. (Налаштування delete_all_posts_max.)" - delete_confirm: "Зазвичай краще анонімізувати користувачів, ніж видаляти їх, щоб уникнути видалення контенту з існуючих обговорень.

    Ви впевнені, що хочете видалити цього користувача? Це назавжди!" + delete_confirm_title: "Ви ВПЕВНЕНІ, що хочете видалити цього користувача? Це назавжди!" + delete_confirm: "Загалом краще анонімізувати користувачів, а не видаляти їх, щоб уникнути видалення вмісту з існуючих обговорень." delete_and_block: "Видалити та заблокувати цей e-mail та IP адресу" delete_dont_block: "Лише видалення" deleting_user: "Видалити користувача..." @@ -5481,7 +5589,6 @@ uk: recommended: "Ми рекомендуємо змінити наступний текст під ваші потреби:" show_overriden: "Показувати тільки перевизначені" locale: "Мова:" - fallback_locale_warning: "Ви редагуєте мову на основі %{fallback}. Користувачі, які обрали %{fallback} як мову інтерфейсу, не бачитимуть ваших змін." more_than_50_results: "Знайдено понад 50 результатів. Будь ласка виправте параметри пошуку." settings: show_overriden: "Показувати тільки перевизначені" @@ -5704,8 +5811,11 @@ uk: replace: "Замінити" wizard_js: wizard: + jump_in: "Готово!" + finish: "Вийти з налаштування" back: "Назад" next: "Далі" + configure_more: "Більше налаштувань..." step-text: "Крок" step: "%{current} з %{total}" upload: "Вивантажити" diff --git a/config/locales/client.ur.yml b/config/locales/client.ur.yml index 79ad402fdb..197a58ed2e 100644 --- a/config/locales/client.ur.yml +++ b/config/locales/client.ur.yml @@ -160,7 +160,6 @@ ur: forwarded: "مندرجہ بالا ای میل بھیجیں" topic_admin_menu: "موضوع کے ایکشنز" skip_to_main_content: "مرکزی مواد پر جائیں" - wizard_required: "اپنے نئے ڈِسکورس پر خوش آمدید! سیٹ اَپ وزرڈ سے آغاز کرتے ہیں۔✨" emails_are_disabled: "ای میل کو منتظم کی طرف سے غیر فعال کر دیا گیا ہے. کسی بھی قسم کی ای میل نہیں بھیجی جائیں گی۔" emails_are_disabled_non_staff: "باہر جانے والی ای میل غیر عملہ صارفین کے لیے غیر فعال کر دی گئی ہیں" software_update_prompt: @@ -170,6 +169,7 @@ ur: one: "اپنی نئی سائٹ کو شروع کرنے کوآسان بنانے کے لیے، آپ بوٹسٹریپ موڈ میں ہیں۔ تمام نئے صارفین کو اعتماد کی سطح 1 دی جائے گی اور روزانہ ای میل سمری ای میلز کو فعال کیا جائے گا۔ %{count} صارف کے شامل ہونے پر یہ خود بخود بند ہو جائے گا۔" other: "اپنی نئی سائٹ کو شروع کرنے کوآسان بنانے کے لیے، آپ بوٹسٹریپ موڈ میں ہیں۔ تمام نئے صارفین کو اعتماد کی سطح 1 دی جائے گی اور روزانہ ای میل سمری ای میلز کو فعال کیا جائے گا۔ %{count} صارفین کے شامل ہونے پر یہ خود بخود بند ہو جائے گا۔" bootstrap_mode_disabled: "بُوٹسٹرَیپ مَوڈ 24 گھنٹوں کے اندر غیر فعال کر دیا جائے گا۔" + bootstrap_invite_button_title: "دعوت بھیجیں" themes: default_description: "ڈِیفالٹ" broken_theme_alert: "ہو سکتا ہے آپ کی سائٹ کام نہ کرے کیونکہ تھیم/جزو میں خامیاں ہیں۔" @@ -206,6 +206,8 @@ ur: not_implemented: "یہ خصوصیت ابھی تک لاگو نہیں کی گئی، معضرت!" no_value: "نہیں" yes_value: "جی ہاں" + ok_value: "ٹھیک ہے" + cancel_value: "منسوخ" submit: "شائع" generic_error: "معذرت، ایک تکنیکی خرابی کا سامنا کرنا پڑا ہے۔" generic_error_with_reason: "ایک تکنیکی خرابی پیش آئی: %{error}" @@ -2269,6 +2271,13 @@ ur: not_logged_in_user: "موجودہ سرگرمی کے خلاصہ اور ترجیحات کے ساتھ صفحہِ صارف" current_user: "اپنے صفحہِ صارف پر جائیں" view_all: "تمام %{tab}دیکھیں" + user_menu: + tabs: + replies: "جوابات" + mentions: "تذکرے" + likes: "لائیکس دیے گئے" + bookmarks: "بُک مارکس" + profile: "پروفائل" topics: new_messages_marker: "آخری وزٹ" bulk: @@ -2893,10 +2902,6 @@ ur: confirm: one: "کیا آپ واقعی اُس پوسٹ کو مٹانا چاہتے ہیں؟" other: "کیا آپ واقعی ان %{count} پوسٹس کو مٹانا چاہتے ہیں؟" - merge: - confirm: - one: "کیا آپ واقعی ان پوسٹس کو ضم کرنا چاہتے ہیں؟" - other: "کیا آپ واقعی ان %{count} پوسٹس کو ضم کرنا چاہتے ہیں؟" revisions: controls: first: "پہلی رَوِیژن" @@ -3457,7 +3462,6 @@ ur: google: "گوگل کیلنڈر" ics: "ICS" tagging: - all_tags: "تمام ٹیگز" other_tags: "دیگر ٹیگز" selector_all_tags: "تمام ٹیگز" selector_no_tags: "کوئی ٹیگ نہیں" @@ -3614,14 +3618,11 @@ ur: unsupported_file_picked: "آپ نے غیر معاونت شدہ فائل منتخب کی ہے۔ معاون فائل کی اقسام — %{types}." user_activity: no_activity_title: "ابھی تک کوئی سرگرمی نہیں" - no_activity_others: "کوئی سرگرمی نہیں۔" no_replies_title: "آپ نے ابھی تک کسی بھی عنوان کا جواب نہیں دیا ہے" - no_replies_others: "کوئی جوابات نہیں۔" no_drafts_title: "آپ نے کوئی ڈرافٹ شروع نہیں کیا ہے" no_drafts_body: "پوسٹ کرنے کے لیے بالکل تیار نہیں؟ جب بھی آپ کوئی موضوع، جواب، یا ذاتی پیغام لکھنا شروع کریں گے تو ہم خود بخود ایک نیا مسودہ محفوظ کریں گے اور اسے یہاں درج کریں گے۔ رد کرنے کے لیے کینسل بٹن کو منتخب کریں یا بعد میں جاری رکھنے کے لیے اپنے ڈرافٹ کو محفوظ کریں۔" no_likes_title: "آپ نے ابھی تک کوئی عنوان پسند نہیں کیا ہے" no_likes_body: "کودنے اور تعاون شروع کرنے کا ایک بہترین طریقہ یہ ہے کہ پہلے سے ہو چکی گفتگو کو پڑھنا شروع کریں، اور اپنی پسند کی پوسٹس پر %{heartIcon} کو منتخب کریں!" - no_likes_others: "کوئی لائیک کردہ پوسٹس نہیں۔" no_topics_title: "آپ نے ابھی تک کوئی عنوان شروع نہیں کیا ہے" no_topics_title_others: "%{username} نے ابھی تک کوئی عنوان شروع نہیں کیا ہے" no_read_topics_title: "آپ نے ابھی تک کوئی عنوان نہیں پڑھا ہے" @@ -3642,7 +3643,10 @@ ur: one: "%{count} نیا" other: "%{count} نئے" more: "مزید..." + all_categories: "تمام زُمرَہ جات" sections: + about: + header_link_text: "بارے میں" messages: header_link_text: "پیغامات" links: @@ -3654,15 +3658,20 @@ ur: unread_with_count: "بغیر پڑھا (%{count})" archive: "آر کائیو" tags: - header_link_title: "تمام ٹیگز" header_link_text: "ٹیگز" categories: - header_link_title: "تمام زُمرَہ جات" header_link_text: "زُمرَہ جات" community: - header_link_title: "ہَوم" header_link_text: "کمیونٹی" links: + about: + content: "بارے میں" + admin: + content: "ایڈمن" + badges: + content: "بَیج" + faq: + content: "عمومی سوالات" tracked: content: "ٹریک کیا ہوا" groups: @@ -4858,7 +4867,6 @@ ur: cant_delete_all_too_many_posts: one: "تمام پوسٹس کو حذف نہیں کیا جاسکتا کیونکہ صارف کی %{count} سے زیادہ پوسٹس ہیں۔ (delete_all_posts_max)" other: "تمام پوسٹس کو حذف نہیں کیا جاسکتا کیونکہ صارف کی %{count} سے زیادہ پوسٹس ہیں۔ (delete_all_posts_max)" - delete_confirm: "صارفین کو حذف کرنے کے بجائے اُن کو نام نہاد کر دینے کو ترجیح دی جاتی ہے، تاکہ موجودہ بات چیتوں سے مواد ہٹانے سے بچا جا سکے۔

    کیا آپ واقعی اِس صارف کو حذف کرنا چاہتے ہیں؟ یہ مُستقِل عمل ہے!" delete_and_block: "اِس اِیمیل اور IP ایڈریس کو حذف اور بلاک کریں" delete_dont_block: "صرف مٹائیں" deleting_user: "صارف حذف کیا جا رہا ہے..." @@ -4989,7 +4997,6 @@ ur: recommended: "اَپنی ضروریات کے مطابق کرنے کے لئے ہم مندرجہ ذیل ٹَیکسٹ کو اپنی مرضی کے حساب سے تبدیل کرنے کی تجویز دیں گے:" show_overriden: "صرف اووَر رائیڈ ہوئے دکھائیں" locale: "زبان:" - fallback_locale_warning: "آپ %{fallback}کی بنیاد پر ایک زبان میں ترمیم کر رہے ہیں۔ وہ صارفین جو %{fallback} کو اپنی انٹرفیس زبان کے طور پر منتخب کرتے ہیں وہ آپ کی تبدیلیاں نہیں دیکھ پائیں گے۔" more_than_50_results: "50 سے زائد نتائج ہیں۔ برائے مہربانی اپنی تلاش کو تنگ کریں۔" settings: show_overriden: "صرف اووَر رائیڈ ہوئے دکھائیں" diff --git a/config/locales/client.vi.yml b/config/locales/client.vi.yml index 178fe68e5f..357c5e6322 100644 --- a/config/locales/client.vi.yml +++ b/config/locales/client.vi.yml @@ -151,7 +151,6 @@ vi: forwarded: "Chuyển tiếp email phía trên" topic_admin_menu: "hành động cho chủ đề" skip_to_main_content: "Chuyển đến nội dung chính" - wizard_required: "Chào mừng bạn đến với Discourse! Hãy bắt đầu với hướng dẫn cài đặt ✨" emails_are_disabled: "Ban quản trị đã tắt mọi thư gửi đi. Sẽ không có bất kỳ thư thông báo nào được gửi." emails_are_disabled_non_staff: "Email gửi đi đã bị vô hiệu hóa đối với người dùng không phải là nhân viên." software_update_prompt: @@ -160,6 +159,8 @@ vi: bootstrap_mode_enabled: other: "Để đơn giản hoá quá trình triển khai trang web, bạn đang ở trong chế độ bootstrap. Mọi người dùng mới đều có mức độ tin cậy 1 và sẽ nhận được email cập nhật thông tin mỗi ngày. Chế độ này sẽ tự động tắt khi số người dùng vượt qua %{count}" bootstrap_mode_disabled: "Chế độ bootstrap sẽ bị vô hiệu trong 24 giờ tới." + bootstrap_invite_button_title: "Gửi Lời Mời" + bootstrap_wizard_link_title: "Hoàn tất trình hướng dẫn thiết lập" themes: default_description: "Mặc định" broken_theme_alert: "Trang web của bạn có thể không hoạt động vì một chủ đề / thành phần có lỗi." @@ -196,6 +197,8 @@ vi: not_implemented: "Tính năng này chưa được hoàn thiện, xin lỗi!" no_value: "Không" yes_value: "Có" + ok_value: "OK" + cancel_value: "Huỷ" submit: "Gửi đi" generic_error: "Rất tiếc, đã có lỗi xảy ra." generic_error_with_reason: "Đã xảy ra lỗi: %{error}" @@ -1574,7 +1577,6 @@ vi: set_custom_status: "Đặt trạng thái tùy chỉnh" what_are_you_doing: "Bạn đang làm gì đấy?" remove_status: "Xóa trạng thái" - until: "Cho đến khi:" loading: "Đang tải..." errors: prev_page: "trong khi cố gắng để tải" @@ -1637,7 +1639,7 @@ vi: hide_forever: "không, cảm ơn" hidden_for_session: "OK, chúng tôi sẽ hỏi bạn vào ngày mai. Bạn cũng có thể sử dụng 'Đăng nhập' để tạo tài khoản." intro: "Xin chào! Có vẻ như bạn đang quan tâm chủ đề này, nhưng bạn chưa đăng ký tài khoản." - value_prop: "Bạn mệt mỏi khi phải cuộn qua các bài viết giống nhau? khi bạn tạo một tài khoản, bạn sẽ luôn quay lại nơi bạn đã dừng lại. Với một tài khoản, bạn cũng có thể được thông báo về các câu trả lời mới, lưu dấu trang và sử dụng lượt thích để cảm ơn người khác. Tất cả chúng ta có thể làm việc cùng nhau để làm cho cộng đồng này trở nên tuyệt vời. :heart:" + value_prop: "Bạn mệt mỏi khi phải cuộn qua các bài viết giống nhau? Khi tạo tài khoản, bạn sẽ luôn quay lại nơi bạn đã dừng lại. Với một tài khoản, bạn cũng có thể được thông báo về các câu trả lời mới, lưu dấu trang và sử dụng lượt thích để cảm ơn người khác. Tất cả chúng ta có thể làm việc cùng nhau để làm cho cộng đồng này trở nên tuyệt vời. :heart:" summary: enabled_description: "Bạn đang xem một bản tóm tắt của chủ đề này: các bài viết thú vị nhất được xác định bởi cộng đồng." description: @@ -2240,13 +2242,43 @@ vi: user_menu: generic_no_items: "Không có mục nào trong danh sách này." view_all_notifications: "xem tất cả các thông báo" + view_all_bookmarks: "xem tất cả các dấu trang" + view_all_messages: "xem tất cả các tin nhắn cá nhân" + tabs: + all_notifications: "Tất cả các thông báo" + replies: "Trả lời" + replies_with_unread: + other: "Trả lời - %{count} trả lời chưa đọc" + mentions: "Được nhắc đến" + mentions_with_unread: + other: "Đề cập - %{count} đề cập chưa đọc" + likes: "Lượt Thích" + likes_with_unread: + other: "Lượt thích - %{count} lượt thích chưa đọc" + watching: "Chủ đề đã xem" + watching_with_unread: + other: "Chủ đề đã xem - %{count} chủ đề đã xem chưa đọc" + messages: "Tin nhắn cá nhân" + messages_with_unread: + other: "Tin nhắn cá nhân - %{count} tin nhắn chưa đọc" + bookmarks: "Các đánh dấu" + bookmarks_with_unread: + other: "Dấu trang - %{count} dấu trang chưa đọc" + review_queue: "Hàng đợi xem lại" + review_queue_with_unread: + other: "Hàng đợi xem lại - %{count} mục cần xem xét" + other_notifications: "Các thông báo khác" + other_notifications_with_unread: + other: "Các thông báo khác - %{count} thông báo chưa đọc" + profile: "Tiểu sử" reviewable: view_all: "xem tất cả các mục đánh giá" queue: "Hàng đợi" deleted_user: "(người dùng đã bị xóa)" + deleted_post: "(bài đã xóa)" post_number_with_topic_title: "bài #%{post_number} - %{title}" new_post_in_topic: "bài mới trong %{title}" - suspicious_user: "người dùng đáng ngờ %{username}" + user_requires_approval: "%{username} yêu cầu phê duyệt" default_item: "mục có thể xem lại #%{reviewable_id}" topics: new_messages_marker: "lần thăm cuối" @@ -2309,6 +2341,7 @@ vi: read: "Không còn thêm chủ đề chưa đọc nào nữa." new: "Không còn thêm chủ đề mới nào nữa." unread: "Không còn thêm chủ đề chưa đọc nào nữa." + unseen: "Không còn chủ đề nào chưa từng thấy." category: "Không còn thêm chủ đề nào trong %{category} ." tag: "Không có thêm %{tag} chủ đề." top: "Không còn của đề top nào nữa." @@ -2350,11 +2383,15 @@ vi: not_found: title: "Không tìm thấy chủ đề" description: "Xin lỗi, chúng tôi không thể tìm thấy chủ đề đó. Có lẽ nó đã bị loại bởi mod?" + unread_posts: + other: "bạn có %{count} bài viết chưa đọc trong chủ đề này" likes: other: "có %{count} thích trong chủ để này" back_to_list: "Quay lại danh sách chủ đề" options: "Các lựa chọn chủ đề" show_links: "Hiển thị liên kết trong chủ đề này" + collapse_details: "thu gọn chi tiết chủ đề" + expand_details: "mở rộng chi tiết chủ đề" read_more_in_category: "Muốn đọc nữa? Xem qua các chủ đề khác trong %{catLink} hoặc %{latestLink}" read_more: "Muốn đọc nữa? %{catLink} hoặc %{latestLink}" unread_indicator: "Chưa có thành viên nào đọc bài cuối cùng của chủ đề này." @@ -2838,9 +2875,6 @@ vi: delete: confirm: other: "Bạn có chắc chắn muốn xóa %{count} bài viết đó không?" - merge: - confirm: - other: "Bạn có chắc chắn muốn hợp nhất %{count} bài viết đó không?" revisions: controls: first: "Sửa đổi đầu tiên" @@ -3385,7 +3419,7 @@ vi: google: "Google Lịch" ics: "ICS" tagging: - all_tags: "Tất cả thẻ" + all_tags: "Tất cả các thẻ" other_tags: "Các thẻ khác" selector_all_tags: "tất cả thẻ" selector_no_tags: "không có thẻ" @@ -3538,9 +3572,8 @@ vi: user_activity: no_activity_title: "Chưa có hoạt động nào" no_activity_body: "Chào mừng đến với cộng đồng của chúng tôi! Bạn là thương hiệu mới ở đây và chưa đóng góp vào các cuộc thảo luận. Bước đầu tiên, hãy truy cập Top hoặc Chuyên mục và chỉ cần bắt đầu đọc! Chọn %{heartIcon} trên các bài đăng mà bạn thích hoặc muốn tìm hiểu thêm. Khi bạn tham gia, hoạt động của bạn sẽ được liệt kê ở đây." - no_activity_others: "Chưa có hoạt động nào." no_replies_title: "Bạn chưa trả lời bất kỳ chủ đề nào" - no_replies_others: "Không có câu trả lời." + no_replies_title_others: "%{username} chưa trả lời bất kỳ chủ đề nào" no_drafts_title: "Bạn chưa bắt đầu bất kỳ bản nháp nào" no_drafts_body: "Bạn chưa hoàn toàn sẵn sàng để đăng bài? Chúng tôi sẽ tự động lưu một bản nháp mới và liệt kê nó ở đây bất cứ khi nào bạn bắt đầu soạn một chủ đề, trả lời hoặc tin nhắn cá nhân. Chọn nút hủy để hủy hoặc lưu bản nháp của bạn để tiếp tục sau." no_likes_title: "Bạn chưa thích bất kỳ chủ đề nào" @@ -3565,9 +3598,11 @@ vi: other: "%{count} mới" toggle_section: "phần chuyển đổi" more: "Thêm..." + all_categories: "Tất cả danh mục" sections: + about: + header_link_text: "Giới thiệu" messages: - header_link_title: "tin nhắn cá nhân" header_link_text: "Tin nhắn" header_action_title: "tạo một tin nhắn cá nhân" links: @@ -3581,23 +3616,28 @@ vi: tags: none: "Bạn chưa thêm bất kỳ thẻ nào." click_to_get_started: "Bấm vào đây để bắt đầu." - header_link_title: "tất cả thẻ" header_link_text: "Thẻ" header_action_title: "chỉnh sửa thẻ thanh bên của bạn" categories: none: "Bạn chưa thêm bất kỳ danh mục nào." click_to_get_started: "Bấm vào đây để bắt đầu." - header_link_title: "tất cả chuyên mục" header_link_text: "Thư mục" header_action_title: "chỉnh sửa danh mục thanh bên của bạn" community: - header_link_title: "trang chủ" header_link_text: "Cộng đồng" header_action_title: "tạo một chủ đề mới" links: + about: + content: "Giới thiệu" + admin: + content: "Quản trị" + badges: + content: "Huy hiệu" everything: content: "Mọi thứ" title: "Tất cả các chủ đề" + faq: + content: "Câu hỏi thường gặp" tracked: content: "Theo dõi" title: "Tất cả các chủ đề được theo dõi" @@ -3612,6 +3652,7 @@ vi: title: "Bài viết của tôi" draft_count: other: "%{count} bản nháp" + until: "Cho đến khi:" admin_js: type_to_filter: "gõ để lọc..." admin: @@ -4753,7 +4794,6 @@ vi: other: "Không thể xóa tất cả các bài viết, một số bài viết cũ hơn %{count} ngày. (Thiết lập delete_user_max_post_age.)" cant_delete_all_too_many_posts: other: "Không thể xóa tất cả các bài viết do tài khoản có hơn %{count} bài viết. (delete_all_posts_max)" - delete_confirm: "Nói chung, bạn nên ẩn danh người dùng hơn là xóa họ, để tránh xóa nội dung khỏi các cuộc thảo luận hiện có.

    Bạn có CHẮC CHẮN muốn xóa người dùng này không? Điều này là vĩnh viễn!" delete_and_block: "Xóa và khóa email này và địa chỉ IP" delete_dont_block: "Chỉ xóa" deleting_user: "Đang xóa người dùng..." @@ -4876,7 +4916,6 @@ vi: recommended: "Bạn nên tùy biến các nội dung sau đây cho phù hợp với nhu cầu:" show_overriden: "Chỉ hiển thị chỗ ghi đè" locale: "Ngôn ngữ:" - fallback_locale_warning: "Bạn đang chỉnh sửa một ngôn ngữ dựa trên %{fallback}. Người dùng chọn %{fallback} làm ngôn ngữ giao diện của họ sẽ không thấy các thay đổi của bạn." more_than_50_results: "Có hơn 50 kết quả. Vui lòng tinh chỉnh tìm kiếm của bạn." settings: show_overriden: "Chỉ hiển thị chỗ ghi đè" diff --git a/config/locales/client.zh_CN.yml b/config/locales/client.zh_CN.yml index f326fb88bb..32d2928ddd 100644 --- a/config/locales/client.zh_CN.yml +++ b/config/locales/client.zh_CN.yml @@ -151,7 +151,6 @@ zh_CN: forwarded: "转发了上述电子邮件" topic_admin_menu: "话题操作" skip_to_main_content: "跳转到主要内容" - wizard_required: "欢迎来到全新的 Discourse!让我们跟随设置向导开始吧 ✨" emails_are_disabled: "所有外发电子邮件已被管理员全局禁用。任何类型的电子邮件通知都不会发出。" emails_are_disabled_non_staff: "非管理员用户无法向外发送电子邮件。" software_update_prompt: @@ -160,6 +159,8 @@ zh_CN: bootstrap_mode_enabled: other: "为了更轻松地启动您的新站点,您现在处于引导模式。所有新用户都将被授予信任级别 1,并且已启用每日摘要电子邮件。引导模式会在达到 %{count} 个用户时自动关闭。" bootstrap_mode_disabled: "引导模式将在 24 小时内禁用。" + bootstrap_invite_button_title: "发送邀请" + bootstrap_wizard_link_title: "完成设置向导" themes: default_description: "默认" broken_theme_alert: "您的网站可能无法运行,因为主题/组件有错误。" @@ -196,6 +197,8 @@ zh_CN: not_implemented: "抱歉,该功能尚未实现!" no_value: "否" yes_value: "是" + ok_value: "确定" + cancel_value: "取消" submit: "提交" generic_error: "抱歉,出错了。" generic_error_with_reason: "出错了:%{error}" @@ -996,6 +999,7 @@ zh_CN: dismiss_notifications: "全部关闭" dismiss_notifications_tooltip: "将所有未读通知标记为已读" dismiss_bookmarks_tooltip: "将所有未读书签提醒标记为已读" + dismiss_messages_tooltip: "将所有未读的个人信息通知标记为已读" no_messages_title: "您没有任何消息" no_messages_body: > 需要直接与某人对话而不是公开讨论?选择他的头像并点击 %{icon} 消息按钮,向他们发送消息。

    如果您需要帮助,可以向管理人员发送消息。 @@ -1579,7 +1583,6 @@ zh_CN: set_custom_status: "设置自定义状态" what_are_you_doing: "你在做什么?" remove_status: "移除状态" - until: "直到:" loading: "正在加载…" errors: prev_page: "无法加载" @@ -1612,6 +1615,8 @@ zh_CN: enabled: "此站点处于只读模式。您可以继续浏览,但是回复、点赞和其他操作暂时被禁用。" login_disabled: "当站点处于只读模式时,登录被禁用。" logout_disabled: "当站点处于只读模式时,退出被禁用。" + staff_writes_only_mode: + enabled: "本站点处于工作人员专用模式。请继续浏览,但回复、赞和其他操作仅限于管理人员。" 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: >- @@ -1642,7 +1647,7 @@ zh_CN: hide_forever: "不,谢谢" hidden_for_session: "好的,我们会在明天问您。您也可以随时使用“登录”来创建帐户。" intro: "您好!看起来您很喜欢讨论,但您还没有注册帐户。" - value_prop: "厌倦了每次从头浏览相同的帖子?当您注册后,您总是可以从上次看到的位置继续阅读。成为用户,您还可以收到新回复通知、保存书签以及使用“赞”来感谢他人。我们可以共同努力使这个社区变得更好。 :heart:" + value_prop: "厌倦了每次从头浏览相同的帖子?当你注册后,总是可以从上次看到的位置继续阅读。有了账户,你还可以收到新回复通知、保存书签以及使用“赞”来感谢他人。我们可以一起努力,使这个社区变得更好。 :heart:" summary: enabled_description: "您正在查看此话题的摘要:社区确定的最有趣的帖子。" description: @@ -1973,6 +1978,7 @@ zh_CN: abandon: "关闭编辑器并舍弃草稿" enter_fullscreen: "进入全屏编辑器" exit_fullscreen: "退出全屏编辑器" + exit_fullscreen_prompt: "按 ESC 退出全屏" show_toolbar: "显示编辑器工具栏" hide_toolbar: "隐藏编辑器工具栏" modal_ok: "确定" @@ -2071,7 +2077,9 @@ zh_CN: other: "您确定吗?您有 %{count} 个重要通知。" bookmarks: other: "确定吗?您共有 %{count} 个未读书签提醒。" - dismiss: "标记为已读" + messages: + other: "确定吗?你有 %{count} 条未读的个人信息。" + dismiss: "忽略" cancel: "取消" group_message_summary: other: "您的 %{group_name} 收件箱中有 %{count} 条消息" @@ -2249,16 +2257,45 @@ zh_CN: view_all: "查看所有%{tab}" user_menu: generic_no_items: "此列表中没有内容。" - sr_menu_tabs: "菜单选项卡" + sr_menu_tabs: "用户菜单标签" view_all_notifications: "查看所有通知" view_all_bookmarks: "查看所有书签" + view_all_messages: "查看所有个人消息" + tabs: + all_notifications: "所有通知" + replies: "回复" + replies_with_unread: + other: "回复 - %{count} 个未读回复" + mentions: "提及" + mentions_with_unread: + other: "提及 - %{count} 个未读提及" + likes: "赞" + likes_with_unread: + other: "赞 - %{count} 个未读赞" + watching: "关注的主题" + watching_with_unread: + other: "关注的主题 - %{count} 未读的关注主题" + messages: "私信" + messages_with_unread: + other: "私信 - %{count} 条未读私信" + bookmarks: "书签" + bookmarks_with_unread: + other: "书签 - %{count} 个未读书签" + review_queue: "审核队列" + review_queue_with_unread: + other: "审核队列 - %{count} 个项目需要审核" + other_notifications: "其他通知" + other_notifications_with_unread: + other: "其他通知 - %{count} 个未读通知" + profile: "个人资料" reviewable: view_all: "查看所有审查项目" queue: "队列" deleted_user: "(删除用户)" + deleted_post: "(已删除的帖子)" post_number_with_topic_title: "帖子 #%{post_number} - %{title}" new_post_in_topic: "%{title} 中的新帖子" - suspicious_user: "可疑用户 %{username}" + user_requires_approval: "%{username} 需要批准" default_item: "可审查项目 #%{reviewable_id}" topics: new_messages_marker: "上次访问" @@ -2770,7 +2807,7 @@ zh_CN: upload: "抱歉,上传该文件时出错。请重试。" file_too_large: "抱歉,该文件太大(最大大小为 %{max_size_kb}KB)。为什么不将您的大文件上传到云共享服务,然后粘贴链接呢?" file_size_zero: "抱歉,好像出了点问题,您要上传的文件大小是 0 字节。请再试一次。" - file_too_large_humanized: "抱歉,该文件太大(最大大小为 %{max_size}KB)。为什么不将您的大文件上传到云共享服务,然后粘贴链接呢?" + file_too_large_humanized: "抱歉,该文件太大(最大大小为 %{max_size})。为什么不将您的大文件上传到云共享服务,然后粘贴链接呢?" too_many_uploads: "抱歉,一次只能上传一个文件。" too_many_dragged_and_dropped_files: other: "抱歉,一次只能上传 %{count} 个文件。" @@ -2862,7 +2899,7 @@ zh_CN: other: "确定要删除这 %{count} 个帖子吗?" merge: confirm: - other: "确定要合并这 %{count} 个帖子吗?" + other: "你确定要合并这 %{count} 个帖子吗?" revisions: controls: first: "第一个修订" @@ -3265,6 +3302,7 @@ zh_CN: today: "今天" other_periods: "查看热门:" browser_update: '很抱歉, 你的浏览器不受支持。请 切换到支持的浏览器 查看丰富的内容、登录和回复。' + safari_13_warning: 该站点将很快停止对 iOS 和 Safari 13 及以下版本的支持。简化的只读版本仍将可用。 (查看更多信息) permission_types: full: "创建/回复/查看" create_post: "回复/查看" @@ -3563,14 +3601,14 @@ zh_CN: user_activity: no_activity_title: "尚无活动" no_activity_body: "欢迎来到我们的社区!作为新人,你还未参与过讨论。第一步,请访问 置顶内容 或 分类 并开始阅读!在你喜欢或想了解更多的帖子上选择 %{heartIcon} 。当你参与时,你的活动将被列在这里。" - no_activity_others: "无活动。" no_replies_title: "您还没有回复任何话题" - no_replies_others: "无回复。" + no_replies_title_others: "%{username} 还没有回复任何话题" + no_replies_body: "当你 发现 一个你希望参与的有趣对话时,请直接按下任何帖子下方的 回复 按钮以开始回复该特定帖子。或者,如果你希望回复一般主题而不是任何个人帖子或个人,请在主题最底部或主题时间线下方按下 回复 按钮。" no_drafts_title: "您还没有写过任何草稿" no_drafts_body: "还没准备好发布?每当您开始撰写主题、回复或个人消息时,我们都会自动保存新草稿并在此处列出。选择取消按钮放弃或保存您的草稿以供稍后继续。" no_likes_title: "您还没有赞任何话题" + no_likes_title_others: "%{username} 还没有喜欢任何话题" no_likes_body: "加入并开始贡献的一个好方法是阅读已有的主题,并在您喜欢的帖子上点击 %{heartIcon}" - no_likes_others: "没有赞过的帖子。" no_topics_title: "您还没有开始任何话题" no_topics_body: "在开始一个新的话题之前,最好先用 搜索 来查找现有的话题,但如果你确信你想要的话题还没有出现,那就开始一个属于你自己的新话题吧。在话题列表、类别或标签页面的右上方找到 + 新建话题 按钮来创建新的话题。" no_topics_title_others: "%{username} 还没有开始任何话题" @@ -3591,9 +3629,12 @@ zh_CN: other: "%{count} 新" toggle_section: "切换部分" more: "更多…" + all_categories: "所有类别" + all_tags: "所有标签" sections: + about: + header_link_text: "关于" messages: - header_link_title: "私信" header_link_text: "消息" header_action_title: "创建个人消息" links: @@ -3607,23 +3648,28 @@ zh_CN: tags: none: "你还没有添加任何标签。" click_to_get_started: "点击这里开始。" - header_link_title: "所有标签" header_link_text: "标签" header_action_title: "编辑您的侧边栏标签" categories: none: "你还没有添加任何类别。" click_to_get_started: "点击这里开始。" - header_link_title: "所有类别" header_link_text: "类别" header_action_title: "编辑你的侧边栏类别" community: - header_link_title: "首页" header_link_text: "社区" header_action_title: "创建新话题" links: + about: + content: "关于" + admin: + content: "管理员" + badges: + content: "徽章" everything: content: "一切" title: "所有话题" + faq: + content: "常见问题解答" tracked: content: "已跟踪" title: "所有跟踪的话题" @@ -3638,6 +3684,11 @@ zh_CN: title: "我的帖子" draft_count: other: "%{count} 草稿" + welcome_topic_banner: + title: "创建你的欢迎话题" + description: '你的欢迎话题是新来的人首先会读到的东西。可以把它看作是你的一段 "电梯推销 "或 "使命宣言"。' + button_title: "开始编辑" + until: "直到:" admin_js: type_to_filter: "输入以筛选…" admin: @@ -4190,6 +4241,8 @@ zh_CN: import_web_advanced: "高级…" import_file_tip: "包含主题的 .tar.gz、.zip 或 .dcstyle.json 文件" is_private: "主题位于私有 git 仓库中" + finish_install: "完成主题安装" + last_attempt: "安装过程未完成,最后一次尝试:" remote_branch: "分支名称(可选)" public_key: "授予以下公钥访问仓库的权限:" public_key_note: "在上面输入有效的私有仓库 URL 后,将生成 SSH 密钥并在此处显示。" @@ -4200,6 +4253,8 @@ zh_CN: install_git_repo: "从 git 仓库" install_create: "创建新主题" duplicate_remote_theme: "主题组件“%{name}”已安装,确定要安装另一个副本吗?" + force_install: "该主题无法安装,因为 Git 仓库无法访问。你确定你要继续安装它吗?" + create_placeholder: "创建占位符" about_theme: "关于" license: "许可证" version: "版本:" @@ -4731,6 +4786,7 @@ zh_CN: suspended: "已封禁?" staged: "暂存?" show_admin_profile: "管理员" + manage_user: "管理用户" show_public_profile: "显示公开个人资料" impersonate: "模拟" action_logs: "操作日志" @@ -4825,7 +4881,8 @@ zh_CN: other: "无法删除所有帖子。某些帖子的存在时间超过 %{count} 天。(delete_user_max_post_age 设置。)" cant_delete_all_too_many_posts: other: "无法删除所有帖子,因为该用户的帖子超过 %{count} 篇。(delete_all_posts_max)" - delete_confirm: "一般而言,最好对用户进行匿名化而不是删除它们,以避免移除现有讨论中的内容。

    确定要删除此用户吗?此操作无法撤消!" + delete_confirm_title: "你确定要删除这个用户吗?这是永久性的!" + delete_confirm: "一般来说,最好是对用户进行匿名处理,而不是删除他们,以避免删除现有讨论的内容。" delete_and_block: "删除并禁止该电子邮件和 IP 地址" delete_dont_block: "仅删除" deleting_user: "正在删除用户…" @@ -4955,7 +5012,6 @@ zh_CN: recommended: "我们建议自定义以下文本以符合您的需求:" show_overriden: "只显示被替换" locale: "语言:" - fallback_locale_warning: "您正在编辑基于%{fallback}的语言。选择%{fallback}作为界面语言的用户不会看到您的变更。" more_than_50_results: "结果超过 50 个。请优化您的搜索。" settings: show_overriden: "只显示被替换" diff --git a/config/locales/client.zh_TW.yml b/config/locales/client.zh_TW.yml index 67b329fcee..fd948efa44 100644 --- a/config/locales/client.zh_TW.yml +++ b/config/locales/client.zh_TW.yml @@ -151,7 +151,6 @@ zh_TW: forwarded: "轉寄上述電子郵件" topic_admin_menu: "話題動作" skip_to_main_content: "跳到主要內容" - wizard_required: "是時候配置你的論壇啦!點擊開始設置嚮導!" emails_are_disabled: "管理員已停用了全域的外部信件功能。將不再寄出任何類型的電子郵件。" emails_are_disabled_non_staff: "非員工用戶的外發電子郵件已被禁用。" software_update_prompt: @@ -160,6 +159,7 @@ zh_TW: bootstrap_mode_enabled: other: "為了讓您更輕鬆地建設網站,您正處於初始模式。將會自動授予所有新註冊的使用者信任等級 1,並自動啟用每日摘要電子郵件。該功能將於 %{count} 個使用者註冊後自動關閉。" bootstrap_mode_disabled: "初始模式將會在 24 小時後自動禁用。" + bootstrap_invite_button_title: "送出邀請" themes: default_description: "預設" broken_theme_alert: "您的網站可能無法運行,因為主題/組件有錯誤。" @@ -195,6 +195,8 @@ zh_TW: not_implemented: "抱歉,此功能尚未開放。" no_value: "否" yes_value: "是" + ok_value: "確定" + cancel_value: "取消" submit: "送出" generic_error: "抱歉,發生錯誤。" generic_error_with_reason: "發生錯誤: %{error}" @@ -1826,6 +1828,13 @@ zh_TW: go_back: "返回" not_logged_in_user: "使用者頁面(包含目前活動及喜好的摘要)" current_user: "到你的使用者頁面" + user_menu: + tabs: + replies: "回覆" + mentions: "提及" + likes: "新的讚" + bookmarks: "書籤" + profile: "基本資料" topics: new_messages_marker: "上次到訪" bulk: @@ -2278,9 +2287,6 @@ zh_TW: delete: confirm: other: "您是否確定要刪除%{count}篇貼文?" - merge: - confirm: - other: "您是否確定要合併%{count}篇貼文?" revisions: controls: first: "第一版" @@ -2702,7 +2708,6 @@ zh_TW: download_calendar: download: "下載" tagging: - all_tags: "所有標籤" other_tags: "其他標籤" selector_all_tags: "所有標籤" selector_no_tags: "無標籤" @@ -2800,17 +2805,16 @@ zh_TW: member: "成員" regular: "活躍使用者" leader: "資深" - user_activity: - no_activity_others: "無活動紀錄。" - no_replies_others: "沒有回覆。" - no_likes_others: "沒有被讚的貼文。" sidebar: unread_count: other: "%{count} 個未讀" new_count: other: "%{count} 近期" more: "更多..." + all_categories: "所有分類" sections: + about: + header_link_text: "關於" messages: header_link_text: "訊息" links: @@ -2822,15 +2826,20 @@ zh_TW: unread_with_count: "未讀 (%{count})" archive: "封存" tags: - header_link_title: "所有標籤" header_link_text: "標籤" categories: - header_link_title: "所有分類" header_link_text: "分類" community: - header_link_title: "主頁" header_link_text: "社區" links: + about: + content: "關於" + admin: + content: "管理員" + badges: + content: "徽章" + faq: + content: "常見問答" tracked: content: "已追蹤" groups: @@ -3749,7 +3758,6 @@ zh_TW: other: "無法刪除所有的貼文。有些貼文時間早於 %{count} 天前。 ( 請見 delete_user_max_post_age 設定 )" cant_delete_all_too_many_posts: other: "無法刪除所有貼文,因為此使用者擁有超過 %{count} 篇貼文。( delete_all_posts_max )" - delete_confirm: "通常相較於直接將使用者刪除,比較建議將使用者除名,避免從現存的討論中移除內容。

    您是否確定要刪除這位使用者?此動作不可復原!" delete_and_block: "刪除並且封鎖此電子郵件地址與 IP 位址" delete_dont_block: "只刪除" deleting_user: "正在刪除使用者..." diff --git a/config/locales/server.ar.yml b/config/locales/server.ar.yml index d5fb0fcd11..aa8c4a628f 100644 --- a/config/locales/server.ar.yml +++ b/config/locales/server.ar.yml @@ -690,8 +690,7 @@ ar: invalid_url: "عنوان URL البديل غير صالح" <<: *errors uncategorized_category_name: "غير مصنَّف" - vip_category_name: "الاستراحة" - vip_category_description: "فئة حصرية للأعضاء من مستوى الثقة 3 وأعلى." + general_category_name: "عام" meta_category_name: "التعليقات على الموقع" meta_category_description: "مناقشة بشأن هذا الموقع، ومؤسسته، وطريقة عمله، وكيف يمكننا تحسينه." staff_category_name: "فريق العمل" @@ -712,29 +711,6 @@ ar: قد ترغب في إغلاق هذا الموضوع من خلال المسؤول :wrench: (في أعلى اليمين والأسفل)؛ حتى لا تتراكم الردود في إعلان. - lounge_welcome: - title: "مرحبًا بك في الاستراحة" - body: |2 - - تهانينا! :confetti_ball: - - إذا كان بإمكانك رؤية هذا الموضوع، فقد تمت ترقيتك مؤخرًا إلى **منتظم** (مستوى الثقة 3). - - يمكنك الآن … - - * تعديل عنوان أي موضوع - * تغيير فئة أي موضوع - * تتبُع جميع روابطك - تتم إزالة ([إلغاء المتابعة التلقائي](https://en.wikipedia.org/wiki/Nofollow) - * الوصول إلى فئة استراحة خاصة مرئية فقط للمستخدمين من مستوى الثقة 3 وأعلى - * إخفاء المنشورات غير المرغوب فيها ببلاغ واحد - - إليك [القائمة الحالية بزملائك من المستخدمين المنتظمين](%{base_path}/badges/3/regular). لا تنسَ إلقاء التحية. - - نشكرك على كونك جزءًا مهمًا من هذا المجتمع! - - (لمزيد من المعلومات بشأن مستويات الثقة، [راجع هذا الموضوع][الثقة]. يُرجى العلم بأن الأعضاء الذين يستمرون في استيفاء المتطلبات بمرور الوقت سيظلون منتظمين.) - - [الثقة]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ admin_quick_start_title: "اقرأني أولًا: دليل البدء السريع للمسؤولين" category: topic_prefix: "نبذة عن الفئة %{category}" @@ -1943,7 +1919,6 @@ ar: min_trust_to_edit_wiki_post: "الحد الأدنى لمستوى الثقة المطلوب لتعديل منشور من نوع Wiki." min_trust_to_edit_post: "الحد الأدنى لمستوى الثقة المطلوب لتعديل المنشورات." min_trust_to_allow_self_wiki: "الحد الأدنى لمستوى الثقة المطلوب لتحويل منشور المستخدم إلى Wiki." - min_trust_to_send_messages: "الحد الأدنى لمستوى الثقة المطلوب لإنشاء رسائل خاصة جديدة" min_trust_to_send_email_messages: "الحد الأدنى لمستوى الثقة المطلوب لإرسال رسائل خاصة عبر البريد الإلكتروني" min_trust_to_flag_posts: "الحد الأدنى لمستوى الثقة المطلوب للإبلاغ عن المنشورات" min_trust_to_post_links: "الحد الأدنى لمستوى الثقة المطلوب لتضمين الروابط في المنشورات" @@ -4345,7 +4320,6 @@ ar: register: button: "التسجيل" title: "تسجيل حساب المسؤول" - help: "أنشئ حسابًا جديدًا للبدء" no_emails: "للأسف، لم يتم تحديد أي رسائل إلكترونية للمسؤول في أثناء الإعداد؛ لذا قد يكون إنهاء الإعداد أمرًا صعبًا. يُرجى إضافة عنوان بريد إلكتروني للمطوِّر في ملف الإعداد أو إنشاء حساب مسؤول من وحدة التحكم ." confirm_email: title: "تأكيد عنوان بريدك الإلكتروني" @@ -4355,9 +4329,7 @@ ar: message: "

    لقد أعدنا إرسال الرسالة الإلكترونية للتنشيط إلى %{email}" safe_mode: title: "الدخول إلى الوضع الآمن" - description: "يسمح لك الوضع الآمن باختبار موقعك دون تحميل المكوِّنات الإضافية أو تخصيصات الموقع." - no_customizations: "إيقاف السمة الحالية" - only_official: "إيقاف المكوِّنات الإضافية غير الرسمية" + no_unofficial_plugins: "إيقاف المكوِّنات الإضافية غير الرسمية" no_plugins: "إيقاف كل المكوِّنات الإضافية" enter: "الدخول إلى الوضع الآمن" must_select: "يجب عليك تحديد خيار واحد على الأقل للدخول إلى الوضع الآمن." diff --git a/config/locales/server.be.yml b/config/locales/server.be.yml index 2dd9a7d00f..1c3f8e8bd1 100644 --- a/config/locales/server.be.yml +++ b/config/locales/server.be.yml @@ -338,16 +338,13 @@ be: too_many: "Занадта шмат слоў для гэтага дзеяння" <<: *errors uncategorized_category_name: "без" - vip_category_name: "гасцёўня" - vip_category_description: "Катэгорыя выключна для членаў з даверным узроўнем 3 і вышэй." + general_category_name: "Агульныя" meta_category_name: "зваротная сувязь" meta_category_description: "Абмеркаванне гэтага сайта, яго арганізацыя, як яна працуе, і як мы можам палепшыць яго." staff_category_name: "персанал" staff_category_description: "Асобная катэгорыя для абмеркавання персаналу. Тэмы бачныя толькі адміністратарам і мадэратарам." discourse_welcome_topic: title: "Сардэчна запрашаем у дыскурсе" - lounge_welcome: - title: "Сардэчна запрашаем у Lounge" admin_quick_start_title: "READ ME FIRST: Адміністратар Quick Start Guide" category: topic_prefix: "Аб %{category} катэгорыі" @@ -1093,7 +1090,6 @@ be: min_trust_to_edit_wiki_post: "Мінімальны ўзровень даверу патрабуецца адрэдагаваць запіс пазначаецца як віка." min_trust_to_edit_post: "Мінімальны ўзровень даверу патрабуецца рэдагаваць паведамленні." min_trust_to_allow_self_wiki: "Мінімальны ўзровень даверу патрабуецца, каб зрабіць карыстальнік ўласнай паста тутэйшыя артыкулы." - min_trust_to_send_messages: "Мінімальны ўзровень даверу, неабходны для стварэння новых асабістых паведамленняў." min_trust_to_flag_posts: "Мінімальны ўзровень даверу патрабуецца сцяг паведамленняў" min_trust_to_post_links: "Мінімальны ўзровень даверу павінен ўключаць спасылкі ў паведамленнях" allowed_link_domains: "Дамены, якія карыстальнікі могуць спасылаюцца нават калі яны не маюць адпаведны ўзровень даверу да паведамлення спасылкі" @@ -2352,7 +2348,6 @@ be: register: button: "рэгістрацыя" title: "Рэгістрацыя ўліковага запісу адміністратара" - help: "зарэгістраваць новы ўліковы запіс, каб пачаць" no_emails: "На жаль, няма электроннай пошты адміністратара не былі вызначаны падчас ўстаноўкі, так завяршае канфігурацыю можа быць абцяжарана. Калі ласка, дадайце ліст распрацоўніка ў файле канфігурацыі або Potser voleu tancar el tema amb l'eina d'administració :wrench: (dalt a la dreta i a baix), perquè les respostes no s'amunteguin sobre una comunicació. - lounge_welcome: - title: "Benvingut a la sala" - body: |2 - - Enhorabona! :confetti_ball: - - Si podeu veure aquest tema, heu estat promogut recentment a **habitual** (nivell 3 de confiança). - - Ara podeu… - - * editar el títol de qualsevol tema - * canviar la categoria de qualsevol tema - * tenir tots els vostres enllaços seguits (s'esborra el [nofollow automàtic](https://ca.wikipedia.org/wiki/Nofollow)) - * accedir a la categoria de sala privada visible solament per a usuaris de nivell de confiança 3 i superior - * amagar correu brossa amb una única bandera - - Vet aquí la [llista actual de companys habituals](%{base_path}/badges/3/regular). Assegureu-vos d'enviar-hi una salutació. - - Gràcies per formar part d'una part important d'aquesta comunitat! - - (Per a més informació sobre nivells de confiança [vegeu aquest tema][trust]. Tingueu en compte que sols els membres que continuïn complint els requisits continuaran sent habituals). - - [trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ admin_quick_start_title: "LLEGIU-ME PRIMER DE TOT: Guia ràpida d'inici per a administradors" category: topic_prefix: "Quant a la categoria %{category} " @@ -1439,7 +1415,6 @@ ca: min_trust_to_edit_wiki_post: "Nivell de confiança mínim necessari per a editar una publicació marcada com a wiki." min_trust_to_edit_post: "Nivell de confiança mínim necessari per a editar publicacions." min_trust_to_allow_self_wiki: "Nivell de confiança mínim necessari per a convertir en wiki les publicacions pròpies. " - min_trust_to_send_messages: "Nivell de confiança mínim necessari per a crear nous missatges personals." min_trust_to_flag_posts: "Nivell de confiança mínim necessari per a marcar amb bandera les publicacions" min_trust_to_post_links: "Nivell de confiança mínim necessari per a incloure enllaços en els missatges" allowed_link_domains: "Dominis als quals els usuaris poden enllaçar fins i tot si no tenen el nivell de confiança adequat per a publicar enllaços" @@ -2957,7 +2932,6 @@ ca: register: button: "Registre" title: "Registra un compte d'administració" - help: "registreu un compte nou per a començar" no_emails: "Malauradament, no s'han definit correus electrònics d'administrador durant la configuració, de manera que pot ser difícil completar la configuració. Afegiu un correu electrònic de desenvolupador en el fitxer de configuració o creeu un compte d'administrador des de la consola." confirm_email: title: "Confirmeu el vostre correu" @@ -2967,9 +2941,7 @@ ca: message: "

    Hem tornat a enviar el correu d'activació a %{email}" safe_mode: title: "Entra en mode segur" - description: "El mode segur us permet provar el lloc web sense carregar-hi connectors o personalitzacions del lloc web." - no_customizations: "Desactiva l'aparença actual" - only_official: "Inhabilita tots els connectors no oficials" + no_unofficial_plugins: "Inhabilita tots els connectors no oficials" no_plugins: "Inhabilita tots els connectors" enter: "Entra en mode segur" must_select: "Cal seleccionar almenys una opció per a entrar en mode segur." diff --git a/config/locales/server.cs.yml b/config/locales/server.cs.yml index d20f70411a..419e5d8da9 100644 --- a/config/locales/server.cs.yml +++ b/config/locales/server.cs.yml @@ -358,8 +358,7 @@ cs: too_many: "Příliš mnoho slov pro tuto akci" <<: *errors uncategorized_category_name: "Nezařazené" - vip_category_name: "VIP" - vip_category_description: "Kategorie je přístupná výhradně členům s důvěryhodností 3 a vyšší." + general_category_name: "Základní" meta_category_name: "Poznámky k webu" meta_category_description: "Diskutuje tento web, jeho organizaci, jak funguje a jak ho vylepšit." staff_category_name: "Redakce" @@ -380,8 +379,6 @@ cs: Možná budete chtít toto téma v administraci (vpravo nahoře a dole) zavřít, aby se nehromadily odpovědi na oznámeních. - lounge_welcome: - title: "Vítejte ve VIP" category: topic_prefix: "O kategorii %{category}" post_template: "%{replace_paragraph}\n\nPoužijte následující odstavce pro delší popis, nebo pro vytvoření pokynů ke kategorii nebo pravidel:\n\n- Proč by lidé měli používat tuto kategorii? K čemu slouží?\n\n- Jak přesně je tato kategorie odlišná od ostatních, které již máme?\n\n- Co by měly témata v této kategorii obvykle obsahovat?\n\n- Potřebujeme tuto kategorii? Můžeme ji sloučit s jinou kategorií nebo subkategorií?\n" diff --git a/config/locales/server.da.yml b/config/locales/server.da.yml index d8568db844..3d5bc0ab8c 100644 --- a/config/locales/server.da.yml +++ b/config/locales/server.da.yml @@ -563,8 +563,7 @@ da: invalid_url: "Erstatnings URL er ugyldig" <<: *errors uncategorized_category_name: "Ukategoriseret" - vip_category_name: "Lounge" - vip_category_description: "En ekslusiv kategori der kun er tilgængelig for medlemmer med tillidsniveu 3 eller højere." + general_category_name: "Overordnet" meta_category_name: "Site Feedback" meta_category_description: "Diskussion om dette websted, hvordan det er organiseret, hvordan det virker og hvordan vi kan forbedre det." staff_category_name: "Personale" @@ -584,29 +583,6 @@ da: Du bør eventuelt lukke dette emne via administratorfunktionen :wrench: (øverst til højre og i bunden), således at der ikke hober sig svar op til denne meddelelse. - lounge_welcome: - title: "Velkommen i loungen" - body: |2 - - Tillykke! :confetti_ball: - - Hvis du kan se dette emne, blev du for nylig forfremmet til **almindelig** (tillidsniveau 3). - - Du kan nu … - - * Rediger titlen på ethvert emne - * Skift kategorien for ethvert emne - * Få alle dine links fulgt ([automatisk nofollow](https://en.wikipedia.org/wiki/Nofollow) fjernes ) - * Adgang til en privat Lounge-kategori, der kun er synlig for brugere på tillidsniveau 3 og højere - * Skjul spam med en enkelt anmeldelse - - Her er den [aktuelle liste over andre almindelige brugere](%{base_path}/badges/3/regular). Sørg for at sige hej. - - Tak for at være en vigtig del af dette fællesskab! - - (For mere information om tillidsniveauer, [se dette emne][trust]. Bemærk, at kun medlemmer, der fortsat overholder kravene over tid, vil fastholde deres status.) - - [trust]: https://translate.google.dk/translate?hl=da&sl=en&u=https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/&prev=search&pto=aue admin_quick_start_title: "LÆS ME FØRST: Admin Quick Start Guide" category: topic_prefix: "Kategoridefinition for %{category}" @@ -1546,7 +1522,6 @@ da: min_trust_to_edit_wiki_post: "Det mindste tillidsniveau, der kræves for at redigere indlæg markeret som wiki." min_trust_to_edit_post: "Det mindste tillidsniveau, der kræves for at redigere indlæg." min_trust_to_allow_self_wiki: "Det mindste tillidsniveau, der kræves for at gøre brugerens egen post til wiki." - min_trust_to_send_messages: "Det mindste tillidsniveau, der kræves for at oprette nye personlige beskeder." min_trust_to_send_email_messages: "Det mindste tillidsniveau, der kræves for at sende personlige beskeder via e-mail." min_trust_to_flag_posts: "Det mindste tillidsniveau, der kræves for at anmelde indlæg" min_trust_to_post_links: "Det mindste tillidsniveau, der kræves for at medtage links i indlæg" @@ -3539,7 +3514,6 @@ da: register: button: "Registrer" title: "Registrer Admin Konto" - help: "registrere en ny konto for at komme i gang" confirm_email: title: "Bekræft din e-mail" message: "

    Vi sendte en aktiveringsmail til %{email}. Følg venligst instruktionerne i e-mailen for at aktivere din konto.

    Hvis den ikke ankommer, bør du tjekke din spam-mappe, og sikre, at du har opsat din e-mail korrekt.

    " @@ -3548,9 +3522,7 @@ da: message: "

    Vi har gensendt aktiverings-e-mailen til %{email}" safe_mode: title: "Gå ind i fejlsikret tilstand" - description: "Fejlsikret tilstand giver dig mulighed for at teste dit websted uden at indlæse plugins eller tilpasninger af webstedet." - no_customizations: "Deaktiver det aktuelle tema" - only_official: "Deaktiver uofficielle udvidelser" + no_unofficial_plugins: "Deaktiver uofficielle udvidelser" no_plugins: "Deaktiver alle udvidelsesmoduler" enter: "Gå ind i fejlsikret tilstand" must_select: "Du skal vælge mindst én mulighed for at gå i fejlsikret tilstand." diff --git a/config/locales/server.de.yml b/config/locales/server.de.yml index a4daad13c0..4263a2bdd7 100644 --- a/config/locales/server.de.yml +++ b/config/locales/server.de.yml @@ -73,6 +73,7 @@ de: file_too_big: "Die unkomprimierte Datei ist zu groß." unknown_file_type: "Die Datei, die du hochgeladen hast, scheint kein gültiges Discourse-Theme zu sein." not_allowed_theme: "`%{repo}` ist nicht in der Liste der zulässigen Themes (überprüfe die globale Einstellung `allowed_theme_repos`)." + ssh_key_gone: "Du hast zu lange mit der Installation des Themas gewartet und der SSH-Schlüssel ist abgelaufen. Bitte versuche es noch einmal." errors: component_no_user_selectable: "Theme-Komponenten können nicht vom Benutzer auswählbar sein" component_no_default: "Theme-Komponenten können nicht Standard-Theme sein" @@ -596,8 +597,8 @@ de: invalid: "ist nicht gültig" <<: *errors uncategorized_category_name: "Nicht kategorisiert" - vip_category_name: "Lounge" - vip_category_description: "Eine Kategorie exklusiv für Mitglieder mit Vertrauensstufe 3 oder höher." + general_category_name: "Allgemein" + general_category_description: "Erstelle hier Themen, die in keine andere bestehende Kategorie passen." meta_category_name: "Feedback" meta_category_description: "Diskussionen über dieses Forum, seine Organisation, wie es funktioniert und wie wir es verbessern können." staff_category_name: "Team" @@ -618,29 +619,6 @@ de: Du solltest dieses Thema eventuell mittels Themen-Administration :wrench: (oben rechts oder unten) schließen, damit sich bei dieser Ankündigung nicht die Antworten anhäufen. - lounge_welcome: - title: "Willkommen in der Lounge" - body: |2 - - Gratuliere! :confetti_ball: - - Wenn du dieses Thema sehen kannst, wurdest du vor Kurzem zum **Stammgast** (Vertrauensstufe 3) befördert. - - Du kannst nun … - - * den Titel eines jeden Themas ändern - * Themen in andere Kategorien verschieben - * Links veröffentlichen, die von Suchmaschinen weiterverfolgt werden (das automatische [nofollow](https://de.wikipedia.org/wiki/Nofollow) wird entfernt) - * auf die private Lounge-Kategorie zugreifen, die für Benutzer mit Vertrauensstufe 3 oder höher sichtbar ist - * Spam durch eine einzige Meldung ausblenden - - Hier ist die [aktuelle Liste aller Stammgäste](%{base_path}/badges/3/regular). Vergiss nicht, Hallo zu sagen! - - Vielen Dank dafür, dass du ein wichtiger Teil dieser Community bist! - - (Wenn du mehr über Vertrauensstufen wissen möchtest, kannst du [dieses Thema lesen][trust]. Beachte bitte, dass nur jene Mitglieder Stammgäste bleiben, die auch im Laufe der Zeit die Anforderungen erfüllen.) - - [trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ admin_quick_start_title: "ZUERST LESEN: Administrator-Kurzanleitung" category: topic_prefix: "Über die Kategorie %{category}" @@ -1500,7 +1478,8 @@ de: summary_percent_filter: "Zeige die Top-% der Beiträge eines Themas in der „Dieses Thema zusammenfassen“-Ansicht." summary_max_results: "Maximale Anzahl der Beiträge in der „Dieses Thema zusammenfassen“-Ansicht" summary_timeline_button: "Schaltfläche \"Zusammenfassen\" in der Zeitleiste anzeigen" - enable_personal_messages: "Erlaube Benutzern mit der Vertrauensstufe 1 (konfigurierbar über die minimale Vertrauensstufe zum Senden von Nachrichten), Nachrichten zu erstellen und auf Nachrichten zu antworten. Beachte, dass das Team immer Nachrichten senden kann." + enable_personal_messages: "VERALTET, nutze stattdessen nun die Einstellung \"Gruppen mit aktivierten persönlichen Nachrichten\". \nErlaube Benutzern mit der Vertrauensstufe 1 (konfigurierbar über die minimale Vertrauensstufe zum Senden von Nachrichten), Nachrichten zu erstellen und auf Nachrichten zu antworten. Beachte, dass das Team immer Nachrichten senden kann." + personal_message_enabled_groups: "Erlaube Nutzern innerhalb dieser Gruppen, Nachrichten zu erstellen und auf Nachrichten zu antworten. Vertrauensstufengruppen schließen alle Vertrauensstufen über dieser Nummer ein. Wenn du z.B. Vertrauensstufe 1 auswählst, können auch Benutzer der Vertrauensstufen 2, 3 und 4 PMs versenden. Beachte, dass Mitarbeiter/innen immer Nachrichten senden können, egal welche Stufe sie wählen." enable_system_message_replies: "Erlaube Benutzern, auf Systemnachrichten zu antworten, auch wenn persönliche Nachrichten deaktiviert sind" enable_chunked_encoding: "Aktiviere „chunked encoding“-Antworten durch den Server. Diese Funktion ist mit den meisten Set-ups kompatibel, aber einige Proxys können puffern, wodurch die Antworten verzögert werden" long_polling_base_url: "Basis-URL für Long Polling (wenn zum Ausliefern von dynamischen Inhalten ein CDN verwendet wird, setze dies auf Origin-Pull), z. B. http://origin.site.com" @@ -1568,6 +1547,7 @@ de: post_menu: "Legt fest, welche Funktionen in welcher Reihenfolge im Beitragsmenü auftauchen. Beispiel: like|edit|flag|delete|share|bookmark|reply" post_menu_hidden_items: "Die Einträge im Menü eines Beitrags, die standardmäßig hinter einer erweiterbaren Ellipse versteckt werden sollen." share_links: "Legt fest, welche Dienste in welcher Reihenfolge im Teilen-Dialog auftauchen." + allow_username_in_share_links: "Erlaube Benutzernamen in Freigabelinks zu verwenden. Dies ist nützlich, um Abzeichen für einzelne Besucher zu vergeben." site_contact_username: "Gültiger Benutzername eines Team-Mitglieds, in dessen Namen alle automatisch erzeugten Nachrichten versendet werden sollen. Falls leer, wird das Standard-System-Konto verwendet." site_contact_group_name: "Ein gültiger Name einer Gruppe, die zu allen automatisch versendeten privaten Nachrichten eingeladen wird." send_welcome_message: "Sende allen neuen Benutzern eine Begrüßungsnachricht mit einer Kurzanleitung." @@ -1677,6 +1657,8 @@ de: top_topics_formula_first_post_likes_multiplier: "Wert des Multiplikators (n) für die „Gefällt mir“-Angaben des ersten Beitrags in der Formel für angesagte Themen: `log(views_count) * 2 + op_likes_count * (n) + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" top_topics_formula_least_likes_per_post_multiplier: "Wert des Multiplikators (n) für die wenigsten „Gefällt mir“-Angaben pro Beitrag in der Formel für angesagte Themen: `log(views_count) * 2 + op_likes_count * 0.5 + LEAST(likes_count / posts_count, (n)) + 10 + log(posts_count)`" enable_safe_mode: "Erlaube Benutzern, den abgesicherten Modus zu betreten, um Plug-ins zu debuggen." + enable_experimental_sidebar_hamburger: "Ermöglicht die Aktivierung der experimentellen Seitenleiste und des Benutzer-Hamburger-Dropdown-Menüs." + enable_sidebar: "Aktiviert die experimentelle Seitenleiste." rate_limit_create_topic: "Nach Erstellen eines Themas muss ein Benutzer (n) Sekunden warten, bevor ein weiteres Thema erstellt werden kann." rate_limit_create_post: "Nach Schreiben eines Beitrags muss ein Benutzer (n) Sekunden warten, bevor ein weiterer Beitrag erstellt werden kann." rate_limit_new_user_create_topic: "Nach Erstellen eines Themas muss ein neuer Benutzer (n) Sekunden warten, bevor ein weiteres Thema erstellt werden kann." @@ -1767,7 +1749,7 @@ de: min_trust_to_edit_wiki_post: "Minimale Vertrauensstufe, um als Wiki markierte Beiträge bearbeiten zu können." min_trust_to_edit_post: "Minimale Vertrauensstufe, um Beiträge bearbeiten zu können." min_trust_to_allow_self_wiki: "Minimale Vertrauensstufe, die ein Benutzer haben muss, um einen eigenen Wiki-Eintrag zu erstellen." - min_trust_to_send_messages: "Minimale Vertrauensstufe, um neue persönliche Nachrichten zu erstellen." + min_trust_to_send_messages: "VERALTET, verwende stattdessen die Einstellung „Gruppen mit aktivierten persönlichen Nachrichten“. Die Mindestvertrauensstufe, die zum Erstellen neuer persönlicher Nachrichten erforderlich ist." min_trust_to_send_email_messages: "Minimale Vertrauensstufe, um persönliche Nachrichten per E-Mail zu versenden." min_trust_to_flag_posts: "Minimale Vertrauensstufe, um Beiträge melden zu können" min_trust_to_post_links: "Minimale Vertrauensstufe, um Links in Beiträge einzufügen" @@ -1872,6 +1854,7 @@ de: max_emails_per_day_per_user: "Maximale Anzahl von E-Mails, die den Benutzern pro Tag gesendet werden. 0 zum Deaktivieren des Limits" enable_staged_users: "Erstelle automatisch vorbereitete Benutzer, wenn eingehende E-Mails verarbeitet werden." maximum_staged_users_per_email: "Maximale Anzahl vorbereiteter Benutzer, wenn eine eingehende E-Mail bearbeitet wird." + maximum_recipients_per_new_group_email: "Blockiere eingehende E-Mails mit zu vielen Empfängern." auto_generated_allowlist: "Liste von E-Mail-Adressen, die nicht auf automatisch generierte Inhalte überprüft werden. Beispiel: foo@bar.com|discourse@bar.com" block_auto_generated_emails: "Eingehende E-Mails blockieren, die als automatisch generiert erkannt werden." ignore_by_title: "Ignoriere eingehende E-Mails basierend auf ihrem Betreff." @@ -2112,6 +2095,7 @@ de: heading_font: "Schriftart für Überschriften auf der Website. Themes können diese Schriftart mit der benutzerdefinierten CSS-Eigenschaft `--heading-font-family` überschreiben." enable_sitemap: "Generiere eine Sitemap für Deine Website und füge sie in die robots.txt-Datei ein." sitemap_page_size: "Anzahl der URLs, die auf jeder Sitemap-Seite enthalten sein sollen. Max 50.000" + enable_user_status: "(experimentell) Erlaubt es den Nutzern, eine eigene Statusmeldung (Emoji + Beschreibung) einzustellen." short_title: "Der Kurztitel wird beim Benutzer auf dem Startbildschirm, im Startmenü oder an anderen Stellen mit begrenztem Platz verwendet. Er sollte auf 12 Zeichen begrenzt sein." dashboard_hidden_reports: "Erlaube das Ausblenden der angegebenen Berichte im Dashboard." dashboard_visible_tabs: "Wähle aus, welche Dashboard-Registerkarten sichtbar sind." @@ -2127,6 +2111,9 @@ de: use_name_for_username_suggestions: "Verwende den vollen Namen eines Benutzers, wenn du Benutzernamen vorschlägst." suggest_weekends_in_date_pickers: "Beziehe die Wochenenden (Samstag und Sonntag) in die Datumsvorschläge mit ein (deaktiviere dies, wenn du Discourse nur an Wochentagen von Montag bis Freitag benutzt)." splash_screen: "Zeigt einen temporären Ladebildschirm an, während Website-Assets geladen werden" + default_sidebar_categories: "Ausgewählte Kategorien werden standardmäßig im Abschnitt Kategorien der Seitenleiste angezeigt." + default_sidebar_tags: "Ausgewählte Schlagwörter werden standardmäßig im Abschnitt Tags der Seitenleiste angezeigt." + enable_new_user_profile_nav_groups: "EXPERIMENTELL: Benutzern der ausgewählten Gruppen wird das neue Benutzerprofil-Navigationsmenü angezeigt" errors: invalid_css_color: "Ungültige Farbe. Gib einen Farbnamen oder einen Hexadezimalwert ein." invalid_email: "Ungültige E-Mail-Adresse." @@ -2154,6 +2141,7 @@ de: reply_by_email_address_is_empty: "Du musst „reply by email address“ definieren, bevor Antworten per E-Mail aktiviert wird." email_polling_disabled: "Du musst entweder manuelle oder POP3-Abfragen aktivieren, bevor Antworten per E-Mail aktiviert wird." user_locale_not_enabled: "Du musst erst „allow user locale“ aktivieren, bevor du diese Einstellung aktivierst." + personal_message_enabled_groups_invalid: "Du musst mindestens eine Gruppe für diese Einstellung angeben. Wenn du nicht möchtest, dass jemand außer den Mitarbeitern PMs verschickt, wähle die Gruppe der Mitarbeiter." invalid_regex: "Regulärer Ausdruck ist ungültig oder nicht erlaubt." invalid_regex_with_message: "Die Regex '%{regex}' hat einen Fehler: %{message}" email_editable_enabled: "Du musst „email editable“ deaktivieren, bevor du diese Einstellung aktivierst." @@ -3029,6 +3017,15 @@ de: Du hast auf eine E-Mail-Zusammenfassung geantwortet, was nicht zulässig ist. Wenn du denkst, dass dies ein Fehler ist, [kontaktiere ein Team-Mitglied](%{base_url}/about). + email_reject_too_many_recipients: + title: "E-Mail lehnt zu viele Empfänger ab" + subject_template: "[%{email_prefix}] E-Mail-Problem - Zu viele Empfänger" + text_body_template: | + Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (mit dem Titel %{former_title}) hat nicht funktioniert. + + Du hast versucht, an mehr als %{max_recipients_count} Personen zu schreiben und unser System hat deine E-Mail automatisch als Spam markiert. + + Wenn du glaubst, dass dies ein Fehler ist, [kontaktiere einen Mitarbeiter](%{base_url}/about). email_error_notification: title: "Benachrichtigung zu E-Mail-Fehler" subject_template: "[%{email_prefix}] E-Mail-Problem -- POP-Authentifizierungsfehler" @@ -4389,6 +4386,7 @@ de: invalid_token: "Ungültiges Token." email_input: "Administrator-E-Mail" submit_button: "E-Mail senden" + safe_mode: "Abgesicherter Modus: Deaktivieren Sie alle Themen/Plugins beim Anmelden" performance_report: initial_post_raw: Dieses Thema enthält tägliche Leistungsberichte für deine Website. initial_topic_title: Berichte zur Website-Leistung @@ -4427,7 +4425,7 @@ de: register: button: "Registrieren" title: "Administrator-Konto registrieren" - help: "registriere ein neues Konto, um loszulegen" + help: "Registriere ein neues Konto, um loszulegen." no_emails: "Leider wurde bei der Einrichtung keine Administrator-E-Mail-Adresse festgelegt, sodass es schwer sein könnte, die Konfiguration abzuschließen. Bitte füge eine Entwickler-E-Mail-Adresse in der Konfigurationsdatei hinzu oder erstelle ein Administrator-Konto über die Konsole." confirm_email: title: "Bestätige deine E-Mail-Adresse" @@ -4437,9 +4435,9 @@ de: message: "

    Wir haben die Aktivierungs-E-Mail noch einmal an %{email} gesendet" safe_mode: title: "Abgesicherten Modus betreten" - description: "Der abgesicherte Modus ermöglicht es dir, deine Website zu testen, ohne Plug-ins oder Website-Anpassungen zu laden." - no_customizations: "Aktuelles Theme deaktivieren" - only_official: "Inoffizielle Plug-ins deaktivieren" + description: "Der abgesicherte Modus ermöglicht es dir, deine Website zu testen, ohne Plugins oder Themes zu laden." + no_themes: "Themen und Themenkomponenten deaktivieren" + no_unofficial_plugins: "Inoffizielle Plug-ins deaktivieren" no_plugins: "Alle Plug-ins deaktivieren" enter: "Abgesicherten Modus betreten" must_select: "Du musst mindestens eine Option auswählen, um den abgesicherten Modus zu betreten." diff --git a/config/locales/server.el.yml b/config/locales/server.el.yml index 43556cfbd5..d1d73a7ea3 100644 --- a/config/locales/server.el.yml +++ b/config/locales/server.el.yml @@ -418,8 +418,7 @@ el: word: too_many: "Πάρα πολλές λέξεις για την ενέργεια" <<: *errors - vip_category_name: "Σαλόνι" - vip_category_description: "Κατηγορία αποκλειστικά για μέλη με επίπεδο εμπιστοσύνης (trust level) 3 ή υψηλότερο." + general_category_name: "Γενικά" meta_category_name: "Σχολιασμός Ιστοσελίδας" meta_category_description: "Συζήτηση σχετικά με την ιστοσελίδα, την οργάνωσή της, τον τρόπο λειτουργίας της και πώς αυτή μπορεί να βελτιωθεί." staff_category_name: "Συνεργάτες" @@ -443,8 +442,6 @@ el: Θα ήταν καλό να κλείσετε αυτό το θέμα μέσω του διαχειριστή :wrench: (στην πάνω δεξιά και κάτω θέση), έτσι ώστε οι απαντήσεις να μην μαζευτούν στην ανακοίνωση. - lounge_welcome: - title: "Καλώς ήρθατε στο Σαλόνι" category: topic_prefix: "Σχετικά με την κατηγορία %{category} " post_template: "%{replace_paragraph}\n\nΧρησιμοποιήστε τις επόμενες παραγράφους για μια μεγαλύτερη περιγραφή ή για να ορίσεις οδηγίες και κανόνες για τις κατηγορίες:\n\n- Γιατί μπορεί να χρησιμοποιηθεί αυτή η κατηγορία; Ποιος είναι ο σκοπός της;\n\n- Αυτή η κατηγορία είναι διαφορετική από αυτές που έχουμε ήδη;\n\n- Τι πρέπει να περιέχουν τα θέματα αυτής της κατηγορίας γενικότερα;\n\n- Χρειαζόμαστε αυτή την κατηγορία; Μπορούμε να την ενώσουμε με άλλη κατηγορία ή υποκατηγορία;\n" @@ -2516,7 +2513,6 @@ el: register: button: "Εγγραφή" title: "Εγγραφή Λογαριασμού Διαχειριστή" - help: "κάνε εγγραφή με ένα καινούριο λογαριασμό για να ξεκινήσεις" confirm_email: title: "Επιβεβαίωσε το email σου" resend_email: @@ -2524,9 +2520,7 @@ el: message: "

    Στείλαμε email ενεργοποίησης στο %{email}" safe_mode: title: "Έναρξη ασφαλούς λειτουργίας" - description: "Η ασφαλής λειτουργία σου επιτρέπει να δοκιμάσεις τον ιστότοπό σου χωρίς να φορτώσεις πρόσθετα ή εξατομικεύσεις ιστοτόπου." - no_customizations: "Απενεργοποίηση τρέχοντος θέματος" - only_official: "Απενεργοποίησε ανεπίσημα πρόσθετα" + no_unofficial_plugins: "Απενεργοποίησε ανεπίσημα πρόσθετα" no_plugins: "Απενεργοποίησε όλα τα πρόσθετα" enter: "Έναρξη Ασφαλούς Λειτουργίας" must_select: "Θα πρέπει να διαλέξτε τουλάχιστον μία επιλογή για να εισέλθετε σε ασφαλή λειτοθργία." diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 8f68eefb55..fdfa668e77 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -82,6 +82,7 @@ en: file_too_big: "The uncompressed file is too big." unknown_file_type: "The file you uploaded does not appear to be a valid Discourse theme." not_allowed_theme: "`%{repo}` is not in the list of allowed themes (check `allowed_theme_repos` global setting)." + ssh_key_gone: "You waited too long to install the theme and SSH key expired. Please try again." errors: component_no_user_selectable: "Theme components can't be user-selectable" component_no_default: "Theme components can't be default theme" @@ -138,7 +139,7 @@ en: unsubscribe_not_allowed: "Happens when unsubscribing via email is not allowed for this user." email_not_allowed: "Happens when the email address is not on the allowlist or is on the blocklist." unrecognized_error: "Unrecognized Error" - secure_media_placeholder: "Redacted: This site has secure media enabled, visit the topic or click View Media to see the attached media." + secure_uploads_placeholder: "Redacted: This site has secure uploads enabled, visit the topic or click View Media to see the attached uploads." view_redacted_media: "View Media" errors: &errors @@ -209,7 +210,7 @@ en: page_publishing_requirements: "Page publishing cannot be enabled if secure media is enabled." s3_backup_requires_s3_settings: "You cannot use S3 as backup location unless you've provided the '%{setting_name}'." s3_bucket_reused: "You cannot use the same bucket for 's3_upload_bucket' and 's3_backup_bucket'. Choose a different bucket or use a different path for each bucket." - secure_media_requirements: "S3 uploads must be enabled before enabling secure media." + secure_uploads_requirements: "S3 uploads must be enabled before enabling secure uploads." share_quote_facebook_requirements: "You must set a Facebook app id to enable quote sharing for Facebook." second_factor_cannot_enforce_with_socials: "You cannot enforce 2FA with social logins enabled. You must first disable login via: %{auth_provider_names}" second_factor_cannot_be_enforced_with_disabled_local_login: "You cannot enforce 2FA if local logins are disabled." @@ -645,11 +646,10 @@ en: linkable_type: invalid: "is not valid" - uncategorized_category_name: "Uncategorized" - vip_category_name: "Lounge" - vip_category_description: "A category exclusive to members with trust level 3 and higher." + general_category_name: "General" + general_category_description: "Create topics here that don’t fit into any other existing category." meta_category_name: "Site Feedback" meta_category_description: "Discussion about this site, its organization, how it works, and how we can improve it." @@ -674,30 +674,6 @@ en: You may want to close this topic via the admin :wrench: (at the upper right and bottom), so that replies don't pile up on an announcement. - lounge_welcome: - title: "Welcome to the Lounge" - body: | - - Congratulations! :confetti_ball: - - If you can see this topic, you were recently promoted to **regular** (trust level 3). - - You can now … - - * Edit the title of any topic - * Change the category of any topic - * Have all your links followed ([automatic nofollow](https://en.wikipedia.org/wiki/Nofollow) is removed) - * Access a private Lounge category only visible to users at trust level 3 and higher - * Hide spam with a single flag - - Here's the [current list of fellow regulars](%{base_path}/badges/3/regular). Be sure to say hi. - - Thanks for being an important part of this community! - - (For more information on trust levels, [see this topic][trust]. Please note that only members who continue to meet the requirements over time will remain regulars.) - - [trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ - admin_quick_start_title: "READ ME FIRST: Admin Quick Start Guide" category: @@ -1590,7 +1566,8 @@ en: summary_max_results: "Maximum posts returned by 'Summarize This Topic'" summary_timeline_button: "Show a 'Summarize' button in the timeline" - enable_personal_messages: "Allow trust level 1 (configurable via min trust to send messages) users to create messages and reply to messages. Note that staff can always send messages no matter what." + enable_personal_messages: "DEPRECATED, use the 'personal message enabled groups' setting instead. Allow trust level 1 (configurable via min trust to send messages) users to create messages and reply to messages. Note that staff can always send messages no matter what." + personal_message_enabled_groups: "Allow users within these groups to create messages and reply to messages. Trust level groups include all trust levels above that number, for example choosing trust_level_1 also allows trust_level_2, 3, 4 users to send PMs. Note that staff can always send messages no matter what." enable_system_message_replies: "Allows users to reply to system messages, even if personal messages are disabled" enable_chunked_encoding: "Enable chunked encoding responses by the server. This feature works on most setups however some proxies may buffer, causing responses to be delayed" long_polling_base_url: "Base URL used for long polling (when a CDN is serving dynamic content, be sure to set this to origin pull) eg: http://origin.site.com" @@ -1664,6 +1641,7 @@ en: post_menu: "Determine which items appear on the post menu, and in what order. Example like|edit|flag|delete|share|bookmark|reply" post_menu_hidden_items: "The menu items to hide by default in the post menu unless an expansion ellipsis is clicked on." share_links: "Determine which items appear on the share dialog, and in what order." + allow_username_in_share_links: "Allow usernames to be included in share links. This is useful to reward badges based on unique visitors." site_contact_username: "A valid staff username to send all automated messages from. If left blank the default System account will be used." site_contact_group_name: "A valid name of a group that gets invited to all automatically sent private messages." send_welcome_message: "Send all new users a welcome message with a quick start guide." @@ -1794,6 +1772,8 @@ en: top_topics_formula_least_likes_per_post_multiplier: "value of least likes per post multiplier (n) in top topics formula: `log(views_count) * 2 + op_likes_count * 0.5 + LEAST(likes_count / posts_count, (n)) + 10 + log(posts_count)`" enable_safe_mode: "Allow users to enter safe mode to debug plugins." + enable_experimental_sidebar_hamburger: "Allows experimental sidebar and user hamburger dropdown menu to be enabled." + enable_sidebar: "Enables experimental sidebar." rate_limit_create_topic: "After creating a topic, users must wait (n) seconds before creating another topic." rate_limit_create_post: "After posting, users must wait (n) seconds before creating another post." @@ -1910,7 +1890,7 @@ en: min_trust_to_allow_self_wiki: "The minimum trust level required to make user's own post wiki." - min_trust_to_send_messages: "The minimum trust level required to create new personal messages." + min_trust_to_send_messages: "DEPRECATED, use the 'personal message enabled groups' setting instead. The minimum trust level required to create new personal messages." min_trust_to_send_email_messages: "The minimum trust level required to send personal messages via email." min_trust_to_flag_posts: "The minimum trust level required to flag posts" min_trust_to_post_links: "The minimum trust level required to include links in posts" @@ -2041,6 +2021,7 @@ en: max_emails_per_day_per_user: "Maximum number of emails to send users per day. 0 to disable the limit" enable_staged_users: "Automatically create staged users when processing incoming emails." maximum_staged_users_per_email: "Maximum number of staged users created when processing an incoming email." + maximum_recipients_per_new_group_email: "Block incoming emails with too many recipients." auto_generated_allowlist: "List of email addresses that won't be checked for auto-generated content. Example: foo@bar.com|discourse@bar.com" block_auto_generated_emails: "Block incoming emails identified as being auto generated." ignore_by_title: "Ignore incoming emails based on their title." @@ -2168,6 +2149,8 @@ en: disable_avatar_education_message: "Disable education message for changing avatar." + pm_warn_user_last_seen_months_ago: "When creating a new PM warn users when target recepient has not been seen more than n months ago." + suppress_uncategorized_badge: "Don't show the badge for uncategorized topics in topic lists." header_dropdown_category_count: "How many categories can be displayed in the header dropdown menu." @@ -2236,9 +2219,12 @@ en: bootstrap_mode_min_users: "Minimum number of users required to disable bootstrap mode (set to 0 to disable)" prevent_anons_from_downloading_files: "Prevent anonymous users from downloading attachments." - secure_media: 'Limits access to ALL uploads (images, video, audio, text, pdfs, zips, and others). If “login required” is enabled, only logged-in users can access uploads. Otherwise, access will be limited only for media uploads in private messages and private categories. WARNING: This setting is complex and requires deep administrative understanding. See the secure media topic on Meta for details.' - secure_media_allow_embed_images_in_emails: "Allows embedding secure images that would normally be redacted in emails, if their size is smaller than the 'secure media max email embed image size kb' setting." - secure_media_max_email_embed_image_size_kb: "The size cutoff for secure images that will be embedded in emails if the 'secure media allow embed in emails' setting is enabled. Without that setting enabled, this setting has no effect." + secure_media: 'DEPRECATED: Use the secure_uploads setting instead, will be removed in Discourse 3.0.' + secure_uploads: 'Limits access to ALL uploads (images, video, audio, text, pdfs, zips, and others). If "login required” is enabled, only logged-in users can access uploads. Otherwise, access will be limited only for media uploads in private messages and private categories. WARNING: This setting is complex and requires deep administrative understanding. See the secure uploads topic on Meta for details.' + secure_media_allow_embed_images_in_emails: "DEPRECATED: Use secure_uploads_allow_embed_images_in_emails, will remove in Discourse 3.0." + secure_uploads_allow_embed_images_in_emails: "Allows embedding secure images that would normally be redacted in emails, if their size is smaller than the 'secure uploads max email embed image size kb' setting." + secure_media_max_email_embed_image_size_kb: "DEPRECATED: Use secure_uploads_max_email_embed_image_size_kb, will be removed in Discourse 3.0." + secure_uploads_max_email_embed_image_size_kb: "The size cutoff for secure images that will be embedded in emails if the 'secure uploads allow embed in emails' setting is enabled. Without that setting enabled, this setting has no effect." slug_generation_method: "Choose a slug generation method. 'encoded' will generate percent encoding string. 'none' will disable slug at all." enable_emoji: "Enable emoji" @@ -2356,6 +2342,8 @@ en: enable_sitemap: "Generate a sitemap for your site and include it in the robots.txt file." sitemap_page_size: "Number of URLs to include in each sitemap page. Max 50.000" + enable_user_status: "(experimental) Allow users to set custom status message (emoji + description)." + 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." dashboard_hidden_reports: "Allow to hide the specified reports from the dashboard." @@ -2377,6 +2365,9 @@ en: suggest_weekends_in_date_pickers: "Include weekends (Saturday and Sunday) in date picker suggestions (disable this if you use Discourse only on weekdays, Monday through Friday)." splash_screen: "Displays a temporary loading screen while site assets load" + default_sidebar_categories: "Selected categories will be displayed under Sidebar's Categories section by default." + default_sidebar_tags: "Selected tags will be displayed under Sidebar's Tags section by default." + enable_new_user_profile_nav_groups: "EXPERIMENTAL: Users of the selected groups will be shown the new user profile navigation menu" errors: invalid_css_color: "Invalid color. Enter a color name or hex value." @@ -2405,6 +2396,7 @@ en: reply_by_email_address_is_empty: "You must set a 'reply by email address' before enabling reply by email." email_polling_disabled: "You must enable either manual or POP3 polling before enabling reply by email." user_locale_not_enabled: "You must first enable 'allow user locale' before enabling this setting." + personal_message_enabled_groups_invalid: "You must specify at least one group for this setting. If you do not want anyone except staff to send PMs, choose the staff group." invalid_regex: "Regex is invalid or not allowed." invalid_regex_with_message: "The regex '%{regex}' has an error: %{message}" email_editable_enabled: "You must disable 'email editable' before enabling this setting." @@ -3357,6 +3349,16 @@ en: If you believe this is an error, [contact a staff member](%{base_url}/about). + email_reject_too_many_recipients: + title: "Email Reject Too Many Recipients" + subject_template: "[%{email_prefix}] Email issue -- Too Many Recipients" + text_body_template: | + We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work. + + You attempted to email more than %{max_recipients_count} people and our system automatically tagged your email as spam. + + If you believe this is an error, [contact a staff member](%{base_url}/about). + email_error_notification: title: "Email Error Notification" subject_template: "[%{email_prefix}] Email issue -- POP authentication error" @@ -4831,6 +4833,7 @@ en: invalid_token: "Invalid token." email_input: "Admin Email" submit_button: "Send Email" + safe_mode: "Safe Mode: disable all themes/plugins when logging in" performance_report: initial_post_raw: This topic includes daily performance reports for your site. @@ -4872,7 +4875,7 @@ en: register: button: "Register" title: "Register Admin Account" - help: "register a new account to get started" + help: "Register a new account to get started." no_emails: "Unfortunately, no administrator emails were defined during setup, so finalizing the configuration may be difficult. Please add a developer email in the configuration file or create an administrator account from console." confirm_email: title: "Confirm your Email" @@ -4883,9 +4886,9 @@ en: safe_mode: title: "Enter safe mode" - description: "Safe mode allows you to test your site without loading plugins or site customizations." - no_customizations: "Disable current theme" - only_official: "Disable unofficial plugins" + description: "Safe mode allows you to test your site without loading plugins or themes." + no_themes: "Disable themes and theme components" + no_unofficial_plugins: "Disable unofficial plugins" no_plugins: "Disable all plugins" enter: "Enter Safe Mode" must_select: "You must select at least one option to enter safe mode." diff --git a/config/locales/server.es.yml b/config/locales/server.es.yml index 9c1e232a86..f2b6567dac 100644 --- a/config/locales/server.es.yml +++ b/config/locales/server.es.yml @@ -596,8 +596,8 @@ es: invalid: "no es válido" <<: *errors uncategorized_category_name: "Sin categoría" - vip_category_name: "Sala VIP" - vip_category_description: "Una categoría exclusiva para miembros con un nivel de confianza de 3 o más." + general_category_name: "General" + general_category_description: "Crea temas aquí si no encajan en ninguna otra categoría." meta_category_name: "Sugerencias sobre el sitio" meta_category_description: "Debate sobre este sitio, su organización, cómo funciona y cómo podemos mejorarlo." staff_category_name: "Personal" @@ -618,29 +618,6 @@ es: Quizás quieras cerrar este tema a través del administrador :wrench: (en la parte superior derecha o en la parte de abajo), para que las respuestas nuevas no se acumulen en un anuncio. - lounge_welcome: - title: "Te damos la bienvenida a la Sala VIP" - body: |2 - - ¡Enhorabuena! :confetti_ball: - - Si puedes ver este tema, es que has sido promovido a usuario **habitual** (nivel de confianza 3). - - Ahora puedes … - - * Editar el título de cualquier tema - * Cambiar la categoría de cualquier tema - * Todos tus enlaces serán seguidos (se elimina automáticamente el [nofollow](http://es.wikipedia.org/wiki/Nofollow)) - * Acceder a la categoría privada Sala VIP, solo visible para usuarios de nivel 3 o más - * Ocultar spam tras un solo reporte - - Consulta aquí la [lista actualizada de usuarios habituales](%{base_path}/badges/3/regular). ¡Recuerda enviar un saludo! - - ¡Gracias por ser parte importante de esta comunidad! - - (Para saber más sobre niveles de confianza, [mira este tema][trust]. Ten en cuenta que solo los usuarios que continúen cumpliendo los requisitos a lo largo del tiempo seguirán considerándose habituales.) - - [trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ admin_quick_start_title: "LEER PRIMERO: Guía rápida de inicio para administradores" category: topic_prefix: "Acerca de la categoría %{category}" @@ -698,6 +675,7 @@ es: public_group_membership: "Estás uniéndote o saliendo de grupos con mucha frecuencia. Espera %{time_left} antes de intentarlo de nuevo." topics_per_day: "Has llegado al límite de nuevos temas permitidos al día. Podrás crear más en %{time_left}." pms_per_day: "Has llegado al máximo de mensajes permitidos al día. Podrás publicar más en %{time_left}." + create_like: "¡Guau! ¡Has estado dándole mucho a me gusta! Has llegado al límite diario, pero conforme vayas subiendo de nivel de confianza, tu límite aumentará. Podrás seguir dándole a me gusta en %{time_left}." create_bookmark: "Has llegado al límite de nuevos marcadores al día. Podrás añadir más cosas a marcadores en %{time_left}." edit_post: "Has llegado al límite de ediciones en un día. Podrás seguir editando en %{time_left}." live_post_counts: "Estás pidiendo recuentos de publicaciones en vivo muy rápido. Espera %{time_left} antes de intentarlo de nuevo." @@ -1485,6 +1463,7 @@ es: favicon: "Un favicon para su sitio, ve https://es.wikipedia.org/wiki/Favicon. Para que funcione correctamente sobre un CDN debe ser un png. Se cambiará automáticamente el tamaño a 32x32. Si se deja en blanco, se utilizará large_icon." apple_touch_icon: "Icono utilizado para dispositivos táctiles de Apple. Se redimensionará automáticamente a 180x180. Si se deja en blanco, se utilizará el icono grande." opengraph_image: "Imagen de gráfico abierto predeterminada, utilizada cuando la página no tiene otra imagen adecuada. Si se deja en blanco, se utilizará large_icon" + twitter_summary_large_image: "\"Imagen grande de resumen\" de la tarjeta de Twitter (debe tener al menos 280 de ancho y al menos 150 de alto, no puede ser .svg). Si se deja en blanco, los metadatos de la tarjeta normal se generan utilizando opengraph_image, siempre que no sea también un .svg, mientras no sea un .svg" notification_email: "La dirección de correo electrónico remitente utilizada al enviar todos los correos electrónicos esenciales de sistema. El dominio especificado debe tener correctamente configurados los registros SPF, DKIM y PTR inversos para que los correos electrónicos se reciban correctamente." email_custom_headers: "Lista de correos electrónicos separados por barras" email_subject: "Formato de asunto personalizable para correos electrónicos estándar. Consulta https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801" @@ -1498,7 +1477,6 @@ es: summary_percent_filter: "Cuando un usuario hace clic en «resumen de este tema», mostrar el % de las publicaciones destacadas" summary_max_results: "Cantidad máxima de publicaciones devueltas en «resumen de este tema»" summary_timeline_button: "Mostrar un botón para «Resumir» en la línea de tiempo" - enable_personal_messages: "Permitir que los usuarios con nivel de confianza 1 (configurable a través del ajuste min trust to send messages) puedan crear y responder mensajes. Ten en cuenta que el personal siempre puede mandar mensajes, sin importar los ajustes." enable_system_message_replies: "Permite a los usuarios responder a los mensajes del sistema, incluso si los mensajes personales están desactivados." enable_chunked_encoding: "Activar respuestas en lotes del servidor. Esta funcionalidad debería funcionar en casi todos los entornos, pero algunos proxies pueden causar que las respuestas tarden" long_polling_base_url: "URL base usada para el long polling (cuando un CDN esta sirviendo contenido dinámico, asegúrate de ajustar esto al pull de origen) ejemplo: http://origin.site.com" @@ -1566,6 +1544,7 @@ es: post_menu: "Determinar los elementos que aparecen en el menú de publicación y su orden. Ejemplo: me gusta|editar|denunciar|eliminar|compartir|guardar en marcadores|responder" post_menu_hidden_items: "Los elementos del menú que se ocultan por defecto en el menú de publicación a menos que se haga clic en el botón para expandir las opciones." share_links: "Determinar los elementos que aparecen en el widget de compartir y su orden." + allow_username_in_share_links: "Permitir que los nombres de usuario se incluyan en los enlaces compartidos. Esto es útil para premiar medallas basadas en visitantes únicos." site_contact_username: "Nombre de usuario de miembro del equipo desde donde se enviarán todos los mensajes automáticos. Si se deja en blanco, se utilizará la cuenta por defecto del sistema." site_contact_group_name: "Un nombre de grupo válido para que sea invitado a todos los mensajes automáticos." send_welcome_message: "Enviar a todos los usuarios nuevos un mensaje de bienvenida con una guía rápida de inicio." @@ -1675,6 +1654,8 @@ es: top_topics_formula_first_post_likes_multiplier: "valor del multiplicador de me gusta en la primera publicación (n) en la fórmula de temas destacados: «log(views_count) * 2 + op_likes_count * (n) + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)»" top_topics_formula_least_likes_per_post_multiplier: "valor del multiplicador de me gusta por publicación (n) en la fórmula de temas destacados: «log(views_count) * 2 + op_likes_count * 0.5 + LEAST(likes_count / posts_count, (n)) + 10 + log(posts_count)»" enable_safe_mode: "Permitir a los usuarios ingresar al modo seguro para depurar plugins." + enable_experimental_sidebar_hamburger: "Permite habilitar la barra lateral experimental y el menú desplegable de hamburguesas del usuario." + enable_sidebar: "Habilita la barra lateral experimental." rate_limit_create_topic: "Después de crear un tema, los usuarios deben esperar (n) segundos antes de crear otro tema." rate_limit_create_post: "Después de realizar una publicación, los usuarios deben esperar (n) segundos antes de crear otra publicación." rate_limit_new_user_create_topic: "Después de crear un tema, los nuevos usuarios deben esperar (n) segundos antes de crear otro tema." @@ -1765,7 +1746,6 @@ es: min_trust_to_edit_wiki_post: "El nivel mínimo de confianza requerido para editar una publicación marcada como wiki." min_trust_to_edit_post: "El nivel mínimo de confianza requerido para editar publicaciones." min_trust_to_allow_self_wiki: "El nivel mínimo de confianza requerido para que un usuario convierta sus propias publicaciones a wiki." - min_trust_to_send_messages: "El nivel mínimo de confianza requerido para crear nuevos mensajes personales." min_trust_to_send_email_messages: "Nivel de confianza mínimo para mandar mensajes personales a través de correo electrónico." min_trust_to_flag_posts: "El nivel mínimo de confianza requerido para denunciar publicaciones" min_trust_to_post_links: "El nivel mínimo de confianza requerido para incluir enlaces en una publicación" @@ -1836,7 +1816,7 @@ es: topic_view_duration_hours: "Contar una visita a un nuevo tema por IP/Usuario cada N horas" user_profile_view_duration_hours: "Contar una nueva visita de perfil por IP/Usuario cada N horas" levenshtein_distance_spammer_emails: "Al revisar coincidencias por correos electrónicos de spammers, cantidad de caracteres diferentes que permiten una coincidencia parcial." - max_new_accounts_per_registration_ip: "Si ya hay (n) cuentas de nivel de confianza 0 en esta IP (y ninguna es de un miembro del personal o tiene al menos nivel de confianza), bloquear nuevos registros desde esa dirección. Poner a 0 para desactivar este límite." + max_new_accounts_per_registration_ip: "Si ya hay (n) cuentas de nivel de confianza 0 en esta IP (y ninguna es de un miembro del STAFF o tiene al menos nivel de confianza), bloquear nuevos registros desde esa dirección. Poner a 0 para desactivar este límite." min_ban_entries_for_roll_up: "Al hacer clic en el botón agrupar, se creará un nuevo rango de entradas prohibidas si hay al menos (N) entradas." max_age_unmatched_emails: "Eliminar entradas de correos electrónicos prohibidos que no coincidan después de (N) días." max_age_unmatched_ips: "Eliminar entradas de IP prohibidos que no coincidan después de (N) días." @@ -1870,6 +1850,7 @@ es: max_emails_per_day_per_user: "Número de correos electrónicos que se enviarán a los usuarios por día. Establece 0 para desactivar el límite" enable_staged_users: "Crear cuentas provisionales automáticamente al procesar correos electrónicos entrantes." maximum_staged_users_per_email: "Número máximo de usuarios provisionales creados al procesar un correo electrónico entrante." + maximum_recipients_per_new_group_email: "Bloquee los correos electrónicos entrantes con demasiados destinatarios." auto_generated_allowlist: "Lista de direcciones de correo electrónico que no se revisarán para ver si es contenido generado automáticamente. Ejemplo: foo@bar.com|discourse@bar.com" block_auto_generated_emails: "Bloquear correos electrónicos entrantes identificados como generados automaticamente." ignore_by_title: "Ignorar correos electrónicos entrantes por su título." @@ -2125,6 +2106,8 @@ es: use_name_for_username_suggestions: "Usar el nombre completo para sugerir nombres de usuario" suggest_weekends_in_date_pickers: "Incluir fines de semana (sábados y domingos) en las sugerencias de los selectores de fecha (desactiva esto si solo usas Discourse de lunes a viernes)" splash_screen: "Muestra una pantalla de carga temporal mientras los archivos de la página se cargan" + default_sidebar_categories: "Las categorías seleccionadas aparecerán por defecto en la sección de categorías de la barra lateral." + enable_new_user_profile_nav_groups: "EXPERIMENTAL: Los usuarios de los grupos seleccionados verán el nuevo menú de navegación del perfil de usuario" errors: invalid_css_color: "Color no válido. Introduce el nombre de un color o su valor hexadecimal." invalid_email: "Dirección de correo electrónico no válida." @@ -2179,6 +2162,7 @@ es: search_tokenize_chinese_enabled: "Debes desactivar el ajuste «search_tokenize_chinese» antes de activar este." search_tokenize_japanese_enabled: "Debes desactivar el ajuste «search_tokenize_japanese» antes de activar este." discourse_connect_cannot_be_enabled_if_second_factor_enforced: "No puedes activar DiscourseConnect si la autenticación de dos factores (2FA) es obligatoria." + delete_rejected_email_after_days: "Esta configuración no puede ser menor que la configuración delete_email_logs_after_days o mayor que %{max}" placeholder: discourse_connect_provider_secrets: key: "www.ejemplo.com" @@ -3027,6 +3011,9 @@ es: Has respondido a un correo electrónico de resumen, lo cual no es aceptable. Si crees que se trata de un error, [ponte en contacto con un miembro del equipo](%{base_url}/acerca de). + email_reject_too_many_recipients: + title: "El correo electrónico rechaza demasiados destinatarios" + subject_template: "[%{email_prefix}] Problema del correo – Demasiados destinatarios" email_error_notification: title: "Error de notificación de correo electrónico" subject_template: "[%{email_prefix}] Problema de correo electrónico -- Error de autenticación POP" @@ -4387,6 +4374,7 @@ es: invalid_token: "Token no válido." email_input: "Correo electrónico de administrador" submit_button: "Enviar correo electrónico" + safe_mode: "Modo seguro: desactivar todos los temas y plugins al iniciar sesión" performance_report: initial_post_raw: Este tema contiene informes diarios sobre el rendimiento de tu sito. initial_topic_title: Informe sobre el rendimiento del sitio @@ -4425,7 +4413,7 @@ es: register: button: "Registrarse" title: "Registrar cuenta de administrador" - help: "registra una cuenta para empezar" + help: "Regístrate para empezar." no_emails: "Por desgracia, no se definió ningún correo electrónico de administrador durante la configuración inicial, por lo que terminar de instalar el foro será complicado. Añade un correo electrónico de desarrollador en el archivo de configuración o crea una cuenta de administrador desde la consola." confirm_email: title: "Confirmar tu correo electrónico" @@ -4435,9 +4423,8 @@ es: message: "

    Hemos reenviado el correo electrónico de activación a %{email}" safe_mode: title: "Activar modo seguro" - description: "El modo seguro permite probar tu página sin cargar plugins o customizaciones." - no_customizations: "Desactivar tema actual" - only_official: "Desactivar plugins no oficiales" + no_themes: "Desactivar temas y componentes de tema" + no_unofficial_plugins: "Desactivar plugins no oficiales" no_plugins: "Desactivar todos los plugins" enter: "Activar modo seguro" must_select: "Debes escoger al menos una opción para entrar en el modo seguro." @@ -4466,6 +4453,7 @@ es: extra_description: "Solo los usuarios con una sesión iniciada pueden acceder a esta comunidad" invite_only: placeholder: "Sólo por invitación" + extra_description: "Los usuarios deben ser invitados por usuarios de confianza o el STAFF antes de que puedan registrarse." must_approve_users: placeholder: "Requiere aprobación" extra_description: "Los usuarios deben ser aprobados por el personal" diff --git a/config/locales/server.et.yml b/config/locales/server.et.yml index 350b3168c3..f42476bd11 100644 --- a/config/locales/server.et.yml +++ b/config/locales/server.et.yml @@ -277,8 +277,7 @@ et: payload_url: invalid: "URL on vigane. URL peab sisaldama http:// või https://. Ning tühikud ei ole lubatud." <<: *errors - vip_category_name: "Lounge" - vip_category_description: "Liik, mis on eksklusiivne kasutajatele, kellel on usaldustase 3 või kõrgem." + general_category_name: "Üldine" meta_category_name: "Saidi tagasiside." meta_category_description: "Arutelu selle saidi, tema korralduse, töömeetodite ja arenguvõimaluste kohta." staff_category_name: "Meeskond" @@ -299,8 +298,6 @@ et: Ilmselt peaksid sa selle teema administreerimise alt sulgema :wrench: (üleval paremal ja allääres), et teadandele vastuseid ei kuhjuks. - lounge_welcome: - title: "Tere tulemast Lounge'i" category: topic_prefix: "Liigist %{category}" post_template: "%{replace_paragraph}\n\nKasuta järgnevaid lõikusid pikema kirjelduse jaoks või foorumi juhendi või reeglite jaoks:\n\n- Miks peaksid inimesed seda foorumit kasutama? Mille jaoks see on?\n\n- Mille poolest erineb see meie teistest foorumitest?\n\n- Mis infot peaksid selle foorumi teemad sisaldama?\n\n- Kas meil on seda foorumit vaja? Kas me saame seda foorumit ühendada teise foorumiga või alamfoorumiga?\n" @@ -1010,12 +1007,11 @@ et: register: button: "Registreeru" title: "Registreeri adminni konto" - help: "alustamiseks registreeri uus konto" resend_email: title: "Saada aktiveerimismeil uuesti" safe_mode: title: "Sisene turvalisse režiimi" - only_official: "Keela kõik mitteametlikud pluginad" + no_unofficial_plugins: "Keela kõik mitteametlikud pluginad" no_plugins: "Keela kõik pluginad" enter: "Sisene turvalisse režiimi" wizard: diff --git a/config/locales/server.fa_IR.yml b/config/locales/server.fa_IR.yml index 0c8f65b0b7..3d2b5f14b9 100644 --- a/config/locales/server.fa_IR.yml +++ b/config/locales/server.fa_IR.yml @@ -64,6 +64,7 @@ fa_IR: generic: خطایی در هنگام وارد کردن پوسته اتفاق افتاده است about_json_values: "about.json حاوی مقادیر نامعتبر است: %{errors}" git: "خطا در کلون کردن مخزن گیت، دسترسی محدود شده یا مخزن یافت نشد" + ssh_key_gone: "شما برای نصب پوسته بیش از حد طولانی صبر کردید و کلید SSH منقضی شده است. لطفا دوباره امتحان کنید." emails: incoming: default_subject: "این موضوع نیاز به عنوان دارد" @@ -363,8 +364,7 @@ fa_IR: invalid: "معتبر نیست" <<: *errors uncategorized_category_name: "دسته‌بندی‌نشده" - vip_category_name: "سالن" - vip_category_description: "دسته‌بندی مخصوص برای اعضا با سطح اعتماد 3 و بالاتر." + general_category_name: "عمومی" meta_category_name: "بازخورد از سایت" meta_category_description: "گفتگو در مورد سایت، این سازمان، چگونه کار می کنه٬ و چطور می‌توانیم آن را بهبود ببخشیم. " staff_category_name: "همکاران" @@ -384,8 +384,6 @@ fa_IR: شاید بخواهید این موضوع را از طریق مدیریت ببندید :wrench: (در قسمت بالا سمت راست و پایین)، بنابراین پاسخ‌ها در اعلان ها انباشته نمی‌شوند. - lounge_welcome: - title: "به سالن خوش آمدید" category: topic_prefix: "در رابطه با دسته‌بندی %{category}" post_template: "%{replace_paragraph}\n\nپاراگراف‌های زیر را برای توضیحات طولانی تر استفاده کنید، یا برای ایجاد راهنمای دسته‌بندی یا قوانین:\n\nچرا مردم باید این دسته‌بندی را استفاده کنند؟ برای چه منظوری است؟\n\nاین دسته‌بندی چقدر با دسته‌بندی‌های موجود تفاوت دارد؟\n\nموضوعات این دسته‌بندی باید شامل چه مواردی باشند؟\n\nآیا به این دسته‌بندی نیاز داریم؟ آیا می‌توانیم این دسته‌بندی را با یک دسته‌بندی یا زیر‌دسته‌بندی دیگر ادغام کنیم؟\n" @@ -1240,6 +1238,7 @@ fa_IR: suppress_overlapping_tags_in_list: "اگر برچسب با عنوان موضوع دقیقا یکی بودند، برچسب را نشان نده." enable_sitemap: "یک نقشه سایت برای سایت خود ایجاد کنید و آن را در پرونده robots.txt قرار دهید." sitemap_page_size: "تعداد آدرس‌های اینترنتی که باید در هر صفحه نقشه سایت گنجانده شود. حداکثر ۵۰٫۰۰۰" + enable_user_status: "(آزمایشی) به کاربران اجازه می‌دهد، که پیام وضعیت را تغییر دهند (شکلک + توضیحات)." use_name_for_username_suggestions: "هنگام پیشنهاد نام‌کاربری از نام کامل، کاربر استفاده کنید." errors: invalid_email: "آدرس ایمیل نامعتبر" @@ -2230,6 +2229,7 @@ fa_IR: success: "ایمیل ارسال شد " email_input: "ایمیل مدیر ارشد" submit_button: "ارسال ایمیل " + safe_mode: "حالت ایمن: هنگام ورود به سیستم، تمام پوسته‌ها/افزونه‌ها را غیرفعال شود" performance_report: initial_post_raw: این مطلب شامل گزارش عملکرد روزانه سایت شماست. initial_topic_title: گزارش عملکرد وب‌سایت @@ -2241,7 +2241,7 @@ fa_IR: register: button: "ثبت‌نام" title: "ثبت‌نام مدیر" - help: "برای شروع ثبت‌نام کنید" + help: "برای شروع یک حساب کاربری جدید ایجاد کنید." confirm_email: title: "ایمیل خود را تایید کنید" resend_email: @@ -2249,9 +2249,9 @@ fa_IR: message: "

    ایمیل فعال‌سازی به %{email} ارسال شد." safe_mode: title: "ورود به حالت امن" - description: "حالت امن به شما اجازه می‌دهد که سایت را بدون افزونه و شخصی‌سازی امتحان کنید." - no_customizations: "غیر‌‌فعال‌سازی قالب فعلی" - only_official: "غیر‌فعال‌سازی افزونه‌های غیر رسمی" + description: "حالت ایمن به شما این امکان را می‌دهد، که سایت خود را بدون بارگیری افزونه‌ها یا پوسته‌ها آزمایش کنید." + no_themes: "غیرفعال کردن پوسته‌ها و اجزای پوسته" + no_unofficial_plugins: "غیر‌فعال‌سازی افزونه‌های غیر رسمی" no_plugins: "غیر‌فعال‌سازی تمام افزونه‌ها" enter: "فعال‌سازی حالت امن" wizard: diff --git a/config/locales/server.fi.yml b/config/locales/server.fi.yml index 3db4750dea..f253e11734 100644 --- a/config/locales/server.fi.yml +++ b/config/locales/server.fi.yml @@ -570,8 +570,7 @@ fi: invalid_url: "Korvaava URL-osoite on virheellinen" <<: *errors uncategorized_category_name: "Luokittelematon" - vip_category_name: "Lounge" - vip_category_description: "Alue luottamustason 3 ja ylemmille käyttäjille." + general_category_name: "Yleistä" meta_category_name: "Sivuston palaute" meta_category_description: "Keskustelua tästä sivustosta, sen järjestämisestä, siitä miten se toimii ja miten sitä voisi parantaa." staff_category_name: "Henkilökunta" @@ -592,29 +591,6 @@ fi: Saattaa olla hyvä sulkea tämä ketju ylläpitäjän :wrench: -valikon kautta (oikealla ylhäällä sekä sivun alaosassa), jottei vastauksia kasaannu ilmoituksen alle. - lounge_welcome: - title: "Tervetuloa Loungeen" - body: |2 - - Onnittelut! :confetti_ball: - - Jos näet tämän ketjun, sinut on juuri ylennetty **mestariksi** (luottamustaso 3). - - Voit nyt … - - * Muokata minkä hyvänsä ketjun otsikkoa - * Siirtää minkä tahansa ketjun toiselle alueelle - * Lisätä linkkejä, joita hakukoneet seuraavat ([nofollow](https://en.wikipedia.org/wiki/Nofollow) on poistettu) - * Päästä suljetulle Lounge-alueelle, joka näkyy vain luottamustason 3 ja korkeammille käyttäjille - * Piilottaa roskapostiviestin yhdellä liputuksella - - Tässä on nykyinen [lista mestareista](%{base_path}/badges/3/regular). Käyhän moikkaamassa. - - Kiitos, että olet tämän yhteisön arvokas jäsen! - - (Lisää tietoa luottamustasoista saat [tästä englanninkielisestä ketjusta][trust]. Huomaa, että pysyäksesi mestarina sinun pitää täyttää vaatimukset jatkossakin.) - - [trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ admin_quick_start_title: "LUE ENSIN: Ylläpitäjän pika-aloitusopas" category: topic_prefix: "Tietoa alueesta %{category}" @@ -1685,7 +1661,6 @@ fi: min_trust_to_edit_wiki_post: "Wiki-viestin muokkaamiseen vaadittava luottamustaso." min_trust_to_edit_post: "Viestin muokkaamiseen vaadittava luottamustaso." min_trust_to_allow_self_wiki: "Minimiluottamustaso, jolla käyttäjä voi tehdä omasta viestistään wiki-viestin." - min_trust_to_send_messages: "Vähimmäisluottamustaso, jolla voi aloittaa yksityisviestiketjuja." min_trust_to_send_email_messages: "Vähimmäisluottamustaso, jolla voi lähettää yksityisviestejä sähköpostitse." min_trust_to_flag_posts: "Vähimmäisluottamustaso, jolla voi merkitä viestejä" min_trust_to_post_links: "Vähimmäisluottamustaso, jolla voi lisätä linkkejä viesteihin" @@ -4145,7 +4120,6 @@ fi: register: button: "Rekisteröidy" title: "Rekisteröi ylläpitäjän tili" - help: "aloita rekisteröimällä uusi tili" no_emails: "Ylläpitäjän sähköpostiosoitetta ei määritetty asennuksen aikana, joten asennuksen viimeistely voi olla vaikeaa. Lisää kehittäjän sähköpostiosoite määritystiedostoon tai luo ylläpitäjän tili konsolissa." confirm_email: title: "Vahvista sähköpostisi" @@ -4155,9 +4129,7 @@ fi: message: "

    Lähetimme uuden aktivointiviestin osoitteeseen %{email}" safe_mode: title: "Siirry vikasietotilaan" - description: "Vikasietotilassa voit testata sivustoasi ilman lisäosia ja sivuston mukautuksia." - no_customizations: "Poista nykyinen teema käytöstä" - only_official: "Poista epäviralliset lisäosat käytöstä" + no_unofficial_plugins: "Poista epäviralliset lisäosat käytöstä" no_plugins: "Poista kaikki lisäosat käytöstä" enter: "Siirry vikasietotilaan" must_select: "Ainakin yksi on valittava, jotta voi siirtyä vikasietotilaan." diff --git a/config/locales/server.fr.yml b/config/locales/server.fr.yml index c5291cfdd7..e0dd389280 100644 --- a/config/locales/server.fr.yml +++ b/config/locales/server.fr.yml @@ -591,8 +591,7 @@ fr: invalid_url: "L'URL de substitution n'est pas valide" <<: *errors uncategorized_category_name: "Sans catégorie" - vip_category_name: "Salon" - vip_category_description: "Une catégorie réservée aux membres avec un niveau de confiance 3 et plus." + general_category_name: "Général" meta_category_name: "Commentaires sur le site" meta_category_description: "Discussions à propos du site, son organisation, son fonctionnement et comment nous pouvons l'améliorer." staff_category_name: "Responsables" @@ -613,29 +612,6 @@ fr: Vous voulez peut-être fermer ce sujet via l'administration :wrench: (dans le coin supérieur droit et en bas) afin que les réponses ne s'accumulent pas après une annonce. - lounge_welcome: - title: "Bienvenue dans le salon" - body: |2 - - Félicitations ! :confetti_ball: - - Si vous voyez ce sujet, vous avez été promu au statut d'**habitué(e)** (niveau de confiance 3). - - Dorénavant vous pouvez : - - * Modifier le titre de n'importe quel sujet - * Modifier la catégorie de n'importe quel sujet - * Avoir des liens qui sont suivis ([automatic nofollow](https://fr.wikipedia.org/wiki/Nofollow) est ôté) - * Accéder à la catégorie privée Salon qui est réservée aux utilisateurs de niveau de confiance 3 et plus - * Masquer le spam avec un seul signalement - - Voilà la [liste des habitués actuels](%{base_path}/badges/3/regular). N'hésitez pas à les saluer. - - Merci pour votre contribution à notre communauté ! - - (Pour plus d'informations sur les niveaux de confiance, [voir ce sujet][trust]. Notez que seuls les utilisateurs qui continuent de remplir les conditions gardent leur statut d'habitués.) - - [trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ admin_quick_start_title: "À LIRE EN PREMIER : Guide de démarrage pour les administrateurs" category: topic_prefix: "À propos de la catégorie %{category}" @@ -1487,7 +1463,6 @@ fr: summary_percent_filter: "Quand un utilisateur clique sur « Résumer ce sujet », montrer le top % des messages" summary_max_results: "Nombre maximal de messages inclus dans le résultat de « Résumer ce sujet »" summary_timeline_button: "Afficher un bouton \"Résumer\" dans la timeline de chaque sujet" - enable_personal_messages: "Autoriser les utilisateurs de niveau de confiance n (défini par le paramètre 'min trust to send messages') à envoyer des messages directs et à y répondre. Veuillez noter que les responsables peuvent envoyer des messages directs dans tous les cas." enable_system_message_replies: "Permettre aux utilisateurs de répondre aux messages système, même si les messages directs sont désactivés." enable_chunked_encoding: "Activer les réponses d'encodage par bloc par le serveur. Cette fonctionnalité fonctionne dans la plupart des configurations, mais certains proxys peuvent mettre les réponses en mémoire tampon et risquent donc de les retarder" long_polling_base_url: "Racine de l'URL utilisée pour les requêtes longues (dans le cas de l'utilisation d'un CDN pour fournir du contenu dynamique, pensez à le configurer en mode « origin pull »). Par exemple : http://origin.site.com" @@ -1555,6 +1530,7 @@ fr: post_menu: "Choisissez les éléments qui apparaissent dans le menu du message, ainsi que leur ordre. Exemple like|edit|flag|delete|share|bookmark|reply" post_menu_hidden_items: "Les éléments du menu qui seront masqués par défaut jusqu'à extension du menu." share_links: "Choisissez les éléments qui apparaissent dans la fenêtre de partage, ainsi que leur ordre." + allow_username_in_share_links: "Autoriser l'inclusion de noms d'utilisateur dans les liens partagés. Ceci est utile pour attribuer les badges en fonction du nombre de visiteurs uniques." site_contact_username: "Un nom d'utilisateur de responsable valide pour envoyer tous les messages automatiques. Si vous laissez ce champ vide, le compte système par défaut sera utilisé." site_contact_group_name: "Un nom de groupe valide à inviter à tous les messages directs automatiques." send_welcome_message: "Envoyer à tous les nouveaux utilisateurs un message de bienvenue avec un guide de démarrage rapide." @@ -1663,6 +1639,7 @@ fr: top_topics_formula_first_post_likes_multiplier: "formule permettant d'obtenir la valeur du multiplicateur des premiers « J'aime » (n) dans les sujets tendance : « log(views_count) * 2 + op_likes_count * (n) + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count) »" top_topics_formula_least_likes_per_post_multiplier: "formule permettant d'obtenir la valeur du multiplicateur du plus petit nombre de « J'aime » par message (n) dans les sujets tendance : « log(views_count) * 2 + op_likes_count * 0.5 + LEAST(likes_count / posts_count, (n)) + 10 + log(posts_count) »" enable_safe_mode: "Permettre aux utilisateurs d'utiliser le mode sans échec pour déboguer les extensions." + enable_sidebar: "Active la barre latérale expérimentale." rate_limit_create_topic: "Après la création d'un sujet, les utilisateurs doivent attendre (n) secondes avant de pouvoir en créer un nouveau." rate_limit_create_post: "Après avoir publié un message, les utilisateurs doivent attendre (n) secondes avant de pouvoir en publier un autre." rate_limit_new_user_create_topic: "Après la création d'un sujet, les nouveaux utilisateurs doivent attendre (n) secondes avant de pouvoir en créer un nouveau." @@ -1753,7 +1730,6 @@ fr: min_trust_to_edit_wiki_post: "Le niveau de confiance minimal requis pour modifier les messages de type wiki." min_trust_to_edit_post: "Le niveau de confiance minimal requis pour modifier des messages." min_trust_to_allow_self_wiki: "Le niveau de confiance minimal requis pour transformer ses propres messages en type wiki." - min_trust_to_send_messages: "Le niveau de confiance minimal pour être autorisé à créer des nouveaux messages directs." min_trust_to_send_email_messages: "Le niveau de confiance minimal pour envoyer un message privé par courriel." min_trust_to_flag_posts: "Le niveau de confiance minimal requis pour signaler des messages" min_trust_to_post_links: "Le niveau de confiance minimal requis pour inclure des liens dans les messages" @@ -4401,7 +4377,6 @@ fr: register: button: "Créer" title: "Créer un compte administrateur" - help: "créer un nouveau compte pour commencer" no_emails: "Malheureusement aucune adresse courriel d'administrateur n'a été définie lors de la configuration. Veuillez ajouter un courriel de développeur dans le fichier de configuration ou créer un compte administrateur depuis la console." confirm_email: title: "Confirmer votre adresse courriel" @@ -4411,9 +4386,9 @@ fr: message: "

    Nous avons renvoyé le courriel d'activation à %{email}" safe_mode: title: "Activer le mode sans échec" - description: "Le mode sans échec vous permet de tester votre site sans charger les extensions ou personnalisations." - no_customizations: "Désactiver le thème actuel" - only_official: "Désactiver les extensions non officielles" + description: "Le mode sans échec vous permet de tester votre site sans charger d'extension ni de thème." + no_themes: "Désactiver les thèmes et leurs composants" + no_unofficial_plugins: "Désactiver les extensions non officielles" no_plugins: "Désactiver toutes les extensions" enter: "Activer le mode sans échec" must_select: "Vous devez sélectionner au moins une option pour activer le mode sans échec." diff --git a/config/locales/server.gl.yml b/config/locales/server.gl.yml index 1b0538404d..c79cdee385 100644 --- a/config/locales/server.gl.yml +++ b/config/locales/server.gl.yml @@ -553,8 +553,7 @@ gl: too_many: "Demasiadas palabras para esa acción" <<: *errors uncategorized_category_name: "Sen categoría" - vip_category_name: "Sala VIP" - vip_category_description: "Unha categoría exclusiva para membros cun nivel de confianza 3 ou superior." + general_category_name: "Xeral" 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" @@ -575,29 +574,6 @@ gl: Quizais queira pechar este tema a través do administrador :wrench: (na parte superior dereita ou na parte inferior) para que as respostas non se acumulen no anuncio. - lounge_welcome: - title: "Dámoslle a benvida á Sala VIP" - body: |2 - - Parabéns! :confetti_ball: - - Se pode ver este tema é porque hai pouco que foi promovido a usuario **habitual** (nivel de confianza 3). - - Agora pode … - - * Editar o título de calquera tema - * Cambiar a categoría de calquera tema - * As súas ligazóns serán fiábeis (retirarase [a etiqueta nofollow](https://en.wikipedia.org/wiki/Nofollow)) - * Acceder á categoría privada Sala VIP só visíbel para usuarios cun nivel de confianza 3 ou superior - * Agochar o lixo cunha soa alerta - - Consulte aquí a [listaxe actual de usuarios habituais](%{base_path}/badges/3/regular). Asegúrese de saudar. - - Grazas por ser parte importante da comunidade! - - (Para máis información sobre os niveis de confianza, [mire este tema][trust]. Repare en que só os membros que continúen cumprindo os requirimentos ao longo do tempo seguirán considerándose habituais.) - - [trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ admin_quick_start_title: "LER PRIMEIRO: Guía de comezo rápido para administradores" category: topic_prefix: "Acerca da categoría %{category}" @@ -1631,7 +1607,6 @@ gl: min_trust_to_edit_wiki_post: "O nivel de confianza mínimo requirido para editar unha publicación marcada como wiki." min_trust_to_edit_post: "O nivel de confianza mínimo requirido para editar publicacións." min_trust_to_allow_self_wiki: "O nivel de confianza mínimo requirido para facer que un usuario converta as súas publicacións a wiki." - min_trust_to_send_messages: "O nivel de confianza mínimo requirido para crear novas mensaxes persoais." min_trust_to_flag_posts: "O nivel de confianza mínimo requirido para denunciar publicacións" min_trust_to_post_links: "O nivel de confianza mínimo requirido para incluír ligazóns nas publicacións" min_trust_to_post_embedded_media: "O nivel de confianza mínimo requirido para incorporar elementos multimedia a unha publicación" @@ -3981,7 +3956,6 @@ gl: register: button: "Rexistrarse" title: "Rexistrar conta de administrador" - help: "rexistrar unha nova conta para comezar" no_emails: "Por desgraza, non se determinaron enderezos de correo de administrador durante a definición inicial, polo que pode ser difícil finalizar a configuración. Engada, por favor, un correo de desenvolvedor no ficheiro de configuración ou mire de crear unha conta de administrador desde a consola." confirm_email: title: "Confirme o seu correo electrónico" @@ -3991,9 +3965,7 @@ gl: message: "

    Volvémoslle enviar o correo de activación a %{email}" safe_mode: title: "Entrar en modo seguro" - description: "O modo seguro permítelle probar o seu sitio sen cargar complementos nin outras personalizacións." - no_customizations: "Desactivar tema actual" - only_official: "Desactivar complementos non oficiais" + no_unofficial_plugins: "Desactivar complementos non oficiais" no_plugins: "Desactivar todos os complementos" enter: "Entrar en modo seguro" must_select: "Debe seleccionar polo menos unha opción para entrar no modo seguro." diff --git a/config/locales/server.he.yml b/config/locales/server.he.yml index 7bd01016d8..29e2d5d216 100644 --- a/config/locales/server.he.yml +++ b/config/locales/server.he.yml @@ -73,6 +73,7 @@ he: file_too_big: "הקובץ גדול מדי ללא דחיסה." unknown_file_type: "הקובץ שהעלית הוא כפי הנראה אינה ערכת עיצוב תקנית של Discourse." not_allowed_theme: "‚%{repo}’ אינו ברשימת הנושאים המורשים (יש לבדוק את ההגדרה הגלובלית `allowed_theme_repos` - מאגרי ערכות עיצוב מורשים)." + ssh_key_gone: "המתנת זמן רב מדי להתקנת ערכת העיצוב ותוקף מפתח ה־SSH פג. נא לנסות שוב." errors: component_no_user_selectable: "רכיבי ערכת העיצוב לא יכולים להיות לבחירת המשתמש" component_no_default: "רכיבי ערכת העיצוב לא יכולים להיות בררת המחדל של ערכת העיצוב" @@ -646,8 +647,8 @@ he: invalid: "לא תקף" <<: *errors uncategorized_category_name: "מחוץ לקטגוריה" - vip_category_name: "טרקלין" - vip_category_description: "קטגוריה ייחודית למשתמשים בדרגת אמון 3 ומעלה." + general_category_name: "כללי" + general_category_description: "כאן מותר ליצור נושאים שלא מתאימים לכך קטגוריה קיימת אחרת." meta_category_name: "משוב על האתר" meta_category_description: "דיון על האתר הזה, הארגון שמאחוריו, איך הוא פועל ואיך נוכל לשפר אותו." staff_category_name: "סגל" @@ -668,9 +669,6 @@ he: ייתכן ותרצו לסגור נושא זה באמצעות :wrench: הניהול (בפינות משמאל למעלה ולמטה), כדי שתגובות לא ייערמו על גבי כרזה. - lounge_welcome: - title: "ברוך בואך לטרקלין" - body: "\nברכותינו! :confetti_ball:\n\nאם יש לך אפשרות לצפות בנושא הזה, קודמת לכדי **קבוע** (דרגת אמון 3).\n\nמעכשיו יש לך אפשרות …\n\n* לערוך כותרת של כל נושא שהוא \n* להחליף קטגוריה לנושא\n* כל הקישורים שלך יחשפו למעקב (הסרה אוטומטית של [nofollow](https://en.wikipedia.org/wiki/Nofollow))\n* גישה לקטגוריית טרקלין פרטית שנגישה רק למשתמשים מדרגת אמון 3 ומעלה\n* הסתרת ספאם בסימון של דגל אחד\n\nלהלן [הרשימה הנוכחית חבריך הקבועים](%{base_path}/badges/3/regular). לא לשכוח להגיד להם שלום.\n\nתודה לך על המעורבות המבורכת שלך בקהילה הזו!\n\n(לפרטים נוספים על דרגות אמון, [מומלץ לעיין בנושא זה][trust]. נא לשים לב שאך ורק משתמשים שממשיכים לשמור על הדרישות לאורך זמן נשארים קבועים.)\n\n[trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/\n" admin_quick_start_title: "לקרוא אותי קודם: מדריך זריז למנהלים מתחילים" category: topic_prefix: "על הקטגוריה %{category}" @@ -732,6 +730,7 @@ he: public_group_membership: "הצטרפת/עזבת קבוצות בתדירות מעט גבוהה מדי. נא להמתין %{time_left} בטרם ביצוע ניסיון חוזר." topics_per_day: "הגעת לכמות המרבית המותרת של נושאים חדשים ביום. ניתן ליצור נושאים חדשים בעוד %{time_left}." pms_per_day: "הגעת לכמות המרבית המותרת של הודעות חדשות ביום. ניתן ליצור הודעות חדשות בעוד %{time_left}." + create_like: "וואו! כמה אהבה שיתפת! הגעת לכמות הלייקים המרבית לטווח של 24 שעות, אך עם העלייה בדרגות האמון הסף הזה יעלה. תהיה לך אפשרות לשוב ולעשות לייק לפוסטים בעוד %{time_left}." create_bookmark: "הגעת לכמות המרבית המותרת של סימניות ביום. ניתן ליצור סימניות חדשות בעוד %{time_left}." edit_post: "הגעת לכמות המרבית המותרת של עריכות ביום. ניתן להגיש עריכות נוספות בעוד %{time_left}." live_post_counts: "ביקשת ספירת פוסטים בזמן אמת מהר מדי. נא להמתין %{time_left} בטרם ביצוע ניסיון חוזר." @@ -1571,7 +1570,7 @@ he: opengraph_image: "תמונת opengraph כבררת מחדל, נעשה בה שימוש כאשר לעמוד אין תמונות אחרות מתאימות. אם השדה נשאר ריק, ייעשה שימוש ב־large_icon (סמל גדול)." twitter_summary_large_image: "‚תמונת סיכום גדולה’ של כרטיס טוויטר (אמורה להיות ברוחב של 280 לפחות ובגובה של 150 לפחות, לא יכולה להיות ‎.svg). אם נשאר ריק, ייווצרו נתוני על של כרטיס רגיל בעזרת ה־opengraph_image (תמונת opengraph) כל עוד זאת גם לא ‎.svg" notification_email: "כתובת הדוא״ל מאת: לטובת שליחת כל הודעות המערכת החיוניות. כדי שהודעות הדוא״ל יגיעו, לשם התחום המצויין כאן חייבת להיות הגדרה נכונה של SPF,‏ DKIM ורשומות reverse PTR." - email_custom_headers: "רשימה מופרדת pipes (הסימון |) של כותרות מייל מותאמות אישית" + email_custom_headers: "רשימה מופרדת בקווים אנכיים (הסימון |) של כותרות דוא״ל מותאמות אישית" email_subject: "תבנית נושא בהתאמה אישית להודעות דוא״ל תקניות. יש לעיין ב־https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801" detailed_404: "מספק פרטים נוספים למשתמשים בנוגע לסיבה שבגינה אין להם גישה לנושא מסוים. לתשומת לבך: מדובר בתצורה לא מאובטחת כיוון שמשתמשים ידעו אם כתובת מקשרת לנושא תקף." enforce_second_factor: "מאלץ משתמשים להפעיל אימות דו־שלבי. יש לבחור ב‚הכול’ כדי לאלץ את כל המשתמשים. יש לבחור ב‚סגל’ כדי לאכוף על חברי סגל בלבד." @@ -1583,7 +1582,6 @@ he: summary_percent_filter: "כאשר משתמש/ת מקליקים על \"סיכום נושא זה\", הציגו את % הפוסטים הראשונים" summary_max_results: "מספר הפוסטים המרבי שיוחזר על ידי ‚סיכום הנושא הזה’" summary_timeline_button: "הצגת כפתור ‚סיכום’ בציר הזמן" - enable_personal_messages: "לאפשר למשתמשים בדרגת אמון 1 (ניתן להגדרה דרך אמון מזערי לשליחת הודעות) ליצור הודעות ולענות להודעות. נא לשים לב שהסגל תמיד יכול לשלוח הודעות, ללא קשר." enable_system_message_replies: "מאפשר למשתמשים להגיב להודעות מערכת אפילו כשהודעות אישיות מושבתות" enable_chunked_encoding: "הפעלת תגובות קידוד מחולקות מצד השרת. תכונה זו עובדת ברוב התצורות אך חלק מהמתווכים עשויים לכלוא כצעד ביניים, מה שעלול לגרום להאטה" long_polling_base_url: "כתובת הבסיס שמשמשת לתשאול ארוך (כאשר CDN מגיש תוכן דינמי, יש להגדיר זאת למשיכה המקורית) למשל: http://origin.site.com" @@ -1760,6 +1758,8 @@ he: top_topics_formula_first_post_likes_multiplier: "מכפיל של לייקים על הפוסט הראשון (n) בנוסת הנושאים המובילים: `log(views_count) * 2 + op_likes_count * (n) + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" top_topics_formula_least_likes_per_post_multiplier: "מכפיל של כמות לייקים מינימלית לפוסט (n) בנוסחת הנושאים המובילים: `log(views_count) * 2 + op_likes_count * 0.5 + LEAST(likes_count / posts_count, (n)) + 10 + log(posts_count)`" enable_safe_mode: "לאפשר למשתמשים להיכנס למצב בטוח כדי לנפות שגיאות בתוספים." + enable_experimental_sidebar_hamburger: "מאפשר להפעיל סרגל צד ניסיוני ותפריט המבורגר נגלל למשתמש." + enable_sidebar: "מפעיל סרגל צד ניסיוני." rate_limit_create_topic: "לאחר יצירת נושא, על המשתמשים להמתין (n) שניות לפני יצירת נושא אחר." rate_limit_create_post: "לאחר הפרסום על המשתמשים להמתין (n) שניות לפני יצירת פוסט חדש." rate_limit_new_user_create_topic: "לאחר יצירת נושא, משתמשים חדשים יחוייבו לחכות (n) שניות לפני שיוכלו ליצור נושא אחר." @@ -1850,7 +1850,6 @@ he: min_trust_to_edit_wiki_post: "דרגת האמון המזערית הנדרשת לעריכת פוסט המסומן כוויקי." min_trust_to_edit_post: "דרגת האמון המזערית הנדרשת לעריכת פוסטים." min_trust_to_allow_self_wiki: "דרגת האמון המזערית הנדרשת להפיכת פוסט עצמי של משתמש לוויקי." - min_trust_to_send_messages: "דרגת האמון המזערית שנדרשת ליצירת הודעות פרטיות." min_trust_to_send_email_messages: "דרגת האמון המזערית שנדרשת לשליחת הודעות פרטיות בדוא״ל." min_trust_to_flag_posts: "דרגת האמון המזערית הנדרשת לסימון פוסטים בדגל" min_trust_to_post_links: "דרגת האמון המזערית להוספת קישורים לפוסטים" @@ -1955,6 +1954,7 @@ he: max_emails_per_day_per_user: "המספר המרבי של הודעות דוא״ל שניתן לשלוח למשתמש ביום. 0 להשבתת ההגבלה." enable_staged_users: "יצירת משתמשים מבוימים באופן אוטומטי בזמן עיבוד הודעות דוא״ל נכנסות." maximum_staged_users_per_email: "מספר מרבי של משתמשים מבוימים שנוצרים בזמן עיבוד הודעת דוא״ל נכנסת." + maximum_recipients_per_new_group_email: "חסימת הודעות דוא״ל נכנסות עם יותר מדי נמענים." auto_generated_allowlist: "רשימת כתובות דואר מהן לא ייבדק אם התוכן נוצר-אוטומטית. למשל: foo@bar.com|discourse@bar.com" block_auto_generated_emails: "לחסום הודעות דוא״ל נכנסות שזוהו ככאלו שנוצרו אוטומטית." ignore_by_title: "להתעלם מהודעות דוא״ל נכנסות לפי הכותרת שלהן." @@ -2210,6 +2210,9 @@ he: use_name_for_username_suggestions: "להשתמש בשם המלא של המשתמש בעת הצעת שמות משתמשים." suggest_weekends_in_date_pickers: "לכלול סופי שבוע (שישי ושבת) בהצעות לבוחר התאריכים (כדאי להשבית זאת אם יוצא לך להשתמש ב־Discourse רק בימי חול, ראשון עד חמישי)." splash_screen: "מציג מסך טעינה בזמן שהמשאבים נטענים" + default_sidebar_categories: "הקטגוריות הנבחרות תוצגנה תחת סעיף הקטגוריות של סרגל הצד כברירת מחדל." + default_sidebar_tags: "התגיות הנבחרות תוצגנה תחת סעיף התגיות של סרגל הצד כברירת מחדל." + enable_new_user_profile_nav_groups: "ניסיוני: משתמשים בקבוצות שנבחרו יופיעו בתפריט הניווט החדש של פרופיל המשתמש" errors: invalid_css_color: "צבע שגוי. נא למלא את שם הצבע או ערך הקסדצימלי." invalid_email: "כתובת דוא״ל שגויה." @@ -3151,6 +3154,15 @@ he: הגבת להודעת תקציר, שזה לא מקובל. + אם לדעתך מדובר בשגיאה [נא ליצור קשר עם חבר סגל](%{base_url}/about). + email_reject_too_many_recipients: + title: "דחיית דוא״ל יותר מדי נמענים" + subject_template: "[%{email_prefix}] תקלת דוא״ל -- יותר מדי נמענים" + text_body_template: | + מחילה אך הודעות הדוא״ל שלך אל %{destination} (עם הכותרת %{former_title}) לא עברה. + + ניסית לשלוח הודעות ללמעלה מ־%{max_recipients_count} אנשים והמערכת שלנו תייגה את ההודעה שלך כספאם אוטומטית. + אם לדעתך מדובר בשגיאה [נא ליצור קשר עם חבר סגל](%{base_url}/about). email_error_notification: title: "התראת בעיית מייל" @@ -3649,7 +3661,7 @@ he: יש ללחוץ על הקישור הבא כדי לבחור סיסמה לחשבון החדש שלך: %{base_url}/u/password-reset/%{email_token} confirm_new_email: - title: "אישור מייל חדש" + title: "אישור דוא״ל חדש" subject_template: "[%{email_prefix}] נא לאשר את כתובת הדוא״ל החדשה שלך" text_body_template: | לחיצה על הקישור %{site_name} תאשר את כתובת הדוא״ל החדשה שלך: @@ -3667,7 +3679,7 @@ he: החלפת כתובת הדוא״ל הוגשה על ידי הנהלת האתר. אם לא ביקשת לערוך שינוי שכזה, נא ליצור קשר עם [הנהלת האתר](%{base_url}/about). confirm_old_email: - title: "אישור מייל ישן" + title: "אישור דוא״ל ישן" subject_template: "[%{email_prefix}] נא לאשר את כתובת הדוא״ל הנוכחית שלך" text_body_template: | לפני שנוכל להחליף את כתובת הדוא״ל שלך, עלינו לאשר שיש לך שליטה @@ -4525,6 +4537,7 @@ he: invalid_token: "אסימון שגוי." email_input: "דוא״ל של המנהל" submit_button: "שליחת דוא״ל" + safe_mode: "מצב בטוח: השבתת כל ערכות העיצוב/תוספים בעת כניסה" performance_report: initial_post_raw: נושא זה כולל דוחות פעילות יומיים עבור האתר שלך. initial_topic_title: דוחות פעילות לאתר @@ -4575,7 +4588,7 @@ he: register: button: "הרשמה" title: "הרשמת חשבון ניהול" - help: "רישמו חשבון חדש כדי להתחיל" + help: "כדי להתחיל יש להירשם." no_emails: "לרוע המזל, לא הוגדרו כתובות דוא״ל של מנהלים במהלך ההקמה, לכן סיום התצורה עשוי להיות מורכב. נא להוסיף כתובת דוא״ל של מפתח בקובץ התצורה או ליצור חשבון מנהל מהמסוף." confirm_email: title: "אישור הדוא״ל שלך" @@ -4585,9 +4598,9 @@ he: message: "

    הודעת ההפעלה נשלחה מחדש בדוא״ל אל %{email}" safe_mode: title: "כנסו למצב בטוח" - description: "מצב בטוח מאפשר לכם לבחון את האתר שלכם מבלי לטעון תוספים או התאמות אתר." - no_customizations: "ניטרול של תמה נוכחית" - only_official: "השבתת תוספים בלתי רשמיים" + description: "מצב בטוח מאפשר לכם לבחון את האתר שלכם מבלי לטעון תוספים או ערכות עיצוב." + no_themes: "השבתת ערכות עיצוב ורכיבי ערכת עיצוב" + no_unofficial_plugins: "השבתת תוספים בלתי רשמיים" no_plugins: "השבתת כל התוספים" enter: "כנסו למצב בטוח" must_select: "עליך לבחור באפשרות אחת לפחות כדי להיכנס למצב בטוח." diff --git a/config/locales/server.hr.yml b/config/locales/server.hr.yml index 6501b86ee6..445e92391a 100644 --- a/config/locales/server.hr.yml +++ b/config/locales/server.hr.yml @@ -374,16 +374,13 @@ hr: in_the_past: "mora biti u budućnosti." <<: *errors uncategorized_category_name: "Nekategorizirano" - vip_category_name: "Foaje" - vip_category_description: "Kategorija ekskluzivna članovima koji imaju razinu povjerenja 3 ili više." + general_category_name: "Općenito" meta_category_name: "Povratne informacije o stranici" meta_category_description: "Rasprave o ovoj stranici, njezinoj organizaciji, kako radi i kako je se može poboljšati." staff_category_name: "Osoblje" staff_category_description: "Privatna kategorija za rasprave osoblja. Teme su vidljive samo administratorima i moderatorima." discourse_welcome_topic: title: "Dobrodošli na Discourse" - lounge_welcome: - title: "Dobrodošli u Foaje" admin_quick_start_title: "PROČITATI PRVO: brzi vodič za administratore" category: topic_prefix: "O %{category} kategoriji" diff --git a/config/locales/server.hu.yml b/config/locales/server.hu.yml index 80aa9555b9..ebd792a82d 100644 --- a/config/locales/server.hu.yml +++ b/config/locales/server.hu.yml @@ -360,8 +360,7 @@ hu: name: taken: már egy másik emodzsi is használja <<: *errors - vip_category_name: "Társalgó" - vip_category_description: "A kategória csak 3-as, vagy magasabb bizalmi szinttel rendelkező tagok számára érhető el." + general_category_name: "Általános" meta_category_name: "Visszajelzés" meta_category_description: "Beszélgetés erről az oldalról, a szervezéséről, a működéséről és arról, hogyan tudnánk jobbá tenni." staff_category_name: "Stáb" @@ -382,29 +381,6 @@ hu: Érdemes bezárnod ezt a témát az admin :wrench: en keresztül (a jobb felső és az alsó részen), hogy a válaszok ne halmozódjanak fel egy bejelentésre. - lounge_welcome: - title: "Üdvözöljük a társalgóban" - body: |2 - - Gratulálunk! :confetti_ball: - - Ha látod ezt a témát, a közelmúltban ** rendes tag** (3. bizalmi szint) rangra emelkedtél. - - Mostantól … - - * Bármely téma címét szerkesztheted - * Bármely téma kategóriáját megváltoztathatod - * Minden link követése (az [automatikus nofollow] (https://en.wikipedia.org/wiki/Nofollow) eltávolításra került ) - * Hozzáférhetsz egy privát társalgó kategóriához, amelyet csak a 3. vagy annál magasabb szintű bizalmas felhasználók láthatnak. - * El tudod rejteni a problémás bejegyzéseket egyetlen kattintással a zászlóra. - - Itt található a [törzsvendégek aktuális listája] (%{base_path}/ badges / 3 / regular). Mindenképpen köszönj be hozzánk! - - Köszönjük, hogy fontos része vagytok ennek a közösségnek! - - (További információért a bizalmi szintekről [nyisd meg ezt a témát].[trust]Felhívjuk figyelmedet, hogy csak azok a tagok maradnak törzsvendégek, akik idővel továbbra is megfelelnek a követelményeknek.) - - [trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ category: topic_prefix: "A(z) %{category} kategóriáról" replace_paragraph: "(Cseréld le ezt az első bekezdést az új kategória rövid leírására. Ez az útmutató a kategória kiválasztási területén jelenik meg, ezért próbálj 200 karakter alatt maradni.)" @@ -658,6 +634,8 @@ hu: moderators_activity: labels: moderator: Moderátor + flag_count: Jóváhagyott jelzők + description: A moderátorok tevékenységének listája, beleértve az ellenőrzött jelzőket, az olvasási időt, a létrehozott témákat, a létrehozott hozzászólásokat, a létrehozott személyes üzeneteket és a módosításokat. flags_status: labels: flag: Típus @@ -894,6 +872,7 @@ hu: topic_excerpt_maxlength: "A témakör kivonatának / összefoglalójának maximális hossza a téma első bejegyzéséből generálva." blocked_onebox_domains: "Azok a domainek, amelyek soha nem kerülnek dobozba, például wikipedia.org\n(A * ? helyettesítő karakterek nem támogatottak)" enforce_second_factor: "Kényszeríti a felhasználókat, hogy engedélyezzék a kétfaktoros hitelesítést. Válassza az 'all' lehetőséget, hogy érvényesítse az összes felhasználó számára. Válassza a „személyzet” lehetőséget, hogy csak a személyzet felhasználói számára érvényesítse." + review_every_post: "Minden bejegyzést jóvá kell hagyni. FIGYELEM! FORGALMAS OLDALAKON NEM AJÁNLOTT." use_admin_ip_allowlist: "Az adminokk csak akkor tudnak bejelentkezni, ha a Screened IPs listában megadott IP-címmel vannak megadva (Admin > Naplók > Screened Ips)." slow_down_crawler_user_agents: 'A forgalmi korlátozás alá elő webes robotok felhasználói ügynökei, ahogy a „robotok sebességének lelassítása” beállításban meg van adva. Minden egyes értéknek legalább 3 karakteresnek kell lennie.' remove_full_quote: "Automatikusan eltávolítja az idézetet, ha (a) a hozzászólás elején jelenik meg, (b) egy teljes hozzászólás, és (c) ha a közvetlenül az előző hozzászólásból származik. A részletekért lásd: Teljes idézetek eltávolítása a közvetlen válaszokból" @@ -903,6 +882,8 @@ hu: min_password_length: "Minimum jelszóhossz." block_common_passwords: "A 10 000 leggyakoribb jelszó tiltása." google_oauth2_hd_groups: "(kísérleti) A felhasználók a kiszolgálóhoz tartozó domainben lévő Google-csoportjainak lekérése hitelesítéskor. A lekért Google-csoportok segítségével automatikusan állíthat be Discourse csoporttagságot (lásd a csoportbeállításokat)." + enable_experimental_sidebar_hamburger: "Lehetővé teszi a kísérleti oldalsáv és a felhasználói hamburger legördülő menü engedélyezését." + enable_sidebar: "Engedélyezi a kísérleti oldalsávot." rate_limit_new_user_create_topic: "Egy téma létrehozása után az új felhasználóknak (n) másodpercet kell várniuk, mielőtt új témát hozhatnak létre." suggested_topics: "A javasolt témák száma a téma alján láthatók." limit_suggested_to_category: "Csak a javasolt kategóriákból származó témakörök jelenhetnek meg a javasolt témakörökben." @@ -1027,12 +1008,12 @@ hu: Ha továbbra is szeretnéd megkapni az e-mailes frissítéseket, csak hagyd figyelmen kívül ezt az e-mailt. invite_password_instructions: text_body_template: | - Köszönjük, hogy elfogadtad a %{site_name} szóló meghívót - üdvözlünk! + Köszönjük, hogy elfogadta a(z) %{site_name} meghívóját – üdvözöljük! - Kattints erre a linkre a jelszó kiválasztásához: - %{base_url}/u/password-reset /%{email_token} + Kattintson erre a hivatkozásra a jelszóválasztáshoz: + %{base_url}/u/password-reset/%{email_token} - (Ha a fenti link lejárt, válaszd az "Elfelejtettem a jelszavamat" lehetőséget, amikor bejelentkezel ezzel az e-mail címeddel.) + (Ha a fenti hivatkozás lejárt, akkor válassza az „Elfelejtettem a jelszavamat” lehetőséget, amikor bejelentkezik az e-mail-címével.) test_mailer: text_body_template: | Ez egy teszt e-mail innen: @@ -1343,6 +1324,9 @@ hu: Gyorsan értékes tagjává váltál közösségünknek. Köszönjük, hogy csatlakoztál, és folytasd ugyanilyen nagyszerűen! Bravo! queued_posts_reminder: + subject_template: + one: "%{count} bejegyzés vár jóváhagyásra" + other: "%{count} bejegyzés vár jóváhagyásra" text_body_template: | Szia! @@ -1997,7 +1981,6 @@ hu: register: button: "Regisztráció" title: "Adminisztrátori fiók regisztrációja" - help: "a kezdéshez regisztráljon egy új fiókot" confirm_email: title: "Erősítse meg az e-mail címét" message: "

    Aktiváló levelet küldtünk az %{email}címre, pár percen belül a postaládádban kell lennie. A fiók aktiválásához kövesd az e-mailben található utasításokat.

    Ha nem érkezik meg, ellenőrizd a spam (és Gmail esetén a Promóciók) mappát is, és ellenőrizd, hogy jó e-mail címet adtál-e meg!.

    " diff --git a/config/locales/server.hy.yml b/config/locales/server.hy.yml index fc73c699d7..f5216a7ee7 100644 --- a/config/locales/server.hy.yml +++ b/config/locales/server.hy.yml @@ -411,8 +411,7 @@ hy: too_many: "Չափազանց շատ բառեր այդ գործողության համար" <<: *errors uncategorized_category_name: "Չկատեգորիազացված" - vip_category_name: "Սպասասրահ" - vip_category_description: "Վստահության 3-րդ և ավելի մակարդակ ունեցող անդամների համար բացառիկ կատեգորիա:" + general_category_name: "Ընդհանուր" meta_category_name: "Կայքի Արձագանքներ" meta_category_description: "Քննարկում այս կայքի, դրա կազմակերպման մասին, թե ինչպես է այն աշխատում, և ինչպես կարող ենք այն բարելավել:" staff_category_name: "Անձնակազմ" @@ -420,9 +419,6 @@ hy: discourse_welcome_topic: title: "Բարի գալուստ Discourse" body: "\nԱյս ամրակցված թեմայի առաջին պարբերությունը տեսանելի կլինի որպես ողջույնի հաղորդագրություն Ձեր գլխավոր էջի բոլոր նոր այցելուներին: Սա կարևոր է!\n\n**Խմբագրեք սա**՝ դարձնելով Ձեր համայնքի համառոտ նկարագրություն՝\n\n- Ո՞ւմ համար է սա:\n- Ի՞նչ կարող են նրանք գտնել այստեղ:\n- Ինչո՞ւ պետք է նրանք գան այստեղ:\n- Որտե՞ղ կարող ենք նրանք կարդալ ավելին (հղումներ, աղբյուրներ և այլն):\n\n\n\nՀարավոր է՝ Դուք ցանկանաք փակել այս թեման ադմինի միջոցով :wrench: (վերին աջ կողմում և ներքևում), որպեսզի մի հայտարարության վրա պատասխաններ չհավաքվեն: \n" - lounge_welcome: - title: "Բարի գալուստ Սպասասրահ" - body: "\nՇնորհավորում ենք! :confetti_ball:\n\nԵթե Դուք տեսնում եք այս թեման, ապա վերջերս Ձեզ բարձրացրել են **սովորական** (վստահության 3-րդ մակարդակ):\n\nԴուք այժմ կարող եք …\n\n* Խմբագրել ցանկացած թեմայի վերնագիր\n* Փոփոխել ցանկացած թեմայի կատեգորիա\n* Հետևել Ձեր բոլոր հղումներին ([ավտոմատ չհետևելը](https://en.wikipedia.org/wiki/Nofollow) հեռացված է)\n* Ունենալ հասանելիություն մասնավոր Սպասասրահի կատեգորիային՝ տեսանելի միայն 3-րդ և ավելի վստահության մակարդակ ունեցող օգտատերերին \n* Թաքցնել սպամը մեկ դրոշակով\n\nԱհա [ընկեր-սովորական օգտատերերին ընթացիկ ցանկը](%{base_path}/badges/3/regular). Անպայման ողջունեք նրանց:\n\nՇնորհակալ ենք այս համայնքի կարևոր մաս լինելու համար!\n\n(Վստահության մակարդակների մասին ավելի շատ տեղեկատվության համար [դիտեք այս թեման][վստահություն]: Խնդրում ենք նկատի ունենալ, որ միայն այն անդամները, որոնք ժամանակի ընթացքում շարունակում են համապատասխանել պահանջներին, կմնան սովորական):\n\n[վստահություն]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/\n" admin_quick_start_title: "ԱՌԱՋԻՆ ՀԵՐԹԻՆ ԿԱՐԴԱՑԵՔ ՍԱ՝ Ադմինի Արագ Մեկնարկի Ուղեցույց" category: topic_prefix: "%{category} կատեգորիայի մասին" @@ -1291,7 +1287,6 @@ hy: min_trust_to_edit_wiki_post: "wiki դարձրած գրառումների խմբագրման համար անհրաժեշտ նվազագույն վստահության մակարդակը:" min_trust_to_edit_post: "Գրառումների խմբագրման համար պահանջվող նվազագույն վստահության մակարդակը:" min_trust_to_allow_self_wiki: "Օգտատիրոջ սեփական գրառումը wiki դարձնելու համար անհրաժեշտ նվազագույն վստահության մակարդակը:" - min_trust_to_send_messages: "Նոր անձնական նամակ ստեղծելու համար պահանջվող նվազագույն վստահության մակարդակը:" min_trust_to_flag_posts: "Գրառումների դրոշակավորման համար անհրաժեշտ նվազագույն վստահության մակարդակը" min_trust_to_post_links: "Գրառումներում հղումներ ներառելու համար պահանջվող նվազագույն վստահության մակարդակը:" allowed_link_domains: "Դոմենները, որոնց օգտատերերը կարող են հղում կատարել, անգամ եթե չունեն հղում հրապարակելու համապատասխան վստահության մակարդակ:" @@ -2958,7 +2953,6 @@ hy: register: button: "Գրանցվել" title: "Գրանցել Ադմինի Հաշիվ" - help: "գրանցել նոր հաշիվ՝ մեկնարկի համար" no_emails: "Ցավոք,տեղադրման ժամանակ չի որոշվել ոչ մի ադմինիստրատորի էլ. հասցե, և կարգավորման վերջնականացումը կարող է դժվար լինել: Խնդրում ենք ավելացնել ծրագրավորողի էլ. հասցեն կարգավորումների ֆայլում կամ ստեղծել ադմինիստրատորի հաշիվ console-ից:" confirm_email: title: "Հաստատեք Ձեր Էլ. հասցեն" @@ -2967,9 +2961,7 @@ hy: message: "

    Մենք կրկին ուղարկել ենք ակտիվացիայի նամակը %{email} հասցեին" safe_mode: title: "Մուտք գործել անվտանգ ռեժիմ" - description: "Անվտանգ ռեժիմը թույլ է տալիս Ձեզ փորձարկել կայքը՝ առանց պլագինների բեռնման կամ կայքի անհատականացման:" - no_customizations: "Անջատել ընթացիկ թեման" - only_official: "Անջատել ոչ պաշտոնական պլագինները" + no_unofficial_plugins: "Անջատել ոչ պաշտոնական պլագինները" no_plugins: "Անջատել բոլոր պլագինները" enter: "Մուտք գործել Ապահով Ռեժիմ" must_select: "Դուք պետք է ընտրեք առնվազն մեկ տարբերակ՝ անվտանգ ռեժիմ մուտք գործելու համար:" diff --git a/config/locales/server.id.yml b/config/locales/server.id.yml index ea14efd3bd..4b74ae0385 100644 --- a/config/locales/server.id.yml +++ b/config/locales/server.id.yml @@ -254,10 +254,7 @@ id: hex: invalid: "bukan warna yang valid." <<: *errors - vip_category_name: "Lounge / Santai" staff_category_name: "Staf" - lounge_welcome: - title: "Selamat datang di Lounge" category: topic_prefix: "Tentang kategori %{category}" errors: diff --git a/config/locales/server.it.yml b/config/locales/server.it.yml index 662120e460..cb7b7cddb9 100644 --- a/config/locales/server.it.yml +++ b/config/locales/server.it.yml @@ -73,6 +73,7 @@ it: file_too_big: "Il file non compresso è troppo grande." unknown_file_type: "Il file che hai caricato non sembra essere un tema valido di Discourse." not_allowed_theme: "`%{repo}` non è nella lista dei temi consentiti (controlla l'impostazione globale `allowed_theme_repos`)." + ssh_key_gone: "Hai aspettato troppo tempo per installare il tema e la chiave SSH è scaduta. Riprova." errors: component_no_user_selectable: "I componenti del tema non sono selezionabili dall'utente" component_no_default: "I componenti del tema non possono essere il tema predefinito" @@ -595,8 +596,7 @@ it: invalid: "non è valido" <<: *errors uncategorized_category_name: "Senza categoria" - vip_category_name: "Salotto" - vip_category_description: "Una categoria esclusiva per i membri con livello di attendibilità 3 o superiore." + general_category_name: "Generale" meta_category_name: "Feedback Sito" meta_category_description: "Discussioni su questo sito, la sua organizzazione, su come funziona e come possiamo migliorarlo." staff_category_name: "Staff" @@ -617,29 +617,6 @@ it: Potresti chiudere questo argomento tramite la :wrench: per amministratori (in alto a destra e in basso), in modo che le risposte non si accumulino sull'annuncio. - lounge_welcome: - title: "Benvenuto nel Salotto" - body: |2 - - Congratulazioni! :confetti_ball: - - Se vedi questo messaggio, significa che sei stato promosso ad **assiduo** (livello di esperienza 3). - - Da ora sarai in grado di: … - - * Cambiare il titolo a qualsiasi argomento - * Cambiare la categoria di qualsiasi argomento - * I tuoi link potranno essere seguiti ([il nofollow automatico](https://en.wikipedia.org/wiki/Nofollow) è stato rimosso) - * Accedere alla categoria privata Salotto visibile ai soli utenti che hanno raggiunto il livello di attendibilità 3 o superiore - * Nascondere messaggi spam con una sola segnalazione - - Ecco la [lista degli attuali utenti con Livello di attendibilità 3](%{base_path}/badges/3/regular). Lascia loro un saluto. - - Grazie per essere un importante membro della nostra comunità! - - (Per ulteriori informazioni sui Livelli di attendibilità dai [uno sguardo a questo Argomento][trust]. Tieni presente che solo gli utenti che continuano a rispettare i requisiti nel tempo resteranno assidui.) - - [trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ admin_quick_start_title: "DA LEGGERE SUBITO: Guida Rapida per Amministratore" category: topic_prefix: "Definizione della categoria %{category}" @@ -1495,7 +1472,6 @@ it: summary_likes_required: "Minimo numero di \"Mi piace\" in un argomento prima che l'opzione 'Riassumi questo argomento' sia abilitata. 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 'Riassumi questo argomento'." - enable_personal_messages: "Autorizza gli utenti con livello di attendibilità 1 (configurabile attraverso \"min livello di attendibilità per l'invio di messaggi\") a creare e rispondere ai messaggi. Nota che lo staff può inviare messaggi in ogni caso." enable_system_message_replies: "Consente agli utenti di rispondere ai messaggi di sistema, anche se i messaggi personali sono disabilitati" enable_chunked_encoding: "Abilita le risposte di codifica in blocchi dal server. Questa funzionalità va bene sulla maggior parte delle configurazioni, tuttavia alcuni proxy possono eseguire la bufferizzazione, provocando un ritardo nelle risposte" long_polling_base_url: "URL di base usato per il long polling (quando una CDN serve contenuto dinamico, bisogna impostarlo come origin pull) es. http://origin.site.com" @@ -1669,6 +1645,8 @@ it: top_topics_formula_first_post_likes_multiplier: "valore del moltiplicatore (n) dei mi piace sul primo messaggio nella formula dei migliori argomenti: `log(views_count) * 2 + op_likes_count * (n) + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" top_topics_formula_least_likes_per_post_multiplier: "valore del moltiplicatore (n) del numero minimo di \"mi piace\" per messaggio nella formula dei migliori argomenti: `log(views_count) * 2 + op_likes_count * 0.5 + LEAST(likes_count / posts_count, (n)) + 10 + log(posts_count)`" enable_safe_mode: "Consenti agli utenti di accedere alla modalità sicura per eseguire il debug dei plug-in." + enable_experimental_sidebar_hamburger: "Consente di abilitare in via sperimentale la barra laterale e il menu utente a tendina." + enable_sidebar: "Abilita la barra laterale sperimentale." rate_limit_create_topic: "Dopo aver creato un argomento, gli utenti devono aspettare (n) secondi prima di poterne creare un altro." rate_limit_create_post: "Dopo aver inviato un messaggio, gli utenti devono aspettare (n) secondi prima di creare un altro messaggio. " rate_limit_new_user_create_topic: "Dopo aver creato un argomento, i nuovi utenti devono aspettare (n) secondi prima di poter creare un altro argomento." @@ -1758,7 +1736,6 @@ it: min_trust_to_edit_wiki_post: "Livello minimo richiesto per modificare un argomento segnato come wiki." min_trust_to_edit_post: "Il livello di attendibilità minimo richiesto per modificare i messaggi." min_trust_to_allow_self_wiki: "Il livello di attendibilità minimo richiesto per consentire agli utenti di pubblicare una propria wiki." - min_trust_to_send_messages: "Il livello di attendibilità minimo richiesto per creare nuovi messaggi personali." min_trust_to_send_email_messages: "Il livello di attendibilità minimo richiesto per inviare messaggi personali via email." min_trust_to_flag_posts: "Il livello di attendibilità minimo richiesto per segnalare messaggi" min_trust_to_post_links: "Il livello di attendibilità minimo richiesto per includere link nei messaggi" @@ -1860,6 +1837,7 @@ it: max_emails_per_day_per_user: "Numero massimo di email da inviare agli utenti per giorno. 0 per disabilitare il limite" enable_staged_users: "Crea automaticamente utenti temporanei quando si elaborano le email in arrivo." maximum_staged_users_per_email: "Numero massimo di utenti temporanei creati quando si elaborano le email in arrivo." + maximum_recipients_per_new_group_email: "Blocca le email in arrivo con troppi destinatari." auto_generated_allowlist: "Lista degli indirizzi email che non verranno verificati per i contenuti generati automaticamente. Esempio: foo@bar.com|discourse@bar.com" block_auto_generated_emails: "Bloccare le email in arrivo identificate come generate automaticamente." ignore_by_title: "Ignora le email in arrivo in base al loro titolo." @@ -2112,6 +2090,8 @@ it: use_name_for_username_suggestions: "Usa il nome completo dell'utente durante il suggerimento di nomi utente." suggest_weekends_in_date_pickers: "Includi i fine settimana (sabato e domenica) nei suggerimenti del selettore di date (disabilita questa opzione se usi Discourse solo nei giorni feriali, dal lunedì al venerdì)." splash_screen: "Visualizza una schermata di caricamento temporanea durante il caricamento delle risorse del sito" + default_sidebar_categories: "Le categorie selezionate appariranno, per impostazione predefinita, nella sezione Categorie della barra laterale." + default_sidebar_tags: "Le etichette selezionate appariranno, per impostazione predefinita, nella sezione Etichette della barra laterale." errors: invalid_email: "Indirizzo email non valido." invalid_username: "Non c'è alcun utente con quel nome." @@ -2875,6 +2855,10 @@ it: title: "Email di risposta a un messaggio di riepilogo rifiutata" subject_template: "[%{email_prefix}] Problema e-mail - Risposta a un messaggio di riepilogo" text_body_template: "Siamo spiacenti, ma il tuo messaggio email per %{destination} (intitolato %{former_title}) non ha funzionato. \n\nHai risposto a un'e-mail di riepilogo, e questo non è consentito.\n\nSe ritieni che si tratti di un errore, [contatta un membro dello staff](%{base_url}/about).\n" + email_reject_too_many_recipients: + title: "Rifiuto di e-mail con troppi destinatari" + subject_template: "[%{email_prefix}] Problema email -- Troppi destinatari" + text_body_template: "Siamo spiacenti, ma l'invio del tuo messaggio email a %{destination} (intitolato %{former_title}) non ha funzionato. \n\nHai provato a scrivere a più di %{max_recipients_count} persone e il nostro sistema ha identificato automaticamente la tua email come spam.\n\nSe credi si tratti di un errore, [contatta lo staff](%{base_url}/about).\n" email_error_notification: title: "Notifica Errore Email" subject_template: "[%{email_prefix}] Problema email -- errore di autenticazione POP" @@ -3913,6 +3897,7 @@ it: invalid_token: "Token non valido." email_input: "Email Amministratore" submit_button: "Invia Email" + safe_mode: "Modalità sicura: disabilita tutti i temi/plugin quando accedi" performance_report: initial_post_raw: Questo argomento include rapporti di rendimento giornalieri per il tuo sito. initial_topic_title: Rapporti sul rendimento del sito web @@ -3948,7 +3933,7 @@ it: register: button: "Registra" title: "Registrare Account Amministratore" - help: "registrare un nuovo account per cominciare" + help: "Registra un nuovo account per iniziare." no_emails: "Sfortunatamente, nessuna email amministratore è stata definita durante l'installazione, quindi potrebbe essere difficile completare la configurazione . Aggiungi una email sviluppatore nel file di configurazione o crea un account amministratore dalla console ." confirm_email: title: "Conferma la tua Email" @@ -3958,9 +3943,9 @@ it: message: "

    Abbiamo rispedito una email di attivazione a %{email}" safe_mode: title: "Avvia Modalità Sicura" - description: "La modalità sicura ti consente di testare il tuo sito senza caricare plugin o personalizzazioni del sito." - no_customizations: "Disabilita il tema corrente" - only_official: "Disabilita i plugin non ufficiali" + description: "La modalità sicura ti consente di testare il tuo sito senza caricare plugin o temi." + no_themes: "Disabilita temi e componenti del tema" + no_unofficial_plugins: "Disabilita i plugin non ufficiali" no_plugins: "Disabilita tutti i plugin" enter: "Avvia Modalità Sicura" must_select: "È necessario selezionare almeno un'opzione per accedere alla modalità sicura." diff --git a/config/locales/server.ja.yml b/config/locales/server.ja.yml index d7f260c66a..19b720aaf8 100644 --- a/config/locales/server.ja.yml +++ b/config/locales/server.ja.yml @@ -545,8 +545,7 @@ ja: invalid_url: "置換 URL は無効です" <<: *errors uncategorized_category_name: "未分類" - vip_category_name: "ラウンジ" - vip_category_description: "信頼レベル 3 以上のメンバーのみが参加できるカテゴリです。" + general_category_name: "一般" meta_category_name: "サイトに関する意見" meta_category_description: "このサイト、組織、仕組み、および改善に関するディスカッションです。" staff_category_name: "スタッフ" @@ -567,29 +566,6 @@ ja: お知らせに返信が溜まらないように、管理からこのトピックをクローズすることができます :wrench: (右上と下)。 - lounge_welcome: - title: "ラウンジへようこそ" - body: |2 - - おめでとうございます! :confetti_ball: - - このトピックを閲覧できるのであれば、最近**レギュラー** (信頼レベル 3) に昇格したということです。 - - 次のことができるようになりました … - - * トピックのタイトルの編集 - * トピックのカテゴリの変更 - * すべてのリンクのフォロー ([自動 nofollow](https://en.wikipedia.org/wiki/Nofollow) が削除されました) - * 信頼レベル 3 以上のユーザーのみが閲覧できる非公開のラウンジカテゴリへのアクセス - * 1 回の通報による迷惑の非表示 - - [現在のレギュラーユーザーのリスト](%{base_path}/badges/3/regular)をご覧ください。ご挨拶しましょう。 - - このコミュニティの大切な一員としての活動に感謝いたします! - - (信頼レベルについて詳しくは、[こちらのトピック][trust] をご覧ください。要件を継続して満たすメンバーのみがレギュラーレベルを維持することができます。) - - [trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ admin_quick_start_title: "最初にお読みください: 管理者クイックスタートガイド" category: topic_prefix: "%{category} カテゴリについて" @@ -1642,7 +1618,6 @@ ja: min_trust_to_edit_wiki_post: "ウィキとしてマークされた投稿を編集するために必要な最低信頼レベル。" min_trust_to_edit_post: "投稿を編集するために必要な最低信頼レベル。" min_trust_to_allow_self_wiki: "ユーザー自身の投稿をウィキにするために必要な最低信頼レベル。" - min_trust_to_send_messages: "新しい個人メッセージを作成するために必要な最低信頼レベル。" min_trust_to_send_email_messages: "メールで個人メッセージを送信するために必要な最低信頼レベル。" min_trust_to_flag_posts: "投稿を通報するために必要な最低信頼レベル" min_trust_to_post_links: "投稿にリンクを含めるために必要な最低信頼レベル" @@ -4062,7 +4037,6 @@ ja: register: button: "登録" title: "管理者アカウントの登録" - help: "まず、新しいアカウントを登録してください" no_emails: "残念ながら、セットアップ中に管理者メールが定義されなかったため、構成を完了するのが困難です。構成ファイルに開発者のメールアドレスを追加するか、コンソールから管理者アカウントを作成してください。" confirm_email: title: "メールの確認" @@ -4072,9 +4046,7 @@ ja: message: "

    %{email} にアクティベーションメールを再送信しました" safe_mode: title: "セーフモードを開始" - description: "セーフモードでは、プラグインやサイトのカスタマイズを読み込まずにサイトをテストすることができます。" - no_customizations: "現在のテーマを無効にする" - only_official: "非公式のプラグインを無効にする" + no_unofficial_plugins: "非公式のプラグインを無効にする" no_plugins: "すべてのプラグインを無効にする" enter: "セーフモードを開始" must_select: "セーフモードを開始するには、少なくとも 1 つのオプションを選択する必要があります。" diff --git a/config/locales/server.ko.yml b/config/locales/server.ko.yml index b7ccbed1e2..a3caeab54f 100644 --- a/config/locales/server.ko.yml +++ b/config/locales/server.ko.yml @@ -6,7 +6,7 @@ ko: dates: - short_date_no_year: "M월 D일" + short_date_no_year: "MMM D" short_date: "YYYY-M-D" long_date: "YYYY-M-D a h:mm" datetime_formats: &datetime_formats @@ -40,337 +40,337 @@ ko: title: "Discourse" topics: "토픽" posts: "포스트" - views: "조회" - loading: "로딩중" - powered_by_html: 'Discourse 으로 호스팅되고 있습니다. JavaScript 가 활성화되어 있을 때 가장 멋지게 보입니다.' + views: "조회수" + loading: "로드 중" + powered_by_html: 'Discourse를 사용합니다. JavaScript가 활성화된 상태에서 가장 잘 보입니다.' sign_up: "회원가입" log_in: "로그인" submit: "제출" - purge_reason: "자동적으로 비활성화된 계정을 삭제하였습니다." - disable_remote_images_download_reason: "디스크저장공간이 부족하여 원격 이미지 다운로드 기능이 비활성화 되었습니다." + purge_reason: "비활성화된 계정 자동 삭제됨" + disable_remote_images_download_reason: "디스크 공간이 부족하여 원격 이미지 다운로드 기능이 비활성화되었습니다." anonymous: "익명" - remove_posts_deleted_by_author: "글쓴이에 의해 삭제된 글" - redirect_warning: "선택한 링크가 실제로 포럼에 게시되어 있는지 확인할 수 없습니다. 계속 진행하려면 아래 링크를 선택하십시오." - on_another_topic: "다른 주제에" + remove_posts_deleted_by_author: "작성자가 삭제함" + redirect_warning: "선택한 링크가 실제로 포럼에 게시되어 있는지 확인할 수 없습니다. 계속 진행하려면 아래 링크를 선택하세요." + on_another_topic: "다른 주제" inline_oneboxer: topic_page_title_post_number: "#%{post_number}" - topic_page_title_post_number_by_user: "%{username}님의 글 #%{post_number}" + topic_page_title_post_number_by_user: "%{username} 님의 게시물 #%{post_number}" themes: - bad_color_scheme: "테마, 유효하지 않은 색상 표를 업데이트 할 수 없습니다" - other_error: "테마를 업데이트할 수 없습니다" - ember_selector_error: "죄송합니다. #ember 또는 .ember-view CSS 선택기를 사용하는 것은 허용되지 않습니다. 이러한 이름은 런타임에 동적으로 생성되고 시간이 지남에 따라 변경되어 결국 CSS가 깨지기 때문입니다. 다른 선택기를 사용해보십시오." + bad_color_scheme: "테마, 유효하지 않은 색상 팔레트를 업데이트할 수 없습니다" + other_error: "테마를 업데이트하는 중에 문제가 발생했습니다" + ember_selector_error: "#ember 또는 .ember-view CSS 선택기 사용은 허용되지 않습니다. 이러한 이름은 런타임에서 동적으로 생성되고 시간이 지남에 따라 변경되어 결국 CSS가 깨지기 때문입니다. 다른 선택기를 사용하세요." compile_error: - unrecognized_extension: "인식 할 수없는 파일 확장자 : %{extension}" + unrecognized_extension: "인식할 수 없는 파일 확장자 : %{extension}" import_error: - generic: 테마를 가져오는 동안 오류가 발생했습니다. - about_json: "가져오기 오류: about.json이 없거나 유효하지 않습니다. Discourse용 테마가 맞는지 확인해주세요." - about_json_values: "about.json에 유효하지 않은 값이 있습니다 : %{errors}" - modifier_values: "about.json 수정 자에 유효하지 않은 값이 있습니다 : %{errors}" - git: "git 저장소를 복제하는 동안 오류가 발생했습니다. 접근이 거부되었거나 저장소를 찾을 수 없습니다." - git_ref_not_found: "git 에서 체크 아웃 할 수 없습니다: %{ref}" + generic: 테마를 임포트하는 중에 오류가 발생했습니다. + about_json: "임포트 오류: about.json이 없거나 유효하지 않습니다. Discourse용 테마가 맞는지 확인하세요." + about_json_values: "about.json에 유효하지 않은 값이 있습니다. %{errors}" + modifier_values: "about.json 모디파이어에 유효하지 않은 값이 있습니다. %{errors}" + git: "Git 저장소를 복제하는 중에 오류가 발생했습니다. 액세스가 거부되었거나 저장소를 찾을 수 없습니다" + git_ref_not_found: "다음 Git 레퍼런스에서 체크아웃할 수 없습니다. %{ref}" unpack_failed: "파일 압축을 풀지 못했습니다" file_too_big: "압축되지 않은 파일이 너무 큽니다." - unknown_file_type: "업로드 한 파일이 유효한 담화 테마가 아닙니다." - not_allowed_theme: "`%{repo}`가 허용 테마의 목록에 없습니다. (글로벌 설정의 `allowed_theme_repos` 확인)" + unknown_file_type: "업로드한 파일이 유효한 Discourse 테마가 아닌 것으로 보입니다." + not_allowed_theme: "`%{repo}` 가 허용 테마의 목록에 없습니다(`allowed_theme_repos` 글로벌 설정을 확인하세요)." errors: component_no_user_selectable: "테마 구성 요소는 사용자가 선택할 수 없습니다" - component_no_default: "테마 구성 요소는 기본 테마가 될 수 없습니다" - component_no_color_scheme: "테마 컴포넌트는 색상 팔레트를 가질 수 없습니다" - no_multilevels_components: "자식 테마가있는 테마는 자식 테마 자체가 될 수 없습니다" - optimized_link: 최적화 된 이미지 링크는 일시적이므로 테마 소스 코드에 포함되지 않아야합니다. + component_no_default: "테마 구성 요소는 디폴트 테마가 될 수 없습니다" + component_no_color_scheme: "테마 구성 요소는 색상 팔레트를 가질 수 없습니다" + no_multilevels_components: "자식 테마가 있는 테마는 자식 테마 자체가 될 수 없습니다" + optimized_link: 최적화된 이미지 링크는 일시적이므로 테마 소스 코드에 포함하지 않아야 합니다. settings_errors: invalid_yaml: "제공된 YAML이 유효하지 않습니다." - data_type_not_a_number: "`%{name}` 유형 설정은 지원되지 않습니다. 지원되는 유형은`integer`,`bool`,`list`,`enum` 및`upload`입니다." + data_type_not_a_number: "`%{name}` 유형 설정은 지원되지 않습니다. 지원되는 유형은 `integer` , `bool` , `list` , `enum` 및 `upload` 입니다." name_too_long: "이름이 너무 긴 설정이 있습니다. 최대 길이는 255입니다" - default_value_missing: "`%{name}` 설정에는 기본값이 없습니다" - default_not_match_type: "`%{name}` 기본 설정 유형이 설정 유형과 일치하지 않습니다." - default_out_range: "`%{name}` 기본값 설정이 지정된 범위 내에 있지 않습니다." - enum_value_not_valid: "선택된 값은 열거 형 선택 중 하나가 아닙니다." - number_value_not_valid: "새 값이 허용 된 범위 내에 있지 않습니다." - number_value_not_valid_min_max: "반드시 값은 %{min}와 %{max}사이어야 합니다." - number_value_not_valid_min: "%{min}과 같거나 커야합니다." - number_value_not_valid_max: "%{max}과 같거나 작아야합니다." - string_value_not_valid: "새로운 값의 길이가 허용된 범위를 벗어났습니다." - string_value_not_valid_min_max: "%{min}과 %{max} 자 사이 여야합니다." - string_value_not_valid_min: "최소 %{min} 글자 이상 이어야 합니다." - string_value_not_valid_max: "최대 %{max} 글자 수 여야합니다." + default_value_missing: "`%{name}` 설정에 디폴트값이 없습니다" + default_not_match_type: "`%{name}` 디폴트값 유형 설정이 설정 유형과 일치하지 않습니다." + default_out_range: "`%{name}` 디폴트값 설정이 지정된 범위 내에 있지 않습니다." + enum_value_not_valid: "선택한 값은 열거형 선택 중 하나가 아닙니다." + number_value_not_valid: "새 값이 허용된 범위 내에 있지 않습니다." + number_value_not_valid_min_max: "%{min} 및 %{max} 사이여야 합니다." + number_value_not_valid_min: "다음과 같거나 커야 합니다. %{min}" + number_value_not_valid_max: "다음과 같거나 작아야 합니다. %{max}" + string_value_not_valid: "새 값의 길이가 허용된 범위 내에 있지 않습니다." + string_value_not_valid_min_max: "%{min} ~ %{max}자 사이여야 합니다." + string_value_not_valid_min: "%{min}자 이상이어야 합니다." + string_value_not_valid_max: "%{max}자 이하여야 합니다." locale_errors: - top_level_locale: "로캘 파일의 최상위 키는 로캘 이름과 일치해야합니다." - invalid_yaml: "YAML 번역이 잘못되었습니다" + top_level_locale: "로캘 파일의 최상위 키는 로캘 이름과 일치해야 합니다." + invalid_yaml: "YAML 번역이 유효하지 않습니다" emails: incoming: - default_subject: "토픽에는 제목이 필요합니다" - show_trimmed_content: "일부 내용만 보기" - maximum_staged_user_per_email_reached: "이메일 당 생성할 수 있는 격리 사용자의 최대치에 도달했습니다." + default_subject: "이 주제에는 제목이 필요합니다" + show_trimmed_content: "일부 콘텐츠만 표시" + maximum_staged_user_per_email_reached: "이메일당 생성할 수 있는 스테이징된 사용자의 최대치에 도달했습니다." no_subject: "(제목 없음)" no_body: "(내용 없음)" - missing_attachment: "(첨부 파일 %{filename}이 없음)" + missing_attachment: "(첨부 파일 %{filename} 누락)" errors: - empty_email_error: "수신한 raw mail이 공백일 때 발생합니다." - no_message_id_error: "메일에 'Message-Id'헤더가 없을 때 발생합니다." - auto_generated_email_error: "'precedence'헤더가 list, junk, bulk, auto_reply로 설정되어 있거나 다른 헤더에 auto-submitted, auto-replied, auto-generated가 있을 때 발생합니다." - no_body_detected_error: "body를 추출할 수 없거나 첨부파일이 없을 때 발생합니다." - no_sender_detected_error: "보낸 사람 헤더에서 유효한 이메일 주소를 찾을 수 없을 때 발생합니다." - from_reply_by_address_error: "보낸 사람 헤더가 이메일 주소 별 회신과 일치 할 때 발생합니다." - inactive_user_error: "발신자(sender)가 비활성상태일 때 발생합니다." - silenced_user_error: "발신자가 무음 상태가되면 발생합니다." - bad_destination_address: "받는 사람 / 참조 필드의 전자 메일 주소가 구성된 수신 전자 메일 주소와 일치하지 않으면 발생합니다." - strangers_not_allowed_error: "사용자가 자신이 속하지 않은 카테고리에 토픽 생성을 시도할 때 발생합니다." - insufficient_trust_level_error: "카테고리가 요구하는 최소 회원레벨이 아닌 사용자가 새 글을 작성하려고 할 때 발생합니다." - reply_user_not_matching_error: "발신한 알림에 대하여 서로 다른 이메일로 답장이 올 때 발생합니다." - topic_not_found_error: "댓글을 달았지만 해당 토픽이 삭제된 경우 발생합니다." - topic_closed_error: "답글을 했지만 해당 토픽이 닫힌 경우 발생합니다." - bounced_email_error: "반송된 이메일 리포트 이메일입니다." - screened_email_error: "발신자의 이메일 주소가 이미 차단되었을 때 발생합니다." - unsubscribe_not_allowed: "이 사용자에게 이메일을 통한 구독 취소가 허용되지 않은 경우에 발생합니다." - email_not_allowed: "이메일 주소가 화이트리스트에 없거나 블랙리스트에있을 때 발생합니다." - unrecognized_error: "인식되지 않은 에러" - secure_media_placeholder: "수정 됨 :이 사이트에 보안 미디어가 활성화되어 있습니다. 주제를 방문하여 첨부 된 이미지 / 오디오 / 비디오를보십시오." + empty_email_error: "수신한 원본 메일이 공백일 때 발생합니다." + no_message_id_error: "메일에 'Message-Id' 헤더가 없을 때 발생합니다." + auto_generated_email_error: "'precedence' 헤더가 list, junk, bulk, auto_reply로 설정되어 있거나 다른 헤더에 auto-submitted, auto-replied, auto-generated가 있을 때 발생합니다." + no_body_detected_error: "본문을 추출할 수 없거나 첨부 파일이 없을 때 발생합니다." + no_sender_detected_error: "보내는 사람 헤더에서 유효한 이메일 주소를 찾을 수 없을 때 발생합니다." + from_reply_by_address_error: "보내는 사람 헤더가 댓글의 이메일 주소와 일치할 때 발생합니다." + inactive_user_error: "보내는 사람이 비활성일 때 발생합니다." + silenced_user_error: "보내는 사람이 차단된 경우 발생합니다." + bad_destination_address: "받는 사람/참조 필드의 이메일 주소가 환경설정된 수신 이메일 주소와 일치하지 않으면 발생합니다." + strangers_not_allowed_error: "사용자가 자신이 속하지 않은 카테고리에 새 주제 생성을 시도할 때 발생합니다." + insufficient_trust_level_error: "카테고리에서 요구하는 최소 신뢰 레벨이 아닌 사용자가 해당 카테고리에서 새 주제를 작성하려고 할 때 발생합니다." + reply_user_not_matching_error: "알림이 전송된 이메일 주소와 다른 이메일 주소로부터 댓글이 달릴 때 발생합니다." + topic_not_found_error: "댓글이 달렸지만 관련 주제가 삭제된 경우 발생합니다." + topic_closed_error: "댓글이 달렸지만 관련 주제가 종료된 경우 발생합니다." + bounced_email_error: "이메일이 반송된 이메일 리포트입니다." + screened_email_error: "보내는 사람의 이메일 주소가 이미 스크린된 경우 발생합니다." + unsubscribe_not_allowed: "이 사용자에게 이메일을 통한 구독 취소가 허용되지 않은 경우 발생합니다." + email_not_allowed: "이메일 주소가 화이트리스트에 없거나 블랙리스트에 있을 때 발생합니다." + unrecognized_error: "인식되지 않은 오류" + secure_media_placeholder: "수정됨 :이 사이트에 보안 미디어가 활성화되어 있습니다. 주제를 방문하거나 미디어 보기를 클릭하여 첨부된 미디어를 확인하세요." view_redacted_media: "미디어 보기" errors: &errors format: ! "%{attribute} %{message}" format_with_full_message: "%{attribute}:%{message}" messages: - too_long_validation: "%{length}자를 입력하셨습니다. 최대 %{max}자까지 입력 가능합니다. " - invalid_boolean: "잘못된 부울린값입니다." - taken: "이미 가져옴" + too_long_validation: "%{max}자로 제한되어 있습니다. 입력한 글자수는 %{length}자입니다." + invalid_boolean: "유효하지 않은 부울입니다." + taken: "이미 사용 중" accepted: 승인 필요 - blank: 비어있으면 안됨 - present: 공백이어야 합니다. - confirmation: ! " %{attribute} 속성과 맞지 않음" - empty: 필수 작성 - equal_to: '다음 숫자와 같아야 함: %{count}' + blank: 공백일 수 없음 + present: 공백이어야 함 + confirmation: ! " %{attribute} 어트리뷰트와 일치하지 않음" + empty: 비워둘 수 없음 + equal_to: 다음과 같아야 함. %{count} even: 짝수여야 함 exclusion: 예약됨 greater_than: '%{count}보다 커야 함' greater_than_or_equal_to: '%{count}보다 크거나 같아야 함' - has_already_been_used: "이미 사용되었음" + has_already_been_used: "이미 사용됨" inclusion: 리스트에 없음 - invalid: 올바르지 않음 - is_invalid: "문장이 불분명합니다." - is_invalid_meaningful: "불분명해 보이지만, 대부분의 단어에 같은 문자가 계속해서 포함되어 있습니까?" - is_invalid_unpretentious: "명확하지 않은 것 같습니다. 하나 이상의 단어가 매우 깁니다." - is_invalid_quiet: "명확하지 않은 것 같습니다. 모두 대문자로 입력 하시겠습니까?" - invalid_timezone: "'%{tz}'은 (는) 유효한 시간대가 아닙니다" - contains_censored_words: "검열된 단어가 있습니다: %{censored_words}" + invalid: 유효하지 않음 + is_invalid: "명확하지 않은 것 같습니다. 완전한 문장인가요?" + is_invalid_meaningful: "명확하지 않은 것 같습니다. 단어 대부분에 같은 문자가 계속해서 포함되어 있나요?" + is_invalid_unpretentious: "명확하지 않은 것 같습니다. 하나 이상의 단어가 매우 길지는 않나요?" + is_invalid_quiet: "명확하지 않은 것 같습니다. 모두 대문자로 입력하셨나요?" + invalid_timezone: "'%{tz}' 시간대가 유효하지 않습니다" + contains_censored_words: "다음과 같은 검열된 단어가 있습니다. %{censored_words}" less_than: '%{count}보다 작아야 함' less_than_or_equal_to: '%{count}보다 작거나 같아야 함' not_a_number: 숫자가 아님 not_an_integer: 정수여야 함 odd: 홀수여야 함 - record_invalid: ! "유효성검사 실패: %{errors}" - max_emojis: "가질수있는 이모티콘 개수가%{max_emojis_count}를 넘을수 없습니다." + record_invalid: ! "유효성 검사 실패: %{errors}" + max_emojis: "이모티콘은 %{max_emojis_count}개를 넘을 수 없습니다" emojis_disabled: "이모티콘을 가질 수 없습니다" - ip_address_already_screened: "기존 규칙에 이미 포함되어 있습니다" + ip_address_already_screened: "기존 규칙에 이미 포함됨" restrict_dependent_destroy: - other: "연관된 %{record} 레코드가 존재하므로 레코드를 지울 수 없음." + other: "%{record} 종속 기록이 존재하므로 기록을 삭제할 수 없음" too_long: - other: 너무 김(최대 %{count} 글자) + other: 너무 긺(최대 %{count}자) too_short: - other: 너무 짦음(최소 %{count} 글자) + other: 너무 짦음(최소 %{count}자) wrong_length: - other: 잘못된 길이 (%{count} 글자여야 함) - other_than: " %{count} 글자가 아니어야 합니다." - auth_overrides_username: "`auth_overrides_username` 설정이 활성화되어 있으므로 인증 제공자 측에서 사용자 이름을 업데이트해야합니다." + other: 길이가 잘못됨(%{count}자여야 함) + other_than: " %{count}자일 수 없음" + auth_overrides_username: "`auth_overrides_username` 설정이 활성화되어 있으므로 인증 제공자 측에서 아이디를 업데이트해야 합니다." template: body: ! "다음 필드에 문제가 있음:" header: - other: ! "%{model} 저장 시에 %{count}개의 에러가 발생하여 진행을 못했습니다." + other: ! "{count}개의 오류로 인해 %{model} 모델을 저장하지 못함" embed: - load_from_remote: "글 로딩 중 오류가 발생하였습니다." + load_from_remote: "이 게시물을 로드하는 중에 오류가 발생했습니다." site_settings: invalid_category_id: "존재하지 않는 카테고리를 지정했습니다" invalid_choice: - other: "잘못된 선택 항목을 지정했습니다. %{name}" - default_categories_already_selected: "다른 목록에서 사용중인 카테고리는 선택할 수 없습니다." - default_tags_already_selected: "다른 목록에 사용 된 태그를 선택할 수 없습니다." - s3_upload_bucket_is_required: "'s3_upload_bucket'이 설정되지 않으면 S3로 업로드하기를 활성화할 수 없습니다." - enable_s3_uploads_is_required: "S3 업로드를 활성화하지 않으면 S3에 인벤토리를 활성화 할 수 없습니다." - page_publishing_requirements: "보안 미디어를 사용하도록 설정한 경우 페이지 게시를 사용할 수 없습니다." - s3_backup_requires_s3_settings: "'%{setting_name}'을 제공하지 않으면 S3을 백업 위치로 사용할 수 없습니다." - s3_bucket_reused: "'s3_upload_bucket'및 's3_backup_bucket'에 동일한 버킷을 사용할 수 없습니다. 다른 버킷을 선택하거나 각 버킷마다 다른 경로를 사용하십시오." - secure_media_requirements: "보안 미디어를 활성화하기 전에 S3 업로드를 활성화해야합니다." - share_quote_facebook_requirements: "페이스북으로의 공유를 활성화 하려면 페이스북 앱 ID를 설정해야 합니다." - second_factor_cannot_enforce_with_socials: "소셜 로그인이 활성화된 상태에서는 2FA를 적용할 수 없습니다. 먼저 다음을 통해 로그인을 비활성화해야합니다: %{auth_provider_names}" - second_factor_cannot_be_enforced_with_disabled_local_login: "로컬 로그인이 비활성화 된 경우 2FA를 시행 할 수 없습니다." - second_factor_cannot_be_enforced_with_discourse_connect_enabled: "DiscourseConnect가 활성화 된 경우 2FA를 적용할 수 없습니다." - local_login_cannot_be_disabled_if_second_factor_enforced: "2FA가 적용되는 경우 로컬 로그인을 비활성화 할 수 없습니다. 로컬 로그인을 비활성화하기 전에 강제 2FA를 비활성화하십시오." - cannot_enable_s3_uploads_when_s3_enabled_globally: "S3 업로드가 이미 전체적으로 활성화되어 있으므로이 사이트 수준을 활성화하면 S3 업로드를 활성화 할 수 없습니다." - cors_origins_should_not_have_trailing_slash: "CORS 원점에 후행 슬래시 (/) 를 추가해서는 안됩니다." - conflicting_google_user_id: '이 계정의 Google 계정 ID가 변경되었습니다. 보안상의 이유로 직원의 개입이 필요합니다. 직원에게 연락하여
    https://meta.discourse.org/t/76575' + other: "유효하지 않은 선택 항목을 지정했습니다. %{name}" + default_categories_already_selected: "다른 목록에서 사용된 카테고리는 선택할 수 없습니다." + default_tags_already_selected: "다른 목록에서 사용된 태그는 선택할 수 없습니다." + s3_upload_bucket_is_required: "'s3_upload_bucket'을 제공하지 않으면 S3 업로드를 활성화할 수 없습니다." + enable_s3_uploads_is_required: "S3 업로드를 활성화하지 않으면 S3 인벤토리 사용을 활성화할 수 없습니다." + page_publishing_requirements: "보안 미디어를 활성화한 경우 페이지 게시를 활성화할 수 없습니다." + s3_backup_requires_s3_settings: "'%{setting_name}' 설정을 제공하지 않으면 S3를 백업 위치로 사용할 수 없습니다." + s3_bucket_reused: "'s3_upload_bucket' 및 's3_backup_bucket'에 동일한 버킷을 사용할 수 없습니다. 다른 버킷을 선택하거나 각 버킷에 다른 경로를 사용하세요." + secure_media_requirements: "보안 미디어를 활성화하기 전에 S3 업로드를 활성화해야 합니다." + share_quote_facebook_requirements: "Facebook 인용 공유를 활성화하려면 Facebook 앱 ID를 설정해야 합니다." + second_factor_cannot_enforce_with_socials: "소셜 로그인이 활성화된 상태에서는 2FA를 적용할 수 없습니다. 먼저 다음을 통해 로그인을 비활성화해야 합니다. %{auth_provider_names}" + second_factor_cannot_be_enforced_with_disabled_local_login: "로컬 로그인이 비활성화된 경우 2FA를 적용할 수 없습니다." + second_factor_cannot_be_enforced_with_discourse_connect_enabled: "DiscourseConnect가 활성화된 경우 2FA를 적용할 수 없습니다." + local_login_cannot_be_disabled_if_second_factor_enforced: "2FA가 적용된 경우 로컬 로그인을 비활성화할 수 없습니다. 로컬 로그인을 비활성화하기 전에 적용된 2FA를 비활성화하세요." + cannot_enable_s3_uploads_when_s3_enabled_globally: "S3 업로드가 이미 전체적으로 활성화되어 있어 이 사이트 레벨을 활성화하면 업로드 관련 심각한 문제가 발생할 수 있으므로 S3 업로드를 활성화할 수 없습니다." + cors_origins_should_not_have_trailing_slash: "CORS 출처 뒤에 슬래시(/)를 추가해서는 안 됩니다." + conflicting_google_user_id: '이 계정의 Google 계정 ID가 변경되었습니다. 보안상의 이유로 운영진의 개입이 필요합니다. 운영진에게 연락하여
    https://meta.discourse.org/t/76575 확인을 요청하세요.' onebox: - invalid_address: "죄송합니다. '%{hostname}'서버를 찾을 수 없어 웹 페이지에 대한 미리보기를 생성 할 수 없습니다. 미리보기 대신 게시물에 링크만 표시됩니다. :cry:" - error_response: "죄송합니다. 웹 서버에서 오류 코드 %{status_code} 를 반환했기 때문에 웹 페이지에 대한 미리보기를 생성 할 수 없습니다. 미리보기 대신 게시물에 링크만 표시됩니다. :cry:" + invalid_address: "'%{hostname}' 서버를 찾을 수 없어 이 웹페이지 미리보기를 생성할 수 없습니다. 미리보기 대신 게시물에 링크만 표시됩니다. :cry:" + error_response: "웹 서버에서 %{status_code} 오류 코드를 반환하여 이 웹페이지 미리보기를 생성할 수 없습니다. 미리보기 대신 게시물에 링크만 표시됩니다. :cry:" missing_data: - other: "죄송합니다. 다음 oEmbed / OpenGraph 태그를 찾을 수 없어 웹 페이지에 대한 미리보기를 생성 할 수 없습니다: %{missing_attributes}" + other: "%{missing_attributes} oEmbed / OpenGraph 태그를 찾을 수 없어 이 웹페이지 미리보기를 생성할 수 없습니다." word_connector: comma: ", " invite: - expired: "초대 토큰이 만료되었습니다. 관리자에게 문의하십시오." - not_found: "초대 토큰이 유효하지 않습니다. 직원에게 문의 하십시오." - not_found_json: "초대 토큰이 유효하지 않습니다. 직원에게 문의하십시오." - not_matching_email: "사용자님의 이메일 주소와 초대 토큰에 연결된 이메일 주소가 일치하지 않습니다. 관리자에게 문의하십시오." + expired: "초대 토큰이 만료되었습니다. 운영진에게 문의하세요." + not_found: "초대 토큰이 유효하지 않습니다. 운영진에게 문의하세요." + not_found_json: "초대 토큰이 유효하지 않습니다. 운영진에게 문의하세요." + not_matching_email: "이메일 주소와 초대 토큰에 연결된 이메일 주소가 일치하지 않습니다. 운영진에게 문의하세요." not_found_template: | -

    %{site_name}의 초대가 이미 사용되었습니다.

    +

    %{site_name} 초대는 이미 사용되었습니다.

    -

    비밀번호가 기억 나시면 로그인을 하십시오.

    +

    비밀번호가 기억나면 로그인하세요.

    -

    그렇지 않으면 비밀번호 재설정을 하십시오.

    +

    그렇지 않으면 비밀번호를 리셋하세요.

    invite_exists: "%{email} 이메일로 이미 초대되었습니다." - invalid_email: "%{email} 은 유효한 이메일 주소가 아닙니다." + invalid_email: "%{email} 이메일은 유효한 이메일 주소가 아닙니다." rate_limit: - other: "사용자님은 이미 %{count}개의 초대장을 발송했습니다. %{time_left} 지난후 다시 시도하십시오." - confirm_email: "

    거의 다 끝났습니다! 귀하의 이메일 주소로 활성화 메일을 보냈습니다. 메일의 지침에 따라 계정을 활성화하십시오.

    도착하지 않으면 스팸 폴더를 확인하십시오.

    " - cant_invite_to_group: "사용자를 지정된 그룹에 초대 할 수 없습니다. 초대하려는 그룹의 소유자인지 확인하십시오." + other: "이미 %{count}개의 초대를 전송했습니다. %{time_left} 후 다시 시도하세요." + confirm_email: "

    거의 다 끝났습니다! 이메일 주소로 활성화 메일을 보냈습니다. 메일의 지침에 따라 계정을 활성화하세요.

    메일이 도착하지 않았다면 스팸 폴더를 확인하세요.

    " + cant_invite_to_group: "사용자를 지정된 그룹에 초대할 수 없습니다. 초대하려는 그룹의 소유자인지 확인하세요." disabled_errors: discourse_connect_enabled: "DiscourseConnect가 활성화되어 있기 때문에 초대가 비활성화됩니다." - invalid_access: "요청한 리소스를 볼 수 없습니다." - domain_not_allowed: "사용자님의 이메일은 이 초대를 사용하는데 사용할 수 없습니다." + invalid_access: "요청한 리소스를 볼 권한이 없습니다." + domain_not_allowed: "이 초대를 사용하는 데 이메일을 사용할 수 없습니다." bulk_invite: - file_should_be_csv: "업로드 파일은 CSV형식이어야 합니다." - max_rows: "첫 번째 %{max_bulk_invites} 초대가 전송되었습니다. 파일을 작은 부분으로 분할하십시오." - error: "해당 파일을 업로드하는 중에 오류가 발생했습니다. 나중에 다시 시도하십시오." + file_should_be_csv: "업로드 파일은 CSV 포맷이어야 합니다." + max_rows: "첫 %{max_bulk_invites} 초대가 전송되었습니다. 파일을 작게 분할하세요." + error: "파일을 업로드하는 중에 오류가 발생했습니다. 나중에 다시 시도하세요." invite_link: - email_taken: "이 이메일은 이미 사용중입니다. 이미 계정이 있는 경우 로그인하거나 비밀번호를 재설정하십시오." - max_redemptions_limit: "2와 %{max_limit} 사이여야 합니다." + email_taken: "이 이메일은 이미 사용 중입니다. 이미 계정이 있는 경우 로그인하거나 비밀번호를 리셋하세요." + max_redemptions_limit: "2 ~ %{max_limit} 사이여야 합니다." topic_invite: - failed_to_invite: "%{group_names} 그룹 중 하나에 그룹 구성원이 없으면이 주제에 사용자를 초대 할 수 없습니다." - user_exists: "해당 사용자는 이미 초대를 받았습니다. 토픽 초대는 딱 한번만 할 수 있습니다." - muted_topic: "죄송합니다. 해당 사용자는 이 글을 관심없음으로 설정했습니다." - receiver_does_not_allow_pm: "죄송합니다. 해당 사용자는 비공개 메시지를 보낼 수 있도록 허용하지 않습니다." - sender_does_not_allow_pm: "죄송합니다. 해당 사용자는 비공개 메시지를 보낼 수 있도록 허용하지 않습니다." - user_cannot_see_topic: "%{username}은 글을 볼 수 없습니다." + failed_to_invite: "%{group_names} 그룹 중 하나에 그룹 구성원이 없으면 이 주제에 사용자를 초대할 수 없습니다." + user_exists: "이 사용자는 이미 초대를 받았습니다. 주제 초대는 한 번만 할 수 있습니다." + muted_topic: "이 사용자는 이 주제를 뮤트했습니다." + receiver_does_not_allow_pm: "이 사용자는 비공개 메시지를 보낼 수 있도록 허용하지 않았습니다." + sender_does_not_allow_pm: "내게 비공개 메시지를 보낼 수 있도록 이 사용자를 허용하지 않았습니다." + user_cannot_see_topic: "%{username} 님은 주제를 볼 수 없습니다." backup: - operation_already_running: "현재 작업이 실행중입니다. 지금은 새로운 일을 시작할 수 없습니다." - backup_file_should_be_tar_gz: "백업 파일은 .tar.gz형식의 파일이어야 합니다." + operation_already_running: "현재 작업이 실행 중입니다. 지금은 새 작업을 시작할 수 없습니다." + backup_file_should_be_tar_gz: "백업 파일은 .tar.gz 아카이브여야 합니다." not_enough_space_on_disk: "백업을 업로드할 디스크 공간이 충분하지 않습니다." - invalid_filename: "백업 파일명에 허용되지 않는 문자가 포함되어 있습니다. 알파벳, 숫자, 점(.), 대쉬(-), 언더바(_)만 사용할 수 있습니다." + invalid_filename: "백업 파일명에 허용되지 않는 문자가 포함되어 있습니다. 알파벳, 숫자, 점(.), 대시(-), 언더스코어(_)만 사용할 수 있습니다." file_exists: "업로드하려는 파일이 이미 있습니다." - invalid_params: "요청에 유효하지 않은 매개 변수를 제공했습니다 : %{message}" - not_logged_in: "로그인이 필요합니다." - not_found: "요청한 URL이나 리소스를 찾지 못했습니다." + invalid_params: "요청에 유효하지 않은 파라미터를 제공했습니다. %{message}" + not_logged_in: "이 작업을 하려면 로그인이 필요합니다." + not_found: "요청한 URL 또는 리소스를 찾을 수 없습니다." invalid_access: "요청한 리소스를 볼 권한이 없습니다." authenticator_not_found: "인증 방법이 존재하지 않거나 비활성화되었습니다." - authenticator_no_connect: "이 인증 공급자는 기존 포럼 계정에 대한 연결을 허용하지 않습니다." - invalid_api_credentials: "요청한 리소스를 볼 수 없습니다. API 사용자 이름 또는 키가 유효하지 않습니다." - provider_not_enabled: "요청한 리소스를 볼 수 없습니다. 인증 공급자가 활성화되어 있지 않습니다." - provider_not_found: "요청한 리소스를 볼 수 없습니다. 인증 제공자가 존재하지 않습니다." - read_only_mode_enabled: "사이트는 현재 읽기 전용 모드입니다. 상호소통이 불가능합니다." - invalid_grant_badge_reason_link: "배지 이유로 외부 또는 잘못된 담화 링크를 사용할 수 없습니다." + authenticator_no_connect: "이 인증 제공자는 기존 포럼 계정으로의 연결을 허용하지 않습니다." + invalid_api_credentials: "요청한 리소스를 볼 권한이 없습니다. API 아이디 또는 키가 유효하지 않습니다." + provider_not_enabled: "요청한 리소스를 볼 권한이 없습니다. 인증 제공자가 활성화되어 있지 않습니다." + provider_not_found: "요청한 리소스를 볼 권한이 없습니다. 인증 제공자가 존재하지 않습니다." + read_only_mode_enabled: "사이트가 읽기 전용 모드입니다. 인터랙션이 비활성화되어 있습니다." + invalid_grant_badge_reason_link: "배지 이유로 외부 또는 유효하지 않은 Discourse 링크를 사용할 수 없습니다" email_template_cant_be_modified: "이 이메일 템플릿은 수정할 수 없습니다" - invalid_whisper_access: "속삭임이 활성화되어 있지 않거나 속삭임 게시물을 작성할 수있는 권한이 없습니다" + invalid_whisper_access: "귓속말이 활성화되어 있지 않거나 귓속말 게시물을 작성할 권한이 없습니다" not_in_group: - title_topic: "이 항목을 보려면 '%{group}' 그룹의 가입을 요청해야 합니다." - title_category: "이 항목을 보려면 '%{group}' 그룹의 가입을 요청해야 합니다." - request_membership: "회원 신청" - join_group: "그룹 참여하기" - deleted_topic: "죄송합니다! 이 주제는 삭제되었으며 더 이상 사용할 수 없습니다." - delete_topic_failed: "해당 주제를 삭제하는 중에 오류가 발생했습니다. 사이트 관리자에게 문의하십시오." + title_topic: "이 주제를 보려면 '%{group}' 그룹의 멤버십을 요청해야 합니다." + title_category: "이 카테고리를 보려면 '%{group}' 그룹의 멤버십을 요청해야 합니다." + request_membership: "멤버십 신청" + join_group: "그룹 가입" + deleted_topic: "이 주제는 삭제되었으며 더는 사용할 수 없습니다." + delete_topic_failed: "이 주제를 삭제하는 중에 오류가 발생했습니다. 사이트 관리자에게 문의하세요." reading_time: "읽은 시간" likes: "좋아요" too_many_replies: - other: "죄송합니다. 신규 가입자는 글 하나에 %{count}개까지만 댓글을 달 수 있습니다." + other: "신규 사용자는 일시적으로 동일 주제에 %{count}개까지만 댓글을 달 수 있습니다." max_consecutive_replies: - other: "연속 댓글은 %{count}개까지만 허용됩니다. 이전 댓글을 수정하거나 다른 사람이 댓글을 작성 할 때까지 기다리십시오." + other: "연속 댓글은 %{count}개까지만 허용됩니다. 이전 댓글을 수정하거나 다른 사람이 나이게 댓글을 작성할 때까지 기다리세요." embed: start_discussion: "토론 시작" - continue: "토론 계속하기" - error: "삽입에 실패했습니다." - referer: "리퍼러(Referer):" - error_topics: "'포함 된 주제 목록'사이트 설정이 활성화되지 않았습니다." + continue: "토론 계속" + error: "임베딩 오류" + referer: "참조자:" + error_topics: "`주제 목록 임베드` 사이트 설정이 활성화되지 않았습니다" mismatch: "참조자가 전송되지 않았거나 다음 호스트와 일치하지 않습니다." - no_hosts: "임베딩을 위한 호스트가 설정되지 않았습니다." - configure: "삽입 설정" + no_hosts: "임베딩을 위한 호스트가 구성되지 않았습니다." + configure: "임베딩 환경설정" more_replies: - other: "추가 %{count} 개 댓글" - loading: "토론 불러오는 중..." + other: "%{count}개 댓글 더 보기" + loading: "토론 로드 중..." permalink: "Permalink" - imported_from: "%{link}에 있는 원글과 유사한 토론 글입니다." + imported_from: "%{link}에 있는 원본 엔트리의 동반 토론 주제입니다." in_reply_to: "▶ %{username}" replies: - other: "%{count} 댓글" + other: "%{count}개의 댓글" likes: - other: "좋아요 %{count}" + other: "%{count}개의 좋아요" last_reply: "마지막 답장" - created: "생성일자" - new_topic: "새글 쓰기" - no_mentions_allowed: "죄송합니다, 다른 사용자를 언급할 수 없습니다." + created: "생성일" + new_topic: "새 주제 생성" + no_mentions_allowed: "다른 사용자를 멘션할 수 없습니다." too_many_mentions: - other: "죄송합니다, 이 포스트에서 %{count}명의 사용자만 언급할 수 있습니다." - no_mentions_allowed_newuser: "죄송합니다. 새로운 사용자는 다른 사용자를 언급할 수 없습니다." + other: "이 게시물에서 %{count}명의 사용자만 멘션할 수 있습니다." + no_mentions_allowed_newuser: "신규 사용자는 다른 사용자를 멘션할 수 없습니다." too_many_mentions_newuser: - other: "죄송합니다. 신규 회원은 %{count}명의 사용자만 언급할 수 있습니다." - no_embedded_media_allowed_trust: "죄송합니다. 게시물에 미디어 항목을 포함할 수 없습니다." - no_embedded_media_allowed: "죄송합니다. 신규 사용자는 게시물에 미디어 항목을 삽입 할 수 없습니다." + other: "신규 사용자는 게시물에서 %{count}명의 사용자만 멘션할 수 있습니다." + no_embedded_media_allowed_trust: "게시물에 미디어 항목을 임베드할 수 없습니다." + no_embedded_media_allowed: "신규 사용자는 게시물에 미디어 항목을 임베드할 수 없습니다." too_many_embedded_media: - other: "죄송합니다. 새 사용자는 게시물에 미디어 항목을 %{count}개만 삽입 할 수 있습니다." - no_attachments_allowed: "죄송합니다. 신규회원은 글에 파일을 첨부할 수 없습니다." + other: "신규 사용자는 게시물에 미디어 항목을 %{count}개만 임베드할 수 있습니다." + no_attachments_allowed: "신규 사용자는 게시물에 파일을 첨부할 수 없습니다." too_many_attachments: - other: "죄송합니다. 신규회원은 글 하나에 %{count}개의 파일만 첨부할 수 있습니다." - no_links_allowed: "죄송합니다. 신규회원은 글에 링크를 넣을 수 없습니다." - links_require_trust: "죄송합니다. 게시물에 링크를 포함 할 수 없습니다." + other: "신규 사용자는 게시물에 %{count}개의 파일만 첨부할 수 있습니다." + no_links_allowed: "신규 사용자는 게시물에 링크를 넣을 수 없습니다." + links_require_trust: "게시물에 링크를 포함할 수 없습니다." too_many_links: - other: "죄송합니다. 신규회원은 글 하나에 링크를 %{count}개까지 넣을 수 있습니다." - contains_blocked_word: "죄송합니다. '%{word}' 는 금지된 단어로 사용할 수 없습니다." - contains_blocked_words: "죄송합니다. 허용되지 않는 단어로 글을 게시할 수 없습니다: %{words}." - spamming_host: "죄송합니다. 회원님은 링크를 첨부할 수 없습니다." - user_is_suspended: "가입이 보류된 회원은 글을 쓸 수 없습니다." - topic_not_found: "뭔가 잘못됐네요. 아마 읽려는 도중에 토픽이 닫혔거나 지워진 건 아닐까요?" - not_accepting_pms: "죄송합니다. %{username} 님이 당분간 메시지를 받지 않습니다." - max_pm_recipients: "죄송합니다. 최대 %{recipients_limit} 명의 수신자에게만 메시지를 보낼 수 있습니다." - pm_reached_recipients_limit: "메시지에 수신자가 %{recipients_limit} 명을 초과 할 수 없습니다." + other: "신규 사용자는 게시물에 링크를 %{count}개까지 넣을 수 있습니다." + contains_blocked_word: "금지어('%{word}')를 게시할 수 없습니다." + contains_blocked_words: "게시할 수 없습니다. 금지어: %{words}." + spamming_host: "이 호스트로의 링크를 게시할 수 없습니다." + user_is_suspended: "정지된 사용자는 게시할 수 없습니다." + topic_not_found: "문제가 발생했습니다. 읽는 도중 이 주제가 종료되었거나 삭제되었을 수 있습니다." + not_accepting_pms: "%{username} 님은 현재 메시지를 받지 않습니다." + max_pm_recipients: "최대 %{recipients_limit}명의 수신자에게만 메시지를 보낼 수 있습니다." + pm_reached_recipients_limit: "메시지에 수신자가 %{recipients_limit}명을 초과할 수 없습니다." removed_direct_reply_full_quotes: "이전 전체 게시물의 인용을 자동으로 제거했습니다." - watched_words_auto_tag: "자동으로 태그가 지정된 글" - secure_upload_not_allowed_in_public_topic: "죄송합니다, 공개 보안 주제로는 %{upload_filenames}을 (를) 사용할 수 없습니다." - create_pm_on_existing_topic: "기존 주제에 대해 PM을 만들 수 없습니다." - slow_mode_enabled: "이 항목은 느린 모드입니다." - just_posted_that: "당신이 이전에 게시한 것과 너무 비슷합니다." - invalid_characters: "사용할 수 없는 문자를 포함하고 있습니다." - is_invalid: "문장이 불분명합니다." + watched_words_auto_tag: "자동으로 태그가 지정된 주제" + secure_upload_not_allowed_in_public_topic: "공개 주제에서 다음 보안 업로드를 사용할 수 없습니다. %{upload_filenames}." + create_pm_on_existing_topic: "기존 주제에 대해 개인 메시지를 생성할 수 없습니다." + slow_mode_enabled: "이 주제는 느린 모드입니다." + just_posted_that: "최근 게시한 것과 너무 비슷합니다" + invalid_characters: "유효하지 않은 문자를 포함하고 있습니다" + is_invalid: "명확하지 않은 것 같습니다. 완전한 문장인가요?" next_page: "다음 페이지 →" prev_page: "← 이전 페이지" page_num: "%{num}페이지 " home_title: "홈" - topics_in_category: "'%{category}' 카테고리의 토픽" - rss_posts_in_topic: "'%{topic}' 의 RSS 피드" - rss_topics_in_category: "'%{category}' 카테고리의 RSS 피드 " + topics_in_category: "'%{category}' 카테고리의 주제" + rss_posts_in_topic: "'%{topic}'의 RSS 피드" + rss_topics_in_category: "'%{category}' 카테고리 내 주제의 RSS 피드 " rss_num_posts: - other: "글 %{count}개" + other: "%{count}개의 게시물" rss_num_participants: - other: "참가자 %{count}명" - read_full_topic: "전체 토픽 읽기" + other: "%{count}명의 참여자" + read_full_topic: "전체 주제 읽기" private_message_abbrev: "메시지" rss_description: - latest: "최신 토픽" - top: "주요 글" - top_all: "전체 기간의 주요 글" - top_yearly: "연간 주요 글" - top_quarterly: "분기별 주요 글" - top_monthly: "월간 주요 글" - top_weekly: "주간 주요 글" - top_daily: "일간 주요 글" - posts: "최근 글" + latest: "최신 주제" + top: "주요 주제" + top_all: "전체 기간의 주요 주제" + top_yearly: "연간 주요 주제" + top_quarterly: "분기별 주요 주제" + top_monthly: "월간 주요 주제" + top_weekly: "주간 주요 주제" + top_daily: "일간 주요 주제" + posts: "최근 게시물" private_posts: "최근 개인 메시지" group_posts: "%{group_name}의 최신 게시글" group_mentions: "%{group_name}의 최신 멘션" - user_posts: "@%{username}님의 최신 포스트" - user_topics: "@%{username}님의 최신 토픽" - tag: "태그된 토픽" + user_posts: "@%{username} 님의 최신 게시물" + user_topics: "@%{username} 님의 최신 주제" + tag: "태그된 주제" badge: "%{site_title}의 %{display_name} 배지" - too_late_to_edit: "이 글은 작성된 지 너무 오랜 기간이 지났습니다. 수정 또는 삭제할 수 없습니다." - edit_conflict: "해당 게시물은 다른 사용자가 수정했으며 변경 사항을 더 이상 저장할 수 없습니다." - revert_version_same: "복구하려는 버전과 현재 버전이 똑같습니다." - cannot_edit_on_slow_mode: "이 항목은 느린 모드입니다. 신중하고 고려된 대화를 장려하기 위해 느린 모드에서는 이 글의 이전 게시물 편집은 허용되지 않습니다." + too_late_to_edit: "이 게시물은 작성된 지 너무 오래되었습니다. 편집 또는 삭제할 수 없습니다." + edit_conflict: "이 게시물은 다른 사용자가 편집했으며 더는 변경사항을 저장할 수 없습니다." + revert_version_same: "되돌리려는 버전과 현재 버전이 동일합니다." + cannot_edit_on_slow_mode: "이 주제는 느린 모드입니다. 신중한 대화를 장려하기 위해 현재 느린 모드에서는 이 주제의 이전 게시물 편집이 허용되지 않습니다." excerpt_image: "이미지" bookmarks: errors: - already_bookmarked_post: "동일한 게시물을 두 번 북마크 할 수 없습니다." - too_many: "죄송합니다. 북마크를 %{limit}개 이상 추가 할 수 없습니다. %{user_bookmarks_url} 을 방문하여 일부를 제거하십시오." - cannot_set_past_reminder: "과거에는 북마크 미리 알림을 설정할 수 없습니다." - cannot_set_reminder_in_distant_future: "앞으로 10 년 이상 책갈피 알림을 설정할 수 없습니다." + already_bookmarked_post: "동일한 게시물을 두 번 북마크할 수 없습니다." + too_many: "북마크를 %{limit}개 이상 추가할 수 없습니다. %{user_bookmarks_url}에서 일부를 제거하세요." + cannot_set_past_reminder: "북마크 미리 알림을 과거로 설정할 수 없습니다." + cannot_set_reminder_in_distant_future: "북마크 미리 알림을 10년 이후로 설정할 수 없습니다." reminders: - at_desktop: "다음에 저는 데스크탑에 있습니다" - later_today: "오늘 늦게" + at_desktop: "다음 데스크톱 접속 시" + later_today: "오늘 중" next_business_day: "다음 영업일" tomorrow: "내일" next_week: "다음 주" @@ -381,278 +381,253 @@ ko: bulk_add: other: "%{count}명의 사용자가 그룹에 추가되었습니다." errors: - grant_trust_level_not_valid: "'%{trust_level}'은 (는) 유효한 신뢰 수준이 아닙니다." - can_not_modify_automatic: "자동 설정 그룹은 수정할 수 없습니다." + grant_trust_level_not_valid: "'%{trust_level}' 신뢰 레벨이 유효하지 않습니다." + can_not_modify_automatic: "자동 그룹은 수정할 수 없습니다." member_already_exist: - other: "%{username} 사용자는 이미 이 그룹의 구성원입니다." - invalid_domain: "'%{domain}'은 유효한 도메인이 아닙니다." - invalid_incoming_email: "'%{email}' 는 올바른 이메일 주소가 아닙니다." - email_already_used_in_group: "'%{email}'는 '%{group_name}' 그룹에서 이미 사용중입니다." - email_already_used_in_category: "'%{email}' 는 '%{category_name}' 카테고리에서 이미 사용중입니다." - cant_allow_membership_requests: "그룹 가입을 승인하려면 그룹 소유자의 승인이 필요합니다." - already_requested_membership: "이 그룹의 회원 자격을 이미 요청하셨습니다." + other: "%{username} 님은 이미 이 그룹의 회원입니다." + invalid_domain: "'%{domain}' 도메인이 유효하지 않습니다." + invalid_incoming_email: "'%{email}' 이메일은 유효한 이메일 주소가 아닙니다." + email_already_used_in_group: "'%{email}' 이메일은 '%{group_name}' 그룹에서 이미 사용 중입니다." + email_already_used_in_category: "'%{email}' 이메일은 '%{category_name}' 카테고리에서 이미 사용 중입니다." + cant_allow_membership_requests: "소유자 없이 그룹의 멤버십 요청을 허용할 수 없습니다." + already_requested_membership: "이 그룹의 멤버십을 이미 요청했습니다." adding_too_many_users: - other: "한 번에 최대 %{count}명의 사용자를 추가 할 수 있습니다." - usernames_or_emails_required: "아이디 또는 이메일이 있어야합니다." - no_invites_with_discourse_connect: "DiscourseConnect가 활성화 된 경우 등록된 사용자만 초대 할 수 있습니다." + other: "한 번에 최대 %{count}명의 사용자를 추가할 수 있습니다" + usernames_or_emails_required: "아이디 또는 이메일이 있어야 합니다" + no_invites_with_discourse_connect: "DiscourseConnect가 활성화된 경우 등록된 사용자만 초대할 수 있습니다." no_invites_without_local_logins: "로컬 로그인이 비활성화된 경우 등록된 사용자만 초대할 수 있습니다." default_names: everyone: "모든 사람" admins: "관리자" moderators: "운영자" - staff: "스태프" + staff: "운영진" trust_level_0: "회원등급 0" trust_level_1: "회원등급 1" trust_level_2: "회원등급 2" trust_level_3: "회원등급 3" trust_level_4: "회원등급 4" request_membership_pm: - title: "@%{group_name}그룹에 가입 신청" + title: "@%{group_name}에 멤버십 요청" request_accepted_pm: - title: "@%{group_name}의 가입이 수락되었습니다." + title: "@%{group_name}의 가입이 수락되었습니다" body: | - @%{group_name} 가입 요청이 수락되었으며 이제 회원이되었습니다. + @%{group_name} 가입 요청이 수락되었으며 이제 회원이 되었습니다. education: until_posts: - other: "글 %{count}개" + other: "%{count}개의 게시물" "new-topic": | - %{site_name} —에 오신 것을 환영합니다. **새로운 대화를 시작해 주셔서 감사합니다!** + %{site_name}에 오신 것을 환영합니다 — **새 대화를 시작해 주셔서 감사합니다!** - 제목을 소리 내어 읽었을 때 흥미롭게 들리나요? 잘 요약되었나요? - - 누가 관심을 가질까요? 왜 중요한가요? 어떤 종류의 응답을 원하시나요? + - 누가 관심을 가질까요? 왜 중요한가요? 어떤 종류의 반응을 원하시나요? - - 다른 사람들이 찾을 수 있도록 주제에 자주 사용되는 단어를 포함하세요. 주제를 관련 주제로 그룹화하려면 카테고리 (또는 태그)를 선택하십시오. + - 다른 사람들이 *찾을 수 있도록* 주제에 자주 사용되는 단어를 포함하세요. 주제를 관련 주제로 그룹화하려면 카테고리(또는 태그)를 선택하세요. - 이 글은 당신의 첫 %{education_posts_text} 에서만 나옵니다. 자세한 내용은 [커뮤니티 가이드라인](%{base_path}/guidelines)을 참조하세요. + 자세한 내용은 [커뮤니티 가이드라인을 참조](%{base_path}/guidelines)하세요. 이 패널은 첫 %{education_posts_text}에만 표시됩니다. "new-reply": | - %{site_name} — ** 참여해 주셔서 감사합니다! ** + %{site_name}에 오신 것을 환영합니다 — **참여해 주셔서 감사합니다!** ** - 다른 커뮤니티 회원에게 친절하게 대하세요. - - 댓글이 대화를 개선합니까? + - 댓글이 대화를 개선하나요? - - 건설적인 비판은 환영하지만 사람이 아닌 *글 내용*을 비판하십시오. + - 건설적인 비판은 환영하지만 사용자가 아닌 *글 내용* 이 대상이 되어야 합니다. - 자세한 내용은 [커뮤니티 가이드 라인 참조](%{base_path}/guidelines). 이 패널은 처음 %{education_posts_text}에 대해서만 표시됩니다. + 자세한 내용은 [커뮤니티 가이드라인을 참조](%{base_path}/guidelines)하세요. 이 패널은 첫 %{education_posts_text}에만 표시됩니다. avatar: |2 - ### 계정에 사진을 걸어두는 건 어떠세요? + ### 계정에 사진을 표시해 보는 건 어떨까요? - 토픽과 포스트를 몇 개 쓰셨습니다. 그런데 프로필 사진에 글자만 덩그러니 있고 특색이 없군요. + 주제와 댓글을 몇 개 게시했지만 프로필 사진이 없군요. 사진으로 개성을 표현해 보세요. - **[사용자 프로필로 가셔서](%{profile_path})** 자신을 나타낼 수 있는 사진이나 그림을 올리는 건 어떠세요? + **[사용자 프로필로 이동하여](%{profile_path})** 나를 표현하는 사진을 업로드해 보는 건 어떨까요? - 프로필 사진을 쓰면 토론의 흐름을 따라가기 쉽고, 흥미있는 사람을 찾기도 쉽답니다! + 모두가 자신의 프로필 사진을 가진 대화에서는 토론을 이해하고 관심 있는 사용자를 찾기가 쉽습니다. sequential_replies: |2 - ### 한번에 여러 포스트에 답글을 써보세요 + ### 한 번에 여러 게시물에 댓글 달기 - 여러 토픽에 일일이 답글을 다는 것보다, 한 답글에 이전에 작성된 여러 포스트를 인용하거나 @아이디 멘션을 하는 게 더 편할 수 있습니다. + 한 주제에서 일일이 댓글을 다는 것보다 한 댓글에 이전 게시물을 인용하거나 @이름 멘션을 하는 게 더 편할 수 있습니다. - 글을 드래그해서 선택한 다음에, 표시되는 '답글 인용하기'버튼을 눌러서 답글을 추가하는 식으로 쓰신 답글을 편집할 수 있습니다. + 이전 댓글을 편집하여 인용을 추가할 수 있습니다. 텍스트를 하이라이트하고 표시되는 '댓글 인용' 버튼을 누르면 됩니다. - 다른 사람도 깨알같이 흩어진 답글을 읽는 것 보다는, 깊이 있게 작성된 몇개의 답글을 읽는 편이 토픽보기에 더 편하답니다. + 작은 개별 댓글을 여러 개 읽는 것 보다는, 깊이 있게 작성된 댓글 몇 개만 읽는 게 더 편리할 것입니다. too_many_replies: |2 - ### 이 토픽 답글 제한량을 모두 채우셨습니다 + ### 이 주제의 댓글 한도에 도달했습니다 - 죄송하지만, 새로운 사용자는 한 토픽 당%{newuser_max_replies_per_topic}개의 답글만 쓸 수 있습니다. + 신규 사용자는 일시적으로 동일 주제에 %{newuser_max_replies_per_topic}개까지만 댓글을 달 수 있습니다. - 새 답글을 다는 대신에, 전에 쓴 답글을 수정하거나 다른 토픽을 구경해보세요. + 새 댓글을 추가하는 대신, 기존 댓글을 편집하거나 다른 주제를 방문해 보세요. reviving_old_topic: | - ### 이 글을 되살리시겠습니까? + ### 이 주제를 되살릴까요? - 이 글에 대한 마지막 댓글은**%{time_ago}**입니다. 댓글을 작성하면 글이 목록 맨 위로 올라가며 이전에 대화에 참여한 사람에게 알릴 수 있습니다. + 이 주제의 마지막 댓글은 **%{time_ago}**에 작성됐습니다. 댓글을 작성하면 주제가 목록 맨 위로 끌어 올림 되며 이전에 대화에 참여한 사람에게 알림이 전송됩니다. - 오래된 이 대화를 계속하시겠습니까? + 이 기존 대화를 계속할까요? activerecord: attributes: category: name: "카테고리 이름" topic: - title: "사이트 이름" - featured_link: "주요 링크" + title: "타이틀" + featured_link: "추천 링크" category_id: "카테고리" post: raw: "본문" user_profile: - bio_raw: "내 소개" + bio_raw: "내 정보" errors: models: topic: attributes: base: - warning_requires_pm: "개인 메시지에만 경고를 첨부 할 수 있습니다." + warning_requires_pm: "개인 메시지에만 경고를 첨부할 수 있습니다." too_many_users: "한 번에 한 명의 사용자에게 경고를 보낼 수 있습니다." - cant_send_pm: "죄송합니다. 해당 사용자에게 개인 메시지를 보낼 수 없습니다." - no_user_selected: "유효한 사용자를 선택해주십시오" - reply_by_email_disabled: "이메일로 답글쓰기가 비활성화되었습니다." - send_to_email_disabled: "죄송합니다. 개인 메시지를 이메일로 보낼 수 없습니다." - target_user_not_found: "이 메시지를 보내는 사용자 중 하나를 찾을 수 없습니다." - unable_to_update: "해당 주제를 업데이트하는 중에 오류가 발생했습니다." - unable_to_tag: "글에 태그를 지정하는 중에 오류가 발생했습니다." + cant_send_pm: "이 사용자에게 개인 메시지를 보낼 수 없습니다." + no_user_selected: "유효한 사용자를 선택하세요." + reply_by_email_disabled: "이메일로 댓글 달기가 비활성화되었습니다." + send_to_email_disabled: "개인 메시지를 이메일로 보낼 수 없습니다." + target_user_not_found: "이 메시지를 보내는 사용자 중 한 명을 찾을 수 없습니다." + unable_to_update: "이 주제를 업데이트하는 중에 오류가 발생했습니다." + unable_to_tag: "주제에 태그를 지정하는 중에 오류가 발생했습니다." featured_link: - invalid: "는 올바르지 않습니다. URL은 http:// 또는 https://를 포함해야 합니다." + invalid: "유효하지 않습니다. URL은 http:// 또는 https://를 포함해야 합니다." user: attributes: password: - common: "가장 자주 사용되는 10000개의 비밀번호 중 하나입니다. 보다 안전한 비밀번호를 사용하세요." - same_as_username: "는 아이디랑 같음. 더 안전한 비밀번호를 사용해주세요." - same_as_email: "는 이메일 주소랑 같음. 더 안전한 비밀번호를 사용해주세요." - same_as_current: "은(는) 현재 비밀번호와 동일합니다." - same_as_name: "당신의 이름과 같습니다." - unique_characters: "반복된 글자가 너무 많습니다. 좀 더 안전한 비밀번호를 사용해주세요." + common: "가장 흔한 10,000개의 비밀번호 중 하나입니다. 더 안전한 비밀번호를 사용하세요." + same_as_username: "아이디랑 같습니다. 더 안전한 비밀번호를 사용하세요." + same_as_email: "이메일과 같습니다. 더 안전한 비밀번호를 사용하세요." + same_as_current: "현재 비밀번호와 같습니다." + same_as_name: "내 이름과 같습니다." + unique_characters: "반복된 문자가 너무 많습니다. 더 안전한 비밀번호를 사용하세요." username: - same_as_password: "비밀번호와 동일합니다." + same_as_password: "비밀번호와 같습니다." name: - same_as_password: "비밀번호와 동일합니다." + same_as_password: "비밀번호와 같습니다." ip_address: - signup_not_allowed: "이 계정에서는 가입 하실 수 없습니다." + signup_not_allowed: "이 계정으로는 가입할 수 없습니다." user_profile: attributes: featured_topic_id: - invalid: "프로필에서이 주제를 추천 할 수 없습니다." + invalid: "프로필에서 이 주제를 추천할 수 없습니다." user_email: attributes: user_id: - reassigning_primary_email: "기본 이메일을 다른 사용자에게 재 할당 할 수 없습니다." + reassigning_primary_email: "기본 이메일을 다른 사용자에게 재할당할 수 없습니다." color_scheme_color: attributes: hex: - invalid: "유효한 색상이 아닙니다." + invalid: "유효한 색상이 아닙니다" post_reply: base: - different_topic: "게시글과 답글은 같은 토픽에 속해야 합니다." + different_topic: "게시글과 댓글은 같은 주제에 속해야 합니다." web_hook: attributes: payload_url: - invalid: "URL이 올바르지 않습니다. URL은 http:// 또는 https://를 포함하며, 공백이 없어야 합니다." + invalid: "URL이 유효하지 않습니다. URL은 http:// 또는 https://를 포함하며, 공백이 없어야 합니다." custom_emoji: attributes: name: - taken: 은(는) 이미 다른 emoji에서 사용중입니다 + taken: 이미 다른 이모티콘에서 사용 중입니다 topic_timer: attributes: execute_at: - in_the_past: "미래값으로 설정되어야 합니다." + in_the_past: "미래여야 합니다." duration_minutes: - cannot_be_zero: "0보다 커야합니다." - exceeds_maximum: "20년을 초과 할 수 없습니다." + cannot_be_zero: "0보다 커야 합니다." + exceeds_maximum: "20년을 초과할 수 없습니다." translation_overrides: attributes: value: - invalid_interpolation_keys: '다음 interpolation key가 유효하지 않습니다: "%{keys}"' + invalid_interpolation_keys: '다음 보간 키가 유효하지 않습니다. "%{keys}"' watched_word: attributes: word: - too_many: "해당 행동을 위한 단어가 너무 많습니다." + too_many: "해당 작업을 위한 단어가 너무 많습니다" base: - invalid_url: "대체 URL이 잘못되었습니다." + invalid_url: "대체 URL이 유효하지 않습니다." <<: *errors uncategorized_category_name: "미분류" - vip_category_name: "라운지" - vip_category_description: "회원등 3 혹은 그 이상의 회원만 입장가능한 카테고리" + general_category_name: "일반" meta_category_name: "사이트 피드백" - meta_category_description: "이 사이트의 운영 방식에 대해 건의하고 토론하는 곳입니다." - staff_category_name: "스태프" - staff_category_description: "스태프들의 논의를 위한 비공개 카테고리입니다. 관리자 및 운영자에게만 보입니다." + meta_category_description: "사이트, 조직, 운영 방식, 개선 방안에 대해 토론하는 곳입니다." + staff_category_name: "운영진" + staff_category_description: "운영진 토론을 위한 비공개 카테고리입니다. 관리자 및 운영자에게만 보입니다." discourse_welcome_topic: title: "Discourse에 오신 것을 환영합니다" body: |2 - 고정된 토픽의 첫 문단은 홈페이지에 들어오는 사람들에게 환영 메시지로 보이게 됩니다. 그래서 매우 중요해요! + 고정된 주제의 첫 문단은 홈페이지 방문자에게 환영 메시지로 표시되므로 매우 중요합니다! - 커뮤니티를 알릴 수 있도록 **이 글을 편집하세요** + 커뮤니티를 간단히 소개할 수 있도록 **이 주제를 편집하세요** - - 누구를 위한 커뮤니티인가요? + - 누구를 위한 커뮤니티인가요? - - 여기에서 무엇을 얻을 수 있나요? + - 여기에 어떤 정보가 있나요? - - 여기에 왜 와야하나요? + - 이곳만의 특징은 무엇인가요? - - 더 알고싶으면 뭘 봐야 하나요 (링크, 자료, 기타 등등)? + - 자세한 내용은 어디에 있나요(링크, 리소스 등)? - - 이 토픽에 답글이 쌓이는 게 싫다면, 관리기능 :wrench:(우측 상단에 있어요)을 통해 이 토픽을 닫을 수 있습니다. - lounge_welcome: - title: "라운지에 오신 것을 환영합니다." - body: |2 - - 축하합니다! :confetti_ball: - - 이 글이 보이면 최근 **일반** (회원레벨 3)으로 승격된 것입니다. - - 이제 다음을 할 수 있습니다 … - - * 모든 글의 제목 편집 - * 글의 카테고리 변경 - * 모든 링크 팔로우 ([automatic nofollow](https://en.wikipedia.org/wiki/Nofollow)가 제거됨) - * 회원레벨 3 이상의 사용자 만 볼 수있는 비공개 카테고리에 접근 - * 한 번의 신고로 스팸 숨기기 - - 다음은 [동일 권한 회원들 목록](%{base_path}/badges/3/regular)입니다. 반갑게 인사 해주세요. - - 이 커뮤니티의 중요한 일원이되어 주셔서 감사합니다! - - (회원레벨에 대한 자세한 내용은 [이 항목 참조][trust]. 지속적으로 기본 필요 사항을 충족해야만 회원레벨이 유지됩니다.) - - [trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ - admin_quick_start_title: "먼저 읽어보기: 빠른 관리 시작 안내서" + admin_quick_start_title: "먼저 읽어보기: 관리 퀵스타트 가이드" category: - topic_prefix: "'%{category}' 카테고리의 설명" - replace_paragraph: "첫 번째 단락을 새 카테고리에 대한 간단한 설명으로 바꾸십시오.이 안내는 카테고리 선택 영역에 나타나므로 200 자 미만으로 유지하십시오." - post_template: "%{replace_paragraph}\n\n다음 문단을 긴 설명을 쓰는데 활용하세요. 카테고리의 가이드라인이나 규칙을 쓰실 수도 있습니다.\n\n- 왜 이 카테고리를 사용해야하나요? 용도가 무엇인가요?\n\n- 기존의 다른 카테고리와 정확히 어떻게 다른가요?\n\n- 이 카테고리에 속한 토픽들은 대체로 무엇을 다루나요?\n\n- 이 카테고리가 필요한가요? 다른 카테고리와 병합하거나 서브 카테고리로 만들면 안되나요?\n" + topic_prefix: "%{category} 카테고리 정보" + replace_paragraph: "(첫 문단을 새 카테고리에 대한 간단한 설명으로 대체하세요. 이 안내는 카테고리 선택 영역에 나타나므로 200자 미만으로 유지하세요.)" + post_template: "%{replace_paragraph}\n\n다음 문단을 긴 설명에 활용하세요. 또는 카테고리의 가이드라인이나 규칙을 적어도 좋습니다.\n\n- 왜 이 카테고리를 사용해야 하나요? 용도가 무엇인가요?\n\n- 기존의 다른 카테고리와 정확히 어떻게 다른가요?\n\n- 이 카테고리에 속한 주제들은 대체로 무엇을 다루나요?\n\n- 이 카테고리가 필요한가요? 다른 카테고리나 서브카테고리와 병합하면 안 되나요?\n" errors: not_found: "카테고리를 찾을수 없습니다!" - uncategorized_parent: "미분류(Uncategorized) 카테고리는 상위 카테고리를 가질 수 없습니다." - self_parent: "하위 카테고리의 상위는 그 자체가 될 수 없습니다." - depth: "하위 카테고리는 계층 구조로 사용할 수 없습니다." - invalid_email_in: "'%{email}' 는 올바른 이메일 주소가 아닙니다." - email_already_used_in_group: "'%{email}'는 '%{group_name}' 그룹에서 이미 사용중입니다." - email_already_used_in_category: "'%{email}' 는 '%{category_name}' 카테고리에서 이미 사용중입니다." - description_incomplete: "카테고리 설명 포스트는 적어도 하나의 문장을 가져야 합니다." - permission_conflict: "하위 범주에 액세스 할 수있는 모든 그룹도 상위 범주에 액세스 할 수 있어야합니다. 다음 그룹은 하위 카테고리 중 하나에 액세스 할 수 있지만 상위 카테고리에는 액세스 할 수 없습니다 : %{group_names}." - disallowed_topic_tags: "이 주제에는 허용되지 않는 태그가 있습니다 : '%{tags}'" + uncategorized_parent: "미분류 카테고리는 상위 카테고리를 가질 수 없습니다" + self_parent: "서브카테고리의 상위 카테고리는 그 자체가 될 수 없습니다." + depth: "서브카테고리는 계층 구조로 사용할 수 없습니다" + invalid_email_in: "'%{email}' 이메일은 유효한 이메일 주소가 아닙니다." + email_already_used_in_group: "'%{email}' 이메일은 '%{group_name}' 그룹에서 이미 사용 중입니다." + email_already_used_in_category: "'%{email}' 이메일은 '%{category_name}' 카테고리에서 이미 사용 중입니다." + description_incomplete: "카테고리 설명 게시물은 적어도 하나의 문장을 가져야 합니다." + permission_conflict: "서브카테고리에 액세스할 수 있는 모든 그룹은 상위 카테고리에도 액세스할 수 있어야 합니다. 다음 그룹은 서브카테고리 중 하나에 액세스할 수 있지만 상위 카테고리에는 액세스할 수 없습니다. %{group_names}." + disallowed_topic_tags: "이 주제에는 이 카테고리에서 허용하지 않는 태그가 있습니다. '%{tags}'" disallowed_tags_generic: "이 주제는 태그를 허용하지 않습니다." slug_contains_non_ascii_chars: "비 ASCII 문자 포함" cannot_delete: - uncategorized: "이 카테고리는 특별합니다. 카테고리가없는 주제의 보관 영역으로 사용됩니다. 삭제할 수 없습니다." - has_subcategories: "하위 카테고리가 있어, 삭제할 수 없습니다." + uncategorized: "특수 카테고리입니다. 카테고리가 없는 주제의 보관 영역으로 사용되므로 삭제할 수 없습니다." + has_subcategories: "서브카테고리가 있기 때문에 이 카테고리를 삭제할 수 없습니다." topic_exists: - other: "%{count}개의 글이 있어 이 카테고리를 삭제할 수 없습니다. 가장 오래된 글은 %{topic_link}입니다." - topic_exists_no_oldest: "%{count}개의 글타래가 이 카테고리 내에 있어 삭제할 수 없습니다." - uncategorized_description: "카테고리가 필요없는 토픽이거나, 토픽에 부합하는 카테고리가 없습니다." + other: "%{count}개의 주제가 있어 이 카테고리를 삭제할 수 없습니다. 가장 오래된 주제는 %{topic_link}입니다." + topic_exists_no_oldest: "%{count}개의 주제가 있어 이 카테고리를 삭제할 수 없습니다." + uncategorized_description: "카테고리가 필요 없는 주제이거나, 주제에 부합하는 카테고리가 없습니다." trust_levels: admin: "관리자" - staff: "스태프" - change_failed_explanation: "당신은 %{user_name} 사용자를 '%{new_trust_level}'으로 강등시키려 하였습니다. 하지만 해당 사용자의 회원등급는 이미 '%{current_trust_level}'입니다. %{user_name} 사용자의 회원등급는 '%{current_trust_level}'으로 유지됩니다. - if you wish to demote user lock trust level first" + staff: "운영진" + change_failed_explanation: "%{user_name} 님을 '%{new_trust_level}' 레벨로 강등시키려 시도했으나 이 사용자의 신뢰 레벨이 이미 '%{current_trust_level}'입니다. %{user_name} 님의 신뢰 레벨은 '%{current_trust_level}' 레벨로 유지됩니다. 이 사용자를 강등시키려면 신뢰 레벨을 먼저 잠가야 합니다." post: image_placeholder: - broken: "이미지를 표시할수없음" + broken: "이미지 깨짐" has_likes: - other: "좋아요 %{count}" + other: "%{count}개의 좋아요" cannot_permanently_delete: - many_posts: "다른 댓글이 있어 이 글을 영구적으로 삭제할 수 없습니다." - wait_or_different_admin: "이 게시물을 영구적으로 삭제하려면 %{time_left}을 기다리거나 다른 관리자가 삭제해야 합니다." + many_posts: "다른 게시물이 있어 이 주제를 영구적으로 삭제할 수 없습니다." + wait_or_different_admin: "이 게시물을 영구적으로 삭제하려면 %{time_left} 동안 기다리거나 다른 관리자가 삭제해야 합니다." rate_limiter: - slow_down: "이 작업을 너무 많이 수행했습니다, 나중에 다시 시도하십시오." - too_many_requests: "이 작업을 너무 많이 수행했습니다. 다시 시도하기 전에 %{time_left}을 기다리십시오." + slow_down: "이 작업을 너무 많이 수행했습니다. 나중에 다시 시도하세요." + too_many_requests: "이 작업을 너무 많이 수행했습니다. %{time_left} 후 다시 시도하세요." by_type: - first_day_replies_per_day: "당신의 열정에 감사드립니다. 신규 사용자가 첫날 작성할 수있는 최대 댓글 수에 도달했습니다. %{time_left}을 기다리면 추가로 댓글을 작성할 수 있습니다." - first_day_topics_per_day: "사용자님의 열정에 감사드립니다! 새로운 사용자가 첫날 만들 수 있는 최대 글 수에 도달했습니다. %{time_left}을 기다리면 추가로 새 글을 작성 할 수 있습니다." - create_topic: "글을 너무 빨리 작성하고 있습니다. 다시 시도하기 전에 %{time_left}을 기다리십시오." - create_post: "너무 빨리 댓글을 작성하고 있습니다. 다시 시도하기 전에 %{time_left}을 기다리십시오." - delete_post: "너무 빨리 게시물을 삭제하고 있습니다. 다시 시도하기 전에 %{time_left}을 기다리십시오." - public_group_membership: "너무 자주 그룹에 가입/탈퇴하고 있습니다. 다시 시도하기 전에 %{time_left}을 기다리십시오." - topics_per_day: "하루에 허용되는 최대 새 글 수에 도달했습니다. %{time_left}후에 추가로 새 글을 작성 할 수 있습니다." - pms_per_day: "하루에 허용되는 최대 메시지 수에 도달했습니다. %{time_left}후에 추가 메시지를 작성 할 수 있습니다." - create_bookmark: "일일 북마크의 최대 수에 도달했습니다. %{time_left}후에 추가로 북마크를 할 수 있습니다." - edit_post: "일일 최대 편집 수에 도달했습니다. %{time_left}후에 추가로 수정 할 수 있습니다." - live_post_counts: "실시간 게시물 수를 너무 빨리 요구하고 있습니다. 다시 시도하기 전에 %{time_left}을 기다리십시오." - unsubscribe_via_email: "이메일을 통해 최대 수신 거부 수에 도달했습니다. 다시 시도하기 전에 %{time_left}을 기다리십시오." - topic_invitations_per_day: "최대 글 초대 수에 도달했습니다. %{time_left}후에 추가로 초대장을 보낼 수 있습니다." + first_day_replies_per_day: "열정에 감사드립니다! 커뮤니티의 안전을 위해 설정된 신규 사용자가 첫날 작성할 수 있는 최대 댓글 수에 도달했습니다. %{time_left} 후 추가로 댓글을 작성할 수 있습니다." + first_day_topics_per_day: "열정에 감사드립니다! 커뮤니티의 안전을 위해 설정된 신규 사용자가 첫날 작성할 수 있는 최대 주제 수에 도달했습니다. %{time_left} 후 새 주제를 생성할 수 있습니다." + create_topic: "주제 생성 속도가 너무 빠릅니다. %{time_left} 후 다시 시도하세요." + create_post: "댓글 달기 속도가 너무 빠릅니다. %{time_left} 후 다시 시도하세요." + delete_post: "게시물 삭제 속도가 너무 빠릅니다. %{time_left} 후 다시 시도하세요." + public_group_membership: "너무 자주 그룹에 가입/탈퇴하고 있습니다. %{time_left} 후 다시 시도하세요." + topics_per_day: "하루에 허용되는 최대 새 주제 수에 도달했습니다. %{time_left} 후 추가로 새 주제를 생성할 수 있습니다." + pms_per_day: "하루에 허용되는 최대 메시지 수에 도달했습니다. %{time_left} 후 추가로 새 메시지를 작성할 수 있습니다." + create_like: "긍정적인 활동에 감사합니다! 오늘 일일 최대 좋아요 수에 도달했지만 신뢰 레벨이 올라감에 따라 일일 좋아요 수를 더 많이 얻을 수 있습니다. %{time_left} 후 다시 게시물에 좋아요를 표시할 수 있습니다." + create_bookmark: "일일 최대 북마크 수에 도달했습니다. %{time_left} 후 추가로 북마크를 생성할 수 있습니다." + edit_post: "일일 최대 편집 수에 도달했습니다. %{time_left} 후 추가로 편집할 수 있습니다." + live_post_counts: "실시간 게시물 수 요청 빈도가 너무 잦습니다. %{time_left} 후 다시 시도하세요." + unsubscribe_via_email: "이메일을 통한 최대 구독 해제 수에 도달했습니다. %{time_left} 후 다시 시도하세요." + topic_invitations_per_day: "최대 주제 초대 수에 도달했습니다. %{time_left} 후 추가로 초대를 전송할 수 있습니다." hours: other: "%{count}시간" minutes: @@ -662,7 +637,7 @@ ko: short_time: "몇초" datetime: distance_in_words: - half_a_minute: "<1분" + half_a_minute: "< 1분" less_than_x_seconds: other: "< %{count}초" x_seconds: @@ -682,16 +657,16 @@ ko: about_x_years: other: "%{count}년" over_x_years: - other: "%{count}년 보다 전" + other: "> %{count}년" almost_x_years: - other: "약 %{count}년" + other: "%{count}년" distance_in_words_verbose: - half_a_minute: "방금 전" - less_than_x_seconds: "방금 전" + half_a_minute: "방금" + less_than_x_seconds: "방금" x_seconds: other: "%{count}초 전" less_than_x_minutes: - other: "%{count}분 보다 이전" + other: "%{count}분 미만" x_minutes: other: "%{count}분 전" about_x_hours: @@ -701,24 +676,24 @@ ko: about_x_months: other: "약 %{count}달 전" x_months: - other: "${count}달 전" + other: "%{count}달 전" about_x_years: other: "약 %{count}년 전" over_x_years: - other: "%{count}년 보다 이전" + other: "%{count}년 전 이상" almost_x_years: other: "약 %{count}년 전" password_reset: - no_token: "죄송하지만, 해당 비밀번호 변경 링크는 너무 오래됐습니다. 로그인 버튼을 눌러서 '비밀번호를 잊어버렸어요'를 사용하여 새로운 링크를 받으세요." - choose_new: "새로운 비밀번호를 입력하세요" - choose: "패스워드를 입력하세요" - update: "비밀번호 변경" + no_token: "이 비밀번호 변경 링크는 너무 오래됐습니다. 로그인 버튼을 눌러서 '비밀번호가 기억나지 않습니다'를 사용하여 새 링크를 받으세요." + choose_new: "새 비밀번호를 입력하세요" + choose: "비밀번호를 입력하세요" + update: "비밀번호 업데이트" save: "비밀번호 설정" - title: "비밀번호 초기화" - success: "비밀번호를 성공적으로 변경하고 지금 로그인 되었습니다." - success_unapproved: "비밀번호를 성공적으로 변경하였습니다." + title: "비밀번호 리셋" + success: "비밀번호를 변경했으며, 로그인되었습니다." + success_unapproved: "비밀번호를 변경했습니다." email_login: - invalid_token: "죄송합니다. 이메일 로그인 링크가 너무 오래되었습니다. 로그인 버튼을 선택하고 '암호를 잊어 버렸습니다'를 사용하여 새 링크를 얻으십시오." + invalid_token: "이 이메일 로그인 링크는 너무 오래됐습니다. 로그인 버튼을 눌러서 '비밀번호가 기억나지 않습니다'를 사용하여 새 링크를 받으세요." title: "이메일 로그인" user_auth_tokens: browser: @@ -731,14 +706,14 @@ ko: safari: "사파리" unknown: "알수없는 브라우저" device: - android: "안드로이드 기기" + android: "Android 디바이스" chromebook: "크롬 OS" ipad: "아이패드" iphone: "아이폰" ipod: "아이팟" linux: "GNU/리눅스 컴퓨터" mac: "맥" - mobile: "모바일 기기" + mobile: "모바일 디바이스" windows: "윈도우 컴퓨터" unknown: "알수없는 디바이스" os: @@ -748,410 +723,410 @@ ko: linux: "리눅스" macos: "맥OS" windows: "마이크로소프트 윈도우" - unknown: "알수없는 운영체제" + unknown: "알 수 없는 운영체제" change_email: - wrong_account_error: "잘못된 계정으로 로그인했습니다. 로그 아웃 한 후 다시 시도하십시오." - confirmed: "이메일 주소가 변경되었습니다." - please_continue: "%{site_name}으로 가기" - error: "이메일 주소를 변경하는데 문제가 있습니다. 주소가 이미 사용되고 있나요?" - doesnt_exist: "해당 이메일 주소는 사용자님의 계정과 연결되어 있지 않습니다." - error_staged: "이메일 주소 변경중에 에러가 발생했습니다. 이 주소는 격리된 사용자가 이미 사용중입니다." - already_done: "죄송합니다. 이 확인 링크는 더 이상 유효하지 않습니다. 이메일이 이미 변경되지는 않았나요?" + wrong_account_error: "잘못된 계정으로 로그인했습니다. 로그아웃한 후 다시 시도하세요." + confirmed: "이메일 주소가 업데이트되었습니다." + please_continue: "%{site_name}에서 계속하기" + error: "이메일 주소 변경 중 오류가 발생했습니다. 이미 사용 중인 이메일일 수 있습니다." + doesnt_exist: "이 이메일 주소는 내 계정과 연결되어 있지 않습니다." + error_staged: "이메일 주소 변경 중에 오류가 발생했습니다. 스테이징된 사용자가 사용 중인 이메일일 수 있습니다." + already_done: "이 확인 링크는 더 이상 유효하지 않습니다. 이메일이 이미 변경되지는 않았나요?" confirm: "확인" max_secondary_emails_error: "허용되는 최대 보조 이메일 한도에 도달했습니다." authorizing_new: title: "새 이메일 확인" - description: "이메일 주소를 다음으로 변경할 것인지 확인하십시오:" - description_add: "보조 이메일 주소를 추가하시겠습니까?" + description: "이메일 주소를 다음으로 변경할지 확인하세요." + description_add: "대체 이메일 주소를 추가할지 확인하세요." authorizing_old: title: "이메일 주소 변경" - description: "이메일 주소 변경을 확인하십시오" - description_add: "보조 이메일 주소를 추가 할 것인지 확인하십시오:" - old_email: "오래된 이메일 : %{email}" + description: "이메일 주소 변경을 확인하세요" + description_add: "대체 이메일 주소를 추가할지 확인하세요." + old_email: "기존 이메일: %{email}" new_email: "새로운 이메일 : %{email}" almost_done_title: "새 이메일 주소 확인" - almost_done_description: "변경 사항을 확인하기 위해 새 이메일 주소로 이메일을 보냈습니다!" + almost_done_description: "변경사항을 확인하기 위해 새 이메일 주소로 이메일을 보냈습니다!" associated_accounts: - revoke_failed: "%{provider_name}으로 계정을 해지하지 못했습니다." + revoke_failed: "%{provider_name}의 계정을 해지하지 못했습니다." connected: "(연결됨)" activation: - action: "여기를 눌러 계정을 활성화하세요." - already_done: "죄송합니다. 이 계정 확인 링크는 더 이상 유효하지 않습니다." - please_continue: "계정이 활성화 되었습니다; 홈페이지로 이동합니다." - continue_button: "%{site_name}으로 가기" + action: "여기를 눌러 계정을 활성화하세요" + already_done: "이 계정 확인 링크는 더 이상 유효하지 않습니다. 계정이 이미 활성화되지는 않았나요?" + please_continue: "새 계정이 확인되었습니다. 홈페이지로 리디렉션됩니다." + continue_button: "%{site_name}에서 계속하기" welcome_to: "%{site_name}에 오신것을 환영합니다." - approval_required: "이 포럼을 사용하기 위해선 운영자가 수동으로 당신의 새로운 계정을 수락해야 합니다. 계정이 수락이 되면 자동으로 이메일이 발송됩니다." - missing_session: "계정이 생성되었는지 감지되지 않습니다. 쿠키 설정을 켰는지 확인해보세요." - activated: "죄송합니다. 이 계정은 이미 활성화되었습니다." + approval_required: "이 포럼에 액세스하려면 운영자가 직접 나의 신규 계정을 승인해야 합니다. 계정이 승인되면 자동으로 이메일이 발송됩니다." + missing_session: "계정이 생성되었는지 탐지할 수 없습니다. 쿠키를 활성화했는지 확인하세요." + activated: "이 계정은 이미 활성화되었습니다." admin_confirm: - title: "관리자 계정 확정하기" - description: "%{target_username} (%{target_email}) 를 관리자로 설정 하시겠습니까?" - grant: "관리자 권한 부여" + title: "관리자 계정 확인" + description: "%{target_username}(%{target_email}) 님을 관리자로 설정할까요?" + grant: "관리자 액세스 부여" complete: "%{target_username} 님은 이제 관리자입니다." - back_to: "%{title}로 돌아가기" + back_to: "%{title} 타이틀로 돌아가기" reviewable_score_types: needs_approval: title: "승인 필요" post_action_types: off_topic: - title: "오프 글타래" - description: "이 글은 이곳의 글타래과 관련된것 같지 않습니다. 다른 글타래로 옮기거나 새로운 글타래를 시작하는 것이 어떤가요?" - short_description: "논의와 관련이 없습니다" + title: "주제에 벗어남" + description: "이 게시물은 제목과 첫 게시물에서 정의된 것과 같이 현재 토론과 관련이 없습니다. 다른 곳으로 이동하세요." + short_description: "토론과 관련 없음" spam: title: "스팸" - description: "이 게시글은 광고나 반달리즘입니다. 이 토픽과 관련이 없거나 쓸모가 없습니다." - short_description: "광고 혹은 반달리즘입니다." - email_title: '"%{title}" 스팸으로 지목됨' + description: "이 게시물은 광고거나 반달리즘입니다. 현재 주제와 관련이 없거나 쓸모가 없습니다." + short_description: "광고 또는 반달리즘입니다" + email_title: '스팸으로 신고됨: "%{title}"' email_body: "%{link}\n\n%{message}" inappropriate: title: "부적절함" - description: '이 게시물에는 합리적인 사람이 모욕적이거나 모욕적이거나 커뮤니티 가이드 라인을 위반 한 것으로 간주하는 내용이 포함되어 있습니다.' - short_description: '커뮤니티 지침 위반' + description: '이 게시물에는 합리적인 판단하에 불쾌하거나 모욕적이거나 커뮤니티 가이드라인 위반으로 간주할 수 있는 콘텐츠가 포함되어 있습니다.' + short_description: '커뮤니티 가이드라인 위반' notify_user: - title: "@%{username} 님에게 메시지를 보냅니다" + title: "@%{username} 님에게 메시지 전송" description: "이 사용자와 게시물에 대해 직접 개인적으로 이야기하고 싶습니다." short_description: "이 사용자와 게시물에 대해 직접 개인적으로 이야기하고 싶습니다." - email_title: '"%{title}" 내의 당신의 글' + email_title: '"%{title}"의 내 게시물' email_body: "%{link}\n\n%{message}" notify_moderators: title: "기타" - description: "항목에 이유가 나와있지는 않지만, 운영진의 관심이 필요한 포스트입니다." - short_description: "기타 이유로 운영진의 관심이 필요합니다" - email_title: '"%{title}"에 운영진의 확인이 필요한 게시글이 있습니다' + description: "이유가 나와 있지는 않지만, 운영진의 확인이 필요한 게시물입니다." + short_description: "기타 이유로 운영진의 확인이 필요합니다" + email_title: '"%{title}"의 게시물이 운영진의 확인이 필요합니다.' email_body: "%{link}\n\n%{message}" bookmark: title: "북마크" - description: "북마크하기" - short_description: "북마크하기" + description: "이 게시물 북마크하기" + short_description: "이 게시물 북마크하기" like: title: "좋아요" description: "좋아요" - short_description: "좋아요" + short_description: "이 게시물에 좋아요 누르기" draft: sequence_conflict_error: title: "초안 오류" - description: "초안이 다른 창에서 편집 중입니다. 이 페이지를 다시로드하십시오." + description: "초안이 다른 창에서 편집 중입니다. 이 페이지를 리로드하세요." draft_backup: - pm_title: "진행중인 주제의 백업 초안" - pm_body: "백업 초안이 포함 된 주제" + pm_title: "진행 중인 주제의 백업 초안" + pm_body: "백업 초안이 포함된 주제" user_activity: - no_log_search_queries: "검색 로그 쿼리는 현재 비활성화되어 있습니다. (관리자가 사이트 설정에서 활성화할 수 있음)" + no_log_search_queries: "검색 로그 쿼리는 현재 비활성화되어 있습니다(관리자가 사이트 설정에서 활성화할 수 있음)." email_settings: - pop3_authentication_error: "제공된 POP3 자격 증명에 문제가 있습니다. 사용자 이름과 비밀번호를 확인하고 다시 시도하세요." - imap_authentication_error: "제공된 IMAP 자격 증명에 문제가 있습니다. 사용자 이름과 비밀번호를 확인하고 다시 시도하세요." - imap_no_response_error: "IMAP 서버와 통신하는 동안 오류가 발생했습니다. %{message}" - smtp_authentication_error: "제공된 SMTP 자격 증명에 문제가 있습니다. 사용자 이름과 비밀번호를 확인하고 다시 시도하세요." - authentication_error_gmail_app_password: '애플리케이션 비밀번호가 필요합니다. 이 Google 도움말 문서에서 자세히 알아보기' - smtp_server_busy_error: "SMTP 서버가 현재 사용 중입니다. 나중에 다시 시도하십시오." - smtp_unhandled_error: "SMTP 서버와 통신할 때 처리되지 않은 오류가 발생했습니다. %{message}" - imap_unhandled_error: "IMAP 서버와 통신할 때 처리되지 않은 오류가 발생했습니다. %{message}" - connection_error: "서버에 연결하는 동안 문제가 발생했습니다. 서버 이름과 포트를 확인한 후 다시 시도하십시오." - timeout_error: "서버 연결 시간이 초과되었습니다. 서버 이름과 포트를 확인한 후 다시 시도하십시오." - unhandled_error: "이메일 설정을 테스트할 때 처리되지 않은 오류가 발생했습니다. %{message}" + pop3_authentication_error: "제공된 POP3 크리덴셜에 문제가 있습니다. 아이디와 비밀번호를 확인하고 다시 시도하세요." + imap_authentication_error: "제공된 IMAP 크리덴셜에 문제가 있습니다. 아이디와 비밀번호를 확인하고 다시 시도하세요." + imap_no_response_error: "IMAP 서버와 통신하는 중에 오류가 발생했습니다. %{message}" + smtp_authentication_error: "제공된 SMTP 크리덴셜에 문제가 있습니다. 아이디와 비밀번호를 확인하고 다시 시도하세요." + authentication_error_gmail_app_password: '애플리케이션 비밀번호가 필요합니다. 이 Google 도움말 문서에서 자세히 알아보세요.' + smtp_server_busy_error: "SMTP 서버가 현재 사용 중입니다. 나중에 다시 시도하세요." + smtp_unhandled_error: "SMTP 서버와 통신 중에 처리되지 않은 오류가 발생했습니다. %{message}" + imap_unhandled_error: "IMAP 서버와 통신 중에 처리되지 않은 오류가 발생했습니다. %{message}" + connection_error: "서버에 연결하는 중에 문제가 발생했습니다. 서버 이름과 포트를 확인한 후 다시 시도하세요." + timeout_error: "서버 연결 시간이 초과되었습니다. 서버 이름과 포트를 확인한 후 다시 시도하세요." + unhandled_error: "이메일 설정을 테스트하는 중에 처리되지 않은 오류가 발생했습니다. %{message}" webauthn: validation: - invalid_type_error: "제공된 웹 인증 유형이 잘못되었습니다. 유효한 유형은 webauthn.get 및 webauthn.create입니다." - challenge_mismatch_error: "제공된 챌린지가 인증 서버에서 생성 된 챌린지와 일치하지 않습니다." + invalid_type_error: "제공된 webauthn 유형이 잘못되었습니다. 유효한 유형은 webauthn.get 및 webauthn.create입니다." + challenge_mismatch_error: "제공된 챌린지가 인증 서버에서 생성된 챌린지와 일치하지 않습니다." invalid_origin_error: "인증 요청의 출처가 서버의 출처와 일치하지 않습니다." malformed_attestation_error: "증명 데이터를 디코딩하는 중에 오류가 발생했습니다." invalid_relying_party_id_error: "인증 요청의 신뢰 당사자 ID가 서버 신뢰 당사자 ID와 일치하지 않습니다." - user_verification_error: "사용자 확인이 필요합니다." + user_verification_error: "사용자 검증이 필요합니다." unsupported_public_key_algorithm_error: "제공된 공개 키 알고리즘이 서버에서 지원되지 않습니다." - unsupported_attestation_format_error: "서버는 증명 형식을 지원하지 않습니다." - credential_id_in_use_error: "제공된 자격 증명 ID가 이미 사용 중입니다." - public_key_error: "신임 정보에 대한 공개 키 검증에 실패했습니다." - ownership_error: "보안 키는 사용자가 소유하지 않습니다." - not_found_error: "제공된 자격 증명 ID가있는 보안 키를 찾을 수 없습니다." - unknown_cose_algorithm_error: "보안 키에 사용 된 알고리즘이 인식되지 않습니다." + unsupported_attestation_format_error: "서버에서 이 증명 포맷을 지원하지 않습니다." + credential_id_in_use_error: "제공된 크리덴셜 ID가 이미 사용 중입니다." + public_key_error: "크리덴셜에 대한 공개 키 검증에 실패했습니다." + ownership_error: "보안 키를 사용자가 소유하지 않습니다." + not_found_error: "제공된 크리덴셜 ID가 있는 보안 키를 찾을 수 없습니다." + unknown_cose_algorithm_error: "보안 키에 사용된 알고리즘이 인식되지 않습니다." topic_flag_types: spam: title: "스팸" - description: "광고글입니다." - long_form: "스팸으로 신고하였습니다." - short_description: "이것은 광고입니다" + description: "이 주제는 광고입니다. 이 사이트와 관련이 없거나 쓸모가 없지만 기본적으로 프로모션 성격을 갖고 있습니다." + long_form: "스팸으로 신고됨" + short_description: "광고입니다" inappropriate: title: "부적절함" - description: '이 주제에는 합리적인 사람이 모욕적이거나 모욕적이거나 커뮤니티 가이드 라인을 위반 한 것으로 간주하는 내용이 포함되어 있습니다.' - long_form: "부적절함으로 신고하였습니다." - short_description: '커뮤니티 지침 위반' + description: '이 주제에는 합리적인 판단하에 불쾌하거나 모욕적이거나 커뮤니티 가이드라인 위반으로 간주할 수 있는 콘텐츠가 포함되어 있습니다.' + long_form: "부적절한 것으로 신고됨" + short_description: '커뮤니티 가이드라인 위반' notify_moderators: title: "기타" - description: '이 주제는 지침 , TOS 또는 위에 나열되지 않은 다른 이유로 인해 일반 직원의주의가 필요합니다.' - long_form: "관리자의 주의를 위해 신고" - short_description: "다른 이유로 운영진의 주의가 필요함" - email_title: '글타래 "%{title}" 은 운영자의 확인이 필요합니다' + description: '이 주제는 가이드라인, TOS 또는 여기에 나열되지 않은 이유에 따라 운영진의 확인이 필요합니다.' + long_form: "운영자의 확인을 위해 신고됨" + short_description: "기타 이유로 운영진의 확인이 필요합니다" + email_title: '"%{title}" 주제는 운영자의 확인이 필요합니다' email_body: "%{link}\n\n%{message}" flagging: - you_must_edit: '

    커뮤니티에서 게시물을 신고했습니다. 메시지를 참조하십시오 .

    ' - user_must_edit: "

    글이 신고되었기 때문에 일시적으로 보이지 않습니다.

    " + you_must_edit: '

    커뮤니티에서 게시물을 신고했습니다. 메시지를 참조하세요.

    ' + user_must_edit: "

    게시물이 신고되었기 때문에 일시적으로 보이지 않습니다.

    " ignored: - hidden_content: "

    무시 된 콘텐츠

    " + hidden_content: "

    무시된 콘텐츠

    " archetypes: regular: - title: "자주보는 글타래" + title: "일반 주제" banner: - title: "배너 글타래" + title: "배너 주제" message: - make: "이 글은 이제 배너입니다. 사용자가 닫을 때까지 모든 페이지의 상단에 나타납니다." - remove: "이 글은 더 이상 배너가 아닙니다. 더 이상 모든 페이지의 상단에 나타나지 않습니다." + make: "이 주제는 이제 배너입니다. 사용자가 닫을 때까지 모든 페이지의 상단에 나타납니다." + remove: "이 글은 이제 배너가 아닙니다. 더 이상 모든 페이지의 상단에 나타나지 않습니다." unsubscribed: - title: "이메일 환경 설정이 업데이트되었습니다!" - description: "이메일 %{email}의 기본 설정이 업데이트되었습니다. 이메일 설정을 변경하려면 사용자 환경 설정을 방문하십시오." - topic_description: "%{link}를 재구독하려면 토픽 하단, 또는 우측에 있는 알림 설정을 사용하세요." - private_topic_description: "다시 구독하려면 주제의 맨 아래 또는 오른쪽에있는 알림 제어를 사용하십시오." + title: "이메일 환경설정이 업데이트되었습니다!" + description: "%{email} 이메일의 환경설정이 업데이트되었습니다. 이메일 설정을 변경하려면 사용자 환경설정을 방문하세요." + topic_description: "%{link} 구독을 다시 하려면 주제 하단, 또는 우측에 있는 알림 컨트롤을 사용하세요." + private_topic_description: "다시 구독하려면 주제 하단 또는 우측에 있는 알림 컨트롤을 사용하세요." uploads: - marked_insecure_from_theme_component_reason: "테마 구성 요소에 사용 된 업로드" + marked_insecure_from_theme_component_reason: "테마 구성 요소에 사용된 업로드" unsubscribe: - title: "구독해지" - stop_watching_topic: "%{link} 이 토픽 그만보기" - mute_topic: "%{link} 이 토픽에 대한 모든 알림끄기" - unwatch_category: "%{category} 카테고리의 모든 토픽 주시 중단하기" + title: "구독 해제" + stop_watching_topic: "이 주제 구독 중지, %{link}" + mute_topic: "이 주제에 대한 모든 알림 뮤트, %{link}" + unwatch_category: "%{category} 카테고리의 모든 주제 구독 중지" mailing_list_mode: "메일링 리스트 모드 끄기" - all: "%{sitename}에서 오는 메일은 전부 받지 않기" - different_user_description: "우리가 메일을 보낸 사용자가 아닌 다른 사용자로 로그인되어 있습니다. 로그아웃하시거나, 익명 모드를 켜시고 다시 시도해주세요." - not_found_description: "죄송합니다. 구독 취소를 찾을 수 없습니다. 이메일의 링크가 너무 오래되어 만료되었을 수 있습니다." + all: "%{sitename}의 메일 전송 중지" + different_user_description: "이메일이 전송되는 사용자가 아닌 계정으로 로그인했습니다. 로그아웃한 후 익명 모드를 시작하고 다시 시도하세요." + not_found_description: "이 구독 해제를 찾을 수 없습니다. 이메일의 링크가 너무 오래되어 만료되었을 수 있습니다." log_out: "로그아웃" - submit: "환경 설정 저장" + submit: "환경설정 저장" digest_frequency: - title: "요약 이메일을 받고 있습니다 %{frequency}" - never_title: "요약 이메일이 수신되지 않습니다" - select_title: "요약 이메일 빈도를 다음으로 설정하십시오." - never: "하지않음" - every_30_minutes: "매 30분 마다" + title: "요약 이메일을 %{frequency} 받고 있습니다" + never_title: "요약 이메일을 수신하지 않습니다" + select_title: "요약 이메일 빈도를 다음으로 설정합니다." + never: "거부" + every_30_minutes: "30분마다" every_hour: "매 시간" daily: "매일" weekly: "매주" every_month: "매월" every_six_months: "6개월마다" user_api_key: - title: "어플리케이션 접근 인증하기" - authorize: "인증하기" + title: "애플리케이션 액세스 인증" + authorize: "인증" read: "읽기" read_write: "읽기/쓰기" - description: '"%{application_name}" 이(가) 당신의 계정에 다음의 접근을 요청합니다:' - instructions: '"%{application_name}"과 함께 사용할 새 사용자 API 키를 생성했습니다. 다음 키를 응용 프로그램에 붙여 넣으십시오.' - otp_description: '"%{application_name}"가이 사이트에 액세스하도록 허용 하시겠습니까?' + description: '"%{application_name}"에서 내 계정에 다음과 같은 액세스를 요청합니다.' + instructions: '"%{application_name}" 애플리케이션과 함께 사용할 새 사용자 API 키를 생성했습니다. 다음 키를 애플리케이션에 붙여 넣으세요.' + otp_description: '"%{application_name}"에서 이 사이트에 액세스하도록 허용할까요?' otp_confirmation: - confirm_title: '%{site_name}으로 가기' - logging_in_as: '%{username}으로 로그인' + confirm_title: '%{site_name}에서 계속하기' + logging_in_as: '%{username} 님으로 로그인' confirm_button: 로그인 완료 - no_trust_level: "죄송합니다. 사용자 API에 액세스하는 데 필요한 회원 레벨이 아닙니다." - generic_error: "죄송합니다. 사용자 API 키를 발급할 수 없습니다. 운영진이 이 기능을 해제한 것 같습니다." + no_trust_level: "사용자 API 액세스에 필요한 신뢰 레벨이 아닙니다." + generic_error: "사용자 API 키를 발급할 수 없습니다. 사이트 관리자가 이 기능을 비활성했을 수 있습니다." scopes: message_bus: "실시간 업데이트" - notifications: "읽고 알림 지우기" - push: "외부 서비스로 알림 푸시하기" + notifications: "알림 읽기 및 지우기" + push: "외부 서비스로 알림 푸시" session_info: "사용자 세션 정보 읽기" read: "모두 읽기" write: "모두 쓰기" one_time_password: "일회성 로그인 토큰 생성" - bookmarks_calendar: "북마크 알림 읽기" + bookmarks_calendar: "북마크 미리 알림 읽기" invalid_public_key: "공개 키가 유효하지 않습니다." - invalid_auth_redirect: "죄송합니다.이 auth_redirect 호스트는 허용되지 않습니다." + invalid_auth_redirect: "이 auth_redirect 호스트는 허용되지 않습니다." invalid_token: "토큰이 없거나 유효하지 않거나 만료되었습니다." flags: errors: - already_handled: "이미 처리된 신고" + already_handled: "이미 처리된 신고입니다" reports: default: labels: - count: 수 + count: 개수 percent: 퍼센트 day: 일 post_edits: - title: "게시물 수정" + title: "게시물 편집" labels: edited_at: 날짜 - post: 글 + post: 게시물 editor: 에디터 - author: 저자 - edit_reason: 사유 - description: "새로운 게시물 수정 횟수" + author: 작성자 + edit_reason: 이유 + description: "새 게시물 편집 횟수입니다." user_flagging_ratio: title: "사용자 신고 비율" labels: user: 사용자 - agreed_flags: 합의 된 플래그 - disagreed_flags: 동의하지 않는 플래그 - ignored_flags: 무시 된 플래그 + agreed_flags: 동의한 신고 + disagreed_flags: 동의하지 않은 신고 + ignored_flags: 무시된 신고 score: 점수 - description: "플래그에 대한 직원 응답 비율로 정렬 된 사용자 목록 (동의되지 않음)." + description: "신고에 대한 운영진 응답 비율로 정렬된 사용자 목록(동의하지 않음 > 동의함)." moderators_activity: - title: "중재자 활동" + title: "운영자 활동" labels: moderator: 운영자 - flag_count: 플래그 검토 - time_read: 읽는 시간 - topic_count: 작성된 주제 - post_count: 작성된 게시물 - pm_count: 작성된 PM - revision_count: 리비젼 - description: 검토 된 플래그, 읽기 시간, 작성된 주제, 작성된 게시물, 작성된 개인 메시지 및 개정을 포함한 중재자 활동 목록. + flag_count: 검토한 신고 + time_read: 읽은 시간 + topic_count: 생성한 주제 + post_count: 생성한 게시물 + pm_count: 생성한 개인 메시지 + revision_count: 수정 버전 + description: 검토한 신고, 읽은 시간, 생성한 주제, 생성한 게시물, 생성한 개인 메시지 및 수정 버전을 포함한 관리자 활동 목록입니다. flags_status: title: "플래그 상태" values: - agreed: 합의 + agreed: 동의함 disagreed: 동의하지 않음 - deferred: 연기 됨 - no_action: 조치 없음 + deferred: 연기됨 + no_action: 아무 작업 안 함 labels: flag: 종류 assigned: 할당됨 - poster: 포스터 + poster: 게시자 flagger: 플래 거 time_to_resolution: 해결 시간 - description: "깃발 유형, 포스터, 깃발 및 해결 시간을 포함한 깃발 상태 목록." + description: "신고 유형, 게시자, 신고자 및 해결 시간을 포함한 신고 상태 목록입니다." visits: - title: "사용자 방문" + title: "사용자 방문 횟수" xaxis: "일" - yaxis: "방문자 수" - description: "모든 사용자 방문수" + yaxis: "방문 횟수" + description: "모든 사용자 방문 횟수" signups: title: "가입" xaxis: "일" yaxis: "가입 수" - description: "이 기간 동안 새 계정 등록." + description: "이 기간에 새 계정이 등록된 수입니다." new_contributors: - title: "새로운 기여자들" + title: "새 기여자" xaxis: "일" - yaxis: "신규 기고자 수" - description: "이 기간 동안 첫 번째 게시물을 작성한 사용자 수" + yaxis: "새 기여자 수" + description: "이 기간에 첫 게시물을 작성한 사용자 수입니다." trust_level_growth: - title: "신뢰 수준의 성장" + title: "신뢰 레벨 성장" xaxis: tl1_reached: "TL1에 도달" tl2_reached: "TL2에 도달" tl3_reached: "TL3에 도달" tl4_reached: "TL4에 도달" yaxis: "일" - description: "이 기간 동안 신뢰 수준을 높인 사용자 수" + description: "이 기간에 신뢰 레벨을 높인 사용자 수입니다." consolidated_page_views: title: "통합 페이지 뷰" xaxis: page_view_crawler: "겉옷" page_view_anon: "익명 사용자" - page_view_logged_in: "로그인 한 사용자" + page_view_logged_in: "로그인한 사용자" yaxis: "일" - description: "로그인 한 사용자, 익명 사용자 및 크롤러에 대한 페이지 뷰" + description: "로그인한 사용자, 익명 사용자 및 크롤러에 대한 페이지 뷰입니다." labels: - post: 글 + post: 게시물 editor: 에디터 - author: 저자 + author: 작성자 edit_reason: 사유 dau_by_mau: title: "DAU / MAU" xaxis: "일" yaxis: "DAU / MAU" - description: "마지막 날에 로그인 한 회원 수를 지난 달에 로그인 한 회원 수로 나눈 값 – 커뮤니티 '고착성'을 나타내는 %를 반환합니다. 30 % 이상을 목표로하십시오." + description: "마지막 날에 로그인한 회원 수를 지난 달에 로그인한 회원 수로 나눈 값 – 커뮤니티 '고착도'를 나타내는 %를 반환합니다. 30% 이상을 목표로 하세요." daily_engaged_users: - title: "참여한 일일 사용자" + title: "일일 참여 사용자" xaxis: "일" yaxis: "참여한 사용자" - description: "마지막 날 좋아요나 글 게시 사용자 수 입니다." + description: "마지막 날 좋아요를 누르거나 게시한 사용자 수 입니다." profile_views: title: "회원 프로필 조회수" xaxis: "일" - yaxis: "회원 프로필 조회된 횟수" - description: "사용자 프로필에 대한 새로운 관점." + yaxis: "회원 프로필이 조회된 횟수" + description: "사용자 프로필의 총 신규 조회수" topics: title: "글타래들" xaxis: "일" - yaxis: "새로운 글타래의 개수" - description: "이 기간 동안 작성된 새로운 주제." + yaxis: "새 주제 수" + description: "이 기간 생성된 새 주제입니다." posts: title: "글들" xaxis: "일" - yaxis: "새로운 글의 개수" - description: "이 기간 동안 작성된 새 게시물" + yaxis: "새 게시물 수" + description: "이 기간 생성된 새 게시물입니다." likes: title: "좋아요" xaxis: "일" - yaxis: "새로운 좋아요 수" - description: "새로운 좋아요 수" + yaxis: "새 좋아요 수" + description: "새 좋아요 수입니다." flags: - title: "신고들" + title: "신고" xaxis: "일" yaxis: "신고 수" - description: "새로운 신고 수" + description: "신규 신고 수입니다." bookmarks: title: "북마크들" xaxis: "일" - yaxis: "새로운 북마크 수" - description: "북마크 된 새 주제 및 게시물 수" + yaxis: "새 북마크 수" + description: "북마크된 새 주제 및 게시물 수입니다." users_by_trust_level: - title: "회원등급당 사용자 수" - xaxis: "회원등급" + title: "신뢰 레벨당 사용자 수" + xaxis: "신뢰 레벨" yaxis: "사용자 수" labels: level: 레벨 - description: "신뢰 수준별로 그룹화 된 사용자 수" + description: "신뢰 레벨별로 그룹화된 사용자 수" description_link: "https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/" users_by_type: title: "유형별 사용자" - xaxis: "형식" + xaxis: "유형" yaxis: "사용자 수" labels: - type: 종류 + type: 유형 xaxis_labels: admin: 관리자 moderator: 운영자 - suspended: 차단됨 - silenced: 쓰기 금지 - description: "관리자, 운영자, 일시 중지 및 자동으로 그룹화 된 사용자 수" + suspended: 정지됨 + silenced: 차단됨 + description: "관리자, 운영자, 정지됨 및 차단됨 유형별로 그룹화된 사용자 수입니다." trending_search: title: 인기 검색어 labels: term: 기간 searches: 검색 click_through: 클릭률 - description: "클릭률이 가장 많이 사용되는 검색어입니다." + description: "최고 인기 검색어와 해당 클릭률입니다." emails: - title: "이메일 보냄" + title: "전송된 이메일" xaxis: "일" yaxis: "이메일 수" - description: "전송된 새 이메일 수 입니다." + description: "전송된 새 이메일 수입니다." user_to_user_private_messages: - title: "사용자 간 (응답 제외)" - xaxis: "일" - yaxis: "메세지 수" - description: "새로 시작된 개인 메시지 수" - user_to_user_private_messages_with_replies: - title: "사용자 간 (응답 포함)" + title: "사용자 간(응답 제외)" xaxis: "일" yaxis: "메시지 수" - description: "모든 새로운 개인 메시지 및 응답 수" + description: "새로 시작된 개인 메시지 수입니다." + user_to_user_private_messages_with_replies: + title: "사용자 간(응답 포함)" + xaxis: "일" + yaxis: "메시지 수" + description: "모든 새로운 개인 메시지 및 응답 수입니다." system_private_messages: title: "시스템" xaxis: "일" - yaxis: "메세지 수" - description: "시스템이 자동으로 보낸 개인 메시지 수." + yaxis: "메시지 수" + description: "시스템에서 자동으로 전송한 개인 메시지 수입니다." moderator_warning_private_messages: - title: "운영자 주의" + title: "운영자 경고" xaxis: "일" - yaxis: "메세지 수" - description: "중재자가 개인 메시지로 보낸 경고 수" + yaxis: "메시지 수" + description: "운영자가 개인 메시지로 전송한 경고 수입니다." notify_moderators_private_messages: - title: "운영자에게 알리기" + title: "운영자에게 알림" xaxis: "일" - yaxis: "메세지 수" - description: "운영자에게 플래그가 개인에게 통지 한 횟수입니다." + yaxis: "메시지 수" + description: "신고로 인해 운영자가 비공개로 알림받은 횟수입니다." notify_user_private_messages: - title: "사용자에게 알리기" + title: "사용자에게 알림" xaxis: "일" - yaxis: "메세지 수" - description: "사용자가 플래그를 통해 비공개로 알림을받은 횟수입니다." + yaxis: "메시지 수" + description: "신고로 인해 사용자가 비공개로 알림받은 횟수입니다." top_referrers: - title: "가장 많이 언급된 사용자들" + title: "주요 참조 사용자" xaxis: "사용자" num_clicks: "클릭" num_topics: "글타래들" labels: user: "사용자" - num_clicks: "클릭수" + num_clicks: "클릭 수" num_topics: "토픽" - description: "사용자가 공유한 링크의 클릭 수로 나열됩니다." + description: "사용자가 공유한 링크의 클릭 수로 사용자를 나열합니다." top_traffic_sources: - title: "트래픽 소스 순위" + title: "주요 트래픽 소스" xaxis: "도메인" num_clicks: "클릭" num_topics: "글타래들" @@ -1160,88 +1135,88 @@ ko: domain: 도메인 num_clicks: 클릭수 num_topics: 토픽 - description: "이 사이트에 가장 많이 연결된 외부 소스." + description: "이 사이트에 가장 많이 연결된 외부 소스입니다." top_referred_topics: - title: "가장 많이 참조된 글타래들" + title: "주요 참조 주제" labels: num_clicks: "클릭수" - topic: "토픽" - description: "외부 소스에서 가장 많은 클릭을 얻은 토픽." + topic: "주제" + description: "외부 소스에서 가장 많은 클릭 수를 받은 주제입니다." page_view_anon_reqs: title: "익명" xaxis: "일" yaxis: "익명 페이지뷰" - description: "방문자가 계정에 로그인하지 않은 새 페이지 뷰 수" + description: "계정에 로그인하지 않은 방문자의 새 페이지뷰 수입니다." page_view_logged_in_reqs: title: "로그인됨" xaxis: "일" - yaxis: "회원 페이지뷰" - description: "로그인 한 사용자의 새 페이지 뷰 수" + yaxis: "로그인한 페이지뷰" + description: "로그인한 사용자의 새 페이지뷰 수입니다." page_view_crawler_reqs: - title: "로봇 페이지뷰" + title: "웹 크롤러 페이지뷰" xaxis: "일" - yaxis: "로봇 페이지뷰" - description: "시간이 지남에 따라 웹 크롤러의 총 페이지 뷰" + yaxis: "웹 크롤러 페이지뷰" + description: "시간이 지남에 따른 웹 크롤러의 총 페이지뷰입니다." page_view_total_reqs: title: "페이지뷰" xaxis: "일" yaxis: "총 페이지뷰" - description: "모든 방문자의 새로운 페이지 뷰 수" + description: "모든 방문자의 새 페이지뷰 수입니다." page_view_logged_in_mobile_reqs: - title: "회원 페이지뷰" + title: "로그인한 페이지뷰" xaxis: "일" - yaxis: "모바일 회원 페이지뷰" - description: "휴대 기기 사용자가 계정에 로그인 한 새로운 페이지 뷰 수입니다." + yaxis: "모바일 로그인한 페이지뷰" + description: "모바일 디바이스에서 계정에 로그인한 사용자의 새 페이지뷰 수입니다." page_view_anon_mobile_reqs: title: "익명 페이지뷰" xaxis: "일" yaxis: "모바일 익명 페이지뷰" - description: "로그인하지 않은 휴대 기기 방문자의 새 페이지 뷰 수입니다." + description: "모바일 디바이스에서 계정에 로그인하지 않은 방문자의 새 페이지뷰 수입니다." http_background_reqs: title: "백그라운드" xaxis: "일" - yaxis: "라이브업데이트와 트랙킹에 사용된 요청" + yaxis: "라이브 업데이트와 추적에 사용된 요청" http_2xx_reqs: - title: "Status 2xx (정상)" + title: "Status 2xx(정상)" xaxis: "일" - yaxis: "정상 요청 (Status 2xx)" + yaxis: "정상 요청(Status 2xx)" http_3xx_reqs: - title: "HTTP 3xx (다른페이지로이동)" + title: "HTTP 3xx(리디렉션)" xaxis: "일" - yaxis: "다른페이지로이동 요청 (Status 3xx)" + yaxis: "리디렉션 요청(Status 3xx)" http_4xx_reqs: - title: "HTTP 4xx (클라이언트 오류)" + title: "HTTP 4xx(클라이언트 오류)" xaxis: "일" - yaxis: "클라이언트 오류 (Status 4xx)" + yaxis: "클라이언트 오류(Status 4xx)" http_5xx_reqs: - title: "HTTP 5xx (서버 오류)" + title: "HTTP 5xx(서버 오류)" xaxis: "일" - yaxis: "서버 오류 (Status 5xx)" + yaxis: "서버 오류(Status 5xx)" http_total_reqs: title: "총" xaxis: "일" yaxis: "총 요청횟수" time_to_first_response: - title: "첫 응답" + title: "첫 응답 시간" xaxis: "일" - yaxis: "평균 시간 (시간단위)" - description: "새 주제에 대한 첫 번째 응답의 평균 시간 (시간)입니다." + yaxis: "평균 시간(시간)" + description: "새 주제에 대한 첫 응답의 평균 시간(시간)입니다." topics_with_no_response: - title: "답글 없는 주제" + title: "댓글 없는 주제" xaxis: "일" yaxis: "총" - description: "응답을받지 못한 새 주제의 수입니다." + description: "응답을 받지 못한 새로 생성된 주제 수입니다." mobile_visits: - title: "사용자 방문 (모바일)" + title: "사용자 방문 횟수(모바일)" xaxis: "일" yaxis: "방문 횟수" - description: "휴대 기기를 사용하여 방문한 순 사용자 수" + description: "모바일 디바이스로 방문한 고유 사용자 수입니다." web_crawlers: title: "웹 크롤러 사용자 에이전트" labels: user_agent: "사용자 에이전트" page_views: "페이지뷰" - description: "페이지 뷰별로 정렬 된 웹 크롤러 사용자 에이전트 목록입니다." + description: "페이지뷰로 정렬된 웹 크롤러 사용자 에이전트 목록입니다." suspicious_logins: title: "의심스러운 로그인" labels: @@ -1249,822 +1224,820 @@ ko: client_ip: 사용자 IP location: 위치 browser: 브라우저 - device: 기기 + device: 디바이스 os: 운영체제 login_time: 로그인 시간 - description: "이전 로그인과 다른 의심스러운 새로운 로그인의 세부 정보." + description: "이전 로그인과 다른 의심스러운 새 로그인의 상세 정보입니다." staff_logins: title: "관리자 로그인" labels: user: 사용자 location: 위치 - login_at: 에 로그인 - description: "위치가있는 관리자 로그인 시간 목록" + login_at: 로그인 시간 + description: "위치가 있는 관리자 로그인 시간 목록입니다." top_uploads: - title: "인기 업로드" + title: "주요 업로드" labels: filename: 파일명 extension: 확장자 author: 저자 filesize: 파일 크기 - description: "확장자, 파일 크기 및 작성자별로 모든 업로드를 나열하십시오." + description: "확장자, 파일 크기 및 작성자별로 모든 업로드를 나열합니다." top_ignored_users: - title: "무시 / 음소거 된 사용자" + title: "주요 무시/뮤트된 사용자" labels: - ignored_user: 무시 된 사용자 - ignores_count: 카운트 무시 - mutes_count: 음소거 수 - description: "다른 많은 사용자가 음소거하거나 무시한 사용자" + ignored_user: 무시된 사용자 + ignores_count: 무시 횟수 + mutes_count: 뮤트 횟수 + description: "많은 사용자로부터 뮤트 및/또는 무시된 사용자입니다." top_users_by_likes_received: - title: "좋아요를 많이 받은 사용자" + title: "좋아요를 많이 받은 주요 사용자" labels: user: 사용자 - qtt_like: '''좋아요'' 받은 횟수' + qtt_like: 받은 좋아요 수 top_users_by_likes_received_from_inferior_trust_level: labels: user: 사용자 - trust_level: 회원 레벨 - qtt_like: '''좋아요'' 받은 횟수' + trust_level: 신뢰 레벨 + qtt_like: 받은 좋아요 수 top_users_by_likes_received_from_a_variety_of_people: - title: "여러 사람들로부터 좋아요를 받은 상위 사용자" + title: "여러 사람들로부터 좋아요를 받은 주요 사용자" labels: user: 사용자 - qtt_like: '''좋아요'' 받은 횟수' + qtt_like: 받은 좋아요 수 dashboard: - rails_env_warning: "당신의 서버는 %{env} 모드에서 실행되고 있습니다." - host_names_warning: "당신의 config/database.yml 파일은 기본 호스트네임을 사용하고 있습니다. 사이트의 호스트네임으로 업데이트 하세요." - sidekiq_warning: 'Sidekiq 이 현재 실행되고 있지 않습니다. Sidekiq는 이메일 전송 같은 많은 작업들을 비동기식으로 처리합니다. 적어도 하나의 sidekiq 프로세서를 실행시켜 주세요. Sidekiq 배우기.' - queue_size_warning: "큐 작업의 수가 %{queue_size} 개 입니다. 작업의 수가 너무 많습니다. Sidekiq에 문제가 있을 수 있습니다. Sidekiq Worker를 더 추가하세요." - memory_warning: "당신의 서버는 1GB 이하 메모리로 실행되고 있습니다. 적어도 1GB 이상의 메모리를 사용하세요." - google_oauth2_config_warning: '서버가 Google OAuth2 (enable_google_oauth2_logins)로 가입 및 로그인을 허용하도록 구성되었지만, 클라이언트 ID 및 클라이언트 비밀 값이 설정되지 않았습니다. 사이트 설정으로 이동하여 설정을 업데이트하십시오. 자세한 내용은 이 가이드를 참조하십시오.' - facebook_config_warning: '서버는 페이스북(enable_facebook_logins)으로 가입 및 로그인을 허용하도록 구성되어 있지만, 앱 ID 및 앱 비밀 값이 설정되지 않았습니다. 사이트 설정으로 이동하여 설정을 업데이트하십시오. 자세한 내용은 이 가이드를 참조하십시오.' - twitter_config_warning: '서버가 트위터(enable_twitter_logins)로 가입 및 로그인을 허용하도록 구성되었지만, 키 및 시크릿 값이 설정되지 않았습니다. 사이트 설정으로 이동하여 설정을 업데이트하십시오. 자세한 내용은 이 안내서를 참조하십시오.' - github_config_warning: '서버가 GitHub(enable_github_logins)으로 가입 및 로그인을 허용하도록 구성되어 있지만, 클라이언트 ID 및 시크릿 값이 설정되지 않았습니다. 사이트 설정으로 이동하여 설정을 업데이트하십시오. 자세한 내용은 이 가이드를 참조하십시오.' - s3_config_warning: '서버가 S3에 파일을 업로드하도록 구성되었지만 s3_access_key_id, s3_secret_access_key, s3_use_iam_profile 또는 s3_upload_bucket 설정 중 하나 이상이 설정되지 않았습니다. 사이트 설정에서 설정을 업데이트하십시오. "S3에 이미지 업로드를 설정하는 방법"을 참조하십시오. 자세히 알아보기.' - s3_backup_config_warning: '서버가 백업을 S3에 업로드하도록 구성되었지만 s3_access_key_id, s3_secret_access_key, s3_use_iam_profile 또는 s3_backup_bucket 중 하나 이상이 설정되지 않았습니다. 사이트 설정으로 이동하여 설정 을 업데이트하십시오. "S3에 이미지 업로드를 설정하는 방법"을 참조하십시오. 자세한 내용은 .' - s3_cdn_warning: '서버가 S3에 파일을 업로드하도록 구성되어 있지만 S3 CDN이 구성되어 있지 않습니다. 이로 인해 S3 비용이 많이 들고 사이트 성능이 저하 될 수 있습니다. 자세한 내용은 "Using Object Storage for Uploads"을 참조하십시오.' - image_magick_warning: '서버가 큰 이미지의 축소판을 만들도록 구성되었지만 ImageMagick이 설치되지 않았습니다. 자주 사용하는 패키지 관리자를 사용하여 ImageMagick을 설치하거나 최신 릴리스를 다운로드하십시오 .' - failing_emails_warning: '실패한 %{num_failed_jobs} 이메일 작업이 있습니다. app.yml을 확인하고 메일 서버 설정이 올바른지 확인하십시오. Sidekiq의 실패한 작업을 참조하십시오 .' - subfolder_ends_in_slash: "서브폴더 설정이 정확하지 않습니다. DISCOURSE_RELATIVE_URL_ROOT 다음에 슬래시가 있습니다." + rails_env_warning: "서버가 %{env} 모드에서 실행 중입니다." + host_names_warning: "config/database.yml 파일은 디폴트 로컬호스트 호스트 이름을 사용하고 있습니다. 내 사이트의 호스트 이름으로 업데이트하세요." + sidekiq_warning: 'Sidekiq이 현재 실행되고 있지 않습니다. Sidekiq은 이메일 전송 같은 많은 작업을 비동기식으로 처리합니다. 최소 하나의 sidekiq 프로세서를 실행하세요. 여기에서 Sidekiq을 자세히 알아보세요.' + queue_size_warning: "대기열 작업이 %{queue_size}개 있습니다. 작업 수가 너무 많아 Sidekiq 프로세스에 문제가 있을 수 있습니다. Sidekiq Worker를 더 추가해야 할 수 있습니다." + memory_warning: "서버가 총 1GB 미만 메모리로 실행되고 있습니다. 최소 1GB 이상의 메모리를 사용하세요." + google_oauth2_config_warning: '서버가 Google OAuth2(enable_google_oauth2_logins)로 가입 및 로그인을 허용하도록 환경설정되었지만, 클라이언트 ID 및 클라이언트 암호 값이 설정되지 않았습니다. 사이트 설정으로 이동하여 설정을 업데이트하세요. 자세한 내용은 이 가이드를 참조하세요.' + facebook_config_warning: '서버가 Facebook(enable_facebook_logins)으로 가입 및 로그인을 허용하도록 환경설정되었지만, 앱 ID 및 앱 암호 값이 설정되지 않았습니다. 사이트 설정으로 이동하여 설정을 업데이트하세요. 자세한 내용은 이 가이드를 참조하세요.' + twitter_config_warning: '서버가 Twitter(enable_twitter_logins)로 가입 및 로그인을 허용하도록 환경설정되었지만, 키 및 암호 값이 설정되지 않았습니다. 사이트 설정으로 이동하여 설정을 업데이트하세요. 자세한 내용은 이 가이드를 참조하세요.' + github_config_warning: '서버가 GitHub(enable_github_logins)로 가입 및 로그인을 허용하도록 환경설정되었지만, 클라이언트 ID 및 암호 값이 설정되지 않았습니다. 사이트 설정으로 이동하여 설정을 업데이트하세요. 자세한 내용은 이 가이드를 참조하세요.' + s3_config_warning: '서버가 S3에 파일을 업로드하도록 환경설정되었지만 s3_access_key_id, s3_secret_access_key, s3_use_iam_profile 또는 s3_upload_bucket 설정 중 하나 이상이 설정되지 않았습니다. 사이트 설정에서 설정을 업데이트하세요. 자세한 내용은 ''S3에 이미지 업로드 구성 방법''을 참조하세요.' + s3_backup_config_warning: '서버가 S3에 백업을 업로드하도록 환경설정되었지만 s3_access_key_id, s3_secret_access_key, s3_use_iam_profile 또는 s3_backup_bucket 설정 중 하나 이상이 설정되지 않았습니다. 사이트 설정에서 설정을 업데이트하세요. 자세한 내용은 ''S3에 이미지 업로드 구성 방법''을 참조하세요.' + s3_cdn_warning: '서버가 S3에 파일을 업로드하도록 환경설정되었지만 S3 CDN이 환경설정되어 있지 않습니다. 이로 인해 S3 비용이 많이 들고 사이트 퍼포먼스가 저하될 수 있습니다. 자세한 내용은 ''업로드용 오브젝트 스토리지 사용''을 참조하세요.' + image_magick_warning: '서버가 큰 이미지의 섬네일을 만들도록 환경설정되었지만 ImageMagick이 설치되지 않았습니다. 즐겨 찾는 패키지 관리자를 사용하여 ImageMagick을 설치하거나 최신 출시 버전을 다운로드하세요.' + failing_emails_warning: '실패한 %{num_failed_jobs} 이메일 작업이 있습니다. app.yml을 확인하고 메일 서버 설정이 올바른지 확인하세요. Sidekiq의 실패한 작업을 참조하세요.' + subfolder_ends_in_slash: "서브폴더 설정이 올바르지 않습니다. DISCOURSE_RELATIVE_URL_ROOT 다음에 슬래시가 있습니다." email_polling_errored_recently: - other: "이메일 폴링에서 지난 24시간 동안%{count}개의 에러가 발생하였습니다. 세부 정보는 로그에서 확인하세요." - missing_mailgun_api_key: "서버가 Mailgun을 통해 이메일을 보내도록 구성되었지만 웹 후크 메시지를 확인하는 데 사용되는 API 키를 제공하지 않았습니다." - bad_favicon_url: "파비콘이로드되지 않습니다. 사이트 설정에서 즐겨 찾기 아이콘 설정을 확인하십시오." - poll_pop3_timeout: "타임아웃으로 POP3 연결이 실패했습니다. 수신 이메일을 가져올 수 없습니다. POP3 설정 과 서비스 제공자를 확인하세요." - poll_pop3_auth_error: "인증 실패로 POP3 연결이 실패했습니다. POP3 설정을 확인하세요." - force_https_warning: "귀하의 웹 사이트는 SSL을 사용하고 있습니다. 그러나 사이트 설정에서` force_https` 가 아직 활성화되어 있지 않습니다." - out_of_date_themes: "다음 테마에 대한 업데이트가 제공됩니다." + other: "이메일 폴링에서 지난 24시간 %{count}개의 오류가 발생했습니다. 자세한 내용은 로그를 확인하세요." + missing_mailgun_api_key: "서버가 Mailgun을 통해 이메일을 전송하도록 환경설정되었지만 Webhook 메시지 검증에 사용되는 API 키를 제공하지 않았습니다." + bad_favicon_url: "즐겨찾기 아이콘을 로드하지 못했습니다. 사이트 설정에서 즐겨찾기 아이콘 설정을 확인하세요." + poll_pop3_timeout: "POP3 서버 연결이 시간 초과되었습니다. 수신 이메일을 가져올 수 없습니다. POP3 설정과 서비스 제공자를 확인하세요." + poll_pop3_auth_error: "인증 오류로 POP3 서버에 연결하지 못했습니다. POP3 설정을 확인하세요." + force_https_warning: "웹사이트에서 SSL을 사용하고 있지만, 사이트 설정에서 `force_https` 가 아직 활성화되어 있지 않습니다." + out_of_date_themes: "다음 테마에 대한 업데이트가 있습니다." unreachable_themes: "다음 테마에 대한 업데이트를 확인할 수 없습니다." site_settings: - allow_bulk_invite: "CSV 파일을 업로드하여 대량 초대 허용" - disabled: "비활성" - display_local_time_in_user_card: "사용자 카드 페이지가 열릴 때 사용자의 시간대를 기준으로 현지 시간을 표시합니다." - censored_words: "단어는 자동적으로 `■■■■` 로 대체 됩니다." - delete_old_hidden_posts: "30일이 지난 숨겨진 글은 자동으로 삭제됩니다." - default_locale: "이 Discourse 인스턴스의 기본 언어입니다. 사용자 정의 / 텍스트 에서 시스템 생성 범주 및 주제의 텍스트를 바꿀 수 있습니다." - allow_user_locale: "사용자에게 자신이 원하는 언어를 선택 허용" - set_locale_from_accept_language_header: "익명 사용자의 인터페이스 언어를 웹브라우저 언어 헤더를 기준으로 변경하기(실험적인 기능입니다. 익명 cache와 동작하지 않습니다.)" - support_mixed_text_direction: "왼쪽에서 오른쪽 및 오른쪽에서 왼쪽으로 혼합 된 텍스트 방향을 지원합니다." - min_post_length: "글의 최소 글자 수" - min_first_post_length: "첫 글 (내용)의 최소 길이" - min_personal_message_post_length: "메시지에 허용되는 최소 글자 수" - max_post_length: "글의 최대 글자 수" - topic_featured_link_enabled: "토픽에 링크 게시글 달기 활성화" - show_topic_featured_link_in_digest: "요약 메일에 토픽 주요 링크 보이게 하기." - min_topic_views_for_delete_confirm: "삭제시 확인 팝업을 위해 필요한 글의 최소 조회수" - min_topic_title_length: "글타래 제목의 최소 글자 수" - max_topic_title_length: "글타래 제목의 최대 글자 수" - min_personal_message_title_length: "메세지 제목의 최소 길이" - max_emojis_in_title: "제목에 허용되는 최대 이모티콘" - min_search_term_length: "검색을 하기 위한 최소 글자 수" + allow_bulk_invite: "CSV 파일 업로드를 통한 일괄 초대 허용" + disabled: "비활성화됨" + display_local_time_in_user_card: "사용자 카드가 열릴 때 사용자의 시간대를 기준으로 현지 시간을 표시합니다." + censored_words: "■■■■로 자동 대체되는 단어" + delete_old_hidden_posts: "30일 이상 숨겨진 게시물은 자동으로 삭제됩니다." + default_locale: "이 Discourse 인스턴스의 디폴트 언어입니다. 사용자 지정 / 텍스트에서 시스템 생성 카테고리 및 주제의 텍스트를 대체할 수 있습니다." + allow_user_locale: "사용자가 자체 인터페이스 환경설정을 선택하도록 허용" + set_locale_from_accept_language_header: "익명 사용자의 인터페이스 언어를 웹브라우저 언어 헤더를 기준으로 설정" + support_mixed_text_direction: "왼쪽에서 오른쪽 및 오른쪽에서 왼쪽 텍스트 방향 혼합을 지원합니다." + min_post_length: "게시물에 허용되는 최소 문자 수" + min_first_post_length: "첫 게시물(주제 본문)에 허용되는 최소 문자 수" + min_personal_message_post_length: "메시지용 게시물에 허용되는 최소 문자 수" + max_post_length: "게시물에 허용되는 최대 문자 수" + topic_featured_link_enabled: "주제와 함께 링크 게시를 활성화합니다." + show_topic_featured_link_in_digest: "다이제스트 메일에 주제 추천 링크를 표시합니다." + min_topic_views_for_delete_confirm: "삭제 시 확인 팝업 표시를 위해 필요한 주제의 최소 조회수" + min_topic_title_length: "주제 제목에 허용되는 최소 문자 수" + max_topic_title_length: "주제 제목에 허용되는 최대 문자 수" + min_personal_message_title_length: "메시지 제목에 허용되는 최소 문자 수" + max_emojis_in_title: "주제 제목에 허용되는 최대 이모티콘 수" + min_search_term_length: "검색어의 유효한 최소 문자 수" search_tokenize_chinese: "중국어가 아닌 사이트에서도 중국어를 토큰화하도록 강제 검색" - search_prefer_recent_posts: "이 옵션을 켜면, 포럼이 너무 커서 검색이 느리게 작동할 때 최근의 포스트부터 먼저 검색합니다." - search_recent_posts_size: "대문에 실을 최신 포스트 수" - log_search_queries: "사용자에 의해 발생된 로그 탐색 쿼리" - search_query_log_max_size: "최대 쿼리 기록 저장 수" - search_query_log_max_retention_days: "검색어를 유지하는 최대 시간 (일)입니다." - search_ignore_accents: "텍스트를 검색 할 때 악센트를 무시하십시오." - category_search_priority_low_weight: "카테고리 검색 우선 순위가 낮은 순위에 가중치가 적용됩니다." - category_search_priority_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: "타이틀 태그에 쓰일 이 사이트의 이름" - site_description: "이 사이트를 한 문장으로 설명해 주세요. 설명 메타태그에 사용됩니다." - short_site_description: "홈페이지의 제목 태그에 사용 된 간단한 설명입니다." - contact_email: "사이트를 담당자 이메일 주소입니다. 긴급한 문제에 대한 문의 뿐만 아니라 중요한 알림에 사용됩니다." - contact_url: "이 사이트의 연락처 URL입니다. 긴급한 사항의 문의는 /about 페이지에서 확인하세요." + search_prefer_recent_posts: "이 옵션을 사용하면 포럼이 너무 커서 검색이 느릴 경우 최근 게시물의 색인부터 시도합니다." + search_recent_posts_size: "색인에 유지할 최근 게시물 수" + log_search_queries: "사용자가 수행한 검색 쿼리 로그" + search_query_log_max_size: "유지할 최대 검색 쿼리 수" + search_query_log_max_retention_days: "검색 쿼리를 유지하는 최대 시간(일)입니다." + search_ignore_accents: "텍스트 검색 시 강세는 무시하세요." + category_search_priority_low_weight: "카테고리 검색 우선순위가 낮은 순위에 가중치가 적용됩니다." + category_search_priority_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: "이 사이트의 이름입니다(제목 태그에 사용)." + site_description: "이 사이트를 한 문장으로 설명하세요(설명 태그에 사용)." + short_site_description: "간단한 설명입니다(홈페이지의 제목 태그에 사용)." + contact_email: "이 사이트의 담당자 이메일 주소입니다. 중요 알림뿐만 아니라 긴급 상황에 대비하여 정보에 표시됩니다." + contact_url: "이 사이트의 연락처 URL입니다. 긴급 상황에 대비하여 정보 페이지에 표시됩니다." crawl_images: "원격 URL에서 이미지를 가져와 올바른 너비 및 높이 치수를 삽입합니다." - download_remote_images_threshold: "원격의 이미지를 로컬에 다운받기 위한 최소 디스크 공간(%)" - disabled_image_download_domains: "이 도메인의 원격 이미지는 다운로드 하지 않습니다. 목록은 ` | `를 사용해 구분하세요." - editing_grace_period: "글 작성 후, 편집해도 히스토리에 남기지 않는 시간 (단위: 초)" - editing_grace_period_max_diff: "다른 변경 후 상점 (신뢰 레벨 0 및 1)을 더 많이 변경 한 경우 유예 기간 편집에 허용되는 최대 문자 변경 수" - editing_grace_period_max_diff_high_trust: "상점이 더 변경된 다른 상점 개정 (신뢰 레벨 2 이상) 인 경우 유예 기간 편집에 허용되는 최대 문자 변경 수" - staff_edit_locks_post: "직원이 게시물을 수정하면 게시물이 수정되지 않습니다." - post_edit_time_limit: "tl0 또는 tl1 작성자는 게시 후 (n) 분 동안 게시물을 편집 할 수 있습니다. 영원히 0으로 설정하십시오." - tl2_post_edit_time_limit: "tl2 + 작성자는 게시 후 (n) 분 동안 게시물을 편집 할 수 있습니다. 영원히 0으로 설정하십시오." - edit_history_visible_to_public: "모든 사용자가 글의 수정 내역을 볼 수 있도록 허용. 비활성화시 스태프 맴버만 수정 내역을 볼 수 있음." - delete_removed_posts_after: "작성자에 의해 삭제된 글은 (n) 시간 뒤 자동으로 삭제됩니다. 0으로 설정 시, 즉시 삭제됩니다." - notify_users_after_responses_deleted_on_flagged_post: "게시물이 신고로 삭제되면 게시물에 답글을 작성했거나 댓글이 삭제된 모든 사용자에게 알림이 전송됩니다." - max_image_width: "글에서 사용할 수 있는 썸네일 이미지의 최대 너비" - max_image_height: "글에서 사용할 수 있는 썸네일 이미지의 최대 높이" - responsive_post_image_sizes: "라이트 박스 미리보기 이미지의 크기를 조정하여 다음 픽셀 비율의 높은 DPI 화면을 허용합니다. 반응 형 이미지를 비활성화하려면 모든 값을 제거하십시오." - fixed_category_positions: "활성화하면 고정된 순서의 카테고리들을 바꿀 수 있다. 활성화 하지 않으면 카테고리는 활동적인 순서에 따라 정렬된다." - fixed_category_positions_on_create: "선택 시, 카테고리 정렬이 유지됩니다. (fixed_category_positions가 체크돼 있어야 합니다.)" - add_rel_nofollow_to_user_content: '사용자 생성 컨텐츠에 대해서 rel nofollow 를 설정함. parent domain을 포함한 internal link는 예외임. 이 설정을 바꾸려면 모든 baked markdown을 "rake posts:rebake" 명령으로 변경해주서야 함' - exclude_rel_nofollow_domains: "nofollow를 링크에 추가하지 않아야하는 도메인 목록입니다. example.com은 자동으로 sub.example.com도 허용합니다. 최소한 웹 크롤러가 모든 콘텐츠를 찾을 수 있도록이 사이트의 도메인을 추가해야합니다. 웹 사이트의 다른 부분이 다른 도메인에있는 경우 해당 도메인도 추가하십시오." - post_excerpt_maxlength: "글 인용에 허용되는 최대 글자수" - topic_excerpt_maxlength: "글의 첫 번째 게시물에서 생성 된 글의 발췌 / 요약의 최대 길이입니다." - show_pinned_excerpt_mobile: "모바일 뷰에서 고정 토픽의 발췌 내용을 보여주기" - show_pinned_excerpt_desktop: "데스크톱 뷰에서 고정 토픽의 발췌 내용을 보여주기" - post_onebox_maxlength: "onebox가 적용된 Discourse 글에 허용되는 최대 글자수" - allowed_inline_onebox_domains: "제목없이 링크 된 경우 미니어처 형식으로 oneboxed 될 도메인 목록" - enable_inline_onebox_on_all_domains: "inline_onebox_domain_whitelist 사이트 설정을 무시하고 모든 도메인에서 인라인 onebox를 허용하십시오." - force_custom_user_agent_hosts: "모든 요청에서 사용자 정의 onebox 사용자 에이전트를 사용할 호스트. (특히 사용자 에이전트의 액세스를 제한하는 호스트에 유용합니다)." - max_oneboxes_per_post: "포스트 당 최대 박스링크(Onebox)의 수" - facebook_app_access_token: "Facebook 앱 ID 및 시크릿에서 생성 된 토큰입니다. Instagram onebox를 생성하는 데 사용됩니다." - logo: "사이트 왼쪽 상단의 로고 이미지 높이가 120이고 가로 세로 비율이 3 : 1보다 큰 넓은 직사각형 이미지를 사용하십시오. 비워두면 사이트 제목 텍스트가 표시됩니다." - logo_small: "아래로 스크롤하면 사이트 왼쪽 상단에 작은 로고 이미지가 표시됩니다. 정사각형 120 × 120 이미지를 사용하십시오. 비워두면 홈 글리프가 표시됩니다." - digest_logo: "사이트 이메일 요약 상단에 사용 된 대체 로고 이미지. 넓은 직사각형 이미지를 사용하십시오. SVG 이미지를 사용하지 마십시오. 비워두면`logo` 설정의 이미지가 사용됩니다." - mobile_logo: "사이트의 모바일 버전에 사용 된 로고입니다. 높이가 120이고 가로 세로 비율이 3 : 1보다 큰 넓은 직사각형 이미지를 사용하십시오. 비워두면`logo` 설정의 이미지가 사용됩니다." - logo_dark: "'로고'사이트 설정에 대한 어두운 구성표 대체." - logo_small_dark: "'로고 작은'사이트 설정에 대한 어두운 구성표 대안." - mobile_logo_dark: "'모바일 로고'사이트 설정에 대한 어두운 구성표 대안." - large_icon: "다른 메타 데이터 아이콘의 기본으로 사용되는 이미지. 이상적으로 512 x 512보다 커야합니다. 비워두면 logo_small이 사용됩니다." - manifest_icon: "Android에서 로고 / 스플래쉬 이미지로 사용되는 이미지. 512 × 512로 자동 크기가 조정됩니다. 비워두면 large_icon이 사용됩니다." - manifest_screenshots: "설치 프롬프트 페이지에서 인스턴스 기능을 보여주는 스크린 샷입니다. 모든 이미지는 로컬 업로드여야 하며 크기가 동일해야 합니다." - favicon: "사이트의 즐겨 찾기 아이콘은 https://en.wikipedia.org/wiki/Favicon을 참조 하십시오 . CDN에서 올바르게 작동하려면 png 여야합니다. 32x32로 크기가 조정됩니다. 비워두면 large_icon이 사용됩니다." - apple_touch_icon: "Apple touch 장치에 사용되는 아이콘. 180x180으로 자동 크기가 조정됩니다. 비워두면 large_icon이 사용됩니다." - opengraph_image: "페이지에 다른 적합한 이미지가 없을 때 사용되는 기본 오픈 그래프 이미지. 비워두면 large_icon이 사용됩니다" - notification_email: "The from: 이 이메일 주소는 모든 기본 시스템 메일을 보내는데 사용됩니다. 여기에 명시된 도메인은 SPF, DKIM가 적용되어 있어야하며, reverse PTR 레코드가 제대로 설정되어 있어야 메일이 도착 할 수 있습니다." - email_custom_headers: "커스텀 이메일 해더의 pipe-delimited" - email_subject: "표준 이메일에 대한 사용자 정의 가능한 주제 형식. https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801을 참조 하십시오." - detailed_404: "특정 주제에 액세스 할 수없는 이유에 대한 자세한 정보를 사용자에게 제공합니다. 참고 : URL이 유효한 주제로 연결되는지 사용자가 알기 때문에 보안 수준이 떨어집니다." - enforce_second_factor: "사용자가 2단계 인증을 사용하도록합니다. 모든 사용자에게 적용하려면 '모두'를 선택하십시오. 관리자에게만 적용하려면 '관리자'를 선택하십시오." - force_https: "사이트가 HTTPS를 사용하도록 강제합니다. 경고: HTTPS가 완벽히 적용되어 있는 것을 확인하기 전까지는 이 옵션을 켜지마세요. CDN, 소셜 로그인, 외부 링크로 가져오는 자료, 로고들이 HTTPS호환성이 있는지 확인하셨나요?" - summary_score_threshold: "요약본에 포함되기 위한 글의 최소 점수 값" - summary_posts_required: "'이 주제 요약'이 활성화되기 전에 주제의 최소 게시물. 이 설정에 대한 변경 사항은 일주일 이내에 소급 적용됩니다." - summary_likes_required: "'이 주제 요약'이 활성화되기 전에 주제에서 최소 좋아요를 찾습니다. 이 설정에 대한 변경 사항은 일주일 이내에 소급 적용됩니다." - summary_percent_filter: "요약본 보기를 클릭시, 글 중에 몇 %의 상위 글을 보여줄 것인가?" - summary_max_results: "'이 주제 요약'에서 반환 한 최대 게시물" + download_remote_images_threshold: "원격 이미지를 로컬에 다운로드하기 위한 최소 디스크 공간(%)" + disabled_image_download_domains: "이 도메인에서 원격 이미지를 다운로드하지 않습니다. 목록은 | 기호를 사용하여 구분하세요." + editing_grace_period: "게시 후 (n)초 동안은 편집해도 게시 히스토리에 새 버전이 생성되지 않습니다." + editing_grace_period_max_diff: "편집 유예 기간에 허용되는 최대 문자 변경사항 수입니다. 더 많이 변경한 경우 다른 게시물 수정 버전을 저장하세요(신뢰 레벨 0 및 1)." + editing_grace_period_max_diff_high_trust: "편집 유예 기간에 허용되는 최대 문자 변경사항 수입니다. 더 많이 변경한 경우 다른 게시물 수정 버전을 저장하세요(신뢰 레벨 2 이상)." + staff_edit_locks_post: "운영진이 게시물을 편집하면 게시물이 편집되지 않게 잠깁니다." + post_edit_time_limit: "tl0 또는 tl1 작성자는 게시 후 (n)분 동안 게시물을 편집할 수 있습니다. 영원히 하려면 0으로 설정하세요." + tl2_post_edit_time_limit: "tl2+ 작성자는 게시 후 (n)분 동안 게시물을 편집할 수 있습니다. 영원히 하려면 0으로 설정하세요." + edit_history_visible_to_public: "모든 사용자가 편집된 게시물의 기존 버전을 보도록 허용합니다. 비활성화하면 운영진만 볼 수 있습니다." + delete_removed_posts_after: "작성자가 제거한 게시물은 (n)시간 뒤 자동으로 삭제됩니다. 0으로 설정 시 즉시 삭제됩니다." + notify_users_after_responses_deleted_on_flagged_post: "게시물이 신고되어 제거되면 게시물에 반응을 보였거나 반응이 제거된 모든 사용자에게 알림이 전송됩니다." + max_image_width: "게시물의 최대 섬네일 이미지 너비" + max_image_height: "게시물의 최대 섬네일 이미지 높이" + responsive_post_image_sizes: "라이트 박스 미리보기 이미지의 크기를 조정하여 다음 픽셀 비율의 높은 DPI 화면을 허용합니다. 반응형 이미지를 비활성화하려면 모든 값을 제거하세요." + fixed_category_positions: "체크하면 고정된 순서로 카테고리를 정렬할 수 있습니다. 체크하지 않으면 카테고리는 활동 순으로 나열됩니다." + fixed_category_positions_on_create: "체크하면 주제 생성 대화창의 카테고리 순서가 유지됩니다(fixed_category_positions 필요)." + add_rel_nofollow_to_user_content: '내부 링크(상위 도메인 포함)를 제외하고 제출된 모든 사용자 콘텐츠에 rel nofollow를 추가합니다. 이를 변경하면 "rake posts:rebake" 로 모든 게시물을 다시 적용해야 합니다.' + exclude_rel_nofollow_domains: "링크에 nofollow를 추가하면 안 되는 도메인 목록입니다. example.com은 자동으로 sub.example.com도 허용합니다. 웹 크롤러가 모든 콘텐츠를 찾을 수 있도록 최소한 이 사이트의 도메인을 추가해야 합니다. 웹사이트의 다른 부분이 다른 도메인에 있는 경우 해당 부분도 추가하세요." + post_excerpt_maxlength: "게시물 발췌 / 요약의 최대 길이입니다." + topic_excerpt_maxlength: "주제의 첫 게시물에서 생성된 주제 발췌 / 요약의 최대 길이입니다." + show_pinned_excerpt_mobile: "모바일 뷰에서 고정된 주제의 발췌를 표시합니다." + show_pinned_excerpt_desktop: "데스크톱 뷰에서 고정된 주제의 발췌를 표시합니다." + post_onebox_maxlength: "onebox 적용된 Discourse 게시물의 최대 문자 수입니다." + allowed_inline_onebox_domains: "제목 없이 링크된 경우 미니어처 형식으로 onebox 적용되는 도메인 목록" + enable_inline_onebox_on_all_domains: "inline_onebox_domain_whitelist 사이트 설정을 무시하고 모든 도메인에서 인라인 onebox를 허용합니다." + force_custom_user_agent_hosts: "모든 요청에서 사용자 지정 onebox 사용자 에이전트를 사용할 호스트입니다. (특히 사용자 에이전트의 액세스를 제한하는 호스트에 유용합니다)" + max_oneboxes_per_post: "게시물당 최대 onebox 수" + facebook_app_access_token: "Facebook 앱 ID 및 암호에서 생성된 토큰입니다. Instagram onebox를 생성하는 데 사용됩니다." + logo: "사이트 왼쪽 상단의 로고 이미지입니다. 높이가 120이고 종횡비가 3:1보다 큰 넓은 직사각형 이미지를 사용하세요. 비워두면 사이트 제목 텍스트가 표시됩니다." + logo_small: "아래로 스크롤하면 사이트 왼쪽 상단에 작은 로고 이미지가 표시됩니다. 정사각형 120 × 120 이미지를 사용하세요. 비워두면 홈 글리프가 표시됩니다." + digest_logo: "사이트 이메일 요약 상단에 사용되는 대체 로고 이미지입니다. 넓은 직사각형 이미지를 사용하세요. SVG 이미지를 사용하면 안 됩니다. 비워두면 `logo` 설정의 이미지가 사용됩니다." + mobile_logo: "사이트의 모바일 버전에 사용된 로고입니다. 높이가 120이고 종횡비가 3:1보다 큰 넓은 직사각형 이미지를 사용하세요. 비워두면 `logo` 설정의 이미지가 사용됩니다." + logo_dark: "'로고' 사이트 설정용 다크 구성표 대안입니다." + logo_small_dark: "'작은 로고' 사이트 설정용 다크 구성표 대안입니다." + mobile_logo_dark: "'모바일 로고' 사이트 설정용 다크 구성표 대안입니다." + large_icon: "다른 메타 데이터 아이콘의 기본으로 사용되는 이미지입니다. 이상적으로 512 x 512보다 커야 합니다. 비워두면 logo_small이 사용됩니다." + manifest_icon: "Android에서 로고/스플래시 이미지로 사용되는 이미지입니다. 512 × 512로 크기가 자동 조정됩니다. 비워두면 large_icon이 사용됩니다." + manifest_screenshots: "설치 프롬프트 페이지에서 인스턴스 기능 및 함수 기능을 보여주는 스크린 샷입니다. 모든 이미지는 로컬 업로드여야 하며 크기가 동일해야 합니다." + favicon: "사이트의 즐겨찾기 아이콘은 https://en.wikipedia.org/wiki/Favicon을 참조하세요. CDN에서 올바르게 작동하려면 png여야 합니다. 32x32로 크기가 조정됩니다. 비워두면 large_icon이 사용됩니다." + apple_touch_icon: "Apple touch 디바이스에 사용되는 아이콘입니다. 180x180으로 크기가 자동 조정됩니다. 비워두면 large_icon이 사용됩니다." + opengraph_image: "페이지에 다른 적절한 이미지가 없을 때 사용되는 디폴트 오픈그래프 이미지입니다. 비워두면 large_icon이 사용됩니다" + notification_email: "from: 이메일 주소는 모든 필수 시스템 이메일을 전송하는 데 사용됩니다. 여기에 지정된 도메인은 SPF, DKIM이 있어야 하며, 리버스 PTR 레코드가 제대로 설정되어 있어야 메일이 도착할 수 있습니다." + email_custom_headers: "사용자 지정 이메일 헤더의 파이프(|)로 구분된 목록" + email_subject: "표준 이메일에 대한 사용자 지정 가능한 제목 형식입니다. https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801을 참조하세요." + detailed_404: "특정 주제에 액세스할 수 없는 이유에 대한 자세한 정보를 사용자에게 제공합니다. 참고: URL이 유효한 주제로 연결되는지 사용자가 알기 때문에 보안 수준이 떨어집니다." + enforce_second_factor: "사용자가 2단계 인증을 사용하도록 강제합니다. 모든 사용자에게 적용하려면 '모두'를 선택하세요. 운영진에게만 적용하려면 '운영진'을 선택하세요." + force_https: "사이트가 HTTPS만을 사용하도록 강제합니다. 경고: HTTPS가 완벽히 구성되어 제대로 작동하는 것을 확인하기 전까지는 이 옵션을 활성화하지 마세요. CDN, 소셜 로그인, 외부 로고 / 종속성이 HTTPS와 호환하는지 확인하셨나요?" + summary_score_threshold: "'이 주제 요약'에 포함되기 위한 게시물의 최소 점수" + summary_posts_required: "'이 주제 요약'이 활성화되기 전 주제의 최소 게시물 수입니다. 이 설정에 대한 변경사항은 일주일 이내에 소급 적용됩니다." + summary_likes_required: "'이 주제 요약'이 활성화되기 전 주제의 최소 좋아요 수입니다. 이 설정에 대한 변경사항은 일주일 이내에 소급 적용됩니다." + summary_percent_filter: "사용자가 '이 주제 요약'을 클릭하면 표시할 게시물의 상위 %" + summary_max_results: "'이 주제 요약'에서 반환한 최대 게시물 수" summary_timeline_button: "타임라인에 '요약' 버튼 표시" - enable_personal_messages: "회원레벨1 사용자가 메시지를 작성하고 메시지에 답장할 수 있도록 허용합니다. 관리자는 언제든지 메시지를 보낼 수 있습니다." - enable_system_message_replies: "개인 메시지가 비활성화 된 경우에도 사용자가 시스템 메시지에 회신 할 수 있습니다" - enable_chunked_encoding: "서버에서 청크 분할 인코딩 응답을 활성화합니다. 이 기능은 대부분의 설정에서 작동하지만 일부 프록시는 버퍼링되어 응답이 지연될 수 있습니다." - long_polling_base_url: "long polling에 사용 될 Base URL (CDN이 동적 콘텐트를 제공할 시에는 origin pull로 설정) eg: http://origin.site.com" - polling_interval: "long polling을 안 쓸 때 로그인된 클라이언트가 몇 밀리초마다 poll해야 하는 지" + enable_system_message_replies: "개인 메시지가 비활성화된 경우에도 사용자가 시스템 메시지에 답장할 수 있습니다" + enable_chunked_encoding: "서버의 청크 인코딩 응답을 활성화합니다. 이 기능은 대부분의 설정에서 작동하지만 일부 프록시는 버퍼링되어 응답이 지연될 수 있습니다." + long_polling_base_url: "긴 폴링에 사용되는 기본 URL(CDN이 동적 콘텐츠를 제공하는 경우 이를 원본 풀(pull)로 설정해야 함)입니다. 예: http://origin.site.com" + polling_interval: "긴 폴링을 안 쓸 때 로그인된 클라이언트가 폴링할 주기(밀리초)" anon_polling_interval: "How often should anonymous clients poll in milliseconds" - background_polling_interval: "(페이지를 안 보고 있을 때) 클라이언트가 몇 밀리초마다 poll해야 하는 지" - hide_post_sensitivity: "신고 된 게시물이 숨겨 질 가능성" - silence_new_user_sensitivity: "스팸 신고에 따라 새 사용자가 쓰기 금지될 가능성" - auto_close_topic_sensitivity: "신고 된 주제가 자동으로 닫힐 가능성" - cooldown_minutes_after_hiding_posts: "신고 당해서 숨겨진 글을 사용자가 편집할 수 있기 전까지 기대려야 하는 시간(분)" - max_topics_in_first_day: "첫 포스트 생성 후 24시간동안 사용자가 생성할 수 있는 최대 토픽 수" - max_replies_in_first_day: "첫 포스트 생성 후 24시간동안 사용자가 쓸 수 있는 최대 답글 수" - tl2_additional_likes_per_day_multiplier: "tl2 (회원)의 일별 좋아요 제한을 올릴 배수" - tl3_additional_likes_per_day_multiplier: "tl3 (정회원)의 일별 좋아요 제한을 올릴 배수" - tl4_additional_likes_per_day_multiplier: "tl4 (리더)의 일별 좋아요 제한을 올릴 배수" - tl2_additional_edits_per_day_multiplier: "tl2 (회원) 에 대해 이 숫자를 곱하여 일일 편집 제한을 늘립니다." - tl3_additional_edits_per_day_multiplier: "tl3 (일반) 에 대해 이 숫자를 곱하여 일일 편집 제한을 늘립니다." - tl4_additional_edits_per_day_multiplier: "tl4 (리더) 의 일일 편집 한도를 이 숫자에 곱하여 늘립니다." - tl2_additional_flags_per_day_multiplier: "이 숫자를 곱하여 tl2(회원)에 대한 하루 신고 제한을 늘립니다." - tl3_additional_flags_per_day_multiplier: "이 숫자를 곱하여 tl3(일반)에 대한 하루 신고 제한을 늘립니다." - tl4_additional_flags_per_day_multiplier: "이 숫자를 곱하여 tl4(리더)에 대한 하루 신고 제한을 늘립니다." - num_users_to_silence_new_user: "새 사용자의 게시물에이 많은 다른 사용자로부터 num_spam_flags_to_silence_new_user 스팸 플래그가 표시되면 모든 게시물을 숨기고 향후 게시를 방지하십시오. 비활성화하려면 0입니다." - num_tl3_flags_to_silence_new_user: "새 사용자의 게시물이 num_tl3_users_to_silence_new_user 다른 신뢰 수준 3 사용자로부터이 많은 플래그를 얻는 경우 모든 게시물을 숨기고 향후 게시를 방지하십시오. 비활성화하려면 0입니다." - num_tl3_users_to_silence_new_user: "새 사용자의 게시물이이 많은 다른 신뢰 수준 3 사용자로부터 num_tl3_flags_to_silence_new_user 플래그를 얻는 경우 모든 게시물을 숨기고 향후 게시를 방지하십시오. 비활성화하려면 0입니다." - notify_mods_when_user_silenced: "사용자가 자동으로 쓰기 금지되면 모든 관리자에게 메시지를 보냅니다." - flag_sockpuppets: "새 사용자가 주제를 시작한 사용자와 동일한 IP 주소로 주제에 응답하면 두 게시물을 모두 스팸 가능성으로 표시하십시오." - traditional_markdown_linebreaks: "Markdown에서 전통적인 linebreak를 사용, linebreak시 두개의 trailing space를 사용하는 것." - enable_markdown_typographer: "타이포그래피 규칙을 사용하여 텍스트의 가독성을 향상 시키십시오. 직선 인용 부호 '를 중괄호'로 바꾸고, (c) (tm)을 기호로 바꾸십시오." - enable_markdown_linkify: "링크처럼 보이는 텍스트를 링크로 자동 처리 : www.example.com 및 https://example.com은 자동으로 연결됩니다" + background_polling_interval: "(창이 백그라운드에 있을 때) 클라이언트가 폴링할 주기(밀리초)" + hide_post_sensitivity: "신고된 게시물이 숨겨질 가능성" + silence_new_user_sensitivity: "스팸 신고로 인해 새 사용자가 차단될 가능성" + auto_close_topic_sensitivity: "신고된 주제가 자동 종료될 가능성" + cooldown_minutes_after_hiding_posts: "커뮤니티 신고로 인해 숨겨진 주제를 사용자가 편집할 수 있기 전까지 대기해야 하는 시간(분)" + max_topics_in_first_day: "첫 게시물 생성 후 24시간 사용자가 생성할 수 있는 최대 주제 수" + max_replies_in_first_day: "첫 게시물 생성 후 24시간 사용자가 생성할 수 있는 최대 댓글 수" + tl2_additional_likes_per_day_multiplier: "tl2(회원)의 일일 좋아요 한도를 올릴 배수" + tl3_additional_likes_per_day_multiplier: "tl3(정회원)의 일일 좋아요 한도를 올릴 배수" + tl4_additional_likes_per_day_multiplier: "tl4(리더)의 일일 좋아요 한도를 올릴 배수" + tl2_additional_edits_per_day_multiplier: "tl2(회원)의 일일 편집 한도를 올릴 배수" + tl3_additional_edits_per_day_multiplier: "tl3(정회원)의 일일 편집 한도를 올릴 배수" + tl4_additional_edits_per_day_multiplier: "tl4(리더)의 일일 편집 한도를 올릴 배수" + tl2_additional_flags_per_day_multiplier: "tl2(회원)의 일일 신고 한도를 올릴 배수" + tl3_additional_flags_per_day_multiplier: "tl3(정회원)의 일일 신고 한도를 올릴 배수" + tl4_additional_flags_per_day_multiplier: "tl4(리더)의 일일 신고 한도를 올릴 배수" + num_users_to_silence_new_user: "신규 사용자의 게시물이 많은 다른 사용자로부터 num_spam_flags_to_silence_new_user 스팸 신고를 받으면 해당 사용자의 모든 게시물을 숨기고 향후 게시를 방지합니다. 비활성화하려면 0으로 설정하세요." + num_tl3_flags_to_silence_new_user: "신규 사용자의 게시물이 num_tl3_users_to_silence_new_user 다른 신뢰 레벨 3 사용자로부터 많은 신고를 받으면 모든 게시물을 숨기고 향후 게시를 방지합니다. 비활성화하려면 0으로 설정하세요." + num_tl3_users_to_silence_new_user: "신규 사용자의 게시물이 많은 다른 사용자로부터 num_tl3_flags_to_silence_new_user 신고를 받으면 해당 사용자의 모든 게시물을 숨기고 향후 게시를 방지합니다. 비활성화하려면 0으로 설정하세요." + notify_mods_when_user_silenced: "사용자가 자동으로 차단되면 모든 운영자에게 메시지를 전송합니다." + flag_sockpuppets: "신규 사용자가 주제를 시작한 사용자와 동일한 IP 주소로 주제에 댓글을 달면 두 게시물을 모두 스팸 가능성이 있다고 신고합니다." + traditional_markdown_linebreaks: "Markdown에서 줄 바꿈에 두 개의 끝 공백이 필요한 기존 줄 바꿈을 사용합니다." + enable_markdown_typographer: "타이포그래피 규칙을 사용하여 텍스트의 가독성을 향상합니다. 예: 직선 따옴표 '를 둥근 따옴표 ’로 바꾸고, (c) (tm)을 기호로, --를 –로 바꾸기 등" + enable_markdown_linkify: "링크처럼 보이는 텍스트를 링크로 자동 처리합니다. www.example.com 및 https://example.com은 자동으로 연결됩니다." markdown_linkify_tlds: "링크로 자동 처리되는 최상위 도메인 목록" - markdown_typographer_quotation_marks: "큰 따옴표와 작은 따옴표 교체 쌍 목록" - post_undo_action_window_mins: "사용자가 어떤 글에 대해서 수행한 작업(신고 등)을 취소하는 것이 허용되는 시간(초)" - must_approve_users: "관리자가 모든 사용자에 대해 사이트 접근 전에 허용을 해야 함" - invite_code: "계정 등록이 가능하도록하려면이 코드를 입력해야합니다 (비어있을 경우 무시)." - approve_suspect_users: "검토 대기열에 의심스러운 사용자를 추가하십시오. 의심스러운 사용자가 바이오 / 웹 사이트에 입장했지만 읽기 활동이 없습니다." - review_every_post: "모든 게시물을 검토해야합니다. 경고! 사용량이 많은 사이트에는 권장되지 않습니다." - pending_users_reminder_delay_minutes: "새 사용자가 다음 시간보다 오랫동안 승인 대기 중일 경우 관리자에게 알립니다. 알림을 비활성화하려면 -1로 설정합니다." - persistent_sessions: "사용자는 웹 브라우저가 닫혀도 로그인 상태를 유지합니다." - maximum_session_age: "마지막 방문으로 부터 n시간 동안 사용자의 로그인이 유지됩니다" - ga_version: "사용할 Google 유니버설 애널리틱스 버전: v3 (analytics.js), v4 (gtag)" - ga_universal_tracking_code: "Google 유니버설 애널리틱스 추적 코드 ID, 예: UA-12345678-9; https://google.com/analytics 참조" - ga_universal_domain_name: "Google Universal Analytics 도메인 이름, 예: mysite.com; https://google.com/analytics 참조" - ga_universal_auto_link_domains: "Google 유니버설 애널리틱스 교차 도메인 추적을 사용합니다. 이러한 도메인으로 나가는 링크에는 클라이언트 ID가 추가됩니다. Google의 교차 도메인 추적 가이드를 참조하세요." - gtm_container_id: "Google 태그 관리자 컨테이너 ID 예 : GTM-ABCDEF.
    참고 : GTM에서로드 한 타사 스크립트는 '콘텐츠 보안 정책 스크립트 src'에 허용 목록에 있어야합니다." - enable_escaped_fragments: "웹 크롤러가 감지되지 않으면 Google의 Ajax-Crawling API로 폴백하십시오. https://developers.google.com/webmasters/ajax-crawling/docs/learn-more를 참조 하십시오." - moderators_change_post_ownership: "관리자가 게시물 소유권을 변경할 수 있도록 허용" - cors_origins: "Allowed origins cross-origin requests (CORS). 각 origin은 반드시 http:// 나 https:// 를 포함해야합니다. DISCOURSE_ENABLE_CORS 환경 변수를 true로 지정해줘야 CORS를 활성화할 수 있습니다." - use_admin_ip_allowlist: "관리자는 선별 된 IP 목록(관리자> 로그> 선별된 IP)에 있는 IP에서만 로그인 할 수 있습니다." - blocked_ip_blocks: "Discourse에서 크롤링해서는 안되는 개인 IP 블록 목록" - allowed_internal_hosts: "원박싱 및 기타 목적을 위해 안전하게 크롤링할 수 있는 내부 호스트 목록" - allowed_onebox_iframes: "Onebox 삽입에 허용되는 iframe src 도메인 목록입니다. `*`는 모든 기본 Onebox 엔진을 허용합니다." - allowed_iframes: "Discourse가 안전한 게시물로 허용 할 수있는 iframe src 도메인 접두사 목록" - allowed_crawler_user_agents: "사이트에 대한 액세스를 허용해야하는 웹 크롤러의 사용자 에이전트입니다. 경고! 이것을 설정하면 여기에 나열되지 않은 모든 크롤러가 비활성화됩니다!" - blocked_crawler_user_agents: "사이트 액세스를 허용해서는 안되는 웹 크롤러를 식별하는 사용자 에이전트 문자열에서 대소 문자를 구분하지 않는 고유 한 단어입니다. 허용 목록이 정의 된 경우 적용되지 않습니다." - slow_down_crawler_rate: "slow_down_crawler_user_agents를 지정하면이 비율이 모든 크롤러에 적용됩니다 (요청 사이의 지연 시간 (초))." - content_security_policy: "콘텐츠 보안 정책 사용" - content_security_policy_report_only: "콘텐츠 보안 정책 보고서 만 사용" - content_security_policy_collect_reports: "/ csp_reports에서 CSP 위반 보고서 수집 사용" - content_security_policy_frame_ancestors: "CSP를 통해 iframe에 이 사이트를 삽입 할 수있는 사용자를 제한합니다. Embedding에서 허용 된 호스트 제어" - content_security_policy_script_src: "추가 허용 된 스크립트 소스. 현재 호스트 및 CDN이 기본적으로 포함됩니다. 컨텐츠 보안 정책으로 XSS 공격 완화를 참조하십시오 ." - invalidate_inactive_admin_email_after_days: "이 기간 동안 사이트를 방문하지 않은 관리자 계정은 로그인하기 전에 이메일 주소를 다시 확인해야합니다. 비활성화하려면 0으로 설정하십시오." - top_menu: "첫페이지 메뉴에 어떤 아이템이 뜨고 어떤 순서로 뜰지 정합니다 예 최근|새로씀|안읽음|카테고리|위로|읽음|쓴글|북마크" - post_menu: "글 메뉴에 어떤 사항들이 무슨 순서로 올라올지 결정합니다. 예: like(좋아요)|edit(수정)|flag(신고)|delete(삭제)|share(공유)|bookmark(북마크)|reply(답글)" - post_menu_hidden_items: "게시 메뉴에서 기본으로 숨길 메뉴 아이템들" - share_links: "공유 다이얼로그에 어떤 아이템이 어떤 순서로 나올지 결정" - site_contact_username: "자동 메세지를 보낼 올바른 스태프 아이디. 빈칸으로 놔두면 기본 시스템 계정이 사용됩니다." - site_contact_group_name: "모든 자동 메시지에 초대 할 유효한 그룹 이름입니다." - send_welcome_message: "모든 신규 유저들에게 시작 매뉴얼과 함께 환영 메세지 보내기" - send_tl1_welcome_message: "새 신뢰 수준 1 사용자에게 환영 메시지를 보냅니다." - send_tl2_promotion_message: "새 회원레벨 2 사용자에게 프로모션에 대한 메시지를 보냅니다." - suppress_reply_directly_below: "글의 바로 아래에 단 하나의 댓글만 있는 경우 '댓글 수'를 보여주지 않음" - suppress_reply_directly_above: "단 하나의 댓글 위의 글이 하나 있는 상황에서 '~에 대한 댓글'을 보여주지 않음." - suppress_reply_when_quoting: "글안에 답글이 인용될 때 in-reply-to를 보여주지 않습니다." - max_reply_history: "확장시 보여지는 최대 댓글 수" - topics_per_period_in_top_summary: "인기 글타래 요약에 기본으로 보여질 글타래 수" - topics_per_period_in_top_page: "인기 글타래에서 '더 보기'를 요청할 시 보여질 글타래 수" - redirect_users_to_top_page: "신규 사용자와 오랜만에 방문한 사용자를 인기글 페이지로 리다이렉트." - top_page_default_timeframe: "탑 뷰 페이지를 위한 타임프레임 기본값" - moderators_view_emails: "중재자가 사용자 이메일을 볼 수 있도록 허용" - prioritize_username_in_ux: "아이디를 사용자 페이지, 사용자 카드, 포스트에 가장 먼저 표시(해제 되면 이름이 가장 먼저 표시됨)" - enable_rich_text_paste: "글 작성기에 텍스트를 붙여 넣을 때 HTML에서 마크 다운으로의 자동 변환을 활성화합니다. (실험용)" - send_old_credential_reminder_days: "며칠 후 이전 자격 증명에 대해 알림" - email_token_valid_hours: "비밀번호 찾기, 계정 활성화에 사용되는 토큰의 유효 기간(시간)" - enable_badges: "배지 기능 사용" - max_favorite_badges: "사용자가 선택할 수있는 최대 배지 수" - enable_whispers: "토픽 내 운영진 비공개 커뮤니케이션 허용" - allow_index_in_robots_txt: "robots.txt에 웹 검색 엔진이이 사이트를 색인 할 수 있도록 지정하십시오. 예외적 인 경우 robots.txt를 영구적으로 무시할 수 있습니다." - blocked_email_domains: "사용자가 계정을 등록 할 수없는 파이프- 로 구분 된 이메일 도메인 목록입니다. 예: mailinator.com | trashmail.net" - allowed_email_domains: "사용자가 계정 등록에 사용해야하는 파이프로 구분 된 이메일 도메인 목록입니다. 경고: 나열된 것 이외의 이메일 도메인을 가진 사용자는 허용되지 않습니다!" + markdown_typographer_quotation_marks: "큰 따옴표와 작은 따옴표 대체 쌍 목록" + post_undo_action_window_mins: "사용자가 게시물에 대한 최근 작업(좋아요, 신고 등)을 취소할 수 있는 시간(분)입니다." + must_approve_users: "운영진은 모든 신규 사용자가 사이트에 액세스할 수 있기 전에 해당 계정을 승인해야 합니다." + invite_code: "계정 등록을 하려면 이 코드를 입력해야 합니다(대소문자 구분). 비어 있으면 무시합니다." + approve_suspect_users: "검토 대기열에 의심스러운 사용자를 추가합니다. 의심스러운 사용자가 소개/웹사이트를 방문했지만 읽기 활동은 없습니다." + review_every_post: "모든 게시물을 검토해야 합니다. 경고! 사용량이 많은 사이트에는 권장되지 않습니다." + pending_users_reminder_delay_minutes: "신규 사용자가 이 시간(분) 이상 승인을 기다리는 경우 운영자에게 알립니다. 알림을 비활성화하려면 -1로 설정합니다." + persistent_sessions: "사용자는 웹 브라우저를 닫아도 로그인 상태를 유지합니다." + maximum_session_age: "마지막 방문 이후 n시간 사용자의 로그인이 유지됩니다" + ga_version: "사용할 Google Universal Analytics 버전: v3(analytics.js), v4(gtag)" + ga_universal_tracking_code: "Google Universal Analytics 추적 코드 ID입니다. 예: UA-12345678-9, https://google.com/analytics를 참조하세요." + ga_universal_domain_name: "Google Universal Analytics 도메인 이름입니다. 예: mysite.com, https://google.com/analytics를 참조하세요." + ga_universal_auto_link_domains: "Google Google Universal Analytics 교차 도메인 추적을 활성화합니다. 이러한 도메인으로 나가는 링크에는 클라이언트 ID가 추가됩니다. Google의 교차 도메인 추적 가이드를 참조하세요." + gtm_container_id: "Google Tag Manager 컨테이너 ID입니다. 예 : GTM-ABCDEF.
    참고 : GTM에서 로드한 서드파티 스크립트는 '콘텐츠 보안 정책 스크립트 소스'의 허용 목록에 있어야 합니다." + enable_escaped_fragments: "웹 크롤러가 탐지되지 않으면 Google의 Ajax-Crawling API로 폴백하세요. https://developers.google.com/webmasters/ajax-crawling/docs/learn-more를 참조하세요." + moderators_change_post_ownership: "운영자가 게시물 소유자를 변경할 수 있도록 허용" + cors_origins: "교차 출처 요청(Cross-Origin Resource Sharing, CORS)의 허용된 출처입니다. 각 출처는 반드시 http:// 나 https://를 포함해야 합니다. DISCOURSE_ENABLE_CORS 환경 변수를 true로 설정해야 CORS를 활성화할 수 있습니다." + use_admin_ip_allowlist: "관리자는 스크린된 IP 목록(관리자 > 로그> 스크린된 IP)에 정의된 IP 주소에서만 로그인할 수 있습니다." + blocked_ip_blocks: "Discourse에서 크롤링해서는 안 되는 개인 IP 차단 목록" + allowed_internal_hosts: "onebox 및 기타 목적을 위해 Discourse에서 안전하게 크롤링할 수 있는 내부 호스트 목록" + allowed_onebox_iframes: "Onebox 임베드를 통해 허용되는 iframe src 도메인 목록입니다. `*` 는 모든 디폴트 Onebox 엔진을 허용합니다." + allowed_iframes: "Discourse가 게시물에서 안전하게 허용할 수 있는 iframe src 도메인 접두사 목록" + allowed_crawler_user_agents: "사이트 액세스를 허용해야 하는 웹 크롤러의 사용자 에이전트입니다. 경고! 이것을 설정하면 여기에 나열되지 않은 모든 크롤러가 비활성화됩니다!" + blocked_crawler_user_agents: "사이트 액세스가 허용되지 않아야 하는 웹 크롤러를 식별하는 사용자 에이전트 스트링에서 대소문자를 구분하지 않는 고유한 단어입니다. 허용 목록이 정의된 경우 적용되지 않습니다." + slow_down_crawler_rate: "slow_down_crawler_user_agents를 지정하면 이 비율이 모든 크롤러에 적용됩니다(요청 간 지연 시간(초))." + content_security_policy: "콘텐츠 보안 정책 활성화" + content_security_policy_report_only: "콘텐츠 보안 정책 리포트만 활성화" + content_security_policy_collect_reports: "/csp_reports에서 CSP 위반 리포트 수집 활성화" + content_security_policy_frame_ancestors: "CSP를 통해 iframe에 이 사이트를 임베드할 수 있는 사용자를 제한합니다. 임베딩에서 허용된 호스트를 제어합니다." + content_security_policy_script_src: "추가 허용 목록에 있는 스크립트 소스입니다. 현재 호스트와 CDN이 기본적으로 포함됩니다. 콘텐츠 보안 정책으로 XSS 공격 완화를 참조하세요." + invalidate_inactive_admin_email_after_days: "이 기간에 사이트를 방문하지 않은 관리자 계정은 로그인하기 전에 이메일 주소를 다시 확인해야 합니다. 비활성화하려면 0으로 설정하세요." + top_menu: "홈페이지 메뉴에 표시할 항목과 순서를 결정합니다. 예: 최신|신규|읽지 않음|카테고리|주요|읽음|게시함|북마크" + post_menu: "게시물 메뉴에 표시할 항목과 순서를 결정합니다. 예: 좋아요|편집|신고|삭제|공유|북마크|댓글" + post_menu_hidden_items: "펼치기 아이콘을 클릭하지 않을 경우 게시물 메뉴에서 기본적으로 숨길 메뉴 항목입니다." + share_links: "공유 대화창에 표시할 항목과 순서를 결정합니다." + site_contact_username: "모든 자동 메시지를 보낼 유효한 운영진 아이디입니다. 비워 두면 기본 시스템 계정이 사용됩니다." + site_contact_group_name: "자동 전송한 모든 비공개 메시지에 초대할 유효한 그룹 이름입니다." + send_welcome_message: "모든 신규 사용자에게 퀵스타드 가이드와 환영 메시지를 전송합니다." + send_tl1_welcome_message: "신규 신뢰 레벨 1 사용자에게 환영 메시지를 전송합니다." + send_tl2_promotion_message: "신규 신뢰 레벨 2 사용자에게 승급에 대한 메시지를 전송합니다." + suppress_reply_directly_below: "이 게시물 바로 아래에 댓글이 하나만 있는 경우 게시물에서 댓글 수 펼치기를 표시하지 않습니다." + suppress_reply_directly_above: "이 게시물 바로 위에 댓글이 하나만 있는 경우 게시물에서 사용자에게 댓글 달기 펼치기를 표시하지 않습니다." + suppress_reply_when_quoting: "게시물에 댓글이 인용될 때 사용자에게 댓글 달기 펼치기를 표시하지 않습니다." + max_reply_history: "사용자에게 댓글 달기를 펼칠 때 표시되는 최대 댓글 수" + topics_per_period_in_top_summary: "디폴트 주요 주제 요약에 표시할 주요 주제 수입니다." + topics_per_period_in_top_page: "주요 주제에서 '더 보기'를 펼칠 때 표시할 주요 주제 수입니다." + redirect_users_to_top_page: "신규 사용자와 오랜만에 방문한 사용자를 주요 페이지로 자동 리디렉션합니다." + top_page_default_timeframe: "주요 페이지용 디폴트 타임라인입니다." + moderators_view_emails: "운영자가 사용자 이메일을 볼 수 있도록 허용" + prioritize_username_in_ux: "아이디를 사용자 페이지, 사용자 카드 및 게시물에 가장 먼저 표시(비활성화 시 이름이 가장 먼저 표시됨)" + enable_rich_text_paste: "작성기에 텍스트를 붙여 넣을 때 HTML에서 Markdown으로의 자동 변환을 활성화합니다. (실험단계)" + send_old_credential_reminder_days: "며칠 후 이전 크리덴셜에 대해 알림" + email_token_valid_hours: "비밀번호 찾기, 계정 활성화 토큰은 (n)시간 유효합니다." + enable_badges: "배지 시스템 활성화" + max_favorite_badges: "사용자가 선택할 수 있는 최대 배지 수" + enable_whispers: "주제 내 운영진 비공개 커뮤니케이션을 허용합니다." + allow_index_in_robots_txt: "웹 검색 엔진에서 이 사이트의 색인을 생성할 수 있도록 robots.txt에 지정합니다. 예외적인 경우 영구적으로 robots.txt를 오버라이드할 수 있습니다." + blocked_email_domains: "사용자가 계정을 등록할 수 없는 파이프(|)로 구분된 이메일 도메인 목록입니다. 예: mailinator.com|trashmail.net" + allowed_email_domains: "사용자가 계정을 등록해야 하는 파이프(|)로 구분된 이메일 도메인 목록입니다. 경고: 나열된 것과 다른 이메일 도메인을 가진 사용자는 허용되지 않습니다!" auto_approve_email_domains: "이 도메인 목록의 이메일 주소를 가진 사용자는 자동으로 승인됩니다." - hide_email_address_taken: "가입하는 동안 또는 비밀번호 찾기 과정에서 입력한 이메일 주소를 사용하는 계정이 있다는 사실을 사용자에게 알리지 마세요. '비밀번호 찾기' 요청에는 전체 이메일이 필요합니다." - log_out_strict: "로그아웃 할때, 모든 장치에서 다같이 로그아웃" - version_checks: "버전 관리를 위해 Discourse Hub를 핑 (Ping)하여 / admin 대시 보드에 새 버전 메시지를 표시합니다." - new_version_emails: "사용가능한 새로운 업데이트가 있으면 등록된 contact_email 주소로 메일을 발송하여 알려줍니다." - invite_expiry_days: "사용자 초대키 유효 기간, 일" - invite_only: "모든 신규 사용자는 신뢰할 수있는 사용자 또는 직원이 명시 적으로 초대해야합니다. 공개 등록이 비활성화되었습니다." - login_required: "글을 읽으려면 인증(로그인)이 필요함" - min_username_length: "최소 아이디 글자수. 경고: 이미 가입한 사용자나 그룹의 아이디 길이가 이 값보다 작으면 사이트가 깨집니다!" - max_username_length: "최대 아이디 글자수. 경고: 이미 가입한 사용자나 그룹의 아이디 길이가 이 값보다 크면 사이트가 깨집니다!" - unicode_usernames: "사용자 이름과 그룹 이름에 유니 코드 문자와 숫자를 포함 할 수 있습니다." - allowed_unicode_username_characters: "사용자 이름 내에 일부 유니 코드 문자만 허용하는 정규식입니다. ASCII 문자와 숫자는 항상 허용되며 허용 목록에 포함될 필요는 없습니다." - reserved_usernames: "가입을 금지하는 아이디. 와일드카드 기호 * 를 사용해서 하나 이상의 글자를 매칭시킬 때 사용할 수 있습니다." - min_password_length: "비밀번호 최소 글자수." - min_admin_password_length: "관리자 계정 비밀번호 최소길이" - password_unique_characters: "패스워드에 포함되어야 하는 최소 유일글자 수" - block_common_passwords: "가장 흔히 사용되는 10,000개 비밀번호 목록에 있는 비밀번호를 사용하는 것을 허용하지 않음." - auth_skip_create_confirm: 외부 인증을 통해 가입하는 경우 계정 생성 팝업을 건너 뜁니다. auth_overrides_email, auth_overrides_username 및 auth_overrides_name과 함께 사용하는 것이 가장 좋습니다. - auth_immediately: "사용자 상호 작용없이 자동으로 외부 로그인 시스템으로 리디렉션합니다. 이는 login_required가 true이고 외부 인증 방법이 하나 뿐인 경우에만 적용됩니다." - enable_discourse_connect: "DiscourseConnect (이전의 'Discourse SSO')를 통해 로그인 활성화 (경고: 사용자의 이메일 주소를 외부 사이트에서 *반드시* 검증해야합니다!)" - verbose_discourse_connect_logging: "자세한 DiscourseConnect 관련 진단을 /logs에 기록" - enable_discourse_connect_provider: "/session/sso_provider 끝점에서 DiscourseConnect (이전의 'Discourse SSO') 공급자 프로토콜을 구현하려면 discourse_connect_provider_secrets를 설정해야합니다." - discourse_connect_url: "DiscourseConnect 엔드포인트의 URL (반드시 http:// 또는 https:// 를 포함해야 함)" - discourse_connect_secret: "DiscourseConnect 정보를 암호화 방식으로 인증하는데 사용되는 비밀 문자열입니다. 10자 이상이어야 합니다." - discourse_connect_provider_secrets: "DiscourseConnect를 사용하는 도메인 시크릿 목록입니다. DiscourseConnect 암호가 10자 이상인지 확인하십시오. 와일드 카드 기호*는 모든 도메인 또는 그 일부만 일치시키는데 사용할 수 있습니다. (예. * .example.com)" - discourse_connect_overrides_bio: "사용자 프로필의 사용자 소개 기능을 무시하고 사용자가 변경할 수 없도록 합니다." - discourse_connect_overrides_groups: "모든 수동 그룹 구성원을 그룹 속성에 지정된 그룹과 동기화합니다. (경고: 그룹을 지정하지 않으면 모든 수동 그룹 구성원이 지워짐)" - auth_overrides_username: "로그인 할 때마다 외부 사이트의 사용자 이름으로 로컬 사용자 이름을 재정의하고 로컬 변경을 방지합니다. 모든 인증 공급자에 적용됩니다. (경고: 사용자 이름 길이/요구 사항의 차이로 인해 불일치가 발생할 수 있음)" - auth_overrides_name: "로그인 할 때마다 사용자의 로컬 전체 이름을 무시하고 외부 사이트 전체 이름을 사용해 로컬 변경을 방지합니다. 모든 인증 공급자에 적용됩니다." - discourse_connect_overrides_profile_background: "DiscourseConnect 페이로드의 값으로 사용자 프로필 배경을 설정합니다." - discourse_connect_overrides_card_background: "사용자 카드 배경을 DiscourSeconNect 페이로드의 값으로 설정합니다." + hide_email_address_taken: "가입하는 동안 또는 비밀번호 찾기 과정에서 제공한 이메일 주소를 사용한 계정이 존재한다는 것을 사용자에게 알리지 마세요. '비밀번호 찾기' 요청에는 전체 이메일이 필요합니다." + log_out_strict: "로그아웃 시, 모든 디바이스에서 사용자의 모든 세션을 로그아웃합니다" + version_checks: "버전 업데이트를 위해 Discourse Hub를 Ping하고 /admin 대시보드에 새 버전 메시지를 표시합니다" + new_version_emails: "사용 가능한 새 Discourse 버전이 있으면 등록된 contact_email 주소로 이메일을 전송합니다." + invite_expiry_days: "사용자 초대 키의 유효 기간(일)" + invite_only: "모든 신규 사용자는 신뢰할 수 있는 사용자 또는 운영진이 명시적으로 초대해야 합니다. 공개 등록이 비활성화되었습니다." + login_required: "이 사이트의 콘텐츠를 읽으려면 인증이 필요하며 익명 액세스를 허용하지 않습니다." + min_username_length: "최소 아이디 길이(문자)입니다. 경고: 기존 사용자 또는 그룹에 이보다 짧은 이름이 있는 경우 사이트가 깨집니다." + max_username_length: "최대 아이디 길이(문자)입니다. 경고: 기존 사용자 또는 그룹에 이보다 긴 이름이 있는 경우 사이트가 깨집니다." + unicode_usernames: "아이디와 그룹 이름에 유니코드 문자와 숫자를 포함할 수 있습니다." + allowed_unicode_username_characters: "아이디 내에서 일부 유니코드 문자만 허용하는 정규식입니다. ASCII 문자와 숫자는 항상 허용되며 허용 목록에 포함할 필요가 없습니다." + reserved_usernames: "가입이 허용되지 않은 아이디입니다. 와일드카드 기호 *를 사용하여 하나 이상의 문자를 일치시키면 사용할 수 있습니다." + min_password_length: "최소 비밀번호 길이입니다." + min_admin_password_length: "관리자의 최소 비밀번호 길이입니다." + password_unique_characters: "비밀번호에 포함해야 하는 최소 고유 문자 수입니다." + block_common_passwords: "가장 흔한 10,000개의 비밀번호에 속하는 비밀번호는 허용되지 않습니다." + auth_skip_create_confirm: 외부 인증으로 가입 시 계정 생성 팝업을 건너뜁니다. auth_overrides_email, auth_overrides_username 및 auth_overrides_name과 함께 사용하는 것이 가장 좋습니다. + auth_immediately: "사용자 인터랙션 없이 자동으로 외부 로그인 시스템으로 리디렉션합니다. 이는 login_required가 true이고 외부 인증 방법이 하나뿐인 경우에만 적용됩니다." + enable_discourse_connect: "DiscourseConnect(기존 'Discourse SSO')를 통한 로그인을 활성화합니다(경고: 사용자의 이메일 주소는 *반드시* 외부 사이트에서 검증되어야 합니다!)" + verbose_discourse_connect_logging: "자세한 DiscourseConnect 관련 진단을 /log에 기록합니다." + enable_discourse_connect_provider: "/session/sso_provider 엔드포인트에서 DiscourseConnect(기존 'Discourse SSO') 공급자 프로토콜을 구현하려면 discourse_connect_provider_secrets를 설정해야 합니다." + discourse_connect_url: "DiscourseConnect 엔드포인트의 URL(반드시 http:// 또는 https://를 포함해야 함)" + discourse_connect_secret: "DiscourseConnect 정보를 암호화 방식으로 인증하는 데 사용되는 암호 문자열이며, 10자 이상이어야 합니다." + discourse_connect_provider_secrets: "DiscourseConnect를 사용하는 도메인 암호 쌍의 목록입니다. DiscourseConnect 암호가 10자 이상인지 확인하세요. 와일드카드 기호 *는 모든 도메인 또는 그 일부(예: *.example.com)와 일치하는 데 사용할 수 있습니다." + discourse_connect_overrides_bio: "사용자 프로필의 사용자 소개 기능를 오버라이드하고 사용자가 변경할 수 없도록 합니다" + discourse_connect_overrides_groups: "모든 수동 그룹 멤버십을 그룹 어트리뷰트에 지정된 그룹과 동기화합니다(경고: 그룹을 지정하지 않으면 사용자의 모든 수동 그룹 멤버십이 지워집니다)" + auth_overrides_username: "로그인할 때마다 로컬 아이디를 외부 사이트 아이디로 오버라이드하고 로컬 변경사항을 방지합니다. 모든 인증 공급자에 적용됩니다. (경고: 아이디 길이/요구사항의 차이로 인해 불일치가 발생할 수 있습니다)" + auth_overrides_name: "로그인할 때마다 로컬 전체 이름을 외부 사이트 전체 이름으로 오버라이드하고 로컬 변경사항을 방지합니다. 모든 인증 공급자에 적용됩니다." + discourse_connect_overrides_profile_background: "DiscourseConnect 페이로드의 값으로 사용자 프로필 배경을 오버라이드합니다." + discourse_connect_overrides_card_background: "사용자 카드 배경을 DiscourseConnect 페이로드의 값으로 오버라이드합니다." discourse_connect_not_approved_url: "승인되지 않은 DiscourseConnect 계정을 이 URL로 리디렉션" - discourse_connect_allows_all_return_paths: "DiscourseConnect에서 제공하는 return_paths에 대한 도메인을 제한하지 마십시오 (기본적으로 반환 경로는 현재 사이트에 있어야 함)." - enable_local_logins: "로컬 사용자 아이디 및 암호 로그인 기반 계정을 활성화합니다. 경고: 비활성화 된 경우 이전에 하나 이상의 대체 로그인 방법을 구성하지 않은 경우 로그인하지 못할 수 있습니다." - enable_local_logins_via_email: "사용자가 원 클릭 로그인 링크를 이메일을 통해 보내도록 요청할 수 있습니다." - allow_new_registrations: "새로운 사용자 가입을 허락함. 새로운 계정 생성을 막으려면 체크하지 않음." - enable_signup_cta: "재방문한 익명 사용자에게 가입 권유 공지 표시" - enable_google_oauth2_logins: "Google Oauth2 인증을 활성화합니다. 현재 Google에서 지원하는 인증 방법입니다. 키와 시크릿 번호가 필요합니다. Google 로그인 구성을 참조하십시오." - google_oauth2_client_id: "Google Application의 Client ID" - google_oauth2_client_secret: "Google Application의 Client Secret" - google_oauth2_prompt: "권한 부여 서버가 사용자에게 재 인증 및 동의를 요구하는지 여부를 지정하는 선택적 공백으로 구분 된 문자열 값 목록입니다. 가능한 값은 https://developers.google.com/identity/protocols/OpenIDConnect#prompt 를 참조 하십시오 ." - google_oauth2_hd: "로그인이 제한되는 선택적 Google Apps 호스팅 도메인. 자세한 내용은 https://developers.google.com/identity/protocols/OpenIDConnect#hd-param 을 참조하십시오." - enable_twitter_logins: "Twitter 인증을 사용하려면 twitter_consumer_key 및 twitter_consumer_secret이 필요합니다. Discourse에 대한 Twitter 로그인 구성 및 리치 임베디드를 참조하십시오." - twitter_consumer_key: "https://developer.twitter.com/apps에 등록 된 Twitter 인증을위한 소비자 키" - twitter_consumer_secret: "https://developer.twitter.com/apps에 등록 된 트위터 인증을위한 소비자 비밀" - enable_facebook_logins: "Facebook 인증을 사용하려면 facebook_app_id 및 facebook_app_secret이 필요합니다. Discourse에 대한 Facebook 로그인 구성을 참조하십시오." - facebook_app_id: "https://developers.facebook.com/apps에 등록 된 Facebook 인증을위한 앱 ID" - facebook_app_secret: "https://developers.facebook.com/apps에 등록 된 Facebook 인증을위한 앱 비밀" - enable_github_logins: "GitHub 인증을 활성화 하려면, github_client_id 및 github_client_secret이 필요합니다. Discourse에 대한 GitHub 로그인 구성을 참조하십시오." - github_client_id: "GitHub 인증을 위한 클라이언트 ID, https://github.com/settings/developers에서 등록됨" - github_client_secret: "GitHub 인증을위한 클라이언트 암호, https://github.com/settings/developers에서 등록됨" - enable_discord_logins: "사용자가 Discord를 사용하여 인증 할 수 있습니까?" - discord_client_id: 'Discord Client ID (하나는 필요합니까? Discord 개발자 포털을 방문하십시오)' - discord_secret: "불화 비밀 키" - discord_trusted_guilds: '이 Discord 구성원만 Discord를 통해 로그인 할 수 있습니다. 숫자 ID를 사용하십시오. 자세한 내용은 여기지침을 확인하십시오. 허용하려면 공백으로 두십시오.' - enable_backups: "관리자가 포럼 백업을 만들 수 있도록 허용" - allow_restore: "모든 사이트 데이터를 대체할 수 있는 복원 허용! 백업을 복원할 계획이 아니라면 비활성화된 상태로 두십시오." - maximum_backups: "디스크에 유지할 최대 백업 개수. 오래된 백업순으로 자동으로 삭제된다." - automatic_backups_enabled: "설정된 백업 주기로 자동 백업 실행" - backup_frequency: "백업 간격 (일)입니다." - 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: "스케쥴링된 백업을 실행할 때 업로드된 자료도 포함. 해제하면 데이터베이스만 백업합니다." - backup_location: "백업이 저장된 위치입니다. 중요 : S3에는 파일 설정에 입력 한 유효한 S3 자격 증명이 필요합니다." - backup_gzip_compression_level_for_uploads: "업로드 압축에 사용되는 Gzip 압축 수준." - include_thumbnails_in_backups: "백업에 생성 된 썸네일을 포함시킵니다. 사용 중지하면 백업이 더 작아 지지만 복원 후 모든 게시물을 다시 작성해야합니다." - active_user_rate_limit_secs: "'last_seen_at'을 업데이트 하는 주기(초)" - verbose_localization: "UI에 언어 팁을 확장해 보여줌" - previous_visit_timeout_hours: "최근 방문한 시간을 저장할 주기(시간)" - top_topics_formula_log_views_multiplier: "인기 토픽 계산 공식의 뷰 가중치 설정: `log(views_count) * (n) + op_likes_count * 0.5 + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" - top_topics_formula_first_post_likes_multiplier: "인기 토픽 계산 공식의 좋아요 가중치 설정: `log(views_count) * 2 + op_likes_count * (n) + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" - top_topics_formula_least_likes_per_post_multiplier: "인기 토픽 계산 공식에서 포스트당 최소 좋아요 가중치 설정: `log(views_count) * 2 + op_likes_count * 0.5 + LEAST(likes_count / posts_count, (n)) + 10 + log(posts_count)`" - enable_safe_mode: "사용자가 안전 모드로 들어가 플러그인을 디버깅 할 수 있도록합니다." - rate_limit_create_topic: "글을 작성 후 다른 글을 작성하기 위해서는 (n)초 동안 기다려야 합니다." - rate_limit_create_post: "사용자가 댓글 작성 후 다른 댓글을 작성하기 위해서는 (n)초를 기다려야합니다." - rate_limit_new_user_create_topic: "새로 가입한 사용자가 글을 작성 후 다른 글을 작성하기 위해서는 (n)초를 기다려야합니다." - rate_limit_new_user_create_post: "새로 가입한 사용자가 댓글을 작성 후 다른 댓글을 작성하기 위해서는 (n)초를 기다려야합니다." - max_likes_per_day: "사용자가 하루동안 할 수 있는 최대 좋아요 개수" - max_flags_per_day: "사용자가 하루동안 할 수 있는 최대 신고 개수" - max_bookmarks_per_day: "사용자가 하루동안 할 수 있는 최대 북마크 개수" - max_edits_per_day: "사용자가 하루동안 할 수 있는 최대 편집 수" - max_topics_per_day: "사용자가 하루에 작성 할 수 있는 최대 글 수입니다." - max_personal_messages_per_day: "사용자가 하루에 작성 할 수있는 최대 새 개인 메시지 수입니다." - max_invites_per_day: "하루에 보낼 수 있는 초대장의 최대치입니다." - max_topic_invitations_per_day: "하루에 유저가 최대로 보낼 수 있는 글타래 초대장 수" - max_logins_per_ip_per_hour: "시간 당 동일 IP에서 로그인할 수 있는 최대 사용자 수" - max_logins_per_ip_per_minute: "1분 당 동일 IP에서 로그인할 수 있는 최대 사용자 수" - max_post_deletions_per_minute: "사용자가 분당 삭제할 수있는 최대 게시물 수입니다. 게시물 삭제를 비활성화하려면 0으로 설정합니다." - max_post_deletions_per_day: "사용자가 하루에 삭제할 수있는 최대 게시물 수입니다. 게시물 삭제를 비활성화하려면 0으로 설정합니다." + discourse_connect_allows_all_return_paths: "DiscourseConnect에서 제공하는 return_paths에 대한 도메인을 제한하지 마세요(기본적으로 반환 경로는 현재 사이트에 있어야 합니다)" + enable_local_logins: "로컬 아이디 및 비밀번호 로그인 기반 계정을 활성화합니다. 경고: 비활성화된 경우 이전에 하나 이상의 대체 로그인 방법을 구성하지 않았다면 로그인하지 못할 수 있습니다." + enable_local_logins_via_email: "사용자가 원클릭 로그인 링크를 이메일로 보내도록 요청할 수 있습니다." + allow_new_registrations: "신규 사용자 등록을 허용합니다. 모든 사용자의 새 계정 생성을 방지하려면 체크하지 마세요." + enable_signup_cta: "재방문한 익명 사용자에게 가입 권유 공지를 표시합니다." + enable_google_oauth2_logins: "Google Oauth2 인증을 활성화합니다. 현재 Google에서 지원하는 인증 방법이며, 키와 암호가 필요합니다. Discourse용 Google 로그인 환경설정을 참조하세요." + google_oauth2_client_id: "Google 애플리케이션의 클라이언트 ID입니다." + google_oauth2_client_secret: "Google 애플리케이션의 클라이언트 암호입니다." + google_oauth2_prompt: "인증 서버가 사용자에게 재인증 및 동의를 요청하는지 여부를 지정하는 공백으로 구분된 스트링 값 선택사항 목록입니다. https://developers.google.com/identity/protocols/OpenIDConnect#prompt에서 가능한 값을 확인하세요." + google_oauth2_hd: "로그인이 제한되는 선택적 Google Apps 호스팅 도메인입니다. 자세한 내용은 https://developers.google.com/identity/protocols/OpenIDConnect#hd-param을 참조하세요." + enable_twitter_logins: "Twitter 인증을 활성화하려면 twitter_consumer_key 및 twitter_consumer_secret이 필요합니다. Discourse용 Twitter 로그인 환경설정 및 리치 임베드를 참조하세요." + twitter_consumer_key: "https://developer.twitter.com/apps에 등록된 Twitter 인증용 소비자 키" + twitter_consumer_secret: "https://developer.twitter.com/apps에 등록된 Twitter 인증용 소비자 암호" + enable_facebook_logins: "Facebook 인증을 사용하려면 facebook_app_id 및 facebook_app_secret이 필요합니다. Discourse용 Facebook 로그인 환경설정을 참조하세요." + facebook_app_id: "https://developers.facebook.com/apps에 등록된 Facebook 인증 및 공유용 앱 ID" + facebook_app_secret: "https://developers.facebook.com/apps에 등록된 Facebook 인증용 앱 암호" + enable_github_logins: "GitHub 인증을 활성화하려면 github_client_id 및 github_client_secret이 필요합니다. Discourse용 GitHub 로그인 환경설정을 참조하세요." + github_client_id: "https://github.com/settings/developers에 등록된 GitHub 인증용 클라이언트 ID" + github_client_secret: "https://github.com/settings/developers에 등록된 GitHub 인증용 클라이언트 암호" + enable_discord_logins: "사용자가 Discord를 사용하여 인증하도록 허용할까요?" + discord_client_id: 'Discord 클라이언트 ID(필요한 경우 Discord 개발자 포털을 방문하세요)' + discord_secret: "Discord 암호 키" + discord_trusted_guilds: '이 Discord 길드 회원만 Discord를 통해 로그인할 수 있습니다. 길드에 숫자 ID를 사용하세요. 자세한 내용은 여기에서 지침을 확인하세요. 모든 길드를 허용하려면 공백으로 두세요.' + enable_backups: "관리자가 포럼 백업을 생성하도록 허용" + allow_restore: "모든 사이트 데이터를 대체할 수 있는 복원을 허용합니다! 백업을 복원할 계획이 아니라면 비활성화된 상태로 두세요." + maximum_backups: "디스크에 유지할 최대 백업 수입니다. 오래된 백업 순으로 자동으로 삭제됩니다" + automatic_backups_enabled: "백업 주기에 정의된 대로 자동 백업 실행" + backup_frequency: "백업 주기(일)입니다." + s3_backup_bucket: "백업을 보관할 원격 버킷입니다. 경고: 비공개 버킷인지 확인하세요." + 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: "예약된 백업에 업로드를 포함합니다. 비활성화하면 데이터베이스만 백업합니다." + backup_location: "백업이 저장된 위치입니다. 중요: S3에는 파일 설정에 입력 한 유효한 S3 크리덴셜이 필요합니다." + backup_gzip_compression_level_for_uploads: "업로드 압축에 사용되는 Gzip 압축 수준입니다." + include_thumbnails_in_backups: "백업에 생성된 섬네일을 포함합니다. 비활성화하면 백업이 더 작아지지만 복원 후 모든 게시물을 다시 작성해야 합니다." + active_user_rate_limit_secs: "'last_seen_at' 필드 업데이트 주기(초)" + verbose_localization: "UI에 현지화 팁을 펼쳐서 표시" + previous_visit_timeout_hours: "방문 '히스토리'로 간주되기 전 방문 지속 기간(시간)" + top_topics_formula_log_views_multiplier: "주요 주제 공식의 로그 조회수 배수 (n) 값: `log(views_count) * (n) + op_likes_count * 0.5 + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" + top_topics_formula_first_post_likes_multiplier: "주요 주제 공식의 첫 게시물 좋아요 배수 (n) 값: `log(views_count) * 2 + op_likes_count * (n) + LEAST(likes_count / posts_count, 3) + 10 + log(posts_count)`" + top_topics_formula_least_likes_per_post_multiplier: "주요 주제 공식의 게시물당 최소 좋아요 배수 (n) 값: `log(views_count) * 2 + op_likes_count * 0.5 + LEAST(likes_count / posts_count, (n)) + 10 + log(posts_count)`" + enable_safe_mode: "사용자가 안전 모드에서 플러그인을 디버깅하도록 허용합니다." + rate_limit_create_topic: "주제 생성 후 추가로 주제를 생성하려면 (n)초 기다려야 합니다." + rate_limit_create_post: "게시물 작성 후 추가로 게시물을 작성하려면 (n)초 기다려야 합니다." + rate_limit_new_user_create_topic: "신규 사용자가 주제 생성 후 추가로 주제를 생성하려면 (n)초 기다려야 합니다." + rate_limit_new_user_create_post: "신규 사용자가 게시물 작성 후 추가로 게시물을 작성하려면 (n)초 기다려야 합니다." + max_likes_per_day: "사용자당 일일 최대 좋아요 수입니다." + max_flags_per_day: "사용자당 일일 최대 신고 수입니다." + max_bookmarks_per_day: "사용자당 일일 최대 북마크 수입니다." + max_edits_per_day: "사용자당 일일 최대 편집 수입니다." + max_topics_per_day: "일일 생성 가능한 최대 주제 수입니다." + max_personal_messages_per_day: "일일 생성 가능한 최대 개인 메시지 수입니다." + max_invites_per_day: "일일 전송 가능한 최대 초대 수입니다." + max_topic_invitations_per_day: "일일 전송 가능한 최대 주제 초대 수입니다." + max_logins_per_ip_per_hour: "시간당 동일 IP에서 로그인할 수 있는 최대 사용자 수" + max_logins_per_ip_per_minute: "분당 동일 IP에서 로그인할 수 있는 최대 사용자 수" + max_post_deletions_per_minute: "분당 삭제할 수 있는 최대 게시물 수입니다. 게시물 삭제를 비활성화하려면 0으로 설정하세요." + max_post_deletions_per_day: "일일 삭제 가능한 최대 게시물 수입니다. 게시물 삭제를 비활성화하려면 0으로 설정하세요." invite_link_max_redemptions_limit: "초대 링크에 허용되는 최대 사용 횟수는 이 값을 초과할 수 없습니다." - invite_link_max_redemptions_limit_users: "일반 사용자가 생성한 초대 링크에 허용되는 최대 사용 횟수는 이 값보다 클 수 없습니다." - alert_admins_if_errors_per_minute: "관리자 경고를 발생시키기 위한 1분당 에러 수. 0으로 설정하면 기능 해제됨. 주의: 재시작이 필요합니다." - alert_admins_if_errors_per_hour: "관리자 경고를 발생시키기 위한 시간당 에러 수. 0으로 설정하면 기능 해제됨. 주의: 재시작이 필요합니다." - categories_topics: "/ 카테고리 페이지에 표시 할 주제 수입니다. 0으로 설정하면 두 열을 대칭 (범주 및 주제)으로 유지하는 값을 자동으로 찾습니다." - suggested_topics: "글타래 아랫부분에 몇개의 글타래를 제안하여 보여준다." - limit_suggested_to_category: "제안된 글타래는 현재의 카테고리에 있는 글타래 중에서만 보여준다." - suggested_topics_max_days_old: "제안 된 글은 n 일을 넘지 않아야합니다." - suggested_topics_unread_max_days_old: "읽지 않은 주제는 n 일을 넘지 않아야합니다." - clean_up_uploads: "불법 호스팅을 막기 위해서 참조되지 않은 업로드 파일은 제거합니다. 주의 : 이 설정을 활성화 하기 전에 `/uploads` 디렉토리를 백업하는 것이 좋습니다." - clean_orphan_uploads_grace_period_hours: "글에 연결되지 않은 업로드 파일을 제거하기 전 유예 기간 (시간) 입니다." - purge_deleted_uploads_grace_period_days: "글에 연결되지 않은 업로드 파일이 삭제되기 전 유예 기간 (일) 입니다." - purge_unactivated_users_grace_period_days: "계정을 활성화하지 않은 사용자가 삭제되기 전의 유예 기간 (일)입니다. 활성화되지 않은 사용자를 제거하지 않으려면 0으로 설정하십시오." - enable_s3_uploads: "Amazon S3 storage에 업로드해주세요. 중요: 올바른 S3 계정이 필요합니다.(access key id와 secret access key 둘다)" - s3_use_iam_profile: 'AWS EC2 인스턴스 프로파일 을 사용하여 S3 버킷에 대한 액세스 권한을 부여하십시오. 참고 :이를 활성화하려면 Discourse가 적절하게 구성된 EC2 인스턴스에서 실행되고 "s3 액세스 키 ID"및 "s3 비밀 액세스 키"설정이 무시됩니다.' - s3_upload_bucket: "파일이 업로드 될 위치의 Amazon S3 bucket name. 경고: 소문자 알파벳만 허용되며 점 . 이나 밑줄문자 _ 가 없어야 함." + invite_link_max_redemptions_limit_users: "일반 사용자가 생성한 초대 링크에 허용되는 최대 사용 횟수는 이 값을 초과할 수 없습니다." + alert_admins_if_errors_per_minute: "관리자 경고를 트리거하기 위한 분당 오류 수입니다. 이 기능을 비활성화하려면 0으로 설정하세요. 참고: 재시작해야 합니다." + alert_admins_if_errors_per_hour: "관리자 경고를 트리거하기 위한 시간당 오류 수입니다. 이 기능을 비활성화하려면 0으로 설정하세요. 참고: 재시작해야 합니다." + categories_topics: "/categories 페이지에 표시할 주제 수입니다. 0으로 설정하면 두 열을 대칭으로 유지하기 위해 값을 자동으로 찾습니다(카테고리 및 주제)." + suggested_topics: "주제 하단에 표시할 제안된 주제 수입니다." + limit_suggested_to_category: "제안된 주제는 현재의 카테고리에 있는 주제만 표시합니다." + suggested_topics_max_days_old: "제안된 주제는 n일을 넘지 않아야 합니다." + suggested_topics_unread_max_days_old: "제안된 읽지 않은 주제는 n일을 넘지 않아야 합니다." + clean_up_uploads: "불법 호스팅을 방지하기 위해 참조되지 않은 분리된 업로드를 제거합니다. 경고: 이 설정을 활성화하기 전에 /uploads 디렉터리를 백업할 수 있습니다." + clean_orphan_uploads_grace_period_hours: "분리된 업로드 파일을 제거하기 전 유예 기간(시간)입니다." + purge_deleted_uploads_grace_period_days: "삭제된 업로드가 지워지기 전 유예 기간(일)입니다." + purge_unactivated_users_grace_period_days: "계정을 활성화하지 않은 사용자가 삭제되기 전의 유예 기간(일)입니다. 활성화되지 않은 사용자를 제거하지 않으려면 0으로 설정하세요." + enable_s3_uploads: "Amazon S3 스토리지에 업로드하세요. 중요: 유효한 S3 크리덴셜이 필요합니다.(액세스 키 ID 및 암호 액세스 키 모두)." + s3_use_iam_profile: 'AWS EC2 인스턴스 프로필을 사용하여 S3 버킷 액세스를 부여합니다. 참고: 이를 활성화하려면 적절하게 환경설정된 EC2 인스턴스에서 Discourse를 실행해야 하며 ''s3 액세스 키 ID'' 및 ''s3 암호 액세스 키'' 설정을 오버라이드합니다.' + s3_upload_bucket: "파일이 업로드될 Amazon S3 버킷 이름입니다. 경고: 소문자 알파벳만 허용되며 마침표나 언더스코어가 없어야 합니다." s3_access_key_id: "이미지, 첨부 파일 및 백업을 업로드하는 데 사용될 Amazon S3 액세스 키 ID입니다." - s3_secret_access_key: "이미지, 첨부 파일 및 백업을 업로드하는 데 사용될 Amazon S3 비밀 액세스 키." - s3_region: "이미지 및 백업을 업로드하는 데 사용될 Amazon S3 리전 이름." - s3_cdn_url: "s3 에셋에 사용될 CDN URL (예: https://cdn.somewhere.com). 경고: 이 설정 뒤에는 모든 글을 다시 구워야rebake 합니다." - avatar_sizes: "자동 생성 아바타 사이즈 목록" - external_system_avatars_enabled: "외부 아바타 시스템을 사용하기" - external_system_avatars_url: "외부 아바타 서비스의 URL. {username} {first_letter} {color} {size} 의 대체가 허용됨" + s3_secret_access_key: "이미지, 첨부 파일 및 백업을 업로드하는 데 사용될 Amazon S3 암호 액세스 키입니다." + s3_region: "이미지 및 백업을 업로드하는 데 사용될 Amazon S3 영역 이름입니다." + s3_cdn_url: "모든 s3 에셋에 사용될 CDN URL(예: https://cdn.somewhere.com)입니다. 경고: 이 설정을 변경한 후 기존 게시물을 다시 작성해야 합니다." + avatar_sizes: "자동 생성 아바타 크기 목록입니다." + external_system_avatars_enabled: "외부 시스템 아바타 서비스를 사용합니다." + external_system_avatars_url: "외부 시스템 아바타 서비스의 URL입니다. 허용된 대체는 {username} {first_letter} {color} {size}입니다." external_emoji_url: "이모티콘 이미지에 대한 외부 서비스의 URL입니다. 비활성화하려면 비워 두세요." - use_site_small_logo_as_system_avatar: "시스템 사용자 아바타 대신 사이트의 작은 로고를 사용하십시오. 로고가 있어야 합니다." - restrict_letter_avatar_colors: "문자 아바타 배경에 사용되는 6 자리 16 진수 색상 값 목록입니다." - enable_listing_suspended_users_on_search: "일반 사용자가 일시 중지된 사용자를 찾을 수 있도록 합니다." - selectable_avatars: "사용자가 선택할 수있는 아바타 목록." - allow_all_attachments_for_group_messages: "그룹 메시지에 모든 이메일 첨부 허용" - png_to_jpg_quality: "변환된 JPG 파일의 퀄리티(1은 최하, 99는 최상, 100은 해제)" - recompress_original_jpg_quality: "업로드된 이미지 파일의 품질 (1은 최저 품질, 99는 최고 품질, 100은 사용하지 않도록 설정)" - image_preview_jpg_quality: "크기가 조정된 이미지 파일의 품질 (1은 가장 낮은 품질, 99는 최고 품질, 100은 사용하지 않도록 설정)" - allow_staff_to_upload_any_file_in_pm: "관리자는 개인메시지에 파일 첨부를 허용합니다." - strip_image_metadata: "스트립 이미지 메타 데이터." - composer_media_optimization_image_enabled: "업로드된 이미지 파일의 클라이언트측 미디어 최적화를 활성화합니다." + use_site_small_logo_as_system_avatar: "시스템 사용자 아바타 대신 사이트의 작은 로고를 사용합니다. 로고가 있어야 합니다." + restrict_letter_avatar_colors: "문자 아바타 배경에 사용할 6자리 16진수 색상 값 목록입니다." + enable_listing_suspended_users_on_search: "일반 사용자가 정지된 사용자를 찾을 수 있도록 합니다." + selectable_avatars: "사용자가 선택할 수 있는 아바타 목록입니다." + allow_all_attachments_for_group_messages: "그룹 메시지에 모든 이메일 첨부를 허용합니다." + png_to_jpg_quality: "변환된 JPG 파일의 퀄리티(1은 최하, 99는 최상, 100은 비활성화)입니다." + recompress_original_jpg_quality: "업로드된 이미지 파일의 퀄리티(1은 최하, 99는 최상, 100은 비활성화)입니다." + image_preview_jpg_quality: "크기가 조정된 이미지 파일의 퀄리티(1은 최하, 99는 최상, 100은 비활성화)입니다." + allow_staff_to_upload_any_file_in_pm: "운영진이 개인 메시지에 모든 유형의 파일을 업로드하도록 허용합니다." + strip_image_metadata: "스트립 이미지 메타데이터입니다." + composer_media_optimization_image_enabled: "업로드된 이미지 파일의 클라이언트 측 미디어 최적화를 활성화합니다." composer_media_optimization_image_bytes_optimization_threshold: "클라이언트 측 최적화를 트리거하기 위한 최소 이미지 파일 크기" - composer_media_optimization_image_resize_dimensions_threshold: "클라이언트측 크기 조정을 트리거하는 최소 이미지 너비" - composer_media_optimization_image_resize_width_target: "너비가`composer_media_optimization_image_dimensions_resize_threshold`보다 큰 이미지는 이 너비로 크기가 조정됩니다. `composer_media_optimization_image_dimensions_resize_threshold`보다 크거나 같아야합니다." - composer_media_optimization_image_encode_quality: "재 인코딩 프로세스에 사용되는 JPEG 인코딩 품질입니다." - min_ratio_to_crop: "큰 이미지를 자르는 데 사용되는 비율. 너비 / 높이의 결과를 입력하십시오." - simultaneous_uploads: "글 작성기에서 끌어서 놓을 수 있는 최대 파일 수" - default_invitee_trust_level: "초대 된 사용자의 기본 회원 등급 (0-4) 입니다." - default_trust_level: "모든 새 사용자에 대한 기본 회원등급 (0-4). 경고! 이를 변경하면 스팸에 대한 심각한 위험에 처하게됩니다." - tl1_requires_topics_entered: "회원레벨 1로 승격하기 위해 사용자가 작성 해야하는 글 수" - tl1_requires_read_posts: "새 사용자가 회원레벨 1로 승격하기 위해 읽어야하는 게시물 수" - tl1_requires_time_spent_mins: "새 사용자가 회원등급 1이 되기 위해 게시물을 읽어야 하는 시간(분)." - tl2_requires_topics_entered: "회원레벨 2로 승격하기 위해 사용자가 작성 해야하는 글 수" - tl2_requires_read_posts: "회원레벨 2로 승격하기 위해 사용자가 읽어야하는 게시물 수" - tl2_requires_time_spent_mins: "회원등급 2가 되기 위해 게시물을 읽어야 하는 시간(분)." - tl2_requires_days_visited: "회원등급 2가 되기 위해 사이트를 방문해야하는 일 수." - tl2_requires_likes_received: "회원등급 2가 되기 위해 사용자가 받아야하는 좋아요 수." - tl2_requires_likes_given: "회원등급 2가 되기 위해 사용자가 클릭해야 하는 좋아요 수." - tl2_requires_topic_reply_count: "회원레벨 2로 승격하기 위해 사용자가 작성 해야하는 댓글 수" - tl3_time_period: "회원 등급 3 자격을 얻기 위한 활동 기간 (일)" - tl3_requires_days_visited: "회원 레벨 3이 자격을 얻기 위하여 지난 (tl3 time period)일 동안 사용자가 사이트에 방문해야하는 최소 일 수. tl3 기간보다 길게 설정하면 회원레벨 3 승격을 해제합니다. (0이상)" - tl3_requires_topics_replied_to: "회원 레벨 3 자격을 얻기 위하여 지난 (tl3 time period)일 동안 사용자가 댓글을 달아야 하는 최소 토픽 수 (0 이상)" - tl3_requires_topics_viewed: "회원 레벨 3 자격을 얻기 위하여 지난 (tl3 time period) 일 동안 작성된 토픽 중에서 사용자가 읽어야 하는 토픽의 퍼센트 비율.(0 에서 100)" - tl3_requires_topics_viewed_cap: "지난 (tl3 time period) 일 동안 사용자가 봐야하는 최대 토픽 조회수." - tl3_requires_posts_read: "회원 레벨 3 자격을 얻기 위하여 지난 (tl3 time period) 일 동안 작성된 토픽 중에서 사용자가 읽어야 하는 포스트의 퍼센트 비율.(0 에서 100)" - tl3_requires_posts_read_cap: "지난 (tl3 time period) 일 동안 사용자가 봐야하는 최대 포스트 조회수." - tl3_requires_topics_viewed_all_time: "VIP 사용자-3 이 되기 위해 꼭 보아야 하는 글타래의 전체 개수" - tl3_requires_posts_read_all_time: "VIP 사용자-3 이 되기 위해 꼭 보아야 하는 글타래의 전체 개수" - tl3_requires_max_flagged: "회원 레벨3의 자격을 얻으려면, 지난 (tl3 time period)일 동안 x명의 사용자로부터 x개 이상의 포스트를 신고당한 일이 없어야 합니다. x 값을 설정.(0이상)" - tl3_promotion_min_duration: "회원등급이 2로 떨어진 후 다시 VIP 사용자-3 이 될 수 있는 최소 일 수" - tl3_requires_likes_given: "회원 레벨3 자격을 얻기 위하여 지난 (tl3 time period)동안 줘야 하는 최소 좋아요 수." - tl3_requires_likes_received: "회원 레벨3 자격을 얻기 위하여 지난 (tl3 time period)일 동안 받아야 하는 최소 좋아요 수." - tl3_links_no_follow: "VIP 사용자-3 의 글에 있는 링크에서 rel=nofollow 를 제거하지 마시오." - trusted_users_can_edit_others: "신뢰 수준이 높은 사용자가 다른 사용자의 컨텐츠를 편집 할 수 있도록 허용" - min_trust_to_create_topic: "새로운 주제를 생성하기 위한 최소 회원등급" - allow_flagging_staff: "사용하도록 설정하면 사용자가 직원 계정의 게시물에 플래그를 지정할 수 있습니다." - min_trust_to_edit_wiki_post: "위키로 설정된 글 수정할 수 있는 최소 회원등급" - min_trust_to_edit_post: "포스트를 편집하기 위한 최소 신뢰도" - min_trust_to_allow_self_wiki: "사용자의 포스트 위키를 만들기 위한 최소 신뢰도" - min_trust_to_send_messages: "새 개인 메시지를 작성하는데 필요한 최소 회원 레벨입니다." - min_trust_to_send_email_messages: "이메일을 통해 개인 메시지를 보내는 데 필요한 최소 회원 레벨입니다." - min_trust_to_flag_posts: "게시물을 신고하는 데 필요한 최소 신뢰 수준" - min_trust_to_post_links: "게시물에 링크를 포함하는 데 필요한 최소 신뢰 수준" - min_trust_to_post_embedded_media: "게시물에 미디어 항목을 삽입하는데 필요한 최소 회원 레벨" - min_trust_level_to_allow_profile_background: "프로필 배경을 업로드하는데 필요한 최소 회원 레벨" - min_trust_level_to_allow_user_card_background: "사용자 카드 배경을 업로드하는데 필요한 최소 회원 레벨" - min_trust_level_to_allow_invite: "사용자를 초대하는 데 필요한 최소 회원 등급" - min_trust_level_to_allow_ignore: "사용자를 무시하는데 필요한 최소 회원등급" - allowed_link_domains: "링크를 삽입 할 수 있는 레벨이 아닌 사용자가 연결할 수 있는 도메인" - newuser_max_links: "새로운 사용자가 글에 붙일 수 있는 최대 링크 개수" - newuser_max_embedded_media: "새 사용자가 게시물에 추가 할 수있는 미디어 항목 수입니다." - newuser_max_attachments: "새로운 사용자가 포스트에 첨부할 수 있는 최대 파일 개수" - newuser_max_mentions_per_post: "새로운 사용자가 글에서 쓸 수 있는 최대 @아이디 멘션 개수" - newuser_max_replies_per_topic: "다른 사용자가 댓글을 달기 전, 새로운 사용자가 개별 토픽에 달 수 있는 최대 답글 개수" - max_mentions_per_post: "글 당 사용할 수 있는 최대 @name 알림의 수" - max_users_notified_per_group_mention: "그룹이 멘션을 받으면 알림을 받는 최대사용자의 수(최대치에 도달하면 알림이 전송되지 않음)" - enable_mentions: "사용자가 다른 사용자를 언급 할 수 있도록합니다." - create_thumbnails: "게시물에 맞지 않는 큰 이미지는 썸네일 이미지와 라이트 박스 이미지를 만듭니다." - email_time_window_mins: "알림 메일을 보내기 전 대기 기간(분), 사용자에게 글의 변경하고 완료할 수 있는 기회를 준다." - personal_email_time_window_seconds: "개인 메시지 알림 이메일을 보내기 전에 사용자가 메시지를 편집하고 마무리 할 수 있도록 (n) 초 동안 기다리십시오." - email_posts_context: "알림메일의 내용에 추가할 기존 답글 수" - flush_timings_secs: "사용자의 이용 시간 데이터를 서버로 보내는 기간(초)" - title_max_word_length: "글타래 제목안에 단어들의 최대 길이" - title_min_entropy: "글타래 제목에 필요한 최소 엔트로피(서로 다른 글자들이 몇개 존재해야하는지)" - body_min_entropy: "글 본문에 필요한 최소 엔트로피(서로 다른 글자들이 몇개 존재해야하는지)" - allow_uppercase_posts: "제목과 내용을 모두 대문자로 작성하는 것을 허용하기" - max_consecutive_replies: "다른 답변을 추가하지 못하기 전에 사용자가 주제에서 한 행에 게시해야하는 게시물 수입니다." - enable_filtered_replies_view: '“(n)개의 댓글” 버튼은 다른 모든 게시물을 축소하고 현재 게시물과 해당 댓글만 표시합니다.' - title_fancy_entities: "주제 제목에서 일반적인 ASCII 문자를 멋진 HTML 엔티티로 변환 하십시오." - min_title_similar_length: "유사 글타래에 대한 체크가 있기 전, 최소 제목 글자 수" - desktop_category_page_style: "/categories 페이지의 비주얼 스타일" - category_colors: "허용된 카테고리에 사용될 hexadecimal 색상 값의 리스트" - category_style: "카테고리 뱃지 시각 스타일" - default_dark_mode_color_scheme_id: "어두운 모드에서 사용되는 색 구성표입니다." + composer_media_optimization_image_resize_dimensions_threshold: "클라이언트 측 크기 조정을 트리거하는 최소 이미지 너비" + composer_media_optimization_image_resize_width_target: "너비가 `composer_media_optimization_image_dimensions_resize_threshold` 보다 큰 이미지는 이 너비로 크기가 조정됩니다. `composer_media_optimization_image_dimensions_resize_threshold` 보다 크거나 같아야 합니다." + composer_media_optimization_image_encode_quality: "재인코딩 프로세스에 사용되는 JPEG 인코딩 퀄리티입니다." + min_ratio_to_crop: "큰 이미지를 자르는 데 사용되는 비율입니다. 너비 / 높이의 결과를 입력하세요." + simultaneous_uploads: "작성기에서 드래그 앤 드롭할 수 있는 최대 파일 수" + default_invitee_trust_level: "초대된 사용자의 디폴트 신뢰 레벨(0~4)입니다." + default_trust_level: "모든 신규 사용자의 디폴트 신뢰 레벨(0~4)입니다. 경고! 이를 변경하면 스팸과 관련하여 심각한 위험이 발생합니다." + tl1_requires_topics_entered: "신뢰 레벨 1로 승급하기 위해 신규 사용자가 입력해야 하는 주제 수입니다." + tl1_requires_read_posts: "신뢰 레벨 1로 승급하기 위해 신규 사용자가 읽어야 하는 게시물 수입니다." + tl1_requires_time_spent_mins: "신뢰 레벨 1로 승급하기 위해 신규 사용자가 게시물을 읽어야 하는 시간(분)입니다." + tl2_requires_topics_entered: "신뢰 레벨 2로 승급하기 위해 사용자가 입력해야 하는 주제 수입니다." + tl2_requires_read_posts: "신뢰 레벨 2로 승급하기 위해 사용자가 읽어야 하는 게시물 수입니다." + tl2_requires_time_spent_mins: "신뢰 레벨 2로 승급하기 위해 사용자가 게시물을 읽어야 하는 시간(분)입니다." + tl2_requires_days_visited: "신뢰 레벨 2로 승급하기 위해 사용자가 사이트를 방문해야 하는 일 수입니다." + tl2_requires_likes_received: "신뢰 레벨 2로 승급하기 위해 사용자가 받아야 하는 좋아요 수입니다." + tl2_requires_likes_given: "신뢰 레벨 2로 승급하기 위해 사용자가 눌러야 하는 좋아요 수입니다." + tl2_requires_topic_reply_count: "신뢰 레벨 2로 승급하기 위해 사용자가 댓글을 달아야 하는 주제 수입니다." + tl3_time_period: "신뢰 레벨 3 요구 기간(일)" + tl3_requires_days_visited: "신뢰 레벨 3으로 승급하기 위해 지난 (tl3 기간)일 동안 사용자가 사이트를 방문해야 하는 최소 일 수입니다. tl3 승급을 비활성화하려면 tl3 기간보다 높게 설정하세요. (0 이상)" + tl3_requires_topics_replied_to: "신뢰 레벨 3으로 승급하기 위해 지난 (tl3 기간)일 동안 사용자가 댓글을 달아야 하는 최소 주제 수입니다. (0 이상)" + tl3_requires_topics_viewed: "신뢰 레벨 3으로 승급하기 위해 사용자가 읽어야 하는 지난 (tl3 기간)일 동안 생성된 주제의 비율입니다. (0~100)" + tl3_requires_topics_viewed_cap: "지난 (tl3 기간)일 동안 사용자가 읽어야 하는 최대 필수 주제 수입니다." + tl3_requires_posts_read: "신뢰 레벨 3으로 승급하기 위해 사용자가 읽어야 하는 지난 (tl3 기간)일 동안 작성된 게시물의 퍼센트입니다. (0~100)" + tl3_requires_posts_read_cap: "지난 (tl3 기간)일 동안 사용자가 읽어야 하는 최대 필수 게시물 수입니다." + tl3_requires_topics_viewed_all_time: "신뢰 레벨 3으로 승급하기 위해 사용자가 읽어야 하는 최소 주제 수입니다." + tl3_requires_posts_read_all_time: "신뢰 레벨 3으로 승급하기 위해 사용자가 읽어야 하는 최소 게시물 수입니다." + tl3_requires_max_flagged: "신뢰 레벨 3으로 승급하려면 지난 (tl3 기간)일 동안 x명의 다른 사용자가 신고한 게시물이 x개를 넘지 않아야 합니다. 여기서 x는 이 설정의 값입니다. (0 이상)" + tl3_promotion_min_duration: "사용자가 신뢰 레벨 2로 다시 강등되기 전 신뢰 레벨 3으로 승급이 지속되는 최소 일 수입니다." + tl3_requires_likes_given: "신뢰 레벨 3으로 승급하기 위해 지난 (tl3 기간)일 동안 사용자가 눌러야 하는 최소 좋아요 수입니다." + tl3_requires_likes_received: "신뢰 레벨 3으로 승급하기 위해 지난 (tl3 기간)일 동안 사용자가 받아야 하는 최소 좋아요 수입니다." + tl3_links_no_follow: "신뢰 레벨 3 사용자가 게시한 링크에서 rel=nofollow를 제거하지 마세요." + trusted_users_can_edit_others: "신뢰 레벨이 높은 사용자가 다른 사용자의 콘텐츠를 편집하도록 허용" + min_trust_to_create_topic: "새로운 주제를 생성하기 위한 최소 신뢰 레벨입니다." + allow_flagging_staff: "활성화하면 사용자는 운영진 계정의 게시물을 신고할 수 있습니다." + min_trust_to_edit_wiki_post: "위키로 표시된 게시물을 편집하기 위한 최소 신뢰 레벨입니다." + min_trust_to_edit_post: "게시물을 편집하기 위한 최소 신뢰 레벨입니다." + min_trust_to_allow_self_wiki: "사용자의 자체 게시물 위키를 만들기 위한 최소 신뢰 레벨입니다." + min_trust_to_send_email_messages: "이메일을 통해 개인 메시지를 보내기 위한 최소 신뢰 레벨입니다." + min_trust_to_flag_posts: "게시물을 신고하기 위한 최소 신뢰 레벨" + min_trust_to_post_links: "게시물에 링크를 포함하기 위한 최소 신뢰 레벨" + min_trust_to_post_embedded_media: "게시물에 미디어 항목을 임베드하기 위한 최소 신뢰 레벨" + min_trust_level_to_allow_profile_background: "프로필 배경을 업로드하기 위한 최소 신뢰 레벨" + min_trust_level_to_allow_user_card_background: "사용자 카드 배경을 업로드하기 위한 최소 신뢰 레벨" + min_trust_level_to_allow_invite: "사용자를 초대하기 위한 최소 신뢰 레벨" + min_trust_level_to_allow_ignore: "사용자를 무시하기 위한 최소 신뢰 레벨" + allowed_link_domains: "링크를 게시할 수 있는 레벨이 아닌 사용자가 링크할 수 있는 도메인" + newuser_max_links: "신규 사용자가 게시물에 추가할 수 있는 링크 수입니다." + newuser_max_embedded_media: "신규 사용자가 게시물에 추가할 수 있는 임베디드 미디어 항목 수입니다." + newuser_max_attachments: "신규 사용자가 게시물에 추가할 수 있는 최대 첨부 파일 수입니다." + newuser_max_mentions_per_post: "신규 사용자가 게시물에서 쓸 수 있는 최대 @이름 알림 수입니다." + newuser_max_replies_per_topic: "다른 사용자가 댓글을 달기 전, 신규 사용자가 단일 주제에 달 수 있는 최대 댓글 수입니다." + max_mentions_per_post: "게시물에 사용할 수 있는 최대 @이름 알림 수입니다." + max_users_notified_per_group_mention: "그룹이 멘션된 경우 알림을 받을 수 있는 최대 사용자 수(한계치에 도달하면 알림이 발생하지 않음)" + enable_mentions: "사용자가 다른 사용자를 멘션하도록 허용합니다." + create_thumbnails: "너무 커서 게시물에 맞지 않는 섬네일 이미지와 라이트박스 이미지를 만듭니다." + email_time_window_mins: "알림 이메일을 보내기 전에 (n)분 정도 기다려서 사용자가 게시물을 편집하고 마무리하도록 합니다." + personal_email_time_window_seconds: "개인 메시지를 보내기 전에 (n)초 정도 기다려서 사용자가 메시지를 편집하고 마무리하도록 합니다." + email_posts_context: "알림 이메일의 콘텐츠로 추가할 기존 댓글 수입니다." + flush_timings_secs: "타이밍 데이터를 서버로 플러시하는 주기(초)입니다." + title_max_word_length: "주제 제목 내 허용되는 최대 단어 길이(문자)입니다." + title_min_entropy: "주제 제목에 필요한 최소 엔트로피(고유 문자, 초과할 경우 영어가 아닌 문자 수)입니다." + body_min_entropy: "게시물 본문에 필요한 최소 엔트로피(고유 문자, 초과할 경우 영어가 아닌 문자 수)입니다." + allow_uppercase_posts: "주제 제목 또는 게시물 본문에서 모든 대문자를 허용합니다." + max_consecutive_replies: "사용자가 다른 댓글을 추가할 수 없도록 하기 전에 한 주제에서 연속으로 작성해야 하는 게시물 수입니다." + enable_filtered_replies_view: '''(n)개의 댓글'' 버튼은 다른 모든 게시물을 접고 현재 게시물과 댓글만 표시합니다.' + title_fancy_entities: "일반적인 ASCII 문자를 주제 제목의 멋진 HTML 엔티티로 변환합니다. 예: SmartyPants https://daringfireball.net/projects/smartypants/" + min_title_similar_length: "유사 주제를 확인하기 전 최소 제목 길이입니다." + desktop_category_page_style: "/categories 페이지의 비주얼 스타일입니다." + category_colors: "카테고리에 허용된 16진수 색상 값의 목록입니다." + category_style: "카테고리 배지의 비주얼 스타일입니다." + default_dark_mode_color_scheme_id: "다크 모드에서 사용되는 색상 구성표입니다." dark_mode_none: "없음" - max_image_size_kb: "최대 이미지 업로드 크기 (KB)입니다. 이것은 nginx (client_max_body_size) / 아파치 또는 프록시에서도 구성해야합니다. 이보다 크고 client_max_body_size보다 작은 이미지는 업로드에 맞게 크기가 조정됩니다." - max_attachment_size_kb: "최대 첨부파일 업로드 사이즈(kB). 이 설정은 꼭 nginx / apache와 proxy에도 적용해야 합니다." - authorized_extensions: "파일 업로드에 허용되는 확장자 리스트 ('*'을 사용하면 모든 타입의 파일이 가능합니다.)" - authorized_extensions_for_staff: "`authorized_extensions` 사이트 설정에 정의 된 목록 외에 직원 사용자가 업로드 할 수있는 파일 확장자 목록입니다. (모든 파일 형식을 활성화하려면 '*'를 사용하십시오)" - theme_authorized_extensions: "테마 업로드에 허용되는 확장자 목록('*'를 입력하면 모든 확장자 허용)" - max_similar_results: "새로운 글타래를 작성할 때, 에디터 위에 보여줄 비슷한 글타래들의 개수. 제목과 본문을 바탕으로 비교합니다." - max_image_megapixels: "이미지에 허용되는 최대 메가 픽셀 수입니다. 메가 픽셀 수가 많은 이미지는 거부됩니다." - title_prettify: "일반적인 제목의 오타 및 오류를 수정해준다. 모두 대문자로 쓰거나, 첫자가 소문자이거나(영문), 복수의 !, ? 혹은 마침표(.)가 중복으로 들어간 것 등" - title_remove_extraneous_space: "구두점 끝 부분 앞의 공백을 제거합니다." - automatic_topic_heat_values: '사이트 활동에 따라 "주제 조회 열"및 "주제 열과 같은 주제"설정을 자동으로 업데이트합니다.' - topic_views_heat_low: "글타래가 연하게 하이라이트 되기 위한 조회수" - topic_views_heat_medium: "글타래가 적당하게 하이라이트 되기 위한 조회수" - topic_views_heat_high: "글타래가 진하게 하이라이트 되기 위한 조회수" - cold_age_days_low: "글의 마지막 활동 날짜가 조금 희미해지기 시작하는 일 수" - cold_age_days_medium: "글의 마지막 활동 날짜가 어느정도 희미해지기 시작하는 일 수" - cold_age_days_high: "글의 마지막 활동 날짜가 많이 희미해지기 시작하는 일 수" - history_hours_low: "글이 수정 뒤에 수정됐다는 표시가 조금 희미해지는 시간" - history_hours_medium: "글이 수정 뒤에 수정됐다는 표시가 어느정도 희미해지는 시간" - history_hours_high: "글이 수정 뒤에 수정됐다는 표시가 많이 희미해지는 시간" - topic_post_like_heat_low: "조회수가 조금 희미해지는 이 글:좋아요 비율" - topic_post_like_heat_medium: "조회수가 어느정도 희미해지는 이 글:좋아요 비율" - topic_post_like_heat_high: "조회수가 많이 희미해지는 이 글:좋아요 비율" - faq_url: "사용하려는 다른 곳의 FAQ가 있는 경우 여기에 전체 URL을 입력하세요." - tos_url: "이용약관이 있으면 전체 URL을 적어주세요." - privacy_policy_url: "개인정보 보호가 있으면 전체 URL을 적어주세요." - log_anonymizer_details: "익명화 된 후 사용자 세부 정보를 로그에 유지할지 여부 GDPR을 준수 할 때는이 기능을 해제해야합니다." - newuser_spam_host_threshold: "새로운 사용자가 동일한 호스트의 링크를 포스팅하더라도 스팸으로 간주되지 않는 최대 포스팅 수 `newuser_spam_host_threshold`" - allowed_spam_host_domains: "스팸 호스트 테스트에서 제외 된 도메인 목록입니다. 신규 사용자는 이러한 도메인에 대한 링크가있는 게시물을 작성하는데 제한을 받지 않습니다." - staff_like_weight: "관리자의 좋아요에 부여 할 가중치 (일반 회원의 가중치는 1임)" - topic_view_duration_hours: "N 시간마다 IP/User 별로 새 토픽 조회수를 셉니다." - user_profile_view_duration_hours: "N 시간마다 IP/User 별로 새 프로필 조회수를 셉니다." - levenshtein_distance_spammer_emails: "스패머 메일을 체크할 때, 허용할 다른 글자 개수(fuzzy match)" - min_ban_entries_for_roll_up: "Roll up 버튼을 눌렀을 때, 적어도 (N)개의 엔트리가 있다면 새 subnet ban 엔트리를 만듭니다." - max_age_unmatched_emails: "(N)일 뒤에 안 맞는 막힌 이메일 접근을 지웁니다." - max_age_unmatched_ips: "(N)일 뒤에 안 맞는 막힌 IP 접근을 지웁니다." - num_flaggers_to_close_topic: "추후 중재를 위해 자동으로 글타래를 일시정지시킬 최소 신고자 수" - num_hours_to_close_topic: "운영진 중재를 위하여 토픽을 중지시킬 시간" - auto_respond_to_flag_actions: "신고 기각 시 자동 답변 활성화" - min_first_post_typing_time: "사용자가 첫번째 포스트를 작성할 때 타이핑에 소요해야 하는 밀리초. 설정값에 도달하지 않았을 때는 자동으로 승인 큐에 포함됩니다. 승인 0으로 설정하면 해제됩니다.(해제는 권장하지 않습니다)" - auto_silence_fast_typers_on_first_post: "min_first_post_typing_time을 충족하지 않는 사용자를 자동으로 쓰기 금지 시킵니다." - auto_silence_fast_typers_max_trust_level: "빠른 타이퍼를 자동으로 쓰기 금지 시키기 위한 최대 신뢰 수준" - reviewable_claiming: "검토 가능한 컨텐츠를 사용하려면 먼저 컨텐츠를 청구해야합니까?" - reviewable_default_topics: "기본적으로 주제별로 그룹화 된 검토 가능한 컨텐츠 표시" - reviewable_default_visibility: "이 우선 순위를 충족하지 않으면 검토 가능한 항목을 표시하지 않습니다." - high_trust_flaggers_auto_hide_posts: "TL3 + 사용자가 스팸으로 신고 한 후 새로운 사용자 게시물이 자동으로 숨겨 짐" - cooldown_hours_until_reflag: "게시물을 다시 게시 할 수있을 때까지 사용자가 기다려야하는 시간" - reply_by_email_enabled: "이메일을 통해 주제에 답글을 달 수 있음." - reply_by_email_address: "이메일 주소로 답글을 다는 템플릿. 예: %%{reply_key}@reply.myforum.com" - alternative_reply_by_email_addresses: "수신된 이메일에 대한 답장메일의 대체 템플릿 목록. 예: %%{reply_key}@reply.example.com|replies+%%{reply_key}@example.com" - incoming_email_prefer_html: "수신 이메일에 텍스트 대신 HTML을 사용하십시오." - strip_incoming_email_lines: "수신 이메일의 각 줄에서 앞뒤 공백을 제거하십시오." - disable_emails: "Discourse가 어떤 종류의 이메일도 보내지 못하도록합니다. 모든 사용자에 대해 이메일을 비활성화하려면 '예'를 선택하십시오. 관리자가 아닌 사용자에게만 이메일을 사용하지 않으려면 '비 관리자'을 선택합니다." - strip_images_from_short_emails: "2800바이트, 즉 2.73 KB 이내 사이즈를 가지도록 이미지를 빼주세요." - short_email_length: "짦은 이메일 바이트 길이" - display_name_on_email_from: "이메일 보낸사람 필드에 전체 이름을 표시" - unsubscribe_via_email: "사용자가 이메일 제목이나 내용에 'unsubscribe' 를 포함시켜서 답장하면 이메일 구독을 해지가 되도록 허용" - unsubscribe_via_email_footer: "이메일의 하단에 이메일 mailto: 링크 방식의 구독해지 링크를 첨부하기" - delete_email_logs_after_days: "(N) 일이 지나면 이메일 로그 삭제하기. 0으로 설정하면 삭제하지 않음" - disallow_reply_by_email_after_days: "(N) 일 후 이메일로 회신을 허용하지 않습니다. 무기한으로 유지하려면 0" - max_emails_per_day_per_user: "사용자에게 보낼 이메일의 하루 최대치. 0으로 설정하면 제한없음." - enable_staged_users: "수신 이메일 처리 중일 때 자동으로 격리된 회원 생성." - maximum_staged_users_per_email: "수신된 이메일을 처리하는 동안 생성할 최대 격리회원 수" + max_image_size_kb: "최대 이미지 업로드 크기(KB)입니다. 이는 nginx(client_max_body_size) / Apache 또는 프록시에서도 환경설정되어야 합니다. 이보다 크고 client_max_body_size보다 작은 이미지는 업로드 시 크기에 맞게 조정됩니다." + max_attachment_size_kb: "최대 첨부 파일 업로드 크기(KB)입니다. 이는 nginx(client_max_body_size) / Apache 또는 프록시에서도 환경설정되어야 합니다." + authorized_extensions: "업로드에 허용되는 파일 확장자 목록('*'을 사용하면 모든 파일 유형 허용)" + authorized_extensions_for_staff: "`authorized_extensions` 사이트 설정에 정의된 목록 외에 운영진이 업로드할 수 있는 파일 확장자 목록입니다. ('*'을 사용하면 모든 파일 유형 허용)" + theme_authorized_extensions: "테마 업로드에 허용되는 파일 확장자 목록('*'을 사용하면 모든 파일 유형 허용)" + max_similar_results: "새 주제를 작성할 때 에디터 위에 표시할 유사 주제의 수입니다. 비교는 제목과 본문을 기준으로 합니다." + max_image_megapixels: "이미지에 허용되는 최대 메가픽셀 수입니다. 메가픽셀 수가 많은 이미지는 거부됩니다." + title_prettify: "모두 대문자 표기, 소문자로 시작, 중복된 ! 및 ?, 문장 뒤 불필요한 추가 마침표 등 일반적인 제목 오타 및 오류를 방지합니다." + title_remove_extraneous_space: "마침표 앞의 공백을 제거합니다." + automatic_topic_heat_values: '사이트 활동을 기반으로 ''주제 조회수 빈도'' 및 ''주제 게시물 좋아요 빈도'' 설정을 자동으로 업데이트합니다.' + topic_views_heat_low: "이 정도의 조회수를 달성하면 조회수 필드가 약간 하이라이트됩니다." + topic_views_heat_medium: "이 정도의 조회수를 달성하면 조회수 필드가 중간 정도로 하이라이트됩니다." + topic_views_heat_high: "이 정도의 조회수를 달성하면 조회수 필드가 진하게 하이라이트됩니다." + cold_age_days_low: "이 정도의 대화 일수를 달성하면 마지막 활동 날짜가 약간 흐려집니다." + cold_age_days_medium: "이 정도의 대화 일수를 달성하면 마지막 활동 날짜가 중간 정도로 흐려집니다." + cold_age_days_high: "이 정도의 대화 일수를 달성하면 마지막 활동 날짜가 많이 흐려집니다." + history_hours_low: "이 시간 내에 편집된 게시물은 편집 표시기가 약간 하이라이트됩니다." + history_hours_medium: "이 시간 내에 편집된 게시물은 편집 표시기가 중간 정도로 하이라이트됩니다." + history_hours_high: "이 시간 내에 편집된 게시물은 편집 표시기가 진하게 하이라이트됩니다." + topic_post_like_heat_low: "좋아요:게시물 비율이 이 비율을 초과하면 게시물 수 필드가 약간 하이라이트됩니다." + topic_post_like_heat_medium: "좋아요:게시물 비율이 이 비율을 초과하면 게시물 수 필드가 중간 정도로 하이라이트됩니다." + topic_post_like_heat_high: "좋아요:게시물 비율이 이 비율을 초과하면 게시물 수 필드가 진하게 하이라이트됩니다." + faq_url: "사용하려는 다른 곳의 호스팅된 FAQ가 있는 경우 여기에 전체 URL을 입력하세요." + tos_url: "사용하려는 다른 곳의 호스팅된 이용약관 문서가 있는 경우 여기에 전체 URL을 입력하세요." + privacy_policy_url: "사용하려는 다른 곳의 호스팅된 개인정보 취급방침 문서가 있는 경우 여기에 전체 URL을 입력하세요." + log_anonymizer_details: "익명화된 후 사용자의 상세 정보를 로그에 유지할지 여부입니다. GDPR을 준수하면 이 기능을 꺼야 합니다." + newuser_spam_host_threshold: "신규 사용자가 스팸으로 간주되기 전에 `newuser_spam_host_threshold` 게시물 내에서 동일한 호스트로의 링크를 게시할 수 있는 횟수입니다." + allowed_spam_host_domains: "스팸 호스트 테스트에서 제외된 도메인 목록입니다. 신규 사용자는 이러한 도메인으로의 링크가 있는 게시물을 작성하는 데 제한을 받지 않습니다." + staff_like_weight: "운영진의 좋아요에 부여할 가중치(일반 회원의 가중치는 1임)" + topic_view_duration_hours: "N시간마다 IP/사용자별로 새 주제 조회수를 계산합니다." + user_profile_view_duration_hours: "N시간마다 IP/사용자별로 신규 사용자 프로필 조회수를 계산합니다." + levenshtein_distance_spammer_emails: "스팸 발송자 이메일을 일치시킬 때 일부 일치를 허용하는 문자 수 차이입니다." + min_ban_entries_for_roll_up: "롤업 버튼을 클릭하면 최소 (N)개 엔트리가 있는 경우 새 서브넷 금지 엔트리가 생성됩니다." + max_age_unmatched_emails: "(N)일 후 일치하지 않는 스크린된 이메일 엔트리를 삭제합니다." + max_age_unmatched_ips: "(N)일 후 일치하지 않는 스크린된 IP 엔트리를 삭제합니다." + num_flaggers_to_close_topic: "중재를 위해 주제를 자동으로 일시 중지하기 위한 최소 고유 신고자 수" + num_hours_to_close_topic: "중재를 위해 주제를 일시 중지하는 시간입니다." + auto_respond_to_flag_actions: "신고를 제거할 때 자동 댓글을 활성화합니다." + min_first_post_typing_time: "사용자가 첫 게시 중에 입력해야 하는 최소 시간(밀리초)입니다. 한계치가 충족되지 않으면 게시물이 자동으로 필요 승인 대기열에 들어갑니다. 비활성화하려면 0으로 설정합니다(권장하지 않음)." + auto_silence_fast_typers_on_first_post: "min_first_post_typing_time 시간을 충족하지 않는 사용자를 자동으로 차단" + auto_silence_fast_typers_max_trust_level: "빠른 게시자를 자동으로 차단하기 위한 최대 신뢰 레벨" + reviewable_claiming: "검토 가능한 콘텐츠에 대해 조치를 취하려면 먼저 독점해야 하나요?" + reviewable_default_topics: "기본적으로 주제별로 그룹화된 검토 가능한 콘텐츠 표시" + reviewable_default_visibility: "이 우선순위를 충족하지 않으면 검토 가능한 항목을 표시하지 않음" + high_trust_flaggers_auto_hide_posts: "TL3+ 사용자가 스팸으로 신고한 후 신규 사용자 게시물이 자동으로 숨겨짐" + cooldown_hours_until_reflag: "게시물을 다시 신고할 수 있을 때까지 사용자가 기다려야 하는 시간" + reply_by_email_enabled: "이메일을 통해 주제에 댓글 달기를 활성화합니다." + reply_by_email_address: "이메일 주소로 댓글 달기 템플릿. 예: %%{reply_key}@reply.myforum.com" + alternative_reply_by_email_addresses: "수신 이메일 주소로 회신 이메일을 보내는 데 사용하는 대체 템플릿 목록입니다. 예: %%{reply_key}@reply.example.com|replies+%%{reply_key}@example.com" + incoming_email_prefer_html: "수신 이메일에 텍스트 대신 HTML을 사용합니다." + strip_incoming_email_lines: "수신 이메일의 각 줄에서 앞뒤 공백을 제거합니다." + disable_emails: "Discourse에서 모든 유형의 이메일을 보내지 못하도록 합니다. 모든 사용자의 이메일을 비활성화하려면 '예'를 선택합니다. 운영진이 아닌 사용자에 대해서만 이메일을 비활성화하려면 '비운영진'을 선택하세요." + strip_images_from_short_emails: "2800바이트, 즉 2.73KB 이내 크기를 가지도록 이메일에서 이미지 제거" + short_email_length: "짦은 이메일 길이(바이트)" + display_name_on_email_from: "이메일 보내는 사람 필드에 전체 이름 표시" + unsubscribe_via_email: "사용자가 이메일 제목이나 본문에 '구독 해제'를 포함하여 답장하면 이메일을 구독 해제하도록 허용" + unsubscribe_via_email_footer: "이메일 바닥글에 mailto: 이메일 링크 방식의 구독 해제 첨부" + delete_email_logs_after_days: "(N)일 후 이메일 로그를 삭제합니다. 0으로 설정하면 무기한 유지" + disallow_reply_by_email_after_days: "(N)일 후 이메일 회신을 허용하지 않습니다. 0으로 설정하면 무기한 유지" + max_emails_per_day_per_user: "사용자에게 전송할 일일 최대 이메일 수입니다. 0으로 설정하면 제한 없음" + enable_staged_users: "수신 이메일을 처리할 때 스테이징된 사용자를 자동으로 생성합니다." + maximum_staged_users_per_email: "수신 이메일을 처리할 때 생성된 최대 스테이징된 사용자 수입니다." auto_generated_allowlist: "자동 생성된 콘텐츠를 확인하지 않을 이메일 주소 목록입니다. 예: foo@bar.com|discourse@bar.com" - block_auto_generated_emails: "자동 생성된 이메일로 확인된 수신 이메일 차단." - ignore_by_title: "제목을 기준으로 수신 메일 무시." - mailgun_api_key: "webhook 메시지를 확인할 Mailgun Secret API 키" - soft_bounce_score: "임시 반송이 일어났을 때 사용자에게 반송 스코어 추가." - hard_bounce_score: "영구 반송이 일어났을 때 사용자에게 반송 스코어 추가." - bounce_score_threshold: "사용자에게 메일을 보낼 최대 반송 스코어." - reset_bounce_score_after_days: "X 일 이후 반송 스코어 자동 초기화." - blocked_attachment_content_types: "콘텐츠 유형에 따라 첨부 파일을 차단하는데 사용되는 키워드 목록입니다." - blocked_attachment_filenames: "파일 이름을 기준으로 첨부 파일을 차단하는데 사용되는 키워드 목록입니다." - forwarded_emails_behaviour: "Discourse로 전달 된 이메일을 처리하는 방법" - always_show_trimmed_content: "항상 수신 메일의 다듬어진 부분을 표시. 경고: 메일 주소가 드러날 수 있습니다." - trim_incoming_emails: "관련이 없는 수신 이메일의 일부를 잘라냅니다." - private_email: "이메일 제목이나 이메일 본문에 게시물이나 주제의 컨텐츠를 포함하지 마십시오. 참고 : 다이제스트 이메일도 비활성화합니다." - email_total_attachment_size_limit_kb: "발신 이메일에 첨부되는 파일의 최대 총 크기(KB) 입니다. 첨부 파일 전송을 비활성화하려면 0 으로 설정합니다." - post_excerpts_in_emails: "알림 이메일에서 항상 전체 게시물 대신 발췌문을 보내십시오." - raw_email_max_length: "수신 이메일에 저장해야하는 문자 수" - raw_rejected_email_max_length: "수신 거부 이메일에 저장해야하는 문자 수" - delete_rejected_email_after_days: "(n) 일이 지난 거부 된 이메일을 삭제합니다." - manual_polling_enabled: "이메일 답장을 위한 API를 사용하여 이메일 푸시" - pop3_polling_enabled: "POP3를 이용한 이메일 설문조사" - pop3_polling_ssl: "SSL로 POP3 서버를 연결합니다. (추천)" - pop3_polling_openssl_verify: "TLS 서버 인증서 검증 (기본값: 적용)" - pop3_polling_period_mins: "이메일을 받기 위해 POP3S 계정을 체크하는 분 단위 NOTE: 재시동 필요." - pop3_polling_port: "이메일 설문조사를 위한 POP3 포트번호 " - pop3_polling_host: "이메일 설문조사를 위한 POP3 호스트" - pop3_polling_username: "이메일 설문조사를 위한 POP3 사용자 계정 이름" - pop3_polling_password: "이메일 설문조사를 위한 POP3 사용자 비밀번호" - pop3_polling_delete_from_server: "서버에서 이메일을 삭제하십시오. 참고 :이 기능을 비활성화하면 메일받은 편지함을 수동으로 정리해야합니다." - log_mail_processing_failures: "모든 이메일 처리 실패를 / logs에 기록" - email_in: '사용자가 이메일을 통해 새 주제를 게시 할 수 있습니다 (수동 또는 pop3 폴링 필요). 각 카테고리의 "설정"탭에서 주소를 구성하십시오.' - email_in_min_trust: "이메일을 통해 새 글타래를 포스팅 할 수 있는 최소 사용자 회원등급" - email_in_authserv_id: "수신 이메일에서 인증 검사를 수행하는 서비스의 식별자입니다. 이를 구성하는 방법에 대한 지침은 https://meta.discourse.org/t/134358 을 참조 하십시오 ." + block_auto_generated_emails: "자동 생성된 이메일로 식별된 수신 이메일을 차단합니다." + ignore_by_title: "제목을 기준으로 수신 이메일을 무시합니다." + mailgun_api_key: "Webhook 메시지를 검증할 Mailgun Secret API 키입니다." + soft_bounce_score: "임시 반송 발생 시 사용자에게 추가된 반송 스코어입니다." + hard_bounce_score: "영구 반송 발생 시 사용자에게 추가된 반송 스코어입니다." + bounce_score_threshold: "사용자에게 이메일 전송을 중지하기 전 최대 반송 스코어입니다." + reset_bounce_score_after_days: "X일 후 반송 스코어를 자동 리셋합니다." + blocked_attachment_content_types: "콘텐츠 유형에 따라 첨부 파일을 차단하기 위한 키워드 목록입니다." + blocked_attachment_filenames: "파일명을 기준으로 첨부 파일을 차단하기 위한 키워드 목록입니다." + forwarded_emails_behaviour: "Discourse로 전달된 이메일을 처리하는 방법" + always_show_trimmed_content: "수신 이메일의 잘린 부분을 항상 표시합니다. 경고: 이메일 주소가 노출될 수 있습니다." + trim_incoming_emails: "수신 이메일 중 관련이 없는 부분을 잘라냅니다." + private_email: "이메일 제목이나 본문에 게시물이나 주제의 콘텐츠를 포함하지 마세요. 참고: 다이제스트 이메일도 비활성화합니다." + email_total_attachment_size_limit_kb: "보내는 이메일에 첨부된 파일의 최대 총 크기(kB)입니다. 첨부 파일 전송을 비활성화하려면 0으로 설정하세요." + post_excerpts_in_emails: "알림 이메일에서 항상 전체 게시물 대신 발췌문을 보내세요." + raw_email_max_length: "수신 이메일에 저장해야 하는 문자 수입니다." + raw_rejected_email_max_length: "거부된 수신 이메일에 저장해야 하는 문자 수입니다." + delete_rejected_email_after_days: "(n)일 지난 거부된 이메일을 삭제합니다." + manual_polling_enabled: "이메일 답장을 위해 API를 사용하여 이메일을 푸시합니다." + pop3_polling_enabled: "이메일 답장을 위해 POP3로 폴링합니다." + pop3_polling_ssl: "POP3 서버 연결 중 SSL을 사용합니다. (추천)" + pop3_polling_openssl_verify: "TLS 서버 인증서 검증(디폴트: 활성화됨)" + pop3_polling_period_mins: "POP3 계정에서 이메일을 확인하는 간격(분)입니다. 참고: 재시작해야 합니다." + pop3_polling_port: "POP3 계정을 폴링할 포트입니다. " + pop3_polling_host: "POP3를 통해 이메일을 폴링할 호스트입니다." + pop3_polling_username: "이메일을 폴링할 POP3 계정의 아이디입니다." + pop3_polling_password: "이메일을 폴링할 POP3 계정의 비밀번호입니다." + pop3_polling_delete_from_server: "서버에서 이메일을 삭제하세요. 참고: 이 기능을 비활성화하면 받은 편지함을 수동으로 정리해야 합니다." + log_mail_processing_failures: "모든 이메일 처리 실패를 /logs에 기록" + email_in: '사용자가 이메일을 통해 새 주제를 게시할 수 있도록 허용합니다(수동 또는 pop3 폴링 필요). 각 카테고리의 ''설정'' 탭에서 주소를 환경설정합니다.' + email_in_min_trust: "이메일을 통해 새 주제를 게시하기 위한 사용자의 최소 신뢰 레벨" + email_in_authserv_id: "수신 이메일에 대한 인증 확인을 수행하는 서비스의 식별자입니다. 이를 환경설정하는 방법에 대한 지침은 https://meta.discourse.org/t/134358을 참조하세요." email_in_spam_header: "스팸을 탐지하는 이메일 헤더입니다." - enable_imap: "그룹 메시지를 동기화하기 위해 IMAP을 사용하도록 설정합니다." - enable_imap_write: "양방향 IMAP 동기화를 사용합니다. 비활성화하면 IMAP 계정에 대한 모든 쓰기 작업이 비활성화됩니다." - enable_imap_idle: "새로운 이메일을 기다리는 IMAP IDLE 메커니즘을 사용합니다." - enable_smtp: "그룹 메시지에 대한 알림을 보내기 위해 SMTP를 사용하도록 설정합니다." - imap_polling_period_mins: "IMAP 계정에서 이메일을 확인하는 간격(분) 입니다." - imap_polling_old_emails: "IMAP 상자가 폴링 될 때마다 업데이트 될 (처리 된) 이전 이메일의 최대 수입니다 (모두 0)." - imap_polling_new_emails: "IMAP 상자가 폴링 될 때마다 업데이트되는 (처리되지 않은) 새 이메일의 최대 수입니다." - imap_batch_import_email: "가져오기 모드를 트리거하는 새 이메일의 최소 수입니다 (게시물 알림 비활성화)." - email_prefix: "이메일 제목에 쓰일 [라벨]. 설정하지 않으면 기본적으로 'title(필수 설정의)' 이 된다." - email_site_title: "사이트에서 전송되는 이메일의 보내는 이를 사이트 이름으로 설정. 설정하지 않으면 'title(필수 설정의)'이 된다. 만약 'title'에 보내는 이에 허용되지 않는 글자가 포함되어 있으면 이 설정이 사용된다." - find_related_post_with_key: "답글을 게시하려면 '답장 키'만 사용하십시오. 경고 :이 기능을 비활성화하면 이메일 주소를 기반으로 사용자 가장이 허용됩니다." - minimum_topics_similar: "새로운 글타래를 작성할 때, 유사한 글타래들을 보여주기 위해 존재해야 할 최소 글타래 개수" - relative_date_duration: "절대적 날짜(9월 3일) 대신 상대적 날짜(7일 전)가 사용될 일 수 (글타래가 작성된 이후부터)" - delete_user_max_post_age: "(x)일 이전의 첫 글가 있는 유저는 삭제할 수 없음." - delete_all_posts_max: "전체 글 지우기 버튼을 통해 한번에 삭제할 수 있는 최대 글 수. 만약 사용자가 이것보다 많은 글을 가지고 있으면 한번에 삭제 할 수 없다." - delete_user_self_max_post_count: "셀프 서비스 계정 삭제를 허용하면서 사용자가 가질 수있는 최대 게시물 수입니다. 셀프 서비스 계정 삭제를 비활성화하려면 -1로 설정하십시오." - username_change_period: "등록 후 계정이 사용자 이름을 변경할 수있는 최대 일수입니다 (0은 사용자 이름 변경을 허용하지 않음)." - email_editable: "가입 후 이메일 주소 변경 허용" - logout_redirect: "로그 아웃 후 브라우저를 리디렉션 할 위치 (예 : https://example.com/logout)" - allow_uploaded_avatars: "사용자가 커스텀 프로필 사진을 올릴 수 있도록 허용." - default_avatars: "신규가입자가 받게될 기본 아바타 URL" - automatically_download_gravatars: "사용자가 계정을 만들거나 이메일을 변경하자마자 Gravatar를 다운로드합니다." - digest_topics: "요약 이메일에 표시할 인기 토픽의 최대 개수." - digest_posts: "요약 이메일에 표시할 인기 포스트의 최대 개수." - digest_other_topics: "요약 이메일의 '신규 토픽과 팔로우하는 카테고리'에 표시되는 토픽의 최대 개수." - digest_min_excerpt_length: "요약 이메일에서 발췌된 포스트의 최소 표시 글자 수." - suppress_digest_email_after_days: "(n) 일 이상 사이트를 방문하지 않은 사용자에게는 요약 이메일 보내지 않기." - digest_suppress_categories: "요약 이메일에서 이 카테고리 숨기기." - disable_digest_emails: "모든 사용자에게 요약 이메일 전송 해제하기" - apply_custom_styles_to_digest: "사용자 정의 이메일 템플릿 및 CSS는 요약 이메일에 적용됩니다." - email_accent_bg_color: "HTML 이메일에서 일부 요소의 배경으로 사용되는 강조 색입니다. 색상 이름 ( '빨간색') 또는 16 진수 값 ( '# FF0000')을 입력하십시오." - email_accent_fg_color: "텍스트 컬러는 HTML 이메일의 배경색상으로 렌더링됩니다. 색상명('white')나 hex값('#FFFFFF')을 입력하세요." - email_link_color: "HTML 이메일의 링크 색상. 색상명('blue')나 hex값('#0000FF')를 입력하세요." - detect_custom_avatars: "사용자가 커스텀 프로필 사진을 올렸는지의 체크 여부." - max_daily_gravatar_crawls: "하루에 Discourse가 커스텀 아파타를 위해 Gravatar를 체크하는 최대 횟수" - public_user_custom_fields: "API를 사용하여 검색 할 수있는 사용자 정의 필드 목록입니다." - staff_user_custom_fields: "API를 사용하여 직원을 위해 검색 할 수있는 사용자 정의 필드 목록입니다." - enable_user_directory: "브라우징을 위한 유저의 디렉토리 제공" - enable_group_directory: "브라우징을 위한 그룹의 디렉토리 제공" + enable_imap: "그룹 메시지를 동기화하기 위해 IMAP을 활성화합니다." + enable_imap_write: "양방향 IMAP 동기화를 활성화합니다. 비활성화하면 IMAP 계정에 대한 모든 쓰기 작업이 비활성화됩니다." + enable_imap_idle: "새 이메일을 기다리는 IMAP IDLE 메커니즘을 사용합니다." + enable_smtp: "그룹 메시지에 대한 알림을 보내기 위해 SMTP를 활성화합니다." + imap_polling_period_mins: "IMAP 계정에서 이메일을 확인하는 간격(분)입니다." + imap_polling_old_emails: "IMAP 상자가 폴링될 때마다 업데이트되는 오래된 이메일(처리됨)의 최대 개수(모두 하려면 0)입니다." + imap_polling_new_emails: "IMAP 상자가 폴링될 때마다 업데이트되는 새 이메일(처리 안 됨)의 최대 개수입니다." + imap_batch_import_email: "임포트 모드를 트리거하는 새 이메일의 최소 개수입니다(임포트한 게시물 알림 비활성화)." + email_prefix: "이메일 제목에 사용할 [라벨]입니다. 설정하지 않으면 기본적으로 '제목'이 됩니다." + email_site_title: "사이트에서 이메일의 발신자로 사용되는 사이트 제목입니다. 설정하지 않으면 기본적으로 '제목'이 됩니다. '제목'에 이메일 발신자 스트링에 허용되지 않는 문자가 포함된 경우 이 설정을 사용하세요." + find_related_post_with_key: "댓글을 달은 게시물을 찾으려면 '댓글 키'만 사용하세요. 경고: 이 기능을 비활성화하면 이메일 주소를 기반으로 사용자 가장이 허용됩니다." + minimum_topics_similar: "새 주제를 작성할 때 유사한 주제가 표시되기 전에 존재해야 하는 주제 수입니다." + relative_date_duration: "게시 날짜가 절대적(2월 20일) 대신 상대적(7일)으로 표시되는 게시 후 일 수입니다." + delete_user_max_post_age: "첫 게시물이 (x)일보다 오래된 사용자 삭제를 허용하지 않습니다." + delete_all_posts_max: "전체 게시물 삭제 버튼으로 한 번에 삭제할 수 있는 최대 게시물 수입니다. 사용자의 게시물이 이보다 많을 경우 게시물을 한 번에 모두 삭제할 수 없으며 사용자를 삭제할 수도 없습니다." + delete_user_self_max_post_count: "셀프 서비스 계정 삭제를 허용하는 동안 사용자가 가질 수 있는 최대 게시물 수입니다. 셀프 서비스 계정 삭제를 비활성화하려면 -1로 설정합니다." + username_change_period: "계정에서 아이디를 변경할 수 있는 등록 후 최대 일 수(아이디 변경을 허용하지 않으려면 0)입니다." + email_editable: "등록 후 사용자가 이메일 주소를 변경하도록 허용합니다." + logout_redirect: "로그아웃 후 브라우저를 리디렉션할 위치(예: https://example.com/logout)" + allow_uploaded_avatars: "사용자가 사용자 지정 프로필 사진을 업로드하도록 허용합니다." + default_avatars: "신규 사용자가 변경할 때까지 기본적으로 사용되는 아바타의 URL입니다." + automatically_download_gravatars: "계정 생성 또는 이메일 변경 시 사용자용 Gravatar를 다운로드합니다." + digest_topics: "이메일 요약에 표시할 인기 주제의 최대 개수입니다." + digest_posts: "이메일 요약에 표시할 인기 게시물의 최대 개수입니다." + digest_other_topics: "이메일 요약의 '내가 팔로우하는 주제 및 카테고리의 새 항목' 섹션에 표시할 최대 주제 수입니다." + digest_min_excerpt_length: "요약 이메일의 최소 게시물 발췌(문자)" + suppress_digest_email_after_days: "(n)일 이상 사이트를 방문하지 않은 사용자에게 요약 이메일을 보내지 않습니다." + digest_suppress_categories: "요약 이메일에서 이 카테고리를 표시하지 않습니다." + disable_digest_emails: "모든 사용자에게 요약 이메일을 전송하지 않습니다." + apply_custom_styles_to_digest: "사용자 지정 이메일 템플릿 및 CSS가 요약 이메일에 적용됩니다." + email_accent_bg_color: "HTML 이메일에서 일부 요소의 배경으로 사용되는 강조 색상입니다. 색상 이름('빨간색') 또는 16진수 값('#FF0000')을 입력합니다." + email_accent_fg_color: "HTML 이메일의 이메일 배경 색상에 렌더링된 텍스트 색상입니다. 색상 이름('흰색') 또는 16진수 값('#FFFFFF')을 입력합니다." + email_link_color: "HTML 이메일의 링크 색상입니다. 색상 이름('파란색') 또는 16진수 값('#0000FF')을 입력합니다." + detect_custom_avatars: "사용자가 사용자 지정 프로필 사진을 업로드했는지 여부를 확인합니다." + max_daily_gravatar_crawls: "Discourse에서 사용자 지정 아바타를 위해 Gravatar를 체크하는 일일 최대 횟수" + public_user_custom_fields: "API로 검색할 수 있는 사용자 지정 필드 목록입니다." + staff_user_custom_fields: "운영진을 위해 API로 검색할 수 있는 사용자 지정 필드 목록입니다." + enable_user_directory: "탐색을 위해 사용자의 디렉터리 제공" + enable_group_directory: "탐색을 위해 그룹의 디렉터리 제공" enable_category_group_moderation: "그룹이 특정 카테고리의 콘텐츠를 관리하도록 허용" - group_in_subject: "PM의 첫 번째 그룹 이름으로 이메일 제목에 %%{optional_pm} 을 설정합니다. 참조: 표준 이메일의 제목 형식 사용자 지정" - allow_anonymous_posting: "익명 모드 허용" - anonymous_posting_min_trust_level: "익명 게시 할 수 있는 최소 회원등급" - anonymous_account_duration_minutes: "한 익명이 익명계정을 만들 때 빨리 만드는 걸 막을 분 단위 시간 예: 600으로 정해놓으면 마지막 게시하고 익명 전환 후로 600분이 지나는 즉시 새 계정이 만들어 집니다." - hide_user_profiles_from_public: "익명사용자의 사용자 카드, 사용자 프로필, 사용자 디렉토리 해제." + group_in_subject: "PM의 첫 번째 그룹 이름으로 이메일 제목의 %%{optional_pm} 설정. 참조: 표준 이메일의 제목 형식 사용자 지정" + allow_anonymous_posting: "사용자의 익명 모드 전환 허용" + anonymous_posting_min_trust_level: "익명 게시를 활성화하기 위한 최소 신뢰 레벨" + anonymous_account_duration_minutes: "익명성을 보호하기 위해 각 사용자에 대해 N분마다 새 익명 계정을 만듭니다. 예: 600으로 설정하면 마지막 게시물로부터 600분이 경과하고 사용자가 익명으로 전환하는 즉시 새 익명 계정이 생성됩니다." + hide_user_profiles_from_public: "익명 사용자의 사용자 카드, 사용자 프로필 및 사용자 디렉터리를 비활성화합니다." allow_users_to_hide_profile: "사용자가 자신의 프로필과 현재 상태를 숨기도록 허용" - allow_featured_topic_on_user_profiles: "사용자가 자신의 사용자 카드 및 프로필에있는 주제에 대한 링크를 제공 할 수 있습니다." - show_inactive_accounts: "로그인 한 사용자가 비활성 계정의 프로필을 찾아 볼 수 있도록합니다." - hide_suspension_reasons: "사용자 프로필에 정지 이유를 공개적으로 표시하지 마십시오." - log_personal_messages_views: "다른 사용자 / 그룹에 대해 관리자가 개인 메시지보기를 기록합니다." - ignored_users_count_message_threshold: "이 많은 다른 사용자가 특정 사용자를 무시하면 중재자에게 알립니다." - ignored_users_message_gap_days: "다른 사람이 무시한 사용자에 대해 중재자에게 다시 알리기 전에 기다리는 시간입니다." - clean_up_inactive_users_after_days: "비활성 사용자 (작성한 게시물이 없는 회원 레벨 0)가 정리되기까지의 일 수입니다. 정리를 비활성화 하려면 0으로 설정합니다." - clean_up_unused_staged_users_after_days: "사용하지 않는 준비된 사용자 (게시물 없음)가 제거되기까지의 일 수입니다. 정리를 비활성화하려면 0으로 설정하십시오." - user_selected_primary_groups: "사용자가 자신의 기본 그룹을 설정하도록 허용" - max_notifications_per_user: "이 수를 초과하면 사용자 당 최대 알림 수는 이전 알림이 삭제됩니다. 매주 시행됩니다. 비활성화하려면 0으로 설정" - allowed_user_website_domains: "다음 도메인의 사용자 웹사이트는 확인됩니다. 파이프로 구분 된 목록." - allow_profile_backgrounds: "사용자에게 프로필 배경 이미지 업로드를 허용합니다." - sequential_replies_threshold: "너무 많은 연속 댓글을 달고 있다고 경고를 받지 않고 사용자가 연달아 쓸 수 있는 포스트 수." - get_a_room_threshold: "경고를 받지 않고, 같은 토픽에서 같은 사람에게 보낼 수 있는 허용 포스트 수." - enable_mobile_theme: "모바일 디바이스는 모바일 환경에 친화적인 테마를 사용합니다, 그리고 PC용 화면으로 전환할 수 있습니다. 만약 커스텀 스타일 시트를 사용한다면 이것을 비활성화 시키세요." - dominating_topic_minimum_percent: "한 글타래에서 한 사용자의 영향력을 결정하는 글 수의 퍼센트" - disable_avatar_education_message: "아바타 변경 교육 메시지 해제." - suppress_uncategorized_badge: "글타래 리스트에서 카테고리가 없는 글타래에 대한 훈장을 보여주지 않는다." - header_dropdown_category_count: "머리글 드롭 다운 메뉴에 표시 할 수있는 범주 수" - permalink_normalizations: "퍼마링크를 매칭하기 전에 다음 정규표현식을 적용. 예: /(topic.*)\\?.*/\\1 를 적용하면 토픽 루트에서 퀴리 스트링을 뽑아냅니다. 캡쳐된 값에 접근하려면 정규표현식+스트링 형식에 \\1 등을 사용하면 됩니다." - global_notice: "모든 방문자에게 긴급, 긴급, 무시할 수없는 글로벌 배너 통지를 표시하고 숨기려면 공백으로 변경하십시오 (HTML 허용)." - disable_system_edit_notifications: "'download_remote_images_to_local'가 활성화되있으면 시스템 사용자에 의한 수정 알림을 비활성화합니다." - disable_category_edit_notifications: "글의 카테고리 편집 알림을 비활성화합니다." - disable_tags_edit_notifications: "글의 태그 수정 알림을 비활성화합니다." - notification_consolidation_threshold: "알림이 단일 알림으로 통합되기 전에 수신 된 좋아요 또는 회원 요청 알림 수 비활성화하려면 0으로 설정하십시오." - likes_notification_consolidation_window_mins: "임계 값에 도달하면 선호 알림이 단일 알림으로 통합되는 시간 (분)입니다. 임계 값은`SiteSetting.notification_consolidation_threshold`를 통해 구성 할 수 있습니다." - automatically_unpin_topics: "사용자가 하단에 도달하면 토픽 고정을 자동 해제." - read_time_word_count: "읽은 시간 추정치 계산을 위한 1분 당 워드 카운트." - topic_page_title_includes_category: "글 페이지 제목 태그에는 카테고리 이름이 포함됩니다." - native_app_install_banner_ios: "iOS 장치의 DiscourseHub 앱 배너를 일반 사용자 (신뢰 수준 1 이상)에게 표시합니다." - native_app_install_banner_android: "일반 사용자 (신뢰 수준 1 이상)에게 Android 장치에 DiscourseHub 앱 배너를 표시합니다." - app_association_android: "Google의 Digital Asset Links API에 사용되는 .well-known / assetlinks.json 엔드 포인트의 컨텐츠" - app_association_ios: "이 사이트와 iOS 앱 사이에 유니버설 링크를 생성하는 데 사용되는 apple-app-site-association 엔드 포인트의 컨텐츠." - share_anonymized_statistics: "익명화된 사용 통계 공유하기" - auto_handle_queued_age: "며칠이 지나면 검토를 기다리고 있는 항목을 자동으로 처리합니다. 신고는 무시됩니다. 대기 중인 게시물 및 사용자는 거부됩니다. 이 기능을 사용하지 않도록 설정하려면 0으로 설정하십시오." - svg_icon_subset: "자산에 포함 할 FontAwesome 5 아이콘을 추가하십시오. 솔리드 아이콘에는 접두사 'fa-', 일반 아이콘에는 'far-', 브랜드 아이콘에는 'fab-'을 사용하십시오." - max_prints_per_hour_per_user: "최대 / print 페이지 노출 수 (사용 안함으로 설정하려면 0으로 설정)" - full_name_required: "사용자 프로필에서 실명을 필수 입력 항목으로 설정" - enable_names: "사용자의 실명을 프로필, 사용자카드, 이메일에서 표시함. 실명을 표시하지 않으려면 체크를 해제하세요." - display_name_on_posts: "글에 @username 뿐만 아니라 사용자의 전체 이름도 보여준다." - show_time_gap_days: "두 글의 일차를 보여주기 위해 두 글이 떨어져 있어야 할 일수" - short_progress_text_threshold: "글타래의 글 개수가 이 값을 넘어서면, 글 프로그래스바는 오직 현재 글 넘버만 보여준다. 만약 글 프로그래스바의 넓이는 변경하면, 이 숫자도 변경해야합니다." - warn_reviving_old_topic_age: "이 값보다 오래된 글타래에 답글을 달면, 오래된 토론이라는 것을 상기시키기 위해 주의 알림이 보여진다. 비활성화 값음 0 이다. " - autohighlight_all_code: "형식이 지정되기 전의(되지 않은) 모든 코드 블럭들에 대해, 사용자가 언어를 지정하지 않아도 강제로 code highlighting이 적용된다." - highlighted_languages: "구문 강조 규칙이 포함되었습니다. (경고 : 너무 많은 언어를 포함하면 성능에 영향을 줄 수 있습니다.) 데모는 https://highlightjs.org/static/demo 를 참조하십시오." + allow_featured_topic_on_user_profiles: "사용자가 자신의 사용자 카드 및 프로필에 있는 주제로 연결되는 링크를 제공하도록 허용합니다." + show_inactive_accounts: "로그인한 사용자가 비활성 계정의 프로필을 탐색할 수 있도록 허용합니다." + hide_suspension_reasons: "사용자 프로필에 정지 이유를 공개적으로 표시하지 않습니다." + log_personal_messages_views: "다른 사용자/그룹에 대해 관리자가 개인 메시지 조회수를 기록합니다." + ignored_users_count_message_threshold: "이 정도의 다른 사용자가 특정 사용자를 무시하는 경우 운영자에게 알립니다." + ignored_users_message_gap_days: "많은 사용자가 무시한 사용자를 운영자에게 다시 알리기 전에 기다려야 하는 시간입니다." + clean_up_inactive_users_after_days: "비활성 사용자(게시물이 없는 신뢰 레벨 0)가 제거되기까지의 일 수입니다. 정리를 비활성화하려면 0으로 설정하세요." + clean_up_unused_staged_users_after_days: "사용이 없는 스테이징된 사용자(게시물 없음)가 제거되기까지의 일 수입니다. 정리를 비활성화하려면 0으로 설정하세요." + user_selected_primary_groups: "사용자가 자체 기본 그룹을 설정하도록 허용합니다." + max_notifications_per_user: "사용자당 최대 알림 수입니다. 이 수를 초과하면 오래된 알림이 삭제됩니다. 매주 시행되며 비활성화하려면 0으로 설정하세요." + allowed_user_website_domains: "이 도메인에서 사용자 웹사이트가 검증됩니다. 파이프(|)로 구분된 목록입니다." + allow_profile_backgrounds: "사용자가 프로필 배경을 업로드하도록 허용합니다." + sequential_replies_threshold: "연속 댓글 과다 알림을 받기 전에 사용자가 한 주제에서 연속으로 작성해야 하는 게시물 수입니다." + get_a_room_threshold: "사용자가 경고를 받기 전에 동일한 주제에서 동일한 사람에게 작성해야 하는 게시물 수입니다." + enable_mobile_theme: "모바일 디바이스는 모바일 환경에 친화적인 테마를 사용하며 PC용 화면으로 전환할 수 있습니다. 완전 반응형 사용자 지정 스타일시트를 사용하려면 이 기능을 비활성화하세요." + dominating_topic_minimum_percent: "주제를 과도하게 점유한다는 알림을 받기 전에 사용자가 주제에서 작성해야 하는 게시물의 퍼센트입니다." + disable_avatar_education_message: "아바타 변경 안내 메시지를 비활성화합니다." + suppress_uncategorized_badge: "주제 목록에서 카테고리가 없는 주제에 대한 배지를 표시하지 않습니다." + header_dropdown_category_count: "헤더 드롭다운 메뉴에 표시할 수 있는 카테고리 수입니다." + permalink_normalizations: "고정 링크를 일치시키기 전에 다음 정규식을 적용합니다. 예를 들어, /(topic.*)\\\\?.*/\\\\1은 주제 경로에서 쿼리 스트링을 제거합니다. 형식은 regex+string입니다. 캡처에 액세스하려면 \\\\1 등을 사용하세요." + global_notice: "모든 방문자에게 긴급, 비상, 닫을 수 없는 글로벌 배너 알림을 표시합니다. 숨기려면 공백으로 변경하세요(HTML 허용)." + disable_system_edit_notifications: "'download_remote_images_to_local'가 활성화되어 있으면 시스템 사용자에 의한 편집 알림을 비활성화합니다." + disable_category_edit_notifications: "주제의 카테고리 편집 알림을 비활성화합니다." + disable_tags_edit_notifications: "주제의 태그 편집 알림을 비활성화합니다." + notification_consolidation_threshold: "알림이 하나로 통합되기 전에 받은 좋아요 또는 멤버십 요청 알림의 수입니다. 비활성화하려면 0으로 설정하세요." + likes_notification_consolidation_window_mins: "한계치에 도달하면 좋아요 알림이 단일 알림으로 통합되는 시간(분)입니다. 한계치는 `SiteSetting.notification_consolidation_threshold` 를 통해 환경설정할 수 있습니다." + automatically_unpin_topics: "주제 하단에 도달하면 주제를 자동으로 고정 해제합니다." + read_time_word_count: "추정 읽은 시간 계산을 위한 1분당 워드 카운트입니다." + topic_page_title_includes_category: "주제 페이지 제목 태그에는 카테고리 이름이 포함됩니다." + native_app_install_banner_ios: "iOS 디바이스의 DiscourseHub 앱 배너를 일반 사용자(신뢰 레벨 1 이상)에게 표시합니다." + native_app_install_banner_android: "일반 사용자(신뢰 레벨 1 이상)에게 Android 디바이스에 DiscourseHub 앱 배너를 표시합니다." + app_association_android: "Google의 Digital Asset Links API에 사용되는 .well-known/assetlinks.json 엔드포인트의 콘텐츠입니다." + app_association_ios: "이 사이트와 iOS 앱 간의 범용 링크를 만드는 데 사용되는 apple-app-site-association 엔드포인트의 콘텐츠입니다." + share_anonymized_statistics: "익명화된 사용 통계 공유" + auto_handle_queued_age: "이 정도 기간이 지나면 검토 대기 기록을 자동으로 처리합니다. 신고는 무시됩니다. 대기 중인 게시물 및 사용자는 거부됩니다. 이 기능을 비활성화하려면 0으로 설정하세요." + svg_icon_subset: "에셋에 포함할 FontAwesome 5 아이콘을 추가합니다. 솔리드 아이콘에는 접두사 'fa-', 일반 아이콘에는 'far-', 브랜드 아이콘에는 'fab-'를 사용하세요." + max_prints_per_hour_per_user: "최대 /print 페이지 노출 수(비활성화하려면 0으로 설정)" + full_name_required: "전체 이름은 사용자 프로필의 필수 필드입니다." + enable_names: "사용자의 전체 이름을 프로필, 사용자 카드, 이메일에서 표시합니다. 모든 곳에서 전체 이름을 숨기려면 비활성화하세요." + display_name_on_posts: "게시물에 @아이디뿐만 아니라 사용자의 전체 이름도 표시합니다." + show_time_gap_days: "이 정도 일 수의 간격으로 두 개의 게시물을 작성한 경우 주제에 시간 간격을 표시합니다." + short_progress_text_threshold: "주제의 게시물 수가 이 수를 초과하면 진행률 표시줄에 현재 게시물 번호만 표시됩니다. 진행률 표시줄의 너비를 변경하는 경우 이 값을 변경해야 할 수도 있습니다." + warn_reviving_old_topic_age: "마지막 댓글이 이 날짜보다 오래된 주제에 누군가가 댓글을 달기 시작하면 경고가 표시됩니다. 비활성화하려면 0으로 설정합니다. " + autohighlight_all_code: "언어를 명시적으로 지정하지 않은 경우에도 미리 형식이 지정된 모든 코드 블록에 코드 하이라이트를 적용합니다." + highlighted_languages: "구문 강조 규칙이 포함되었습니다. (경고: 너무 많은 언어를 포함하면 퍼포먼스에 영향을 줄 수 있습니다) 데모는 https://highlightjs.org/static/demo를 참조하세요." show_copy_button_on_codeblocks: "코드 블록에 버튼을 추가하여 블록 내용을 사용자의 클립보드에 복사합니다." - embed_any_origin: "출처와 상관없이 퍼갈 수있는 콘텐츠를 허용합니다. 정적 HTML을 사용하는 모바일 앱에 필요합니다." + embed_any_origin: "출처와 상관없이 임베드 가능한 콘텐츠를 허용합니다. 정적 HTML을 사용하는 모바일 앱에 필요합니다." embed_topics_list: "주제 목록의 HTML 임베딩 지원" - embed_set_canonical_url: "포함된 글의 표준 URL을 포함된 콘텐츠의 URL로 설정합니다." - embed_truncate: "임베드된 글 비우기" - embed_unlisted: "가져온 주제는 사용자가 답장 할 때까지 나열되지 않습니다." - embed_support_markdown: "임베드 된 게시물에 대한 마크 다운 형식을 지원합니다." - allowed_embed_selectors: "삽입에 허용되는 쉼표로 구분 된 CSS 요소 목록입니다." - allowed_href_schemes: "http 및 https 외에도 링크에 허용되는 체계." - embed_post_limit: "글 개수가 최대치입니다." - embed_username_required: "토픽 생성을 위한 사용자명이 필요합니다." - notify_about_flags_after: "이 시간이 지난 후에도 처리되지 않은 신고가있는 경우 관리자에게 개인 메시지를 보냅니다. 비활성화하려면 0으로 설정하십시오." - show_create_topics_notice: "이 사이트에 5개 이하의 공개 글타래가 있으면, 관리자에게 글타래 좀 만들라고 알려줍니다." - delete_drafts_older_than_n_days: "(n) 일지난 임시 보관글 삭제하기" - delete_merged_stub_topics_after_days: "완전히 병합된 스텁 글을 자동으로 삭제하기 전에 대기하는 일 수입니다. 스텁 글을 삭제하지 않으려면 0으로 설정하십시오." - bootstrap_mode_min_users: "부트 스트랩 모드를 비활성화하는 데 필요한 최소 사용자 수 (비활성화하려면 0으로 설정)" - prevent_anons_from_downloading_files: "익명 사용자가 첨부 파일을 다운로드하지 못하도록합니다." - secure_media: '모든 업로드 (이미지, 비디오, 오디오, 텍스트, pdf, zip 및 기타)에 대한 액세스를 제한합니다. "로그인 필요"가 활성화 된 경우 로그인 한 사용자 만 업로드에 액세스 할 수 있습니다. 그렇지 않으면 개인 메시지 및 개인 범주의 미디어 업로드에 대해서만 액세스가 제한됩니다. 경고 :이 설정은 복잡하며 관리에 대한 깊은 이해가 필요합니다. 세부 사항 은 메타에 대한 보안 매체 주제 를 참조하십시오.' - secure_media_allow_embed_images_in_emails: "크기가 '이메일에 포함을 허용하는 보안 미디어 kb 크기' 설정보다 작은 경우 일반적으로 이메일에서 수정되는 보안 이미지를 포함 할 수 있습니다." - secure_media_max_email_embed_image_size_kb: "'이메일에 포함을 허용하는 보안 미디어' 설정이 활성화 된 경우 이메일에 포함되는 보안 이미지의 크기 제한입니다. 해당 설정을 사용하지 않으면 이 설정이 적용되지 않습니다." - slug_generation_method: "slug 생성 방식. 'encoded'는 퍼센트 기호로 인코딩해서 생성합니다. 'none'은 slug 자체를 비활성화합니다.." - enable_emoji: "emoji 활성화" - enable_emoji_shortcuts: ":) : p :(과 같은 일반적인 스마일 텍스트는 이모티콘으로 변환됩니다." - emoji_set: "어떤 emoji가 좋은가요?" - emoji_autocomplete_min_chars: "자동 완성 이모티콘 팝업을 트리거하는 데 필요한 최소 문자 수" - enable_inline_emoji_translation: "공백이나 문장 부호없이 인라인 이모티콘을 번역 할 수 있습니다." - approve_post_count: "승인을 받아야하는 신규 또는 기본 사용자의 게시물 수" - approve_unless_trust_level: "허가 받고 글 올려야 하는 유저들 최저 회원등급" - approve_new_topics_unless_trust_level: "이 신뢰 수준 미만의 사용자를위한 새로운 주제는 승인되어야합니다." - approve_unless_staged: "단계별 사용자를위한 새로운 주제 및 게시물은 승인되어야합니다." - notify_about_queued_posts_after: "여러 시간 동안 검토 대기중인 게시물이있는 경우 모든 중재자에게 알림을 보냅니다. 이러한 알림을 비활성화하려면 0으로 설정하십시오." - auto_close_messages_post_count: "메시지가 자동으로 닫히기 전에 허용되는 최대 게시물 수 (0은 비활성화)" - auto_close_topics_post_count: "주제가 자동으로 닫히기 전에 허용되는 최대 게시물 수 (0은 사용 안함)" - auto_close_topics_create_linked_topic: "글이 '게시물 자동 닫기' 설정에 따라 자동으로 닫히면 연결된 새 글을 만듭니다." - code_formatting_style: "글 작성기의 코드 버튼은 기본적으로 이 코드 형식 스타일로 설정됩니다" + embed_set_canonical_url: "임베드된 주제의 표준 URL을 임베드 콘텐츠의 URL로 설정합니다." + embed_truncate: "임베드된 게시물을 자릅니다." + embed_unlisted: "임포트한 주제는 댓글이 있을 때까지 나열되지 않습니다." + embed_support_markdown: "임베드된 게시물에 대한 Markdown 서식을 지원합니다." + allowed_embed_selectors: "임베드에서 허용되는 쉼표로 구분된 CSS 요소 목록입니다." + allowed_href_schemes: "http 및 https 외에도 링크에 허용되는 스키마입니다." + embed_post_limit: "임베드할 최대 게시물 수입니다." + embed_username_required: "주제 생성을 위해 아이디가 필요합니다." + notify_about_flags_after: "이 시간이 지나도 처리되지 않은 신고가 있으면 운영자에게 개인 메시지를 보냅니다. 비활성화하려면 0으로 설정하세요." + show_create_topics_notice: "사이트에 5개 미만의 공개 주제가 있는 경우 관리자에게 주제를 만들도록 요청하는 공지를 표시합니다." + delete_drafts_older_than_n_days: "(n)일 지난 초안을 삭제합니다." + delete_merged_stub_topics_after_days: "완전히 병합된 스텁 주제를 자동으로 삭제하기 전에 대기할 일 수입니다. 스텁 주제를 삭제하지 않으려면 0으로 설정하세요." + bootstrap_mode_min_users: "부트스트랩 모드를 비활성화하기 위한 최소 사용자 수(비활성화하려면 0으로 설정)" + prevent_anons_from_downloading_files: "익명 사용자가 첨부 파일을 다운로드하지 못하도록 합니다." + secure_media: '모든 업로드(이미지, 비디오, 오디오, 텍스트, pdf, zip 및 기타)에 대한 액세스를 제한합니다. ''로그인 필요''가 활성화된 경우 로그인한 사용자만 업로드에 액세스할 수 있습니다. 그렇지 않으면 비공개 메시지 및 비공개 카테고리의 미디어 업로드에 대해서만 액세스가 제한됩니다. 경고: 이 설정은 복잡하며 관리에 대한 지식이 충분해야 합니다. 자세한 내용은 Meta의 보안 미디어 주제를 참조하세요.' + secure_media_allow_embed_images_in_emails: "크기가 '보안 미디어 최대 이메일 임베드 이미지 크기 kb' 설정보다 작은 경우 일반적으로 이메일에서 수정되는 보안 이미지 임베드를 허용합니다." + secure_media_max_email_embed_image_size_kb: "'보안 미디어에서 이메일에 임베드 허용' 설정이 활성화된 경우 이메일에 임베드할 보안 이미지의 크기 컷오프입니다. 이 설정을 활성화하지 않으면 효과가 없습니다." + slug_generation_method: "슬러그 생성 방법을 선택합니다. 'encoded'는 퍼센트 인코딩 스트링을 생성합니다. 'none'은 슬러그를 완전히 비활성화합니다." + enable_emoji: "이모티콘 활성화" + enable_emoji_shortcuts: ":) : p :( 같은 일반적인 스마일 텍스트는 이모티콘으로 변환됩니다." + emoji_set: "이모티콘을 어떻게 사용할까요?" + emoji_autocomplete_min_chars: "자동 완성 이모티콘 팝업을 실행하는 데 필요한 최소 문자 수" + enable_inline_emoji_translation: "인라인 이모티콘 번역 활성화(앞에 공백이나 구두점 없이)." + approve_post_count: "승인을 받아야 하는 신규 또는 기본 사용자의 게시물 수" + approve_unless_trust_level: "이 신뢰 수준 미만의 사용자 게시물은 승인되어야 합니다" + approve_new_topics_unless_trust_level: "이 신뢰 수준 미만의 사용자 주제는 승인되어야 합니다" + approve_unless_staged: "스테이징된 사용자의 새 주제 및 게시물은 승인되어야 합니다" + notify_about_queued_posts_after: "이 시간 이상 검토 대기 중인 게시물이 있는 경우 모든 운영자에게 알림을 보냅니다. 이러한 알림을 비활성화하려면 0으로 설정하세요." + auto_close_messages_post_count: "자동으로 종료되기 전에 메시지에 허용되는 최대 게시물 수(비활성화하려면 0으로 설정)" + auto_close_topics_post_count: "자동으로 종료되기 전에 주제에 허용되는 최대 게시물 수(비활성화하려면 0으로 설정)" + auto_close_topics_create_linked_topic: "'주제 자동 종료 게시물 수' 설정에 따라 주제가 자동으로 종료될 때 새 연결된 주제 생성" + code_formatting_style: "작성기의 코드 버튼은 기본적으로 이 코드 서식 스타일로 설정됩니다" max_allowed_message_recipients: "메시지에 허용되는 최대 수신자입니다." - watched_words_regular_expressions: "시청 한 단어는 정규식입니다." - enable_diffhtml_preview: "전체 재 렌더링 대신 DiffHTML을 사용하여 미리보기를 동기화하는 실험 기능" - old_post_notice_days: "게시물 알림이 오래되기 전날" - new_user_notice_tl: "새로운 사용자 게시물 알림을 보려면 최소 신뢰 수준이 필요합니다." - returning_user_notice_tl: "사용자에게 다시 게시 알림을 표시하는 데 필요한 최소 신뢰 수준입니다." - returning_users_days: "사용자가 돌아오는 것으로 간주되기까지 며칠이 경과해야합니다." - review_media_unless_trust_level: "관리자는 회원레벨이 낮은 사용자의 게시물에 임베디드 미디어가 포함 된 경우 이를 검토합니다." + watched_words_regular_expressions: "구독한 단어는 정규식입니다." + enable_diffhtml_preview: "전체 재렌더링 대신 미리보기를 동기화하기 위해 diffHTML을 사용하는 실험단계 기능" + old_post_notice_days: "게시물 공지가 오래된 것으로 간주되기까지 일 수" + new_user_notice_tl: "신규 사용자 게시물 알림을 보기 위한 최소 신뢰 레벨입니다." + returning_user_notice_tl: "재방문 사용자 게시물 알림을 보기 위한 최소 신뢰 레벨입니다." + returning_users_days: "재방문 사용자로 간주되기까지 경과해야 하는 일 수입니다." + review_media_unless_trust_level: "운영진은 임베디드 미디어가 포함된 경우 신뢰 레벨이 낮은 사용자의 게시물을 검토합니다." blur_tl0_flagged_posts_media: "잠재적인 NSFW 콘텐츠를 숨기기 위해 신고된 게시물 이미지를 흐리게 처리합니다." - enable_page_publishing: "직원이 자신의 스타일을 사용하여 주제를 새 URL에 게시 할 수 있습니다." + enable_page_publishing: "운영진은 자체 스타일을 사용하여 주제를 새 URL에 게시할 수 있습니다." show_published_pages_login_required: "익명 사용자는 로그인이 필요한 경우에도 게시된 페이지를 볼 수 있습니다." - skip_auto_delete_reply_likes: "이전 답글을 자동으로 삭제하는 경우 좋아요 수가 이 이상인 게시물 삭제를 건너 뜁니다." - default_email_digest_frequency: "사용자가 기본적으로 요약 이메일을받는 빈도입니다." - default_include_tl0_in_digests: "기본적으로 새 사용자의 게시물을 요약 이메일에 포함시킵니다. 사용자는 원하는대로이를 변경할 수 있습니다." - default_email_level: "일반 주제에 대한 기본 이메일 알림 레벨을 설정하십시오." - default_email_messages_level: "누군가가 사용자에게 메시지를 보낼 때 기본 이메일 알림 레벨을 설정하십시오." - default_email_mailing_list_mode: "기본으로 새로운 포스트가 생길 때마다 이메일 보내기" - default_email_mailing_list_mode_frequency: "이 빈도로 이메일 받기를 설정한 메일링 리스트 가입자" - disable_mailing_list_mode: "사용자가 메일링 리스트 모드를 활성화하지 못하도록합니다. (메일 링리스트 이메일이 전송되지 않도록합니다.)" - default_email_previous_replies: "기본적으로 이메일에 이전 회신을 포함시킵니다." - default_email_in_reply_to: "기본적으로 이메일에 게시 된 답글을 포함시킵니다." - default_other_new_topic_duration_minutes: "주제가 새로운 것으로 간주되는 전역 기본 조건." - default_other_auto_track_topics_after_msecs: "주제가 자동 추적되기 전의 전역 기본 시간입니다." - default_other_notification_level_when_replying: "사용자가 주제에 응답 할 때의 전역 기본 알림 레벨." - default_other_external_links_in_new_tab: "기본적으로 새 탭에서 외부 링크를 엽니 다." - default_other_enable_quoting: "강조 표시된 텍스트에 대해 기본적으로 견적 회신을 사용하십시오." - default_other_enable_defer: "기본적으로 주제 기능 연기를 사용하십시오." - default_other_dynamic_favicon: "기본적으로 브라우저 아이콘에 새로운 / 업데이트 된 주제 수를 표시합니다." - default_other_skip_new_user_tips: "신규 사용자 온 보딩 팁 및 배지를 건너 뜁니다." - default_other_like_notification_frequency: "기본적으로 좋아요에 사용자에게 알림" - default_topics_automatic_unpin: "사용자가 기본적으로 하단에 도달하면 주제를 자동으로 고정 해제합니다." - default_categories_watching: "기본적으로 검열되는 카테고리 목록." - default_categories_tracking: "기본적으로 추적되는 카테고리 목록." - default_categories_muted: "기본적으로 음소거 된 카테고리 목록." - default_categories_watching_first_post: "각 새 주제의 첫 번째 게시물이 기본적으로 감시되는 카테고리 목록입니다." - default_categories_normal: "기본적으로 뮤트 되지 않은 카테고리 목록입니다. 'mute_all_categories_by_default' 사이트 설정이 활성화된 경우 유용합니다." - mute_all_categories_by_default: "모든 카테고리의 기본 알림 레벨을 음소거로 설정하십시오. 사용자가 '최신'및 '카테고리'페이지에 표시되도록 카테고리를 선택해야합니다. 익명 사용자의 기본값을 수정하려면 'default_categories_'설정을 설정하십시오." - default_tags_watching: "기본적으로 볼 수있는 태그 목록입니다." + skip_auto_delete_reply_likes: "오래된 댓글을 자동 삭제할 때 이 좋아요 수 이상의 게시물은 삭제를 건너뜁니다." + default_email_digest_frequency: "사용자가 기본적으로 요약 이메일을 수신하는 빈도입니다." + default_include_tl0_in_digests: "기본적으로 요약 이메일에 신규 사용자의 게시물을 포함합니다. 사용자는 환경설정에서 이를 변경할 수 있습니다." + default_email_level: "일반 주제에 대한 디폴트 이메일 알림 레벨을 설정합니다." + default_email_messages_level: "누군가가 사용자에게 메시지를 보낼 때의 기본 이메일 알림 레벨을 설정합니다." + default_email_mailing_list_mode: "기본적으로 모든 새 게시물에 대해 이메일 보내기" + default_email_mailing_list_mode_frequency: "메일링 리스트 모드를 활성화한 사용자는 기본적으로 이 이메일을 자주 수신하게 됩니다." + disable_mailing_list_mode: "사용자가 메일링 리스트 모드를 활성화하는 것을 허용하지 않습니다(메일링 리스트 이메일이 전송되지 않도록 방지)." + default_email_previous_replies: "기본적으로 이메일에 이전 회신을 포함합니다." + default_email_in_reply_to: "기본적으로 이메일에 게시물의 댓글을 발췌해서 포함합니다." + default_other_new_topic_duration_minutes: "주제가 새 주제로 간주되는 글로벌 디폴트 조건입니다." + default_other_auto_track_topics_after_msecs: "주제가 자동 추적되기 전의 글로벌 디폴트 시간입니다." + default_other_notification_level_when_replying: "사용자가 주제에 댓글을 달 때의 글로벌 디폴트 알림 레벨입니다." + default_other_external_links_in_new_tab: "기본적으로 새 탭에서 외부 링크를 엽니다." + default_other_enable_quoting: "기본적으로 하이라이트된 텍스트에 대한 인용 댓글을 활성화합니다." + default_other_enable_defer: "기본적으로 주제 함수 기능 연기를 활성화합니다." + default_other_dynamic_favicon: "기본적으로 브라우저 아이콘에 신규/업데이트된 주제 수를 표시합니다." + default_other_skip_new_user_tips: "신규 사용자 온보딩 팁 및 배지를 건너뜁니다." + default_other_like_notification_frequency: "기본적으로 사용자에게 좋아요 알림 전송" + default_topics_automatic_unpin: "기본적으로 사용자가 주제 하단에 도달하면 주제를 자동으로 고정 해제합니다." + default_categories_watching: "기본적으로 구독하는 카테고리 목록입니다." + default_categories_tracking: "기본적으로 추적되는 카테고리 목록입니다." + default_categories_muted: "기본적으로 뮤트되는 카테고리 목록입니다." + default_categories_watching_first_post: "기본적으로 각 새 주제의 첫 게시물이 구독되는 카테고리 목록입니다." + default_categories_normal: "기본적으로 뮤트되지 않은 카테고리 목록입니다. `mute_all_categories_by_default` 사이트 설정이 활성화된 경우 유용합니다." + mute_all_categories_by_default: "모든 카테고리의 디폴트 알림 레벨을 뮤트로 설정합니다. 사용자가 '최신' 및 '카테고리' 페이지에 표시되도록 카테고리를 선택해야 합니다. 익명 사용자의 디폴트값을 수정하려면 'default_categories_' 설정을 설정하세요." + default_tags_watching: "기본적으로 구독되는 태그 목록입니다." default_tags_tracking: "기본적으로 추적되는 태그 목록입니다." - default_tags_muted: "기본적으로 음소거 된 태그 목록입니다." - default_tags_watching_first_post: "기본적으로 각 새 주제의 첫 번째 게시물을 볼 수있는 태그 목록입니다." + default_tags_muted: "기본적으로 뮤트되는 태그 목록입니다." + default_tags_watching_first_post: "기본적으로 각 새 주제의 첫 게시물이 구독되는 태그 목록입니다." default_text_size: "기본적으로 선택된 텍스트 크기" - default_title_count_mode: "페이지 제목 카운터의 기본 모드" - retain_web_hook_events_period_days: "웹 후크 이벤트 레코드를 보유하는 일 수" - retry_web_hook_events: "실패한 웹 후크 이벤트를 4 번 자동으로 다시 시도하십시오. 재시도 사이의 시간 간격은 1, 5, 25 및 125 분입니다." - revoke_api_keys_days: "사용하지 않는 API 키가 자동으로 취소되기 전의 일수 (0은 아님)" + default_title_count_mode: "페이지 제목 카운터의 디폴트 모드" + retain_web_hook_events_period_days: "Webhook 이벤트 기록 보유 기간(일)입니다." + retry_web_hook_events: "실패한 Webhook 이벤트를 4번 자동으로 재시도합니다. 재시도 간 간격은 1, 5, 25 및 125분입니다." + revoke_api_keys_days: "사용하지 않는 API 키가 자동으로 취소되기까지의 기간(일)(0은 취소 안 함)" allow_user_api_keys: "사용자 API 키 생성 허용" allow_user_api_key_scopes: "사용자 API 키에 허용되는 범위 목록" - min_trust_level_for_user_api_key: "사용자 API 키 생성에 필요한 신뢰 수준" - allowed_user_api_auth_redirects: "사용자 API 키의 인증 리디렉션을 위해 허용 된 URL입니다. 와일드 카드 기호 *를 사용하면 그 일부를 일치시킬 수 있습니다 (예 : www.example.com/*)." - allowed_user_api_push_urls: "사용자 API에 대한 서버 푸시에 허용 된 URL" - expire_user_api_keys_days: "사용자 API 키가 자동으로 만료되기까지의 일 수 (0은 절대 안 됨)" - tagging_enabled: "주제에 태그를 사용 하시겠습니까?" - min_trust_to_create_tag: "태그를 만드는 데 필요한 최소 신뢰 수준입니다." - max_tags_per_topic: "주제에 적용 할 수있는 최대 태그입니다." - max_tag_length: "태그에 사용할 수있는 최대 문자 수입니다." - max_tag_search_results: "태그를 검색 할 때 표시 할 최대 결과 수입니다." - max_tags_in_filter_list: "필터 드롭 다운에 표시 할 최대 태그 수입니다. 가장 많이 사용 된 태그가 표시됩니다." - tags_sort_alphabetically: "알파벳 순서로 태그를 표시합니다. 기본값은 인기순으로 표시하는 것입니다." - tags_listed_by_group: "태그 페이지 에서 태그 그룹별로 태그를 나열 하십시오 ." - tag_style: "태그 배지 시각 스타일" - min_trust_level_to_tag_topics: "토픽에 태깅할 수 있는 최소 신뢰도" - suppress_overlapping_tags_in_list: "태그가 글 제목의 단어와 정확히 일치하면 태그를 표시하지 않습니다." - remove_muted_tags_from_latest: "최신 주제 목록에서 음소거 태그로만 태그 된 주제를 표시하지 마십시오." + min_trust_level_for_user_api_key: "사용자 API 키 생성을 위한 신뢰 레벨" + allowed_user_api_auth_redirects: "사용자 API 키의 인증 리디렉션을 위해 허용된 URL입니다. 와일드 카드 기호 *를 사용하면 일부를 일치시킬 수 있습니다(예 : www.example.com/*)." + allowed_user_api_push_urls: "사용자 API의 서버 푸시를 위한 허용된 URL" + expire_user_api_keys_days: "사용자 API 키가 자동으로 만료되기까지의 기간(일)(0은 만료 안 함)" + tagging_enabled: "주제에 태그를 활성화할까요?" + min_trust_to_create_tag: "태그를 생성하기 위한 최소 신뢰 레벨입니다." + max_tags_per_topic: "주제에 적용할 수 있는 최대 태그입니다." + max_tag_length: "태그에 사용할 수 있는 최대 문자 수입니다." + max_tag_search_results: "태그를 검색할 때 표시할 최대 결과 수입니다." + max_tags_in_filter_list: "필터 드롭다운에 표시할 최대 태그 수입니다. 가장 많이 사용된 태그가 표시됩니다." + tags_sort_alphabetically: "알파벳 순서로 태그를 표시합니다. 디폴트는 인기 순입니다." + tags_listed_by_group: "태그 페이지에서 태그 그룹별로 태그를 나열합니다." + tag_style: "태그 배지의 비주얼 스타일입니다." + min_trust_level_to_tag_topics: "주제를 태그할 수 있는 최소 신뢰 레벨입니다." + suppress_overlapping_tags_in_list: "태그가 주제 제목의 단어와 정확히 일치하면 태그를 표시하지 않습니다." + remove_muted_tags_from_latest: "최신 주제 목록에서 뮤트된 태그로만 태그된 주제를 표시하지 않습니다." force_lowercase_tags: "모든 새 태그를 완전히 소문자로 만듭니다." company_name: "회사 이름" governing_law: "준거법" - city_for_disputes: "분쟁의 도시" - shared_drafts_category: "주제 초안의 범주를 지정하여 공유 초안 기능을 사용하십시오. 이 범주의 주제는 직원 사용자의 주제 목록에서 표시되지 않습니다." + city_for_disputes: "분쟁 도시" + shared_drafts_category: "주제 초안에 카테고리를 지정하여 공유 초안을 활성화합니다. 이 카테고리의 주제는 운영진의 주제 목록에서 표시되지 않습니다." shared_drafts_min_trust_level: "사용자가 공유 초안을 보고 편집할 수 있도록 허용합니다." push_notifications_prompt: "사용자 동의 프롬프트를 표시합니다." - push_notifications_icon: "알림 모서리에 나타나는 배지 아이콘입니다. 투명도가 있는 96×96 단색 PNG 이미지를 사용하는 것이 좋습니다." - base_font: "사이트에서 대부분의 텍스트에 사용할 기본 글꼴입니다. 테마는`--font-family` CSS 사용자 정의 속성을 통해 재정의 할 수 있습니다." - heading_font: "사이트의 제목에 사용할 글꼴입니다. 테마는`--heading-font-family` CSS 사용자 정의 속성을 통해 재정의 할 수 있습니다." - short_title: "짧은 제목은 사용자의 홈 화면, 실행기 또는 공간이 제한 될 수있는 다른 장소에서 사용됩니다. 12 자로 제한되어야합니다." - dashboard_hidden_reports: "대시 보드에서 지정된 보고서를 숨길 수 있습니다." - dashboard_visible_tabs: "표시 할 대시 보드 탭을 선택합니다." - dashboard_general_tab_activity_metrics: "일반 탭에서 활동 메트릭으로 표시 할 보고서를 선택하십시오." - gravatar_name: "Gravatar 제공 업체 이름" + push_notifications_icon: "알림 코너에 표시되는 배지 아이콘입니다. 투명도가 있는 96×96 단색 PNG를 사용하는 것이 좋습니다." + base_font: "사이트에서 대부분의 텍스트에 사용할 기본 글꼴입니다. 테마는 `--font-family` CSS 사용자 지정 프로퍼티를 통해 오버라이드할 수 있습니다." + heading_font: "사이트 헤딩에 사용할 폰트입니다. 테마는 `--heading-font-family` CSS 사용자 지정 프로퍼티를 통해 재정의할 수 있습니다." + short_title: "짧은 제목은 사용자의 홈 화면, 런처 또는 공간이 제한될 수 있는 기타 위치에 사용되며, 12자로 제한됩니다." + dashboard_hidden_reports: "대시보드에서 지정된 리포트를 숨기도록 허용합니다." + dashboard_visible_tabs: "표시할 대시보드 탭을 선택합니다." + dashboard_general_tab_activity_metrics: "일반 탭에서 활동 메트릭으로 표시할 리포트를 선택합니다." + gravatar_name: "Gravatar 제공자 이름" gravatar_base_url: "Gravatar 제공자의 API 기반 URL" - gravatar_login_url: "사용자에게 Gravatar 서비스에 대한 로그인을 제공하는 gravatar_base_url과 관련된 URL" - share_quote_buttons: "견적 공유 위젯에 표시되는 항목과 순서를 결정합니다." - share_quote_visibility: "견적 공유 버턴을 표시할 시기를 결정합니다. 익명 사용자만 또는 모든 사용자에게 표시하지 않습니다. " - create_revision_on_bulk_topic_moves: "주제가 대량으로 새 카테고리로 이동되면 첫 번째 게시물에 대한 개정판을 만듭니다." + gravatar_login_url: "사용자에게 Gravatar 서비스 로그인을 제공하는 gravatar_base_url과 관련된 URL" + share_quote_buttons: "인용 공유 위젯에 표시되는 항목과 순서를 결정합니다." + share_quote_visibility: "인용 공유 버튼을 언제 표시할지 결정합니다. 표시 안 함, 익명 사용자만, 모든 사용자 중 선택합니다. " + create_revision_on_bulk_topic_moves: "주제가 일괄 새 카테고리로 이동되면 첫 게시물에 대한 수정 버전을 생성합니다." errors: - invalid_css_color: "잘못된 색상입니다. 색상 이름 또는 16진수 값을 입력해야 합니다." + invalid_css_color: "유효하지 않은 색상입니다. 색상 이름 또는 16진수 값을 입력하세요." invalid_email: "유효하지 않은 이메일 주소입니다." - invalid_username: "해당 이름의 사용자가 없습니다." - valid_username: "해당 아이디의 사용자가 없습니다." - invalid_group: "그 이름을 가진 그룹이 없습니다." - invalid_integer_min_max: "%{min}이상 %{max}이하이어야 합니다." - invalid_integer_min: "%{min}이상 이어야 합니다." - invalid_integer_max: "%{max}이하 이어야 합니다." - invalid_integer: "정수만 허용됩니다." - regex_mismatch: "해당 포멧은 허용되지 않습니다." - must_include_latest: "Top메뉴는 '최근' 탭을 반드시 갖고 있어야 합니다." - invalid_string: "허용되는 정보가 아닙니다." - invalid_string_min_max: "글자 수가 %{min}자 이상 %{max}자 이하이어야 합니다." - invalid_string_min: "글자수가 %{min}자 이상이어야 합니다." - invalid_string_max: "글자 수가 %{max}자 이상이어야 합니다." - invalid_json: "잘못된 JSON입니다." - invalid_reply_by_email_address: "값이 반드시 '%{reply_key}'를 갖고 있어야하며 알림 이메일과 달라야합니다." - invalid_alternative_reply_by_email_addresses: "모든 값은 '%{reply_key}'을 포함해야하며 알림 이메일과 달라야합니다." - invalid_domain_hostname: "문자에 * 또는? 를 포함해서는 안 됩니다." - pop3_polling_host_is_empty: "POP3 폴링을 활성화하기 전에 'pop3 폴링 호스트'를 설정해야합니다." - pop3_polling_username_is_empty: "POP3 폴링을 활성화하기 전에 'pop3 폴링 사용자 이름'을 설정해야합니다." - pop3_polling_password_is_empty: "POP3 폴링을 활성화하기 전에 'pop3 폴링 비밀번호'를 설정해야합니다." - pop3_polling_authentication_failed: "POP3 인증에 실패했습니다. pop3 자격 증명을 확인하십시오." - reply_by_email_address_is_empty: "이메일로 회신을 활성화하기 전에 '이메일 주소로 회신'을 설정해야합니다." - email_polling_disabled: "이메일로 회신을 활성화하기 전에 수동 또는 POP3 폴링을 활성화해야합니다." - user_locale_not_enabled: "이 설정을 활성화하기 전에 먼저 '사용자 로캘 허용'을 활성화해야합니다." - invalid_regex: "허용되지 않거나 올바르지 않은 정규표현식입니다." - email_editable_enabled: "이 설정을 활성화하기 전에 '이메일 편집 가능'을 비활성화해야합니다." - staged_users_disabled: "이 설정을 활성화하기 전에 먼저 '단계별 사용자'를 활성화해야합니다." - reply_by_email_disabled: "이 설정을 활성화하기 전에 먼저 '이메일로 회신'을 활성화해야합니다." + invalid_username: "해당 아이디의 사용자가 없습니다." + valid_username: "해당 아이디의 사용자가 있습니다." + invalid_group: "이 이름을 가진 그룹이 없습니다." + invalid_integer_min_max: "값은 %{min} 및 %{max} 사이여야 합니다." + invalid_integer_min: "값은 %{min} 이상이어야 합니다." + invalid_integer_max: "값은 %{max} 이하이어야 합니다." + invalid_integer: "값은 정수만 허용됩니다." + regex_mismatch: "값이 필수 포맷과 일치하지 않습니다." + must_include_latest: "주요 메뉴는 '최근' 탭을 포함해야 합니다." + invalid_string: "유요하지 않은 값입니다." + invalid_string_min_max: "%{min} ~ %{max}자 사이여야 합니다." + invalid_string_min: "%{min}자 이상이어야 합니다." + invalid_string_max: "%{max}자 이하여야 합니다." + invalid_json: "유효하지 않은 JSON입니다." + invalid_reply_by_email_address: "값은 '%{reply_key}' 키를 포함해야 하며 알림 이메일과 달라야 합니다." + invalid_alternative_reply_by_email_addresses: "모든 값은 '%{reply_key}' 키를 포함해야 하며 알림 이메일과 달라야 합니다." + invalid_domain_hostname: "* 또는 ?를 포함해서는 안 됩니다." + pop3_polling_host_is_empty: "POP3 폴링을 활성화하기 전에 'pop3 폴링 호스트'를 설정해야 합니다." + pop3_polling_username_is_empty: "POP3 폴링을 활성화하기 전에 'pop3 폴링 아이디'를 설정해야 합니다." + pop3_polling_password_is_empty: "POP3 폴링을 활성화하기 전에 'pop3 폴링 비밀번호'를 설정해야 합니다." + pop3_polling_authentication_failed: "POP3 인증에 실패했습니다. POP3 크리덴셜을 확인하세요." + reply_by_email_address_is_empty: "이메일로 회신을 활성화하기 전에 '이메일 주소로 회신'을 설정해야 합니다." + email_polling_disabled: "이메일로 회신을 활성화하기 전에 수동 또는 POP3 폴링을 활성화해야 합니다." + user_locale_not_enabled: "이 설정을 활성화하기 전에 먼저 '사용자 로캘 허용'을 활성화해야 합니다." + invalid_regex: "허용되지 않거나 유효하지 않은 정규식입니다." + email_editable_enabled: "이 설정을 활성화하기 전에 '이메일 편집 가능'을 비활성화해야 합니다." + staged_users_disabled: "이 설정을 활성화하기 전에 먼저 '스테이징된 사용자'를 활성화해야 합니다." + reply_by_email_disabled: "이 설정을 활성화하기 전에 먼저 '이메일로 회신'을 활성화해야 합니다." discourse_connect_url_is_empty: "이 설정을 활성화하기 전에 'discourse connect url'을 설정해야 합니다." discourse_connect_invite_only: "DiscourseConnect와 초대를 동시에 활성화할 수는 없습니다." - enable_local_logins_disabled: "이 설정을 활성화하기 전에 먼저 '로컬 로그인 활성화'를 활성화해야합니다." - min_username_length_exists: "최소 사용자 이름 길이를 가장 짧은 사용자 이름 (%{username}) 이상으로 설정할 수 없습니다." - min_username_length_range: "최소값은 최대값보다 크게 설정할 수 없습니다." - max_username_length_exists: "가장 긴 사용자 이름 (%{username}) 아래에서 최대 사용자 이름 길이를 설정할 수 없습니다." - max_username_length_range: "최대값은 최소값보다 작게 설정할 수 없습니다." - invalid_hex_value: "색상 값은 6 자리 16 진수 코드 여야합니다." - empty_selectable_avatars: "이 설정을 활성화하기 전에 먼저 두 개 이상의 선택 가능한 아바타를 업로드해야합니다." + enable_local_logins_disabled: "이 설정을 활성화하기 전에 먼저 '로컬 로그인 활성화'를 활성화해야 합니다." + min_username_length_exists: "최소 아이디 길이를 가장 짧은 아이디(%{username}) 이상으로 설정할 수 없습니다." + min_username_length_range: "최솟값은 최댓값보다 크게 설정할 수 없습니다." + max_username_length_exists: "최대 아이디 길이를 가장 긴 아이디(%{username}) 이하로 설정할 수 없습니다." + max_username_length_range: "최솟값은 최댓값보다 작게 설정할 수 없습니다." + invalid_hex_value: "색상 값은 6자리 16진수 코드여야 합니다." + empty_selectable_avatars: "이 설정을 활성화하기 전에 먼저 두 개 이상의 선택 가능한 아바타를 업로드해야 합니다." category_search_priority: low_weight_invalid: "가중치를 1보다 크거나 같게 설정할 수 없습니다." high_weight_invalid: "가중치를 1보다 작거나 같게 설정할 수 없습니다." allowed_unicode_usernames: - regex_invalid: "정규식이 잘못되었습니다: %{error}" - leading_trailing_slash: "정규식은 슬래시로 시작하거나 끝나서는 안됩니다." - unicode_usernames_avatars: "내부 시스템 아바타는 유니 코드 사용자 이름을 지원하지 않습니다." - list_value_count: "목록에는 정확히 %{count} 값이 포함되어야합니다." + regex_invalid: "정규식이 유효하지 않습니다. %{error}" + leading_trailing_slash: "정규식은 슬래시로 시작하거나 끝나서는 안 됩니다." + unicode_usernames_avatars: "내부 시스템 아바타는 유니코드 아이디를 지원하지 않습니다." + list_value_count: "목록에 정확히 %{count} 값을 포함해야 합니다." google_oauth2_hd_groups: "이 설정을 활성화하기 전에 먼저 'google oauth2 hd'를 설정해야 합니다." - search_tokenize_chinese_enabled: "이 설정을 활성화하기 전에 'search_tokenize_chinese '를 비활성화해야 합니다." + search_tokenize_chinese_enabled: "이 설정을 활성화하기 전에 'search_tokenize_chinese'를 비활성화해야 합니다." search_tokenize_japanese_enabled: "이 설정을 활성화하기 전에 'search_tokenize_japanese'를 비활성화해야 합니다." placeholder: discourse_connect_provider_secrets: key: "www.example.com" - value: "DiscourseConnect 시크릿" + value: "DiscourseConnect 암호" search: - extreme_load_error: "사이트의로드가 심하고 검색이 사용 중지되었습니다. 나중에 다시 시도하십시오." + extreme_load_error: "사이트 과부하로 검색이 비활성화되었습니다. 나중에 다시 시도하세요." within_post: "#%{post_number} by %{username}" types: category: "카테고리" @@ -2074,231 +2047,231 @@ ko: audio: "[오디오]" video: "[비디오]" discourse_connect: - login_error: "로그인 에러" - not_found: "사용자님의 계정을 찾을 수 없습니다. 사이트 관리자에게 문의하십시오." - account_not_approved: "사용자님의 계정은 승인 대기 중입니다. 승인되면 이메일 알림을 받게됩니다." - unknown_error: "계정에 문제가 있습니다. 사이트 관리자에게 문의하십시오." - timeout_expired: "계정 로그인 시간이 초과되었습니다. 다시 로그인하십시오." - no_email: "이메일 주소가 제공되지 않았습니다. 사이트 관리자에게 문의하십시오." - blank_id_error: "'external_id'는 필수이지만 비어 있습니다." - email_error: "이메일 주소 %{email}으로는 계정을 등록 할 수 없습니다. 사이트 관리자에게 문의하십시오." - missing_secret: "시크릿이 없어 인증에 실패했습니다. 이 문제를 해결하려면 사이트 관리자에게 문의하십시오." - invite_redeem_failed: "초대 사용에 실패했습니다. 사이트 관리자에게 문의하십시오." + login_error: "로그인 오류" + not_found: "계정을 찾을 수 없습니다. 사이트 관리자에게 문의하세요." + account_not_approved: "계정이 승인 보류 중입니다. 승인되면 이메일 알림이 전송됩니다." + unknown_error: "계정에 문제가 있습니다. 사이트 관리자에게 문의하세요." + timeout_expired: "계정 로그인 시간이 초과되었습니다. 다시 로그인하세요." + no_email: "이메일 주소가 제공되지 않았습니다. 사이트 관리자에게 문의하세요." + blank_id_error: "'external_id'는 필수이지만 비어 있습니다" + email_error: "%{email} 이메일 주소로는 계정을 등록할 수 없습니다. 사이트 관리자에게 문의하세요." + missing_secret: "암호가 없어 인증에 실패했습니다. 이 문제를 해결하려면 사이트 관리자에게 문의하세요." + invite_redeem_failed: "초대를 사용하지 못했습니다. 사이트 관리자에게 문의하세요." original_poster: "원본 게시자" most_recent_poster: "최근 게시자" - frequent_poster: "빈번한 게시자" + frequent_poster: "자주 게시하는 사용자" poster_description_joiner: ", " redirected_to_top_reasons: - new_user: "우리 커뮤니티에 오신 것을 환영합니다! 다음은 우리 사이트에서 가장 인기 많은 최근 글타래들입니다." - not_seen_in_a_month: "잘 돌아오셨습니다. 다음은 당신이 오지 않은 동안 가장 인기있던 글타래들입니다." + new_user: "커뮤니티에 오신 것을 환영합니다! 다음은 가장 인기 있는 최신 주제입니다." + not_seen_in_a_month: "다시 찾아주셔서 감사합니다! 다음은 그동안 가장 인기 있던 주제입니다." merge_posts: edit_reason: - other: "%{count}개의 게시물이 %{username}에 의해 병합되었습니다." + other: "%{username} 님이 %{count}개의 게시물을 병합했습니다" errors: - different_topics: "다른 주제에 속하는 게시물은 병합 할 수 없습니다." - different_users: "다른 사용자에게 속한 게시물은 병합 할 수 없습니다." - max_post_length: "게시물 길이가 허용 된 길이보다 길기 때문에 게시물을 병합 할 수 없습니다." + different_topics: "다른 주제에 속하는 게시물은 병합할 수 없습니다." + different_users: "다른 사용자에게 속한 게시물은 병합할 수 없습니다." + max_post_length: "결합된 게시물 길이가 허용된 길이보다 길기 때문에 게시물을 병합할 수 없습니다." move_posts: new_topic_moderator_post: - other: "%{count}개의 게시물이 새 글로 분할되었습니다: %{topic_link}" + other: "%{count}개의 게시물이 새 주제로 분할되었습니다. %{topic_link}" new_message_moderator_post: - other: "%{count}개의 글이 새 글로 분할되었습니다: %{topic_link}" + other: "%{count}개의 게시물이 새 메시지로 분할되었습니다. %{topic_link}" existing_topic_moderator_post: - other: "%{count}개의 글이 다음 글에 병합되었습니다: %{topic_link}" + other: "%{count}개의 게시물이 기존 주제로 병합되었습니다. %{topic_link}" existing_message_moderator_post: - other: "%{count}개의 게시물이 기존 글에 병합되었습니다: %{topic_link}" + other: "%{count}개의 게시물이 기존 메시지로 병합되었습니다. %{topic_link}" change_owner: - post_revision_text: "소유권 이전" + post_revision_text: "소유권 이전됨" publish_page: slug_errors: - blank: "비어있으면 안됨" - unavailable: "사용할 수 없습니다" - invalid: "사용할 수 없는 문자를 포함하고 있습니다." + blank: "공백일 수 없음" + unavailable: "사용할 수 없음" + invalid: "유효하지 않은 문자를 포함함" topic_statuses: autoclosed_message_max_posts: - other: "이 글은 최대 %{count}개의 최대 댓글 제한에 도달하여 자동으로 닫혔습니다." + other: "이 메시지는 %{count}개의 최대 댓글 한도에 도달하여 자동으로 종료되었습니다." autoclosed_topic_max_posts: - other: "이 글은 최대 %{count}개의 최대 댓글 제한에 도달하여 자동으로 닫혔습니다." + other: "이 주제는 %{count}개의 최대 댓글 한도에 도달하여 자동으로 종료되었습니다." autoclosed_enabled_days: - other: "이 글은 %{count}일 뒤 자동적으로 닫혔습니다. 새 댓글을 다실 수 없습니다." + other: "이 주제는 %{count}일 뒤 자동으로 종료되었습니다. 새 댓글을 달 수 없습니다." autoclosed_enabled_hours: - other: "이 글은 %{count}시간 뒤 자동적으로 닫혔습니다. 새 댓글을 다실 수 없습니다." + other: "이 주제는 %{count}시간 뒤 자동으로 종료되었습니다. 새 댓글을 달 수 없습니다." autoclosed_enabled_minutes: - other: "이 글은 %{count}분 뒤 자동적으로 닫혔습니다. 새 댓글을 다실 수 없습니다." + other: "이 주제는 %{count}분 뒤 자동으로 종료되었습니다. 새 댓글을 달 수 없습니다." autoclosed_enabled_lastpost_days: - other: "이 글은 마지막 댓글이 달리고 %{count}일 뒤 자동적으로 닫혔습니다. 새 댓글을 다실 수 없습니다." + other: "이 주제는 마지막 댓글로부터 %{count}일 뒤 자동으로 종료되었습니다. 새 댓글을 달 수 없습니다." autoclosed_enabled_lastpost_hours: - other: "마지막 댓글로부터 %{count} 시간이 지나 글타래가 자동으로 닫혔습니다. 새로운 댓글을 다실 수 없습니다." + other: "이 주제는 마지막 댓글로부터 %{count}시간 뒤 자동으로 종료되었습니다. 새 댓글을 달 수 없습니다." autoclosed_enabled_lastpost_minutes: - other: "이 글은 마지막 댓글이 달리고 %{count}분 뒤 자동적으로 닫혔습니다. 새 댓글을 다실 수 없습니다." + other: "이 주제는 마지막 댓글로부터 %{count}분 뒤 자동으로 종료되었습니다. 새 댓글을 달 수 없습니다." autoclosed_disabled_days: - other: "이 글은 %{count}일 후 자동으로 열렸습니다." + other: "이 주제는 %{count}일 후 자동으로 열렸습니다." autoclosed_disabled_hours: - other: "이 글은 %{count}시간 후 자동으로 열렸습니다." + other: "이 주제는 %{count}시간 후 자동으로 열렸습니다." autoclosed_disabled_minutes: - other: "이 글은 %{count}분 후에 자동으로 열렸습니다." + other: "이 주제는 %{count}분 후 자동으로 열렸습니다." autoclosed_disabled_lastpost_days: - other: "이 글은 마지막 댓글 작성 후 %{count}일 뒤 자동으로 열렸습니다." + other: "이 주제는 마지막 댓글로부터 %{count}일 뒤 자동으로 열렸습니다." autoclosed_disabled_lastpost_hours: - other: "이 글은 마지막 댓글 작성 후 %{count}시간 뒤 자동으로 열렸습니다." + other: "이 주제는 마지막 댓글로부터 %{count}시간 뒤 자동으로 열렸습니다." autoclosed_disabled_lastpost_minutes: - other: "이 글은 마지막 댓글 작성 후 %{count}분 뒤 자동으로 열렸습니다." - autoclosed_disabled: "이제 이 항목이 열립니다. 새 댓글이 허용됩니다." - autoclosed_disabled_lastpost: "이제 이 항목이 열립니다. 새로운 댓글이 허용됩니다." - auto_deleted_by_timer: "타이머에 의해 자동삭제됨" + other: "이 주제는 마지막 댓글로부터 %{count}분 뒤 자동으로 열렸습니다." + autoclosed_disabled: "이 주제가 열렸습니다. 새 댓글을 달 수 있습니다." + autoclosed_disabled_lastpost: "이 주제가 열렸습니다. 새 댓글을 달 수 있습니다." + auto_deleted_by_timer: "타이머에 의해 자동 삭제되었습니다." login: - invalid_second_factor_method: "선택한 2단계 방법이 잘못되었습니다." - not_enabled_second_factor_method: "선택한 2단계 방법이 사용자님의 계정에서 활성화되지 않았습니다." - security_key_description: "실제 보안 키가 준비되면 아래의 보안 키로 인증 버튼을 누릅니다." + invalid_second_factor_method: "선택한 2단계 방법이 유효하지 않습니다." + not_enabled_second_factor_method: "선택한 2단계 방법을 계정에서 활성화하지 않았습니다." + security_key_description: "실제 보안 키가 준비되면 보안 키와 함께 아래의 인증 버튼을 누르세요." security_key_alternative: "다른 방법으로 시도" security_key_authenticate: "보안 키로 인증" security_key_not_allowed_error: "보안 키 인증 프로세스가 시간 초과되었거나 취소되었습니다." - security_key_no_matching_credential_error: "제공된 보안 키에서 일치하는 자격 증명을 찾을 수 없습니다." - security_key_support_missing_error: "현재 장치 또는 브라우저가 보안 키 사용을 지원하지 않습니다. 다른 방법을 사용하십시오." - security_key_invalid: "보안 키를 확인하는 중에 오류가 발생했습니다." - not_approved: "당신의 계정은 아직 활성화되지 않았습니다. 이메일을 확인하시고 로그인 해주세요." - incorrect_username_email_or_password: "계정 아이디, 이메일 또는 패스워드가 다릅니다." - incorrect_password: "잘못된 비밀번호" - wait_approval: "가입해 주셔서 감사합니다. 곧 활성화 메일이 도착할 것 입니다." - active: "당신의 계정이 활성화되었습니다." - activate_email: "

    거의 다 끝났습니다! 활성화 메일을 %{email}으로 보냈습니다. 메일의 지침에 따라 계정을 활성화하십시오.

    도착하지 않으면 스팸 폴더를 확인하십시오.

    " - not_activated: "당신은 아직 로그인 할 수 없습니다. 계정 활성화 이메일을 보냈습니다. 계정을 활성화하기 위해 지침을 따라주세요." - not_allowed_from_ip_address: "이 IP 주소에서는 %{username} 으로 로그인 할 수 없습니다." - admin_not_allowed_from_ip_address: "그 IP로는 관리자로 로그인할 수 없습니다." - reset_not_allowed_from_ip_address: "해당 IP 에서는 비밀번호 재설정을 요청할 수 없습니다." - suspended: "당신은 %{date} 까지 로그인할 수 없습니다. " - suspended_with_reason: "%{date}까지 계정 정지 됨: %{reason}" - suspended_with_reason_forever: "계정 정지: %{reason}" + security_key_no_matching_credential_error: "제공한 보안 키에서 일치하는 크리덴셜을 찾을 수 없습니다." + security_key_support_missing_error: "현재 디바이스 또는 브라우저가 보안 키 사용을 지원하지 않습니다. 다른 방법을 사용하세요." + security_key_invalid: "보안 키를 검증하는 중에 오류가 발생했습니다." + not_approved: "계정이 아직 승인되지 않았습니다. 로그인이 가능하게 되면 이메일로 알림이 전송됩니다." + incorrect_username_email_or_password: "아이디, 이메일 또는 비밀번호가 올바르지 않습니다" + incorrect_password: "비밀번호가 올바르지 않습니다" + wait_approval: "가입해 주셔서 감사합니다. 계정이 승인되면 알림을 보내드리겠습니다." + active: "계정이 활성화되어 사용할 수 있습니다." + activate_email: "

    거의 다 끝났습니다. %{email} 주소로 메일을 보냈습니다. 메일의 지침에 따라 계정을 활성화하세요.

    메일이 도착하지 않았다면 스팸 폴더를 확인하세요.

    " + not_activated: "아직 로그인할 수 없습니다. 활성화 이메일을 전송했습니다. 해당 이메일의 지침에 따라 계정을 활성화하세요." + not_allowed_from_ip_address: "이 IP 주소로는 %{username} 아이디로 로그인할 수 없습니다." + admin_not_allowed_from_ip_address: "이 IP 주소로는 관리자로 로그인할 수 없습니다." + reset_not_allowed_from_ip_address: "이 IP 주소로는 비밀번호 리셋을 요청할 수 없습니다." + suspended: "%{date}까지 로그인할 수 없습니다. " + suspended_with_reason: "%{date}까지 계정 정지됨: %{reason}" + suspended_with_reason_forever: "계정 정지됨: %{reason}" errors: "%{errors}" - not_available: "불가능합니다. %{suggestion}" - something_already_taken: "뭔가가 이상합니다. 아마도 계정의 아이디 또는 이메일이 이미 등록된것 같습니다. 비밀번호 찾기 링크를 이용해주세요." + not_available: "사용할 수 없습니다. %{suggestion} 아이디는 어떠세요?" + something_already_taken: "문제가 발생했습니다. 아이디 또는 이메일이 이미 등록되어 있을 수 있습니다. 비밀번호 찾기 링크를 시도해 보세요." omniauth_error: - generic: "죄송합니다. 계정을 인증하는 중에 오류가 발생했습니다. 다시 시도하십시오." - csrf_detected: "인증 시간이 초과되었거나 브라우저를 전환했습니다. 다시 시도하십시오." - request_error: "권한 부여를 시작할 때 오류가 발생했습니다. 다시 시도하십시오." - invalid_iat: "서버 시계 차이로 인해 권한 토큰을 확인할 수 없습니다. 다시 시도하십시오." - omniauth_error_unknown: "로그인을 처리하는 중에 문제가 발생했습니다. 다시 시도하십시오." - omniauth_confirm_title: "%{provider}을 사용하여 로그인" + generic: "계정 인증 중에 오류가 발생했습니다. 다시 시도하세요." + csrf_detected: "인증 시간이 초과되었거나 브라우저를 전환했습니다. 다시 시도하세요." + request_error: "인증 시작 시 오류가 발생했습니다. 다시 시도하세요." + invalid_iat: "서버 시계 차이로 인해 인증 토큰을 검증할 수 없습니다. 다시 시도하세요." + omniauth_error_unknown: "로그인을 처리하는 중에 문제가 발생했습니다. 다시 시도하세요." + omniauth_confirm_title: "%{provider} 로그인" omniauth_confirm_button: "계속" - authenticator_error_no_valid_email: "%{account}와 관련된 이메일 주소는 허용되지 않습니다. 다른 이메일 주소로 계정을 구성해야 할 수도 있습니다." - new_registrations_disabled: "지금은 새로 가입할 수 없습니다." - password_too_long: "비밀번호는 200글자 이내만 허용됩니다." - email_too_long: "제공하신 이메일이 너무 깁니다. 사서함 이름은 254 자 이하 여야하며 도메인 이름은 253 자 이하 여야합니다." - wrong_invite_code: "입력 한 초대 코드가 잘못되었습니다." - reserved_username: "해당 사용자 이름은 허용되지 않습니다." - missing_user_field: "사용자 정보 입력을 덜 끝마쳤습니다." + authenticator_error_no_valid_email: "%{account} 계정과 연결된 이메일 주소는 허용되지 않습니다. 다른 이메일 주소로 계정을 환경설정해야 할 수도 있습니다." + new_registrations_disabled: "지금은 새 계정을 등록할 수 없습니다." + password_too_long: "비밀번호는 200자로 제한됩니다." + email_too_long: "제공한 이메일이 너무 깁니다. 메일함 이름은 254자 이하여야 하며 도메인 이름은 253자 이하여야 합니다." + wrong_invite_code: "입력한 초대 코드가 잘못되었습니다." + reserved_username: "이 아이디는 허용되지 않습니다." + missing_user_field: "입력 누락된 사용자 필드가 있습니다." auth_complete: "인증이 완료되었습니다." - click_to_continue: "계속하려면 여기를 클릭하십시오." - already_logged_in: "죄송합니다! 이 초대는 기존 계정이 없는 신규 사용자를 위한 것입니다." + click_to_continue: "계속하려면 여기를 클릭하세요." + already_logged_in: "이 초대는 기존 계정이 없는 신규 사용자를 위한 것입니다." second_factor_title: "2단계 인증" - second_factor_description: "앱에서 필요한 인증 코드를 입력하십시오 :" - second_factor_backup_description: "백업 코드 중 하나를 입력하세요:" + second_factor_description: "앱의 필수 인증 코드를 입력하세요." + second_factor_backup_description: "백업 코드 중 하나를 입력하세요." second_factor_backup_title: "2단계 백업 코드" - invalid_second_factor_code: "인증 코드가 잘못되었습니다. 각 코드는 한 번만 사용할 수 있습니다." - invalid_security_key: "잘못된 보안 키." - missing_second_factor_name: "이름을 알려주십시오." - missing_second_factor_code: "코드를 입력하십시오." + invalid_second_factor_code: "인증 코드가 유효하지 않습니다. 각 코드는 한 번만 사용할 수 있습니다." + invalid_security_key: "보안 키가 유효하지 않습니다." + missing_second_factor_name: "이름을 입력하세요." + missing_second_factor_code: "코드를 입력하세요." second_factor_toggle: - totp: "대신 인증 자 앱 또는 보안 키를 사용하십시오." + totp: "대신 인증 앱 또는 보안 키 사용" backup_code: "대신 백업 코드 사용" admin: email: - sent_test: "전송됨!" + sent_test: "전송되었습니다!" user: merge_user: - updating_username: "사용자명 업데이트 중..." - changing_post_ownership: "글 작성자 변경 중..." - merging_given_daily_likes: "일일 좋아요 병합 중..." - merging_post_timings: "게시 시간 병합 중..." + updating_username: "아이디 업데이트 중..." + changing_post_ownership: "게시물 소유자 변경 중..." + merging_given_daily_likes: "보낸 일일 좋아요 병합 중..." + merging_post_timings: "게시물 시간 병합 중..." merging_user_visits: "사용자 방문 병합 중..." updating_site_settings: "사이트 설정 업데이트 중..." updating_user_stats: "사용자 통계 업데이트 중..." - merging_user_attributes: "사용자 속성 병합 중..." + merging_user_attributes: "사용자 어트리뷰트 병합 중..." updating_user_ids: "사용자 ID 업데이트 중..." deleting_source_user: "소스 사용자 삭제 중..." user: - deactivated: "'%{email}'에 반송 이메일이 너무 많아 비활성화되었습니다." + deactivated: "'%{email}'에 반송 이메일이 너무 많아 비활성화되었습니다." deactivated_by_staff: "운영진에 의해 비활성화됨" deactivated_by_inactivity: - other: "%{count}일 동안 활동이 없으면 자동으로 비활성화 됨" + other: "%{count}일 동안 활동이 없으면 자동으로 비활성화됨" activated_by_staff: "운영진에 의해 활성화됨" - new_user_typed_too_fast: "타이핑이 너무 빠른 신규 사용자" - content_matches_auto_silence_regex: "내용이 자동 차단 정규식과 일치합니다." - content_matches_auto_block_regex: "자동 블럭 문구와 일치하는 내용" + new_user_typed_too_fast: "입력이 너무 빠른 신규 사용자" + content_matches_auto_silence_regex: "콘텐츠가 자동 차단 정규식과 일치합니다" + content_matches_auto_block_regex: "콘텐츠가 자동 차단 정규식과 일치합니다" username: - short: "최소 %{min}자 이상이어야 합니다." - long: "%{max}자 이상 사용할 수 없습니다." - too_long: "너무 길어" - characters: "숫자, 문자, 대시, 점 및 밑줄 만 포함해야합니다." - unique: "이미 사용중입니다." - blank: "공백이 없어야 합니다." - must_begin_with_alphanumeric_or_underscore: "첫글자는 알파벳, 숫자, 언더바만 쓸 수 있습니다." - must_end_with_alphanumeric: "마지막 글자는 알파벳이나 숫자만 가능합니다." - must_not_contain_two_special_chars_in_seq: "특수 문자(.-_)를 연달아 사용할 수 없습니다." - must_not_end_with_confusing_suffix: "혼동을 일으키는 접미사(.json, .png 등등)로 끝나면 안됩니다." + short: "최소 %{min}자 이상이어야 합니다" + long: "%{max}자 이하여야 합니다" + too_long: "너무 깁니다" + characters: "숫자, 문자, 대시, 마침표 및 언더스코어만 포함해야 합니다" + unique: "고유해야 합니다" + blank: "공백이 없어야 합니다" + must_begin_with_alphanumeric_or_underscore: "첫 글자는 문자, 숫자, 언더스코어만 쓸 수 있습니다" + must_end_with_alphanumeric: "마지막 글자는 문자나 숫자만 가능합니다" + must_not_contain_two_special_chars_in_seq: "특수 문자(.-_)를 연속으로 사용할 수 없습니다" + must_not_end_with_confusing_suffix: "혼동을 일으키는 접미사(.json, .png 등)로 끝나면 안 됩니다" email: invalid: "유효하지 않습니다." - not_allowed: "이 이메일 제공업체는 허용되지 않습니다. 다른 이메일 제공 업체를 사용하세요." + not_allowed: "이 이메일 제공자에서 허용하지 않습니다. 다른 이메일 주소를 사용하세요." blocked: "는 허용되지 않습니다" - revoked: "'%{email}'로 %{date}까지는 이메일을 보내지 않습니다." + revoked: "%{date}까지는 '%{email}' 주소로 이메일을 보내지 않습니다." does_not_exist: "N/A" ip_address: - blocked: "이 IP주소에서는 가입이 안됩니다." - max_new_accounts_per_registration_ip: "이 IP에서는 가입이 더이상 되지 않습니다(최대 가입 제한 도달). 스태프에게 연락주세요." + blocked: "이 IP 주소에서는 신규 등록할 수 없습니다." + max_new_accounts_per_registration_ip: "이 IP 주소에서는 신규 등록할 수 없습니다(최대 한도에 도달함). 운영진에게 문의하세요." website: - domain_not_allowed: "유효하지 않은 웹사이트입니다. 허용되는 도메인 목록: %{domains}" - auto_rejected: "나이 때문에 자동으로 거부됩니다. auto_handle_queued_age 사이트 설정을 참조하십시오." + domain_not_allowed: "유효하지 않은 웹사이트입니다. 허용되는 도메인: %{domains}" + auto_rejected: "나이 때문에 자동으로 거부됩니다. auto_handle_queued_age 사이트 설정을 참조하세요." destroy_reasons: - unused_staged_user: "사용하지 않은 단계적 사용자" - fixed_primary_email: "단계별 사용자를위한 기본 이메일 수정" - same_ip_address: "다른 사용자와 동일한 IP 주소 (%{ip_address})" + unused_staged_user: "사용하지 않은 스테이징된 사용자" + fixed_primary_email: "스테이징된 사용자의 기본 이메일 수정됨" + same_ip_address: "다른 사용자와 동일한 IP 주소(%{ip_address})" inactive_user: "비활성 사용자" - reviewable_reject_auto: "대기중인 검토 가능 항목 자동 처리" - reviewable_reject: "검토 가능한 사용자가 거부됨" - email_in_spam_header: "사용자의 첫 번째 이메일이 스팸으로 표시되었습니다" - already_silenced: "사용자가 이미 %{time_ago}전 %{staff}의해 글 작성이 금지되었습니다." - already_suspended: "사용자의 계정이 이미 %{time_ago}전 %{staff}의해 일시 중지되었습니다." + reviewable_reject_auto: "대기 중인 검토 가능 항목 자동 처리" + reviewable_reject: "검토 가능한 사용자 거부됨" + email_in_spam_header: "사용자의 첫 이메일이 스팸으로 신고됨" + already_silenced: "사용자가 이미 %{time_ago} 전 %{staff}에 의해 차단되었습니다." + already_suspended: "사용자가 이미 %{time_ago} 전 %{staff}에 의해 정지되었습니다." cannot_delete_has_posts: - other: "사용자 %{username}님은 %{count}개의 게시물이 있으므로 삭제할 수 없습니다." + other: "사용자 %{username} 님은 공개 주제 또는 개인 메시지에 %{count}개의 게시물이 있으므로 삭제할 수 없습니다." unsubscribe_mailer: - title: "메일링 구독해지" - subject_template: "더 이상 %{site_title}에서 이메일 업데이트를 수신하지 않기를 확인하십시오" + title: "구독 해제 메일러" + subject_template: "더 이상 %{site_title}에서 이메일 업데이트를 수신하지 않음을 확인합니다" text_body_template: | - 누군가 (본인이거나?) %{site_domain_name}에서 이 주소로 더 이상 이메일 업데이트를 보내지 않도록 요청했습니다. - 이를 확인하려면 다음 링크를 클릭하십시오. + 누군가가(본인일 수 있음) %{site_domain_name}에서 이 주소로 더 이상 이메일 업데이트를 전송하지 않도록 요청했습니다. + 이를 확인하려면 다음 링크를 클릭하세요. %{confirm_unsubscribe_link} - 이메일 업데이트를 계속 받으려면 이 이메일을 무시하십시오. + 이메일 업데이트를 계속 수신하려면 이 이메일을 무시하세요. invite_mailer: - title: "메일러 초대" - subject_template: "%{inviter_name}님이 %{site_domain_name}의 %{topic_title}에 사용자님을 초대했습니다." + title: "초대 메일러" + subject_template: "%{inviter_name} 님이 %{site_domain_name}의 '%{topic_title}'에 나를 초대했습니다" text_body_template: | - %{inviter_name}님이 사용자님을 대화에 초대했습니다. + %{inviter_name} 님이 나를 토론에 초대했습니다 > **%{topic_title}** > > %{topic_excerpt} - 에서 + - > %{site_title} -- %{site_description} - 대화에 참여 하시려면 아래 링크를 클릭 하세요: + 관심이 있다면 아래 링크를 클릭하세요. %{invite_link} custom_invite_mailer: - title: "맞춤 초대 메일러" - subject_template: "%{inviter_name}님이 %{site_domain_name}의 %{topic_title}에 사용자님을 초대했습니다." + title: "초대 사용자 지정 메일러" + subject_template: "%{inviter_name} 님이 %{site_domain_name}의 '%{topic_title}'에 나를 초대했습니다" text_body_template: | - %{inviter_name}님이 사용자님을 대화에 초대했습니다. + %{inviter_name} 님이 나를 토론에 초대했습니다 > **%{topic_title}** > > %{topic_excerpt} - 에서 + - > %{site_title} -- %{site_description} @@ -2306,27 +2279,27 @@ ko: > %{user_custom_message} - 대화에 참여 하시려면 아래 링크를 클릭 하세요: + 관심이 있다면 아래 링크를 클릭하세요. %{invite_link} invite_forum_mailer: - title: "포럼 메일러 초대" - subject_template: "%{inviter_name} 님이 초대했습니다. %{site_domain_name}" + title: "포럼 초대 메일러" + subject_template: "%{inviter_name} 님이 %{site_domain_name}에 가입하도록 나를 초대했습니다" text_body_template: | - %{inviter_name}님이 사용자님을 대화에 초대했습니다. + %{inviter_name} 님이 가입하도록 초대했습니다 > **%{site_title}** > > %{site_description} - 대화에 참여 하시려면 아래 링크를 클릭 하세요: + 관심이 있다면 아래 링크를 클릭하세요. %{invite_link} custom_invite_forum_mailer: - title: "맞춤 초대 포럼 메일러" - subject_template: "%{inviter_name} 님이 초대했습니다. %{site_domain_name}" + title: "포럼 초대 사용자 지정 메일러" + subject_template: "%{inviter_name} 님이 %{site_domain_name}에 가입하도록 나를 초대했습니다" text_body_template: | - %{inviter_name}님이 사용자님을 대화에 초대했습니다. + %{inviter_name} 님이 가입하도록 초대했습니다 > **%{site_title}** > @@ -2336,505 +2309,505 @@ ko: > %{user_custom_message} - 대화에 참여 하시려면 아래 링크를 클릭 하세요: + 관심이 있다면 아래 링크를 클릭하세요. %{invite_link} invite_password_instructions: - title: "비밀번호 안내 초대" + title: "초대 비밀번호 지침" subject_template: "%{site_name} 계정을 위해 비밀번호 설정" text_body_template: | - %{site_name} 초대를 수락 해 주셔서 감사합니다. 환영합니다! + %{site_name} 초대를 수락해 주셔서 감사합니다. 환영합니다! - 지금 비밀번호를 설정 하려면 아래 링크를 클릭하십시오: + 지금 비밀번호를 설정하려면 다음 링크를 클릭하세요. %{base_url}/u/password-reset/%{email_token} - (위 링크가 만료 된 경우 이메일 주소로 로그인 할 때 "비밀번호를 잊어 버렸습니다"를 선택하십시오.) + (위 링크가 만료된 경우 이메일 주소로 로그인할 때 '비밀번호를 잊어 버렸습니다'를 선택하세요.) download_backup_mailer: - title: "백업 메일러 다운로드" + title: "백업 다운로드 메일러" subject_template: "[%{email_prefix}] 사이트 백업 다운로드" text_body_template: | 요청하신 [사이트 백업 다운로드](%{backup_file_path})입니다. - 보안상의 이유로 다운로드 링크가 이메일 주소로 발송되었습니다. + 보안상의 이유로 다운로드 링크가 검증된 이메일 주소로 발송되었습니다. - (이 다운로드를 요청하지 *않은* 경우, 누군가가 사용자님의 사이트에 대한 관리자 액세스 권한을 가지고 있을 가능성이 있습니다.) + (이 다운로드를 요청하지 *않은* 경우 유의하세요. 누군가가 내 사이트의 관리자 액세스 권한을 가지고 있을 가능성이 있습니다.) no_token: | - 죄송합니다. 이 백업 다운로드 링크는 이미 사용되었거나 만료되었습니다. + 이 백업 다운로드 링크는 이미 사용되었거나 만료되었습니다. admin_confirmation_mailer: title: "관리자 확인" subject_template: "[%{email_prefix}] 새 관리자 계정 확인" text_body_template: | - **%{target_username} (%{target_email})** 을 포럼의 관리자로 추가 할 것인지 확인하세요. + **%{target_username}(%{target_email})** 님을 포럼의 관리자로 추가할 것인지 확인하세요. [관리자 계정 확인](%{admin_confirm_url}) test_mailer: - title: "메일러 테스트" + title: "테스트 메일러" subject_template: "[%{email_prefix}] 이메일 전달 테스트" new_version_mailer: title: "새 버전 메일러" - subject_template: "[%{email_prefix}] 새로운 담화 버전, 업데이트 가능" + subject_template: "[%{email_prefix}] 새 Discourse 버전 업데이트 사용 가능" text_body_template: | - [Discourse](https://www.discourse.org)의 새로운 버전이 출시되었습니다! + [Discourse](https://www.discourse.org)의 새 버전이 출시되었습니다! - 사용자의 현재 버전: %{installed_version} + 내 현재 버전: %{installed_version} 새 버전: **%{new_version}** - - 간편한 **[원클릭 브라우저 업그레이드](%{base_url}/admin/upgrade)** + - 간편한 **[원클릭 브라우저 업그레이드](%{base_url}/admin/upgrade)**로 업그레이드 - - [릴리스 노트]( https://meta.discourse.org/tag/release-notes) 또는 [GitHub 변경 로그](https://github.com/discourse/discourse/commits/main) 보기 + - [출시 노트](https://meta.discourse.org/tag/release-notes) 또는 [GitHub 체인지로그](https://github.com/discourse/discourse/commits/main)의 새 소식 확인하기 - - [meta.discourse.org](https:// meta.discourse.org)를 방문해 뉴스, 토론 및 Discourse 지원 확인 + - [meta.discourse.org](https:// meta.discourse.org)에서 뉴스, 토론 및 Discourse 지원 확인 new_version_mailer_with_notes: - title: "노트가있는 새로운 버전 메일러" - subject_template: "[%{email_prefix}] 업데이트 가능" + title: "노트가 있는 새 버전 메일러" + subject_template: "[%{email_prefix}] 업데이트 사용 가능" text_body_template: | - [Discourse](https://www.discourse.org)의 새 버전을 사용할 수 있습니다! + [Discourse](https://www.discourse.org)의 새 버전이 출시되었습니다! - 현재 버전: %{installed_version} + 내 현재 버전: %{installed_version} 새 버전: **%{new_version}** - - 쉬운 방법으로 업그레이드 **[원클릭 브라우저 업그레이드](%{base_url}/admin/upgrade)** + - 간편한 **[원클릭 브라우저 업그레이드](%{base_url}/admin/upgrade)**로 업그레이드 - - [릴리스 노트](https://meta.discourse.org/tag/release-notes) 또는 [GitHub 변경 로그](https://github.com/discourse/discourse/commits/main)에서 새로운 내용을 확인해보세요. + - [출시 노트](https://meta.discourse.org/tag/release-notes) 또는 [GitHub 체인지로그](https://github.com/discourse/discourse/commits/main)의 새 소식 확인하기 - - 새로운 소식이나 Discourse에 대한 지원이 필요하면 [meta.discourse.org](https://meta.discourse.org)를 방문해보세요. + - [meta.discourse.org](https:// meta.discourse.org)에서 뉴스, 토론 및 Discourse 지원 확인 - ### 릴리즈 노트 + ### 출시 노트 %{notes} flag_reasons: - off_topic: "내가 올린 글타래가 **주제 벗어난 이야기**으로 신고 되었습니다. 사람들이 이 글타래의 제목이랑 글 내용이 안 맞는다고 느끼나 봅니다. " - inappropriate: "내가 올린 글타래가 **부적절**로 신고 되었습니다. 사람들이 이 글타래가 [가이드라인](%{base_path}/guidelines)에서 벗어나 공격적, 모욕적, 폭력적이라고 느낍니다." - spam: "내가 올린 글타래가 **스팸**으로 신고 되었습니다. 커뮤니티가 이 글타래가 생각보다 광고성, 선동적이라고 느끼나 봅니다." - notify_moderators: "내가 올린 글타래가 **관리자의 관심 필요**로 신고 되었습니다. 커뮤니티가 관리자의 세심한 중재가 필요하다고 느낍니다." + off_topic: "내 게시물이 **주제에 벗어남** 으로 신고되었습니다. 커뮤니티에서 이 게시물이 현재 제목 및 첫 게시물로 지정된 이 주제와 맞지 않는다고 생각하는 것 같습니다. " + inappropriate: "내 게시물이 **부적절** 로 신고되었습니다. 커뮤니티에서 이 게시물이 불쾌하거나 모욕적이거나 [커뮤니티 가이드라인](%{base_path}/guidelines)을 위반했다고 생각하는 것 같습니다." + spam: "내 게시물이 **스팸** 으로 신고되었습니다. 커뮤니티에서 이 게시물이 유용하거나 주제와 관련되지 않고 생각보다 너무 프로모션 성격을 갖고 있어 광고라고 생각하는 것 같습니다." + notify_moderators: "내 게시물이 **운영자 확인 필요** 로 신고되었습니다. 커뮤니티에서 이 게시물이 운영진의 직접적인 개입이 필요하다고 생각하는 것 같습니다." flags_dispositions: - agreed: "알려줘서 감사합니다. 문제가 있음에 동의하며 내용을 살펴보겠습니다." - agreed_and_deleted: "알려줘서 감사합니다. 문제가 있음에 동의하며 해당 글을 삭제했습니다." - disagreed: "알려줘서 감사합니다. 살펴보겠습니다." - ignored: "알려줘서 감사합니다. 살펴보겠습니다." - ignored_and_deleted: "알려줘서 감사합니다. 해당 글을 삭제했습니다." + agreed: "알려주셔서 감사합니다. 문제가 있음에 동의하며 자세히 확인해 보겠습니다." + agreed_and_deleted: "알려주셔서 감사합니다. 문제가 있음에 동의하며 게시물을 제거했습니다." + disagreed: "알려주셔서 감사합니다. 자세히 확인해 보겠습니다." + ignored: "알려주셔서 감사합니다. 자세히 확인해 보겠습니다." + ignored_and_deleted: "알려주셔서 감사합니다. 게시물을 제거했습니다." temporarily_closed_due_to_flags: - other: "이 글은 많은 신고로 인해 최소 %{count}시간 동안 일시적으로 닫힙니다." + other: "이 주제는 다수의 커뮤니티 신고로 인해 최소 %{count}시간 일시적으로 종료됩니다." system_messages: reviewables_reminder: subject_template: "검토 대기열에 검토가 필요한 항목이 있습니다." - private_topic_title: "주제 # %{id}" - contents_hidden: "내용을 보려면 게시물을 방문하십시오." + private_topic_title: "주제 #%{id}" + contents_hidden: "콘텐츠를 보려면 게시물을 방문하세요." post_hidden: title: "숨겨진 게시물" - subject_template: "커뮤니티 플래그로 숨겨진 게시물" + subject_template: "커뮤니티 신고로 숨겨진 게시물" text_body_template: | 안녕하세요, - 사용자님의 게시물이 숨겨 졌음을 알리기 위한 %{site_name} 에서 보낸 자동 메시지입니다. + 게시물이 숨겨졌음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. <%{base_url}%{url}> %{flag_reason} - 이 게시물은 신고로 인해 숨겨 졌으므로 이를 보완하기 위해 게시물을 수정하는 방법을 고려하십시오. **%{edit_delay}분 후에 게시물을 수정할 수 있으며, 수정 후 자동으로 숨김 해제됩니다.** + 이 게시물은 커뮤니티 신고로 인해 숨겨졌으므로 커뮤니티 피드백을 반영하여 게시물을 되살릴 방법을 고려해 보시기 바랍니다. **%{edit_delay}분 후에 게시물을 편집할 수 있으며 자동으로 숨김 해제됩니다.** - 그러나 게시물이 두 번째로 신고되면 관리자가 처리 할 때까지 숨겨집니다. + 하지만 게시물이 커뮤니티에 의해 한 번 더 숨겨질 경우 운영진이 처리할 때까지 숨겨진 상태로 유지됩니다. - 추가 안내는 [커뮤니티 가이드 라인](%{base_url}/guidelines)을 참조하세요. + 자세한 내용은 [커뮤니티 가이드라인](%{base_url}/guidelines)을 참조하세요. post_hidden_again: title: "다시 숨겨진 게시물" - subject_template: "커뮤니티 플래그에 의해 숨겨진 게시물, 직원에게 알림" + subject_template: "커뮤니티 신고로 숨겨진 게시물, 운영진 알림 전송됨" text_body_template: | 안녕하세요, - 사용자님의 게시물이 다시 숨겨 졌음을 알리기 위한 %{site_name} 에서 보낸 자동 메시지입니다. + 게시물이 다시 숨겨졌음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. <%{base_url}%{url}> %{flag_reason} - 이 게시물은 신고로 인해 숨겨졌습니다. **이 게시물은 두 번 이상 숨겨졌으므로 이제 이 게시물은 관리자가 처리 할 때까지 숨겨진 상태로 유지됩니다.** + 커뮤니티 신고로 인해 게시물이 숨겨졌습니다. **게시물이 두 번째 숨겨졌으므로 이제 이 게시물은 운영진이 처리할 때까지 숨겨진 상태로 유지됩니다.** - 추가 지침은 [커뮤니티 가이드 라인](%{base_url}/guidelines)을 참조하세요. + 자세한 내용은 [커뮤니티 가이드라인](%{base_url}/guidelines)을 참조하세요. queued_by_staff: title: "승인이 필요한 게시물" - subject_template: "관리자가 숨긴 승인 대기중 게시물" + subject_template: "운영진이 숨긴 게시물, 승인 대기 중" text_body_template: | 안녕하세요, - 사용자님의 게시물이 숨겨 졌음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. + 게시물이 숨겨졌음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. <%{base_url}%{url}> - 사용자님의 게시물은 관리자가 검토 할 때까지 숨겨진 상태로 유지됩니다. + 게시물은 운영진이 검토할 때까지 숨겨진 상태로 유지됩니다. - 추가 안내는 [커뮤니티 가이드 라인](%{base_url}/guidelines)을 참조하세요. + 자세한 내용은 [커뮤니티 가이드라인](%{base_url}/guidelines)을 참조하세요. flags_disagreed: - title: "직원이 복원 한 신고 된 게시물" - subject_template: "직원이 복원 한 신고 된 게시물" + title: "운영진이 복원한 신고된 게시물" + subject_template: "운영진이 복원한 신고된 게시물" text_body_template: | 안녕하세요, - [사용자님의 게시물](%{base_url}%{url})이 복원 되었음을 알려 드리기 위해 %{site_name} 에서 보낸 자동 메시지입니다. + [게시물](%{base_url}%{url})이 복원되었음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. - 신고된 이 게시물은 관리자가 복원하기로 결정했습니다. + 커뮤니티에서 이 게시물을 신고했으며 운영진 판단하에 복원 처리되었습니다. - [상세="클릭해 복원된 글 보기"] + [details="클릭하여 복원된 게시물을 펼치기"] ``` markdown %{flagged_post_raw_content} ``` [/details] flags_agreed_and_post_deleted: - title: "직원이 신고 한 소식을 삭제했습니다." - subject_template: "직원이 신고 한 소식을 삭제했습니다." + title: "운영진이 신고된 게시물 제거함" + subject_template: "운영진이 신고된 게시물 제거함" text_body_template: | 안녕하세요, - [사용자님의 게시물](%{base_url}%{url})이 삭제되었음을 알려 드리기 위해 %{site_name}에서 발송된 자동 메시지입니다. + [게시물](%{base_url}%{url})이 제거되었음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. %{flag_reason} - 이 게시물은 커뮤니티에서 신고되어 관리자에 의해 삭제되었습니다. + 커뮤니티에서 이 게시물을 신고했으며 운영진 판단하에 제거되었습니다. ``` markdown %{flagged_post_raw_content} ``` - [커뮤니티 가이드라인](%{base_url}/guidelines)을 참조하시기 바랍니다. + 자세한 내용은 [커뮤니티 가이드라인](%{base_url}/guidelines)을 검토하시기 바랍니다. flags_agreed_and_post_deleted_for_responders: - title: "관리자가 신고한 게시물을 삭제했습니다." - subject_template: "관리자가 신고한 게시물을 삭제했습니다." + title: "운영진이 신고된 게시물에서 댓글 제거함" + subject_template: "운영진이 신고된 게시물에서 댓글 제거함" usage_tips: text_body_template: | - 신규 사용자를 위한 몇 가지 간단한 도움말은 [이 블로그 게시물](https://blog.discourse.org/2016/12/discourse-new-user-tips-and-tricks/)을 참조하세요. + 신규 사용자를 위한 몇 가지 간단한 시작 도움말은 [이 블로그 게시물](https://blog.discourse.org/2016/12/discourse-new-user-tips-and-tricks/)을 참조하세요. - 여기를 확인하면 일시적인 신규 사용자 제한이 해제됩니다. 시간이 지남에 따라 커뮤니티를 함께 관리하는데 도움이되는 기능을 포함하는 [회원 레벨](https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/)을 얻게됩니다. + 여기를 확인하면 일시적인 신규 사용자 제한이 해제됩니다. 시간이 지남에 따라 [신뢰 레벨](https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/)이 부여되어 함께 커뮤니티를 관리하는 데 유용한 특수 기능을 사용하실 수 있습니다. welcome_user: title: "사용자 환영" - subject_template: "%{site_name} 사이트에 오신것을 환영합니다!" + subject_template: "%{site_name}에 오신 것을 환영합니다!" text_body_template: | - %{site_name} 사이트에 오신것을 환영합니다! + %{site_name}에 가입해 주셔서 감사합니다. 환영합니다! %{new_user_tips} - 저희는 [커뮤니티 행동 방침](%{base_url}/guidelines)을 잘 따라주실 것을 믿습니다. + [성숙한 커뮤니티 활동](%{base_url}/guidelines)을 해 주시리라 믿습니다. - 다시한번 환영합니다! + 즐거운 시간 보내세요! welcome_tl1_user: title: "TL1 사용자 환영" - subject_template: "우리와 함께 시간을 보내 주셔서 감사합니다" + subject_template: "함께해 주셔서 감사합니다" text_body_template: | - 안녕하세요. 많은 글을 읽어주셔서 감사드립니다. 그래서 사용자님을 [회원 레벨!](https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/)으로 승격 시켰습니다. + 안녕하세요, 많은 글을 읽어 주셔서 [신뢰 레벨](https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/)이 승급되었습니다! - 저희와 함께 시간을 보내 주셔서 정말 기쁩니다. 저희는 여러분에 대해 더 많이 알고 싶습니다. 잠시 시간을내어 [프로필 작성](%{base_url}/my/preferences/profile) 또는 [새 글 작성](%{base_url}/categories)을 권유드립니다. + 저희와 많은 시간을 보내 주셔서 정말 기쁩니다. 여러분에 대해 알아갈 수 있도록 잠시 시간을 내어 [프로필 작성](%{base_url}/my/preferences/profile)을 하거나 [새 주제 작성](%{base_url}/categories)을 해 보는 건 어떨까요? welcome_staff: - title: "직원 환영" - subject_template: "축하합니다, 귀하는 %{role} 등급을 받았습니다!" + title: "운영진 환영" + subject_template: "축하합니다, %{role} 역할이 부여되었습니다!" text_body_template: | - 다른 관리자에 의해 %{role} 등급으로 변경되었습니다. + 동료 운영진에 의해 %{role} 역할이 부여되었습니다. - 이제 %{role}로서 관리 인터페이스에 접근 할 수 있습니다. + %{role} 역할은 관리 인터페이스에 액세스할 수 있습니다. - 게시물 검토가 처음이라면 [관리자 가이드](https://meta.discourse.org/t/discourse-moderation-guide/63116)를 참조하세요. + 이런 권한에는 책임이 따르기 마련입니다. 운영이 처음이라면 [관리 가이드](https://meta.discourse.org/t/discourse-moderation-guide/63116)를 참조하세요. welcome_invite: - title: "초대합니다" - subject_template: "%{site_name} 사이트에 오신것을 환영합니다!" + title: "초대 환영" + subject_template: "%{site_name}에 오신 것을 환영합니다!" text_body_template: | - %{site_name}의 초대를 수락해 주셔서 감사합니다 -- 환영합니다! + %{site_name} 초대를 수락해 주셔서 감사합니다. 환영합니다! - - 새로운 계정 **%{username}**을 만들었습니다. [사용자 프로필][prefs]을 방문하여 사용자명 또는 비밀번호를 변경하세요. + - **%{username}** 신규 계정이 생성되었습니다. [사용자 프로필][prefs]을 방문하여 이름 또는 비밀번호를 변경하세요. - - 로그인 할 때 **원래 초대장과 동일한 이메일 주소를 사용하십시오** — 그렇지 않으면 본인임을 알 수 없습니다! + - 로그인할 때 **원래 초대장에 표시된 것과 동일한 이메일 주소를 사용하세요.** — 그렇지 않으면 본인임을 확인할 수 없습니다! %{new_user_tips} - 그리고 [올바른 커뮤니티 활동](%{base_url}/guidelines)을 확인해주세요. + [성숙한 커뮤니티 활동](%{base_url}/guidelines)을 해 주시리라 믿습니다. - 즐거운 시간 되십시오! + 즐거운 시간 보내세요! [prefs]: %{user_preferences_url} tl2_promotion_message: - subject_template: "회원 레벨 승격을 축하합니다!" + subject_template: "신뢰 레벨 승급을 축하합니다!" backup_succeeded: title: "백업 성공" - subject_template: "백업 성공" + subject_template: "백업을 완료했습니다" text_body_template: | - 백업이 성공적으로 완료되었습니다. + 백업을 완료했습니다. - [관리자 > 백업 섹션](%{base_url}/admin/backups)을 방문해 백업을 다운로드하세요. + [관리자 > 백업 섹션](%{base_url}/admin/backups)을 방문하여 새 백업을 다운로드하세요. - 로그는 다음과 같습니다: + 로그: %{logs} backup_failed: title: "백업 실패" - subject_template: "백업에 실패했습니다." + subject_template: "백업하지 못했습니다" text_body_template: | - 백업에 실패했습니다. + 백업하지 못했습니다. - 로그는 다음과 같습니다: + 로그: %{logs} restore_succeeded: title: "복원 성공" - subject_template: "복원 성공" + subject_template: "복원을 완료했습니다" text_body_template: | - 복원에 성공했습니다. + 복원을 완료했습니다. - 로그는 다음과 같습니다: + 로그: %{logs} restore_failed: title: "복원 실패" - subject_template: "복원 실패" + subject_template: "복원하지 못했습니다" text_body_template: | - 복원에 실패했습니다. + 복원하지 못했습니다. - 로그는 다음과 같습니다: + 로그: %{logs} bulk_invite_succeeded: - title: "대량 초대 성공" - subject_template: "대량 사용자 초대가 성공적으로 진행되었습니다." - text_body_template: "대량 사용자 초대가 진행되어 %{sent}개의 초대장을 보냈습니다." + title: "일괄 초대 성공" + subject_template: "일괄 사용자 초대가 처리되었습니다" + text_body_template: "일괄 사용자 초대 파일이 처리되어 %{sent}명에게 초대를 발송했습니다." bulk_invite_failed: - title: "대량 초대 실패" - subject_template: "대량 사용자 초대 중 오류가 났습니다." + title: "일괄 초대 실패" + subject_template: "일괄 사용자 초대 처리 중에 오류가 발생했습니다" text_body_template: | - 대량 사용자 초대 파일이 처리되었습니다. %{sent}명의 초대가 %{failed}개의 오류와 함께 발송되었습니다. + 일괄 사용자 초대 파일이 처리되어 %{sent}명에게 초대를 발송했고 %{failed}개의 오류가 발생했습니다. - 로그는 다음과 같습니다: + 로그: ``` text %{logs} ``` user_added_to_group_as_owner: title: "그룹에 소유자로 추가됨" - subject_template: "%{group_name} 그룹의 소유자로 추가되었습니다." + subject_template: "%{group_name} 그룹의 소유자로 추가되었습니다" text_body_template: | - [%{group_name}] (%{base_url}%{group_path}) 그룹의 소유자로 추가되었습니다. + [%{group_name}](%{base_url}%{group_path}) 그룹의 소유자로 추가되었습니다. user_added_to_group_as_member: - title: "그룹에 구성원으로 추가됨" - subject_template: "%{group_name} 그룹의 구성원으로 추가되었습니다." + title: "그룹에 회원으로 추가됨" + subject_template: "%{group_name} 그룹의 회원으로로 추가되었습니다" text_body_template: | - [%{group_name}] (%{base_url}%{group_path}) 그룹의 구성원으로 추가되었습니다. + [%{group_name}](%{base_url}%{group_path}) 그룹의 회원으로 추가되었습니다. csv_export_succeeded: - title: "CSV 내보내기 성공" - subject_template: "[%{export_title}] 데이터 내보내기 완료" + title: "CSV 익스포트 성공" + subject_template: "[%{export_title}] 데이터 익스포트 완료" text_body_template: | - 데이터 내보내기에 성공했습니다! :dvd: + 데이터를 익스포트했습니다! :dvd: %{download_link} - 위의 다운로드 링크는 48시간 동안 유효합니다. + 위의 다운로드 링크는 48시간 유효합니다. - 데이터는 zip 아카이브로 압축됩니다. 아카이브를 열 때 압축이 풀리지 않으면 여기에서 권장하는 도구를 사용하십시오. https://www.7-zip.org/ + 데이터는 zip 아카이브로 압축됩니다. 아카이브를 열 때 자체적으로 압축이 풀리지 않으면 이 권장 툴을 사용하세요. https://www.7-zip.org/ csv_export_failed: - title: "CSV 내보내기 실패" - subject_template: "데이터 추출 실패" - text_body_template: "죄송합니다. 데이터 내보내기에 실패했습니다. 로그를 확인하거나 [직원에게 문의하십시오] (%{base_url} / about)." + title: "CSV 익스포트 실패" + subject_template: "데이터 익스포트 실패" + text_body_template: "데이터를 익스포트하지 못했습니다. 로그를 확인하거나 [운영진에게 문의하세요](%{base_url} / about)." email_reject_insufficient_trust_level: - title: "이메일 거부 신뢰 수준이 충분하지 않습니다" - subject_template: "[%{email_prefix}] 이메일 문제-불충분 한 신뢰 수준" + title: "이메일 거부, 신뢰 레벨 미달" + subject_template: "[%{email_prefix}] 이메일 문제 -- 신뢰 레벨 미달" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 사용자님은 현재 권한이 없습니다. 오류라고 생각되면 [관리자에게 문의](%{base_url}/about) 하세요. + 이 이메일 주소로 새 주제를 게시할 신뢰 레벨을 충족하지 않습니다. 오류라고 생각되면 [운영진에게 문의하세요](%{base_url}/about). email_reject_user_not_found: - title: "이메일 거부 사용자를 찾을 수 없음" - subject_template: "[%{email_prefix}] 이메일 문제-사용자를 찾을 수 없음" + title: "이메일 거부, 사용자를 찾을 수 없음" + subject_template: "[%{email_prefix}] 이메일 문제 -- 사용자를 찾을 수 없음" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 알 수없는 이메일 주소에서 보냈습니다. 다른 이메일 주소에서 보내거나 [관리자에게 문의](%{base_url}/about) 하세요. + 알 수 없는 이메일 주소를 사용하여 보낸 답장입니다. 다른 이메일 주소로 보내거나 [운영진에게 문의하세요](%{base_url}/about). email_reject_screened_email: - title: "이메일 거부 된 이메일 거부" - subject_template: "[%{email_prefix}] 이메일 문제-차단 된 이메일" + title: "이메일 거부, 스크린된 이메일" + subject_template: "[%{email_prefix}] 이메일 문제 -- 차단된 이메일" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 차단된 이메일 주소에서 전송되었습니다. 다른 이메일 주소에서 보내거나 [관리자에게 문의](%{base_url}/about) 하세요. + 차단된 이메일 주소를 사용하여 보낸 답장입니다. 다른 이메일 주소로 보내거나 [운영진에게 문의하세요](%{base_url}/about). email_reject_not_allowed_email: - title: "이메일 거부가 허용되지 않는 이메일" - subject_template: "[%{email_prefix}] 이메일 문제-차단 된 이메일" + title: "이메일 거부, 허용되지 않는 이메일" + subject_template: "[%{email_prefix}] 이메일 문제 -- 차단된 이메일" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 차단된 이메일 주소에서 전송되었습니다. 다른 이메일 주소에서 보내거나 [관리자에게 문의](%{base_url}/about) 하세요. + 차단된 이메일 주소를 사용하여 보낸 답장입니다. 다른 이메일 주소로 보내거나 [운영진에게 문의하세요](%{base_url}/about). email_reject_inactive_user: - title: "이메일 거부 비활성 사용자" - subject_template: "[%{email_prefix}] 이메일 문제-비활성 사용자" + title: "이메일 거부, 비활성 사용자" + subject_template: "[%{email_prefix}] 이메일 문제 -- 비활성 사용자" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 이 이메일 주소와 연결된 계정이 활성화되지 않았습니다. 이메일을 보내기 전에 계정을 활성화하십시오. + 이 이메일 주소와 연결된 계정이 활성화되지 않았습니다. 이메일을 보내기 전에 계정을 활성화하세요. email_reject_silenced_user: - title: "이메일 거부 사일런트 사용자" - subject_template: "[%{email_prefix}] 이메일 문제-무음 사용자" + title: "이메일 거부, 차단된 사용자" + subject_template: "[%{email_prefix}] 이메일 문제 -- 차단된 사용자" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 이 이메일 주소와 연결된 사용자님의 계정은 글 작성이 금지된 상태입니다. + 이 이메일 주소와 연결된 계정이 차단되었습니다. email_reject_reply_user_not_matching: - title: "이메일 거부 사용자가 일치하지 않습니다" - subject_template: "[%{email_prefix}] 이메일 문제-예기치 않은 회신 주소" + title: "이메일 거부, 사용자 불일치" + subject_template: "[%{email_prefix}] 이메일 문제 -- 예기치 않은 답장 주소" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 기존의 이메일과 다른 이메일 주소에서 발송되어 동일 사용자인지 확인이 어렵습니다. 기존의 이메일 주소에서 보내거나 [관리자에게 문의](%{base_url}/about) 하세요. + 기존 이메일이 아닌 이메일 주소로 발송한 답장이므로 동일 사용자로 판단할 수 없습니다. 기존 이메일 주소를 사용하여 보내거나 [운영진에게 문의하세요](%{base_url}/about). email_reject_empty: - title: "이메일 거부 빈" - subject_template: "[%{email_prefix}] 이메일 문제-내용 없음" + title: "이메일 거부, 비어 있음" + subject_template: "[%{email_prefix}] 이메일 문제 -- 콘텐츠 없음" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 사용자님의 이메일에서 내용을 찾을 수 없습니다. + 답장 내용이 비어 있습니다. - 전송 _완료_ 후 이 메시지를 받았다면, 더 간단한 서식으로 다시 시도하십시오. + 콘텐츠를 _포함했지만_ 이 이메일을 받은 경우 더 단순한 서식으로 다시 시도하세요. email_reject_parsing: - title: "이메일 거부 파싱" - subject_template: "[%{email_prefix}] 이메일 문제-인식 할 수없는 콘텐츠" + title: "이메일 거부, 파싱" + subject_template: "[%{email_prefix}] 이메일 문제 -- 인식할 수 없는 콘텐츠" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 이메일에서 내용을 찾을 수 없습니다. **답장이 이메일 상단에 있는지 확인하세요** -- 한 줄 답변은 처리 할 수 없습니다. + 답장에서 내용을 인식할 수 없습니다. **답장이 이메일 상단에 있는지 확인하세요** -- 인라인 답장은 처리할 수 없습니다. email_reject_invalid_access: - title: "이메일이 잘못된 액세스를 거부" - subject_template: "[%{email_prefix}] 이메일 문제-잘못된 액세스" + title: "이메일 거부, 유효하지 않은 액세스" + subject_template: "[%{email_prefix}] 이메일 문제 -- 유효하지 않은 액세스" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 사용자님의 계정은 해당 카테고리에 새 글을 쓸 권한이 없습니다. 오류라고 생각되면 [관리자에게 문의](%{base_url}/about) 하세요. + 이 카테고리에 새 주제를 게시할 권한이 없습니다. 오류라고 생각되면 [운영진에게 문의하세요](%{base_url}/about). email_reject_strangers_not_allowed: - title: "이메일 거부 낯선 사람은 허용되지 않습니다" - subject_template: "[%{email_prefix}] 이메일 문제-잘못된 액세스" + title: "이메일 거부, 낯선 사용자 금지" + subject_template: "[%{email_prefix}] 이메일 문제 -- 유효하지 않은 액세스" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 전송하고자 하는 카테고리는 허용된 이메일과 사용자만 글을 게시 할 수 있습니다. 오류라고 생각되면 [관리자에게 문의] (%{base_url}/about) 하세요. + 이메일을 보낸 카테고리는 유효한 계정과 알려진 이메일 주소를 가진 사용자의 답장만 허용합니다. 오류라고 생각되면 [운영진에게 문의하세요](%{base_url}/about). email_reject_invalid_post: - title: "이메일 거부 잘못된 게시물" - subject_template: "[%{email_prefix}] 이메일 문제-게시 오류" + title: "이메일 거부, 유효하지 않은 게시물" + subject_template: "[%{email_prefix}] 이메일 문제 -- 게시 오류" text_body_template: | - 죄송합니다, 이메일 메세지 %{destination} (titled %{former_title})가 안 됐습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 복잡한 포매팅, 대용량 메세지, 너무 짧은 메세지가 문제일 수 있습니다. 다시 시도 해보고 계속 문제 된다면 웹사이트를 통해 글을 올리세요. + 복잡한 서식, 너무 용량이 큰 메시지, 너무 용량이 적은 메시지는 아닌지 확인하세요. 다시 시도하고 문제가 지속될 경우 웹사이트를 통해 게시해 보세요. email_reject_invalid_post_specified: - title: "이메일 거부 잘못된 게시물 지정" - subject_template: "[%{email_prefix}] 이메일 문제-게시 오류" - text_body_template: "죄송합니다, 이메일 메세지 %{destination} (titled %{former_title})가 안 됐습니다. \n\n이유:\n\n%{post_error}\n\n문제를 고치고 다시 시도해 보세요.\n" - date_invalid: "게시물 작성 날짜가 없습니다. 이메일에 날짜 : 헤더가 누락 되었습니까?" + title: "이메일 거부, 유효하지 않은 게시물 지정" + subject_template: "[%{email_prefix}] 이메일 문제 -- 게시 오류" + text_body_template: "%{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. \n\n이유:\n\n%{post_error}\n\n문제 해결 후 다시 시도해 보세요.\n" + date_invalid: "%{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다." email_reject_post_too_short: - title: "이메일 거부 게시물이 너무 짧음" - subject_template: "[%{email_prefix}] 이메일 문제-게시물이 너무 짧습니다" + title: "이메일 거부, 너무 짧은 게시물" + subject_template: "[%{email_prefix}] 이메일 문제 -- 너무 짧은 게시물" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 너무 짧은 글은 허용되지 않습니다. %{count}자 이상으로 작성하거나 "+1"로 작성해 해당 게시물을 좋아한다고 표시할 수 있습니다. + 심도 있는 대화를 독려하기 위해 매우 짧은 답장은 허용하지 않습니다. %{count}자 이상으로 답장을 보내거나, '+1'로 답장하여 이메일을 통해 게시물에 좋아요를 표시할 수 있습니다. email_reject_invalid_post_action: - title: "이메일 거부 잘못된 사후 조치" - subject_template: "[%{email_prefix}] 이메일 문제-잘못된 사후 조치" + title: "이메일 거부, 유효하지 않은 게시 작업" + subject_template: "[%{email_prefix}] 이메일 문제 -- 유효하지 않은 게시 작업" text_body_template: | - 죄송합니다. %{destination} (제목은 %{former_title}) 으로 보내는 이메일 메시지가 작동하지 않습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 사후 작업을 인식하지 못했습니다. 다시 시도하거나 웹 사이트를 통해 게시하십시오. + 게시 작업을 인식하지 못했습니다. 다시 시도하고 문제가 지속될 경우 웹사이트를 통해 게시해 보세요. email_reject_reply_key: - title: "이메일 거부 회신 키" - subject_template: "[%{email_prefix}] 이메일 문제-알 수없는 회신 키" + title: "이메일 거부, 답장 키" + subject_template: "[%{email_prefix}] 이메일 문제 -- 알 수 없는 답장 키" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 이메일의 답장 키가 잘못되었거나 알수없습니다. [관리자에게 문의](%{base_url}/about) 하세요. + 이메일의 답장 키가 유효하지 않거나 확인이 불가하여 답장 대상을 파악할 수 없습니다. [운영진에게 문의하세요](%{base_url}/about). email_reject_bad_destination_address: - title: "이메일 거부 잘못된 대상 주소" - subject_template: "[%{email_prefix}] 이메일 문제-알 수 없음 : 주소" + title: "이메일 거부, 잘못된 대상 주소" + subject_template: "[%{email_prefix}] 이메일 문제 -- 알 수 없는 To: 주소" text_body_template: | - %{destination} (제목 : %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 확인해야 할 사항은 다음과 같습니다. + 확인할 사항은 다음과 같습니다. - - 하나 이상의 이메일 주소를 사용하십니까? 원래 사용한 이메일 주소와 다른 이메일 주소로 답장 했습니까? 이메일 답장을 보내려면 답장 할 때 동일한 이메일 주소를 사용해야합니다. + - 하나 이상의 이메일 주소를 사용하나요? 기존 이메일 주소가 아닌 이메일 주소로 답장을 보내셨나요? 이메일 답장은 답장할 때 동일한 이메일 주소를 사용해야 합니다. - - 이메일 소프트웨어가 답장 할 때 Reply-To: 이메일 주소를 올바르게 사용 했습니까? 일부 이메일 소프트웨어는 From: 주소로 잘못 답장을 보냅니다. + - 이메일 소프트웨어에서 답장할 때 Reply-To: 이메일 주소를 올바르게 사용했나요? 일부 이메일 소프트웨어는 From: 주소로 답장을 잘못 보내 문제가 발생합니다. - - 이메일의 Message-ID 헤더가 수정 되었습니까? Message-ID는 일관성이 있고 변경되지 않아야합니다. + - 이메일의 Message-ID 헤더가 수정되었나요? Message-ID는 일관되어야 하며 변경되지 않아야 합니다. - 도움이 더 필요하세요? %{base_url}/about 의 연락처 세부 정보를 통해 저희에게 연락하십시오. + 도움이 더 필요하다면 %{base_url}/about의 문의하기 정보를 통해 저희에게 문의하세요. email_reject_old_destination: - title: "이메일 거부 이전 대상" - subject_template: "[%{email_prefix}] 이메일 문제-이전 알림에 답장하려고합니다" + title: "이메일 거부, 오래된 대상" + subject_template: "[%{email_prefix}] 이메일 문제 -- 오래된 알림에 답장 시도" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 알림에 대한 답변은 %{number_of_days}일 동안만 가능합니다. 대화를 계속하려면 [글을 방문](%{short_url})해 보세요. + 원래 알림에 답장을 보내는 것은 %{number_of_days}일 동안만 가능합니다. 대화를 계속하려면 [주제를 방문하세요](%{short_url}). email_reject_topic_not_found: - title: "이메일 거부 주제를 찾을 수 없습니다" - subject_template: "[%{email_prefix}] 이메일 문제-주제를 찾을 수 없습니다" + title: "이메일 거부, 주제를 찾을 수 없음" + subject_template: "[%{email_prefix}] 이메일 문제 -- 주제를 찾을 수 없음" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 댓글을 작성하려는 원래의 글이 더 이상 존재하지 않습니다. 삭제되었을 수 있습니다. 오류라고 생각되면 [관리자에게 문의](%{base_url}/about) 하세요. + 댓글을 달려는 주제가 존재하지 않습니다. 아마도 삭제된 것 같습니다. 오류라고 생각되면 [운영진에게 문의하세요](%{base_url}/about). email_reject_topic_closed: - title: "이메일 거부 주제 종료" - subject_template: "[%{email_prefix}] 이메일 문제-주제 마감" + title: "이메일 거부, 주제 종료됨" + subject_template: "[%{email_prefix}] 이메일 문제 -- 주제 종료됨" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 댓글을 작성하려는 원래의 글이 현재 닫혀 있으며 더 이상 해당 글에 댓글을 작성 할 수 없습니다. 오류라고 생각되면 [관리자에게 문의](%{base_url}/about) 하세요. + 댓글을 달려는 주제가 현재 종료된 상태이며 댓글을 허용하지 않습니다. 오류라고 생각되면 [운영진에게 문의하세요](%{base_url}/about). email_reject_auto_generated: - title: "이메일 거부 자동 생성" - subject_template: "[%{email_prefix}] 이메일 문제-자동 생성 된 회신" + title: "이메일 거부, 자동 생성됨" + subject_template: "[%{email_prefix}] 이메일 문제 -- 자동 생성된 답장" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 사용자님의 이메일은 "자동 생성"으로 표시되었습니다. 이것은 사람이 입력하는 대신 컴퓨터에 의해 자동으로 생성되었음을 의미합니다. 이것이 오류라고 생각되면 [관리자에게 문의](%{base_url}/about) 하세요. + 이메일이 '자동 생성됨'으로 표시되었습니다. 이는 사람이 작성하는 대신 컴퓨터에서 자동으로 생성된 것을 의미합니다. 이런 유형의 이메일은 허용되지 않습니다. 오류라고 생각되면 [운영진에게 문의하세요](%{base_url}/about). email_reject_unrecognized_error: - title: "이메일 거부 인식 할 수없는 오류" - subject_template: "[%{email_prefix}] 이메일 문제-인식 할 수없는 오류" + title: "이메일 거부, 인식되지 않은 오류" + subject_template: "[%{email_prefix}] 이메일 문제 -- 인식되지 않은 오류" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 이메일을 처리하는 동안 알 수없는 오류가 발생하여 글이 게시되지 않았습니다. 다시 시도하거나 [관리자에게 문의](%{base_url}/about) 하세요. + 이메일을 처리하는 동안 인식되지 않은 오류가 발생하여 게시되지 않았습니다. 다시 시도하거나 [운영진에게 문의하세요](%{base_url}/about). email_reject_attachment: - title: "이메일 첨부가 거부 됨" - subject_template: "[%{email_prefix}] 이메일 문제-첨부 파일 거부" + title: "이메일 첨부 거부됨" + subject_template: "[%{email_prefix}] 이메일 문제 -- 첨부 파일 거부됨" text_body_template: | - 죄송합니다. 사용자님의 이메일 메시지에서 %{destination} (제목 %{former_title})에 대한 일부 첨부 파일이 거부되었습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지의 첨부 파일 중 일부가 거부되었습니다. - 내용: + 상세 정보: %{rejected_errors} - 오류라고 생각되면 [관리자에게 문의](%{base_url}/about) 하세요. + 오류라고 생각되면 [운영진에게 문의하세요](%{base_url}/about). email_reject_reply_not_allowed: - title: "이메일 거부 회신이 허용되지 않습니다" - subject_template: "[%{email_prefix}] 이메일 문제-회신이 허용되지 않습니다" + title: "이메일 거부, 댓글 허용 불가" + subject_template: "[%{email_prefix}] 이메일 문제 -- 댓글 허용 불가" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 글 작성 권한이 없습니다. 오류라고 생각되면 [관리자에게 문의] (%{base_url}/about) 하세요. + 주제에 댓글을 달 권한이 없습니다. 오류라고 생각되면 [운영진에게 문의하세요](%{base_url}/about). email_reject_reply_to_digest: - title: "회신 거부 이메일 요약" - subject_template: "[%{email_prefix}] 이메일 문제 — 요약에 답장" + title: "이메일 거부, 요약에 답장" + subject_template: "[%{email_prefix}] 이메일 문제 -- 요약에 답장" text_body_template: | - 죄송합니다. %{destination} (제목 %{former_title})에 대한 이메일 메시지가 작동하지 않았습니다. + %{destination}(제목: %{former_title})에 보낸 이메일 메시지가 거부되었습니다. - 수락되지 않은 요약 이메일에 답장했습니다. + 요약 이메일에 답장하였으나 거부되었습니다. - 오류라고 생각되면 [관리자에게 문의] (%{base_url}/about) 하세요. + 오류라고 생각되면 [운영진에게 문의하세요](%{base_url}/about). email_error_notification: - title: "이메일 에러 알림" - subject_template: "[%{email_prefix}] 이메일 문제-POP 인증 오류" + title: "이메일 오류 알림" + subject_template: "[%{email_prefix}] 이메일 문제 -- POP 인증 오류" text_body_template: | - 죄송합니다. POP 서버에서 메일을 폴링하는 동안 인증 오류가 발생했습니다. + POP 서버에서 메일을 폴링하는 중에 인증 오류가 발생했습니다. - [사이트 설정](%{base_url}/admin/site_settings/category/email)에서 POP 자격 증명을 올바르게 구성했는지 확인하십시오. + [사이트 설정](%{base_url}/admin/site_settings/category/email)에서 POP 크리덴셜을 올바르게 환경설정했는지 확인하세요. - POP 이메일 계정에 대한 웹 UI가있는 경우 웹에 로그인하여 설정을 확인해야 할 수 있습니다. + POP 이메일 계정에 대한 웹 UI가 있는 경우 웹에 로그인하여 설정을 확인해야 할 수 있습니다. email_revoked: - title: "이메일 해지" - subject_template: "이메일 주소가 맞습니까?" + title: "이메일 취소됨" + subject_template: "이메일 주소가 맞는지 확인해 주세요." text_body_template: | - 죄송합니다. 이메일로 연락하는 데 문제가 있습니다. 사용자님에게 보내 드린 최근 몇 개의 이메일이 모두 반송되었습니다. + 이메일로 연락하는 데 문제가 있습니다. 최근 이메일을 몇 차례 전송했으나 모두 전송 불가로 반송되었습니다. - [사용자님의 이메일 주소] (%{base_url}/my/preferences/email)가 유효하고 작동하는지 확인할 수 있습니까? 전송 가능성을 높이기 위해 주소록/연락처 목록에 이메일 주소를 추가 할 수도 있습니다. + [이메일 주소](%{base_url}/my/preferences/email)가 유효하며 정상적으로 작동하는지 확인하시기 바랍니다. 주소록/연락처 목록에 이메일 주소를 추가하면 전송 가능성을 높일 수 있습니다. email_bounced: | - %{email} 에 대한 메시지가 반송되었습니다. + %{email}에 보낸 메시지가 반송되었습니다. ### 세부 사항 @@ -2842,191 +2815,191 @@ ko: %{raw} ``` ignored_users_summary: - title: "무시 된 사용자가 임계 값을 통과했습니다." - subject_template: "다른 많은 사용자가 사용자를 무시하고 있습니다." + title: "무시된 사용자가 한계치를 넘음" + subject_template: "특정 사용자가 많은 사용자로부터 무시됨" text_body_template: | 안녕하세요, - %{ignores_threshold}명의 사용자가 @%{username} 사용자를 무시했음을 알리는 %{site_name}의 자동 메시지입니다. 커뮤니티에서 어떠한 문제가 발생하고 있음을 나타내는 것일 수 있습니다. + %{ignores_threshold}명의 사용자가 @%{username} 님을 무시했음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. 커뮤니티에서 문제가 발생했을 수 있습니다. - 이 사용자의 [최근 게시물 검토](%{base_url}/u/%{username}/summary)와 [무시 및 글 작성 차단 사용자 확인](%{base_url}/admin/reports/top_ignored_users). + 이 사용자의 [최근 게시물을 검토](%{base_url}/u/%{username}/summary)하고 [무시 및 뮤트된 사용자 리포트](%{base_url}/admin/reports/top_ignored_users)에서 다른 사용자도 확인하세요. - 추가 안내는 [커뮤니티 가이드 라인](%{base_url}/guidelines)을 참조하세요. + 자세한 내용은 [커뮤니티 가이드라인](%{base_url}/guidelines)을 참조하세요. too_many_spam_flags: - title: "너무 많은 스팸 플래그" - subject_template: "대기중인 신규 계정" + title: "스팸 신고 과다" + subject_template: "신규 계정 보류됨" text_body_template: | 안녕하세요, - 사용자님의 게시물이 신고로 인해 일시적으로 숨겨 졌음을 알려 드리기 위해 %{site_name} 에서 보낸 자동 메시지입니다. + 커뮤니티에서 신고를 받아 게시물이 일시적으로 숨겨졌음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. - 예방 조치로 사용자님의 계정이 일시적으로 숨겨졌으며 관리자가 사용자님의 계정을 검토 할 수있을 때까지 새 글이나 댓글을 작성할 수 없습니다. 불편을 드려 죄송합니다. + 예방 조치로 신규 계정이 차단되었으며 운영진이 계정을 검토할 때까지 댓글이나 주제를 생성할 수 없습니다. 불편을 드려 죄송합니다. - 추가 안내는 [커뮤니티 가이드 라인](%{base_url}/guidelines)을 참조하세요. + 자세한 내용은 [커뮤니티 가이드라인](%{base_url}/guidelines)을 참조하세요. too_many_tl3_flags: - title: "TL3 Flag가 너무 많음" - subject_template: "대기중인 신규 계정" + title: "TL3 신고 과다" + subject_template: "신규 계정 보류됨" text_body_template: | 안녕하세요, - 사용자님의 계정은 많은 신고로 인해 계정이 보류 상태가 되었음을 알려 드리기 위해 %{site_name} 에서 보낸 자동 메시지입니다. + 커뮤니티에서 많은 신고를 받아 계정이 일시적으로 보류되었음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. - 예방 조치로서, 관리자가 사용자님의 계정을 검토 할 수있을 때까지 새 글이나 댓글을 작성하지 못하도록 차단되었습니다. 불편을 드려 죄송합니다. + 예방 조치로 신규 계정이 차단되었으며 운영진이 계정을 검토할 때까지 댓글이나 주제를 생성할 수 없습니다. 불편을 드려 죄송합니다. - 추가 안내는 [커뮤니티 가이드 라인](%{base_url}/guidelines)을 참조하세요. + 자세한 내용은 [커뮤니티 가이드라인](%{base_url}/guidelines)을 참조하세요. silenced_by_staff: - title: "관리자에 의해 쓰기 금지됨" - subject_template: "일시적으로 보류중인 계정" + title: "운영진에 의해 차단됨" + subject_template: "계정이 일시적으로 보류됨" text_body_template: | 안녕하세요, - 예방 조치로 사용자님의 계정이 일시적으로 보류 상태가 되었음을 알려 드리기 위해 %{site_name} 에서 보낸 자동 메시지입니다. + 예방 조치로 계정이 일시적으로 보류되었음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. - [관리자](%{base_url}/about)가 사용자님의 최근 게시물을 검토 할 때까지 새 글을 작성하거나 댓글을 작성할 수 없습니다. 불편을 드려 죄송합니다. + 사이트 탐색은 가능하지만 [운영진](%{base_url}/about)이 최근 게시물을 검토할 때까지 댓글이나 주제를 생성할 수 없습니다. 불편을 드려 죄송합니다. - 추가 안내는 [커뮤니티 가이드 라인](%{base_url}/guidelines)을 참조하세요. + 자세한 내용은 [커뮤니티 가이드라인](%{base_url}/guidelines)을 참조하세요. user_automatically_silenced: - title: "사용자가 자동으로 쓰기 금지됨" - subject_template: "신고로 인해 새 사용자 %{username}이 쓰기 금지됨" + title: "사용자가 자동 차단됨" + subject_template: "커뮤니티 신고로 신규 유저 %{username} 님이 차단됨" text_body_template: | - 이것은 자동 발송되는 메시지입니다. + 자동 메시지입니다. - 여러 사용자가 %{username}의 게시물을 신고해 신규 사용자 [%{username}](%{user_url})님은 글 작성이 금지되었습니다. + 여러 사용자가 %{username} 님의 게시물을 신고하여 신규 사용자 [%{username}](%{user_url})님이 자동 차단되었습니다. - [신고 검토](%{base_url}/admin/flags). 만약 %{username}님이 잘못 처리 된 경우 [이 사용자의 관리자 페이지](%{user_url})에서 글작성 금지 해제 버튼을 클릭합니다. + [신고를 검토](%{base_url}/admin/flags)하고, %{username} 님의 게시 차단이 잘못되었다고 판단되는 경우 [이 사용자의 관리 페이지](%{user_url})에서 차단 해제 버튼을 클릭하세요. - 이 기본 값은 사이트 설정 `silence_new_user` 를 통해 변경할 수 있습니다. + 한계치는 `silence_new_user` 사이트 설정에서 변경할 수 있습니다. spam_post_blocked: title: "스팸 게시글 차단됨" - subject_template: "%{username} 신규가입자가 연속 링크로 블락됨" + subject_template: "신규 사용자 %{username} 님의 게시물이 연속된 링크로 인해 차단됨" text_body_template: | - 이것은 자동 전송되는 메시지 입니다. + 자동 메시지입니다. - 신규 사용자 [%{username}](%{user_url})님이 %{domains} 링크가있는 여러 게시물을 작성하려고 했지만 스팸으로 의심되어 게시물이 차단되었습니다. 해당 사용자는 %{domains}과 관련없는 새 게시물은 작성할 수 있습니다. + 신규 사용자 [%{username}](%{user_url}) 님이 %{domains} 링크를 포함하여 여러 게시물을 생성하려고 시도했으나 스팸 방지를 위해 게시물이 차단되었습니다. 이 사용자는 %{domains} 링크를 포함하지 않으면 계속해서 새 게시물을 생성할 수 있습니다. - [사용자 확인](%{user_url}) 이 필요합니다. + [사용자 검토](%{user_url})를 진행해 주세요. - 사이트 설정에서 `newuser_spam_host_threshold` 와 `allowed_spam_host_domains` 에서 수정할 수 있습니다. 제외 하고자 하는 경우 허용 목록에 %{domains} 을 추가하는 것을 고려하십시오. + 이는 `newuser_spam_host_threshold` 및 `allowed_spam_host_domains` 사이트 설정에서 수정할 수 있습니다. 도메인에 문제가 없다면 허용 목록에 %{domains} 도메인을 추가하세요. unsilenced: - title: "쓰기 금지 해제" - subject_template: "계정의 대기가 해제되었습니다" + title: "차단 해제됨" + subject_template: "계정 보류 해제됨" text_body_template: | 안녕하세요, - 관리자의 검토 후 사용자님의 계정이 더 이상 보류 상태가 아님을 알려 드리기 위해 %{site_name} 에서 보낸 자동 메시지입니다. + 운영진 검토를 마친 결과 계정 보류가 해제되었음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. - 이제 새 댓글과 글을 작성 할 수 있습니다. 양해 해 주셔서 감사합니다. + 이제 다시 새 댓글과 주제를 작성할 수 있습니다. 기다려 주셔서 감사합니다. pending_users_reminder: - title: "대기중인 사용자 알림" + title: "보류 중 사용자 미리 알림" subject_template: - other: "%{count}명의 새로운 사용자가 가입 승인 대기중 입니다." + other: "%{count}명의 사용자 승인 대기 중" text_body_template: | - 이 포럼에서 활동하기위해 승인 (또는 거부)을 기다리고있는 신규 사용자가 있습니다. + 이 포럼에 액세스하기 위해 승인/거부를 기다리고 있는 신규 사용자 가입 요청이 있습니다. - [확인하세요](%{base_url}/review). + [검토하시기 바랍니다](%{base_url}/review). download_remote_images_disabled: - title: "해제된 원격 이미지 다운로드하기" - subject_template: "외부에서 이미지 다운로드 못함" - text_body_template: "`download_remote_images_to_local` 설정이`download_remote_images_threshold`에서 정한 디스크 용량에 도달하여 비활성화 되었습니다." + title: "원격 이미지 다운로드 비활성화됨" + subject_template: "원격 이미지 다운로드 비활성화됨" + text_body_template: "`download_remote_images_threshold` 디스크 용량 한도에 도달하여 `download_remote_images_to_local` 설정이 비활성화되었습니다." dashboard_problems: - title: "대시보드 문제사항" - subject_template: "사이트 대시 보드에 대한 새로운 조언" + title: "대시보드 문제" + subject_template: "사이트 대시보드에 대한 새로운 조언" text_body_template: | - 현재 사이트 설정의 새로운 조언과 권장 사항이 있습니다. + 현재 사이트 설정과 관련하여 새로운 조언과 권장 사항이 있습니다. - [사이트 대시 보드 방문] (%{base_url}/admin)을 확인하세요. + [사이트 대시보드를 방문](%{base_url}/admin)하여 확인하세요. - 대시 보드에 아무것도 표시되지 않으면 다른 관리자가 이미 이 조언에 따라 조치를 취했을 수 있습니다. 관리자의 작업 목록은 [Staff Action Logs] (%{base_url}/admin/logs/staff_action_logs)에서 찾을 수 있습니다. + 대시보드에 아무것도 표시되지 않으면 다른 운영진이 이미 이 조언에 따라 조치를 취했을 수 있습니다. 운영진의 작업 목록은 [운영진 작업 로그](%{base_url}/admin/logs/staff_action_logs)를 확인하세요. new_user_of_the_month: - title: "이달의 신규회원으로 선정되었습니다!" - subject_template: "이달의 신규회원으로 선정되었습니다!" + title: "이달의 신규 사용자로 선정되었습니다!" + subject_template: "이달의 신규 사용자로 선정되었습니다!" text_body_template: | 축하합니다. **%{month_year}의 신규 사용자** 로 선정되었습니다. :trophy: - 이상은 매월 2명의 신규 사용자에게만 수여되며 [배지 페이지](%{url})에 영구적으로 표시됩니다. + 매달 2명의 신규 사용자에게만 수여되며 [배지 페이지](%{url})에 영구적으로 표시됩니다. - 사용자님은 빠르게 우리 커뮤니티의 소중한 구성원이되었습니다. 참여 해주셔서 감사합니다! + 정말 빠르게 커뮤니티의 소중한 일원이 되셨네요! 가입에 감사드리며 계속해서 많이 활동해 주세요! queued_posts_reminder: - title: "대기중인 게시물 알림" + title: "대기 중인 게시물 미리 알림" subject_template: - other: "%{count} 게시물 검토 대기" + other: "%{count}개의 게시물 검토 대기 중" text_body_template: | 안녕하세요, - 신규 사용자의 게시물이 잠시 보류되어 현재 검토 대기 중입니다. [여기에서 승인 또는 거부](%{base_url}/review?type=ReviewableQueuedPost). + 신규 사용자의 게시물이 검토를 위해 보류되어 현재 검토 대기 중입니다. [여기에서 승인 또는 거부하세요](%{base_url}/review?type=ReviewableQueuedPost). unsubscribe_link: | - 이러한 이메일을 수신 거부하려면 [여기를 클릭](%{unsubscribe_url}). + 이러한 이메일을 구독 해제하려면 [여기를 클릭하세요](%{unsubscribe_url}). unsubscribe_link_and_mail: | - 이메일 수신 거부는 [여기를 클릭](%{unsubscribe_url}). + 이러한 이메일을 구독 해제하려면 [여기를 클릭하세요](%{unsubscribe_url}). unsubscribe_mailing_list: | - 메일링리스트 모드를 활성화했기 때문에 이 메일을 수신 한 것입니다. + 메일링 리스트 모드를 활성화했기 때문에 이 메일이 전송되었습니다. - 이메일 수신 거부는 [여기를 클릭](%{unsubscribe_url}). + 이러한 이메일을 구독 해제하려면 [여기를 클릭하세요](%{unsubscribe_url}). subject_re: "덧: " subject_pm: "[PM] " - email_from: "%{site_name}를 통한 %{user_name}" + email_from: "%{site_name}의 %{user_name} 님" user_notifications: - previous_discussion: "이전 답글" + previous_discussion: "이전 답장" reached_limit: - other: "주의: 매일 최대 %{count}개의 이메일을 보냅니다. 보류 될 수있는 사이트를 확인하십시오." - in_reply_to: "에 회신하여" + other: "주의: 매일 최대 %{count}개의 이메일을 전송합니다. 사이트를 확인하여 보류될 수 있는 사이트가 있는지 확인하세요. 활발한 활동에 감사드립니다!" + in_reply_to: "답장 대상" unsubscribe: - title: "구독해지" - description: "이메일들에 관심이 없나요? 아래 구독해지를 눌러서 바로 구독을 해지할 수 있습니다:" - reply_by_email: "[방문 주제] (%{base_url}%{url}) 또는이 이메일에 회신하여 회신하십시오." - reply_by_email_pm: "[방문 메시지] (%{base_url}%{url}) 또는이 이메일에 회신하여 %{participants}에 응답하십시오." - only_reply_by_email: "답장을 보내려면이 이메일에 회신하십시오." - only_reply_by_email_pm: "%{participants}에 응답하려면이 이메일에 회신하십시오." - visit_link_to_respond: "[글](%{base_url}%{url})을 살펴보고 댓글을 작성해보세요." - visit_link_to_respond_pm: "%{participants}에 응답하려면 [글 보기](%{base_url}%{url})을 살펴보세요." - reply_above_line: "##이 줄 위에 댓글을 입력하십시오. ##" - posted_by: "%{username} 사용자가 %{post_date}에 게시하였습니다." - pm_participants: "참가자 : %{participants}" + title: "구독 해제" + description: "이 이메일에 관심이 없나요? 아래 구독 해제를 눌러서 바로 구독을 해제할 수 있습니다." + reply_by_email: "[주제를 방문](%{base_url}%{url})하거나 이 이메일에 답장하여 응답하세요." + reply_by_email_pm: "[주제를 방문](%{base_url}%{url})하거나 이 이메일에 답장하여 %{participants}에 응답하세요." + only_reply_by_email: "이 이메일에 답장하여 응답하세요." + only_reply_by_email_pm: "이 이메일에 답장하여 %{participants}에 응답하세요." + visit_link_to_respond: "[주제를 방문](%{base_url}%{url})하여 응답하세요." + visit_link_to_respond_pm: "[메시지로 이동](%{base_url}%{url})하여 %{participants}에 응답하세요." + reply_above_line: "## 이 줄 위에 답장을 입력하세요. ##" + posted_by: "%{username} 님이 %{post_date}에 게시함" + pm_participants: "참여자: %{participants}" invited_group_to_private_message_body: | - %{username}님이 사용자님을 @%{group_name} 대화에 초대했습니다. + %{username} 님이 @%{group_name} 그룹을 메시지에 초대했습니다 > **[%{topic_title}](%{topic_url})** > > %{topic_excerpt} - 에서 + - > %{site_title} -- %{site_description} - 대화에 참여 하시려면 아래 링크를 클릭 하세요: + 메시지에 참여하려면 아래 링크를 클릭하세요. %{topic_url} invited_to_private_message_body: | - %{username}님이 사용자님을 대화에 초대했습니다. + %{username} 님이 나를 메시지에 초대했습니다 > **[%{topic_title}](%{topic_url})** > > %{topic_excerpt} - 에서 + - > %{site_title} -- %{site_description} - 대화에 참여 하시려면 아래 링크를 클릭 하세요: + 메시지에 참여하려면 아래 링크를 클릭하세요. %{topic_url} invited_to_topic_body: | - %{username}님이 사용자님을 대화에 초대했습니다. + %{username} 님이 나를 메시지에 초대했습니다 > ** [%{topic_title}] (%{topic_url}) ** > > %{topic_excerpt} - 에서 + - > %{site_title} - %{site_description} - 대화에 참여 하시려면 아래 링크를 클릭 하세요: + 토론에 참여하려면 아래 링크를 클릭하세요. %{topic_url} user_invited_to_private_message_pm_group: - title: "PM에 사용자 초대 그룹" - subject_template: "[%{email_prefix}] %{username} 님이 @ %{group_name}를 '%{topic_title}'메시지에 초대했습니다" + title: "사용자가 그룹을 개인 메시지에 초대함" + subject_template: "[%{email_prefix}] %{username} 님이 @%{group_name} 그룹을 '%{topic_title}' 메시지에 초대했습니다" text_body_template: | %{header_instructions} @@ -3034,8 +3007,8 @@ ko: %{respond_instructions} user_invited_to_private_message_pm: - title: "PM에 초대 된 사용자" - subject_template: "[%{email_prefix}] %{username}가 '%{topic_title}'메시지에 초대했습니다." + title: "사용자가 개인 메시지에 초대함" + subject_template: "[%{email_prefix}] %{username} 님이 나를 '%{topic_title}' 메시지에 초대했습니다" text_body_template: | %{header_instructions} @@ -3043,8 +3016,8 @@ ko: %{respond_instructions} user_invited_to_private_message_pm_staged: - title: "PM 단계별 사용자 초대" - subject_template: "[%{email_prefix}] %{username}가 '%{topic_title}'메시지에 초대했습니다." + title: "사용자가 개인 메시지에 초대함, 스테이징됨" + subject_template: "[%{email_prefix}] %{username} 님이 나를 '%{topic_title}' 메시지에 초대했습니다" text_body_template: | %{header_instructions} @@ -3052,8 +3025,8 @@ ko: %{respond_instructions} user_invited_to_topic: - title: "주제에 초대 된 사용자" - subject_template: "[%{email_prefix}] %{username} 님이 '%{topic_title}'에 초대했습니다." + title: "사용자가 주제에 초대함" + subject_template: "[%{email_prefix}] %{username} 님이 나를 '%{topic_title}'에 초대했습니다" text_body_template: | %{header_instructions} @@ -3061,7 +3034,7 @@ ko: %{respond_instructions} user_replied: - title: "응답 한 사용자" + title: "사용자가 답장함" subject_template: "[%{email_prefix}] %{topic_title}" text_body_template: |2 @@ -3073,7 +3046,7 @@ ko: %{respond_instructions} user_replied_pm: - title: "사용자 답변 PM" + title: "사용자가 개인 메시지에 답장함" subject_template: "[%{email_prefix}] [PM] %{topic_title}" text_body_template: |2 @@ -3085,7 +3058,7 @@ ko: %{respond_instructions} user_quoted: - title: "명의 사용자가 인용" + title: "사용자가 인용함" subject_template: "[%{email_prefix}] %{topic_title}" text_body_template: |2 @@ -3097,7 +3070,7 @@ ko: %{respond_instructions} user_linked: - title: "연결된 사용자" + title: "사용자가 링크함" subject_template: "[%{email_prefix}] %{topic_title}" text_body_template: |2 @@ -3109,7 +3082,7 @@ ko: %{respond_instructions} user_mentioned: - title: "언급 된 사용자" + title: "사용자가 멘션함" subject_template: "[%{email_prefix}] %{topic_title}" text_body_template: |2 @@ -3121,7 +3094,7 @@ ko: %{respond_instructions} user_mentioned_pm: - title: "PM을 언급 한 사용자" + title: "사용자가 개인 메시지를 멘션함" subject_template: "[%{email_prefix}] [PM] %{topic_title}" text_body_template: |2 @@ -3133,7 +3106,7 @@ ko: %{respond_instructions} user_group_mentioned: - title: "언급 된 사용자 그룹" + title: "사용자가 그룹 멘션함" subject_template: "[%{email_prefix}] %{topic_title}" text_body_template: |2 @@ -3167,7 +3140,7 @@ ko: %{respond_instructions} user_posted: - title: "게시 된 사용자" + title: "사용자가 게시함" subject_template: "[%{email_prefix}] %{topic_title}" text_body_template: |2 @@ -3179,7 +3152,7 @@ ko: %{respond_instructions} user_watching_first_post: - title: "첫 포스트를 주시하고 있는 사용자" + title: "사용자가 첫 게시물을 구독함" subject_template: "[%{email_prefix}] %{topic_title}" text_body_template: |2 @@ -3191,7 +3164,7 @@ ko: %{respond_instructions} user_posted_pm: - title: "게시 된 사용자 오후" + title: "사용자가 개인 메시지를 게시함" subject_template: "[%{email_prefix}] [PM] %{topic_title}" text_body_template: |2 @@ -3203,321 +3176,321 @@ ko: %{respond_instructions} user_posted_pm_staged: - title: "PM 게시 된 사용자" + title: "사용자가 개인 메시지를 게시함, 스테이징됨" subject_template: "%{optional_re}%{topic_title}" text_body_template: |2 %{message} account_suspended: - title: "계정 일시 중지" - subject_template: "[%{email_prefix}] 귀하의 계정이 정지되었습니다" + title: "계정이 정지됨" + subject_template: "[%{email_prefix}] 계정이 정지되었습니다" text_body_template: | - 사용자님은 %{suspended_till}까지 사이트의 사용이 중지되었습니다. + %{suspended_till}까지 포럼에서 계정이 정지되었습니다. 이유 - %{reason} account_suspended_forever: - title: "계정 일시 중지" - subject_template: "[%{email_prefix}] 귀하의 계정이 정지되었습니다" + title: "계정이 정지됨" + subject_template: "[%{email_prefix}] 계정이 정지되었습니다" text_body_template: | - 사이트 이용이 중지되었습니다. + 포럼에서 계정이 정지되었습니다. 이유 - %{reason} account_silenced: - title: "계정이 쓰기 금지됨" - subject_template: "[%{email_prefix}] 사용자님의 계정이 쓰기 금지 되었습니다" + title: "계정이 차단됨" + subject_template: "[%{email_prefix}] 계정이 차단되었습니다" text_body_template: | - 사용자님은 %{silenced_till}까지 사이트내 글쓰기가 일시적으로 차단되었습니다. + %{suspended_till}까지 포럼에서 계정이 차단되었습니다. 이유 - %{reason} account_silenced_forever: - title: "계정이 쓰기 금지됨" - subject_template: "[%{email_prefix}] 사용자님의 계정이 쓰기 금지 되었습니다" + title: "계정이 차단됨" + subject_template: "[%{email_prefix}] 계정이 차단되었습니다" text_body_template: | - 사이트에서 글쓰기가 금지되었습니다. + 포럼에서 계정이 차단되었습니다. 이유 - %{reason} account_exists: - title: "계정이 이미 존재합니다" + title: "계정이 이미 존재함" subject_template: "[%{email_prefix}] 계정이 이미 존재합니다" text_body_template: | - %{site_name}에서 계정을 만들려고 했거나 계정의 이메일을 %{email}로 변경하려고했습니다. 그러나, %{email}의 계정이 이미 존재합니다. + %{site_name}에서 계정을 만들려고 했거나 계정의 이메일을 %{email} 이메일로 변경하려고 시도했으나 %{email}의 계정이 이미 존재합니다. - 비밀번호를 잊은 경우 [지금 재설정](%{base_url}/password-reset). + 비밀번호를 잊은 경우 [지금 리셋](%{base_url}/password-reset)하세요. - %{email}의 계정을 만들지 않았거나 이메일 주소를 변경하지 않았다면 걱정하지 마십시오. 이 메시지를 무시해도됩니다. + %{email}에 대한 계정을 만들지 않았거나 이메일 주소를 변경하려고 시도하지 않았다면 이 메시지를 무시하세요. - 궁금한 점이 있으면 [관리자에게 문의](%{base_url}/about)하세요. + 궁금한 점이 있으면 [운영진에게 문의하세요](%{base_url}/about). account_second_factor_disabled: - title: "2단계 인증 사용 안 함" - subject_template: "[%{email_prefix}] 2단계 인증 사용 안 함" + title: "2단계 인증 비활성화됨" + subject_template: "[%{email_prefix}] 2단계 인증 비활성화됨" text_body_template: | - %{site_name} 계정에서 2단계 인증이 비활성화되었습니다. 이제 비밀번호만으로 로그인 할 수 있습니다. 추가 인증 코드가 더 이상 필요하지 않습니다. + %{site_name} 계정에서 2단계 인증이 비활성화되었습니다. 이제 비밀번호만으로 로그인할 수 있으며 추가 인증 코드가 더 이상 필요하지 않습니다. - 2단계 인증 비활성화를 선택하지 않은 경우 누군가가 귀하의 계정을 도용했을 수 있습니다. + 2단계 인증 비활성화를 선택하지 않은 경우 누군가가 계정을 도용했을 수 있습니다. - 궁금한 점이 있으면 [친절한 관리자에게 문의](%{base_url}/about) 바랍니다. + 궁금한 점이 있으면 [운영진에게 문의하세요](%{base_url}/about). digest: - why: "%{last_seen_at}부터 지금까지 %{site_link} 사이트 근황" - since_last_visit: "마지막 방문 후 경과시간" - new_topics: "새로운 토픽" - unread_notifications: "읽지않은 알림" - unread_high_priority: "읽지 않은 높은 우선 순위 알림" + why: "%{last_seen_at}부터 지금까지 %{site_link}의 간략한 요약" + since_last_visit: "마지막 방문 이후" + new_topics: "새 주제" + unread_notifications: "읽지 않은 알림" + unread_high_priority: "읽지 않은 높은 우선순위 알림" liked_received: "받은 좋아요 수" - new_users: "새로운 사용자" - popular_topics: "인기 글" - follow_topic: "이 토픽 팔로우" + new_users: "신규 사용자" + popular_topics: "인기 주제" + follow_topic: "이 주제 팔로우" join_the_discussion: "더 보기" - popular_posts: "인기 포스트" - more_new: "당신을위한 새로운" + popular_posts: "인기 게시물" + more_new: "맞춤 신규 항목" subject_template: "[%{email_prefix}] 요약" - unsubscribe: "이 요약은 한동안 보지 못했을 때 %{site_link}에서 전송됩니다. 구독을 취소하려면 %{email_preferences_link} 또는 %{unsubscribe_link}을 변경하십시오." + unsubscribe: "이 요약은 한동안 방문하지 않은 경우 %{site_link}에서 전송됩니다. %{email_preferences_link}에서 변경하거나 %{unsubscribe_link}에서 구독 해제할 수 있습니다." your_email_settings: "이메일 설정" - click_here: "클릭" + click_here: "여기를 클릭" from: "%{site_name}" - preheader: "%{last_seen_at}을 마지막으로 방문한 후 간단한 요약" + preheader: "%{last_seen_at}부터 지금까지 간략한 요약" forgot_password: - title: "비밀번호 찾기" + title: "비밀번호가 기억나지 않나요?" subject_template: "[%{email_prefix}] 비밀번호 리셋" text_body_template: | - 누군가가 [%{site_name}] (%{base_url})에서 비밀번호를 재설정하도록 요청했습니다. + 누군가가 [%{site_name}](%{base_url}) 비밀번호를 리셋하도록 요청했습니다. - 본인이 아닌 경우 이 이메일을 무시해도 됩니다. + 본인이 아닌 경우 이 이메일을 무시하세요. - 새 비밀번호를 설정하려면 다음 링크를 클릭하십시오: + 새 비밀번호를 설정하려면 다음 링크를 클릭하세요. %{base_url}/u/password-reset/%{email_token} email_login: title: "링크를 통해 로그인" subject_template: "[%{email_prefix}] 링크를 통해 로그인" text_body_template: | - 다음은 [%{site_name}] (%{base_url})에서 로그인 할 수있는 링크입니다. + 다음은 [%{site_name}](%{base_url})에 로그인할 수 있는 링크입니다. - 이 링크를 요청하지 않으셨다면 이 이메일을 무시 하셔도됩니다. + 이 링크를 요청하지 않았다면 이 이메일을 무시하세요. - 다음 링크를 클릭하여 로그인합니다. + 다음 링크를 클릭하여 로그인하세요. %{base_url}/session/email-login/%{email_token} set_password: title: "비밀번호 설정" subject_template: "[%{email_prefix}] 비밀번호 설정" text_body_template: | - 누군가 [%{site_name}](%{base_url})에서 사용자님의 계정에 비밀번호를 추가하도록 요청했습니다. 또는 소셜 로그인 (Google, Facebook 등)을 사용하여 로그인 할 수 있습니다. + 누군가가 [%{site_name}](%{base_url}) 계정에 비밀번호를 추가하도록 요청했습니다. 대안으로 검증된 이 이메일 주소와 연결된 지원되는 온라인 서비스(Google, Facebook 등)를 사용하여 로그인할 수 있습니다. - 이 요청을하지 않았면 이 이메일을 무시 하셔도됩니다. + 이 요청을 하지 않았다면 이 이메일을 무시하세요. - 비밀번호를 입력 하려면 다음 링크를 클릭하십시오: + 비밀번호를 설정하려면 다음 링크를 클릭하세요: %{base_url}/u/password-reset/%{email_token} admin_login: title: "관리자 로그인" subject_template: "[%{email_prefix}] 로그인" text_body_template: | - 누군가 [%{site_name}](%{base_url})에서 사용자님의 계정에 로그인하도록 요청했습니다. + 누군가가 [%{site_name}](%{base_url}) 계정에 로그인하도록 요청했습니다. - 이 요청을하지 않으셨다면 이 이메일을 무시 하셔도됩니다. + 이 요청을 하지 않았다면 이 이메일을 무시하세요. - 다음 링크를 클릭하여 로그인하세요: + 다음 링크를 클릭하여 로그인하세요. %{base_url}/session/email-login/%{email_token} account_created: - title: "계정 생성" + title: "계정 생성됨" subject_template: "[%{email_prefix}] 새 계정" text_body_template: | - %{site_name}에서 새로운 계정이 만들어졌습니다. + %{site_name}에서 새 계정이 생성되었습니다. - 새 계정의 비밀번호를 선택하려면 다음 링크를 클릭하십시오: + 새 계정의 비밀번호를 설정하려면 다음 링크를 클릭하세요. %{base_url}/u/password-reset/%{email_token} confirm_new_email: title: "새 이메일 확인" subject_template: "[%{email_prefix}] 새 이메일 주소 확인" text_body_template: | - 다음 링크를 클릭하여 %{site_name}의 새 이메일 주소를 확인하십시오. + 다음 링크를 클릭하여 %{site_name}의 새 이메일 주소를 확인하세요. %{base_url}/u/confirm-new-email/%{email_token} - 이 변경을 요청하지 않은 경우 [사이트 관리자](%{base_url}/about)에게 문의하십시오. + 이 변경을 요청하지 않은 경우 [사이트 관리자](%{base_url}/about)에게 문의하세요. confirm_new_email_via_admin: title: "새 이메일 확인" subject_template: "[%{email_prefix}] 새 이메일 주소 확인" text_body_template: | - 다음 링크를 클릭하여 %{site_name}의 새 이메일 주소를 확인하십시오. + 다음 링크를 클릭하여 %{site_name}의 새 이메일 주소를 확인하세요. %{base_url}/u/confirm-new-email/%{email_token} - 이 이메일 변경은 사이트 관리자가 요청했습니다. 변경을 요청하지 않으셨다면 [사이트 관리자](%{base_url}/about)에게 문의하시기 바랍니다. + 이 이메일 변경은 사이트 관리자가 요청했습니다. 변경을 요청하지 않았다면 [사이트 관리자](%{base_url}/about)에게 문의하세요 confirm_old_email: - title: "오래된 이메일 확인" + title: "기존 이메일 확인" subject_template: "[%{email_prefix}] 현재 이메일 주소 확인" text_body_template: | - 이메일 주소를 변경하기 전, 사용자님의 현재 이메일 계정을 확인해야 합니다. 이 단계를 완료 한 후, 새로운 이메일 주소를 확인합니다. + 이메일 주소를 변경하기 전, 현재 이메일 계정을 관리하는지 확인이 필요합니다. 이 단계를 완료한 후 새 이메일 주소를 확인합니다. - 다음 링크를 클릭하여 %{site_name}의 현재 이메일 주소를 확인하십시오. + 다음 링크를 클릭하여 %{site_name}의 현재 이메일 주소를 확인하세요. %{base_url}/u/confirm-old-email/%{email_token} confirm_old_email_add: - title: "이전 이메일 확인 (추가)" + title: "기존 이메일 확인(추가)" subject_template: "[%{email_prefix}] 현재 이메일 주소 확인" text_body_template: | - 새로운 이메일 주소를 추가하기 위해서는 현재 이메일 계정에 대한 사용자님의 확인이 필요합니다. 이 단계를 완료 한 후, 새로운 이메일 주소를 입력해야 합니다. + 새 이메일 주소를 추가하기 전, 현재 이메일 계정을 관리하는지 확인이 필요합니다. 이 단계를 완료한 후 새 이메일 주소를 확인합니다. - 다음 링크를 클릭하여 %{site_name}의 현재 이메일 주소를 확인하십시오: + 다음 링크를 클릭하여 %{site_name}의 현재 이메일 주소를 확인하세요. %{base_url}/u/confirm-old-email/%{email_token} notify_old_email: - title: "오래된 이메일 알림" - subject_template: "[%{email_prefix}] 귀하의 이메일 주소가 변경되었습니다" + title: "기존 이메일 알림" + subject_template: "[%{email_prefix}] 이메일 주소가 변경되었습니다" text_body_template: | - 이것은 %{site_name}에서 사용자님의 계정 이메일 주소가 변경되었음을 알리는 자동 메일입니다. 오류가 발생한 경우 - 사이트 관리자에게 문의하십시오. + %{site_name}의 이메일 주소가 변경되었음을 알리는 자동 메시지입니다. 오류라고 생각되면 사이트 관리자에게 문의하세요. - 사용자님의 이메일 주소는 다음으로 변경되었습니다: + + 이메일 주소가 다음으로 변경되었습니다. %{new_email} notify_old_email_add: - title: "이전 이메일 알림 (추가)" - subject_template: "[%{email_prefix}] 새 이메일 주소가 추가되었습니다." + title: "기존 이메일 알림(추가)" + subject_template: "[%{email_prefix}] 새 이메일 주소가 추가되었습니다" text_body_template: | - %{site_name}에서 사용자님의 이메일 주소가 추가되었음을 알리는 자동 메시지입니다. 오류가 발생한 경우 사이트 관리자에게 문의하십시오. + %{site_name}의 이메일 주소가 추가되었음을 알리는 자동 메시지입니다. 오류라고 생각되면 사이트 관리자에게 문의하세요. - 추가 된 이메일 주소: + 추가한 이메일 주소는 다음과 같습니다. %{new_email} signup_after_approval: - title: "승인 후 가입" - subject_template: "당신은 %{site_name} 가입이 승인되었습니다!" + title: "가입 승인" + subject_template: "%{site_name} 가입이 승인되었습니다!" text_body_template: | %{site_name}에 오신 것을 환영합니다! - %{site_name}에서 사용자님의 계정이 승인되었습니다. + 운영진이 %{site_name} 계정을 승인했습니다. - 아래 링크를 클릭하면 새 계정에 로그인 할 수 있습니다. + 아래 링크에서 새 계정에 액세스할 수 있습니다. %{base_url} - 위 링크를 클릭 할 수 없으면 웹 브라우저의 주소 표시 줄에 복사하여 붙여 넣으십시오. + 위 링크를 클릭할 수 없으면 웹 브라우저의 주소 표시줄에 복사하여 붙여 넣으세요. %{new_user_tips} - 사이트 이용은 [커뮤니티의 가이드라인](%{base_url}/guidelines)을 참고해 주시기 바랍니다. + [성숙한 커뮤니티 활동](%{base_url}/guidelines)을 해 주시리라 믿습니다. - 즐거운 시간 되세요! + 즐거운 시간 보내세요! signup_after_reject: - title: "거부 후 가입" - subject_template: "%{site_name}에서 거부되었습니다." + title: "가입 거부" + subject_template: "%{site_name}에서 가입이 거부되었습니다." text_body_template: | - 관리자가 %{site_name}의 사용자님 계정을 거부했습니다. + 운영진이 %{site_name} 계정 가입을 거부했습니다. %{reject_reason} signup: - title: "가입하기" + title: "가입" subject_template: "[%{email_prefix}] 새 계정 확인" text_body_template: | %{site_name}에 오신 것을 환영합니다! - 다음 링크를 클릭하여 새 계정을 확인하고 활성화하십시오: + 다음 링크를 클릭하여 새 계정을 확인하고 활성화하세요. %{base_url}/u/activate-account/%{email_token} - 위 링크를 클릭 할 수 없는 경우 웹 브라우저의 주소 표시 줄에 복사하여 붙여 넣으십시오. + 위 링크를 클릭할 수 없으면 웹 브라우저의 주소 표시줄에 복사하여 붙여 넣으세요. activation_reminder: - title: "활성화 알림" - subject_template: "[%{email_prefix}] 계정 확인 알림" + title: "활성화 미리 알림" + subject_template: "[%{email_prefix}] 계정 확인 미리 알림" text_body_template: | %{site_name}에 오신 것을 환영합니다! - 사용자님의 계정을 활성화하기 위한 알림입니다. + 계정을 활성화하기 위한 미리 알림입니다. - 다음 링크를 클릭하여 새 계정을 확인하고 활성화하십시오: + 다음 링크를 클릭하여 새 계정을 확인하고 활성화하세요. %{base_url}/u/activate-account/%{email_token} - 위 링크를 클릭 할 수 없는 경우 웹 브라우저의 주소 표시 줄에 복사하여 붙여 넣으십시오. + 위 링크를 클릭할 수 없으면 웹 브라우저의 주소 표시줄에 복사하여 붙여 넣으세요. suspicious_login: - title: "새로운 로그인 알림" - subject_template: "[%{site_name}] %{location}에서 새 로그인" + title: "새 로그인 알림" + subject_template: "[%{site_name}] %{location}에서 새 로그인 발생" post_approved: - title: "사용자님의 게시물이 승인되었습니다." - subject_template: "[%{site_name}] 사용자님의 게시물이 승인되었습니다." + title: "게시물 승인됨" + subject_template: "[%{site_name}] 게시물이 승인되었습니다" text_body_template: | - 안녕하세요. + 안녕하세요, - [사용자님의 게시물](%{base_url}%{post_url})이 승인되었음을 알리는 %{site_name}에서 발송된 자동 메시지 입니다. + [게시물](%{base_url}%{post_url})이 승인되었음을 알리기 위해 %{site_name}에서 보낸 자동 메시지입니다. page_forbidden: - title: "죄송합니다! 비공개 페이지 입니다." - site_setting_missing: "`%{name}' 사이트 설정을 해야합니다." + title: "비공개 페이지입니다." + site_setting_missing: "`%{name}' 사이트 설정이 필요합니다." page_not_found: - page_title: "페이지를 찾을 수 없습니다" - title: "이런! 그 페이지는 더 이상 존재하지 않거나 비공개 상태입니다." + page_title: "페이지를 찾을 수 없음" + title: "이 페이지가 존재하지 않거나 비공개입니다." popular_topics: "인기" recent_topics: "최근" - see_more: "더" + see_more: "더 보기" search_title: "이 사이트 검색" search_button: "검색" offline: - title: "앱을로드 할 수 없습니다" - offline_page_message: "오프라인 상태 인 것 같습니다. 네트워크 연결을 확인하고 다시 시도하십시오." + title: "앱을 로드할 수 없음" + offline_page_message: "오프라인 상태인 것 같습니다. 네트워크 연결을 확인하고 다시 시도하세요." login_required: welcome_message: | ## [%{title}에 오신 것을 환영합니다](#welcome) - 계속하려면 계정을 만들거나 로그인하십시오. + 계정이 필요합니다. 계속하려면 계정을 만들거나 로그인하세요. welcome_message_invite_only: | ## [%{title}에 오신 것을 환영합니다](#welcome) - 계속하려면 기존 회원에게 초대를 요청하거나 로그인하십시오. + 계정이 필요합니다. 계속하려면 기존 회원에게 초대를 요청하거나 로그인하세요. deleted: "삭제되었습니다" image: "이미지" upload: - edit_reason: "이미지를 다운로드 합니다." - unauthorized: "업로드 하시려는 파일 확장자는 사용이 불가능합니다 (사용가능 확장자: %{authorized_extensions})." - pasted_image_filename: "게시된 이미지" - store_failure: "#%{user_id}가 업로드한 파일 #%{upload_id} 을 저장하는데 실패함." - file_missing: "죄송합니다. 업로드 할 파일을 지정하셔야 합니다." - empty: "죄송합니다. 지정된 파일은 빈 파일입니다." - failed: "죄송합니다. 업로드에 실패했습니다. 다시 시도해 주세요." - png_to_jpg_conversion_failure_message: "PNG에서 JPG로 변환 할 때 오류가 발생했습니다." - optimize_failure_message: "업로드된 이미지를 최적화하는 동안 오류가 발생했습니다." + edit_reason: "이미지 로컬 사본 다운로드됨" + unauthorized: "업로드하려는 파일 확장자는 허용되지 않습니다(허용 확장자: %{authorized_extensions})." + pasted_image_filename: "붙여 넣은 이미지" + store_failure: "#%{user_id} 님의 업로드 #%{upload_id} 저장에 실패했습니다." + file_missing: "업로드할 파일을 제공해야 합니다." + empty: "파일이 비어 있습니다." + failed: "업로드하지 못했습니다. 다시 시도하세요." + png_to_jpg_conversion_failure_message: "PNG에서 JPG로 변환 중에 오류가 발생했습니다." + optimize_failure_message: "업로드된 이미지를 최적화하는 중에 오류가 발생했습니다." download_failure: "외부 공급자로부터 파일을 다운로드하지 못했습니다." create_multipart_failure: "외부 저장소에서 멀티파트 업로드를 생성하지 못했습니다." abort_multipart_failure: "외부 저장소에서 멀티파트 업로드를 중단하지 못했습니다." complete_multipart_failure: "외부 저장소에서 멀티파트 업로드를 완료하지 못했습니다." external_upload_not_found: "업로드를 외부 저장소에서 찾을 수 없습니다. %{additional_detail}" - checksum_mismatch_failure: "업로드한 파일의 체크섬이 일치하지 않습니다. 업로드 시 파일 내용이 변경되었을 수 있습니다. 다시 시도해 주세요." + checksum_mismatch_failure: "업로드한 파일의 체크섬이 일치하지 않습니다. 업로드 시 파일 콘텐츠가 변경되었을 수 있습니다. 다시 시도하세요." cannot_promote_failure: "업로드를 완료할 수 없습니다. 이미 완료되었거나 이전에 실패했을 수 있습니다." attachments: - too_large: "죄송합니다, 업로드하려는 파일이 너무 큽니다. (최대 크기 %{max_size_kb}KB)." - too_large_humanized: "죄송합니다. 업로드하려는 파일이 너무 큽니다. (최대 크기는 %{max_size})." + too_large: "업로드하려는 파일이 너무 큽니다(최대 크기: %{max_size_kb}KB)." + too_large_humanized: "업로드하려는 파일이 너무 큽니다(최대 크기: %{max_size})." images: - too_large: "죄송합니다, 업로드하려는 이미지가 너무 큽니다. (최대 크기 %{max_size_kb}KB). 크기를 줄여서 다시 시도해보세요." - too_large_humanized: "죄송합니다. 업로드하려는 이미지가 너무 큽니다. (최대 크기는 %{max_size}). 크기를 조정하고 다시 시도하십시오." - larger_than_x_megapixels: "죄송합니다. 업로드하려는 이미지가 너무 큽니다 (최대 크기는 %{max_image_megapixels}- 메가 픽셀). 크기를 조정하고 다시 시도하십시오." - size_not_found: "죄송합니다. 이미지 사이즈가 잘못 되었습니다. 혹시 깨진 이미지가 아닌가요?" + too_large: "업로드하려는 이미지가 너무 큽니다(최대 크기: %{max_size_kb}KB). 크기를 조정하고 다시 시도하세요." + too_large_humanized: "업로드하려는 이미지가 너무 큽니다(최대 크기: %{max_size}KB). 크기를 조정하고 다시 시도하세요." + larger_than_x_megapixels: "업로드하려는 이미지가 너무 큽니다(최대 크기: %{max_image_megapixels}메가픽셀). 크기를 조정하고 다시 시도하세요." + size_not_found: "이미지 크기를 확인할 수 없습니다. 이미지가 손상되었을 수 있습니다." placeholders: too_large: "(%{max_size_kb}KB보다 큰 이미지)" too_large_humanized: "(%{max_size}보다 큰 이미지)" avatar: - missing: "해당 이메일 주소와 관련된 아바타를 찾을 수 없습니다. 다시 업로드 할 수 있습니까?" + missing: "해당 이메일 주소와 연결된 아바타를 찾을 수 없습니다. 다시 업로드해 주세요." flag_reason: - sockpuppet: "새로운 사용자가 주제를 작성했고 동일한 IP 주소 (%{ip_address})의 다른 새로운 사용자가 응답했습니다. `flag_sockpuppets` 사이트 설정을 참조하십시오." - spam_hosts: "이 새로운 사용자는 동일한 도메인에 대한 링크를 사용하여 여러 게시물을 만들려고했습니다. 링크를 포함하는이 사용자의 모든 게시물을 검토해야합니다. `newuser_spam_host_threshold` 사이트 설정을 참조하십시오." + sockpuppet: "신규 사용자가 주제를 생성했고, 동일한 IP 주소(%{ip_address})의 다른 신규 사용자가 댓글을 달았습니다. `flag_sockpuppets` 사이트 설정을 확인하세요." + spam_hosts: "이 신규 사용자는 동일한 도메인에 대한 링크를 사용하여 여러 게시물을 만들려고 했습니다. 링크가 포함된 이 사용자의 모든 게시물을 검토해야 합니다. `newuser_spam_host_threshold` 사이트 설정을 확인하세요." skipped_email_log: exceeded_emails_limit: "max_emails_per_day_per_user 초과" exceeded_bounces_limit: "bounce_score_threshold 초과" - mailing_list_no_echo_mode: "사용자 자신의 게시물에 대해서는 메일 링리스트 알림을 사용할 수 없습니다." - user_email_no_user: "ID %{user_id} 인 사용자를 찾을 수 없습니다" - user_email_post_not_found: "해당하는 ID %{post_id} 을 찾을 수 없습니다. " - user_email_anonymous_user: "사용자는 익명입니다" - user_email_user_suspended_not_pm: "메세지가 아니라 사용자가 정지됐습니다." - user_email_seen_recently: "최근 보여진 사용자" - user_email_notification_already_read: "이 알림 이미 읽은 것에 대한 이메일 입니다." - user_email_notification_topic_nil: "글 제목이 없음" - user_email_post_user_deleted: "이 포스트를 쓴 사용자가 삭제되었습니다" - user_email_post_deleted: "글쓴이에 의해 삭제된 글" - user_email_user_suspended: "사용자가 차단됨" - user_email_already_read: "이미 읽은 글" - user_email_access_denied: "사용자는이 게시물을 볼 수 없습니다" - user_email_no_email: "사용자 ID %{user_id}과 연결된 이메일이 없습니다." + mailing_list_no_echo_mode: "사용자 자신의 게시물에 대해 메일링 리스트 알림이 비활성화됨" + user_email_no_user: "ID가 %{user_id}인 사용자를 찾을 수 없음" + user_email_post_not_found: "ID가 %{post_id}인 게시물을 찾을 수 없음 " + user_email_anonymous_user: "사용자가 익명입니다" + user_email_user_suspended_not_pm: "메시지가 아닌 사용자가 정지되었습니다" + user_email_seen_recently: "최근 활동한 사용자" + user_email_notification_already_read: "이 이메일에 대한 알림은 이미 읽었습니다" + user_email_notification_topic_nil: "post.topic이 nil입니다" + user_email_post_user_deleted: "이 게시물을 작성한 사용자가 삭제되었습니다." + user_email_post_deleted: "작성자가 게시물을 삭제했습니다" + user_email_user_suspended: "사용자가 정지되었습니다" + user_email_already_read: "사용자가 이 게시물을 이미 읽었습니다" + user_email_access_denied: "사용자는 이 게시물을 볼 수 없습니다" + user_email_no_email: "사용자 ID %{user_id}에 연결된 이메일이 없습니다" sender_message_blank: "메시지 내용이 없습니다" - sender_message_to_blank: "메세지가 비어있음" - sender_text_part_body_blank: "본문이 비어있음" + sender_message_to_blank: "message.to가 비어 있습니다" + sender_text_part_body_blank: "text_part.body가 비어 있습니다" sender_body_blank: "본문 내용이 없습니다" sender_post_deleted: "게시물이 삭제되었습니다" - sender_message_to_invalid: "수신자에게 잘못된 이메일 주소가 있습니다" + sender_message_to_invalid: "수신자에게 유효하지 않은 이메일 주소가 있습니다" sender_topic_deleted: "주제가 삭제되었습니다" group_smtp_post_deleted: "게시물이 삭제되었습니다" group_smtp_topic_deleted: "주제가 삭제되었습니다" - group_smtp_disabled_for_group: "그룹에 대해 smtp가 비활성화되었습니다." + group_smtp_disabled_for_group: "그룹에 대해 smtp가 비활성화되었습니다" color_schemes: base_theme_name: "기본 테마 색상" light: "라이트" @@ -3541,28 +3514,28 @@ ko: latte_theme_name: "라떼" summer_theme_name: "여름" dark_rose_theme_name: "다크 로즈" - edit_this_page: "이 페이지 수정" + edit_this_page: "이 페이지 편집" csv_export: boolean_yes: "네" boolean_no: "아니오" - rate_limit_error: "게시글은 하루에 한번만 다운로드할 수 있습니다. 내일 다시 시도해보세요." + rate_limit_error: "게시물은 하루에 한 번만 다운로드할 수 있습니다. 내일 다시 시도하세요." static_topic_first_reply: |2 - 이 글타래인 %{page_name} 페이지의 첫글 수정. + %{page_name} 페이지의 콘텐츠를 변경하려면 이 주제의 첫 게시물을 편집하세요. guidelines_topic: - title: "자주하는 질문/가이드라인" + title: "FAQ/가이드라인" tos_topic: - title: "서비스 이용약관" + title: "이용약관" body: | - 이 약관은 <%{base_url}>의 사이트 사용에 적용됩니다. 사이트를 이용 하려면 사이트를 운영하는 %{company_name}의 약관에 동의해야합니다. + 이 약관은 <%{base_url}>의 인터넷 포럼 사용에 적용됩니다. 포럼을 사용하려면 포럼을 운영하는 회사인 %{company_name}의 약관에 동의해야 합니다. - 사이트 운영자는 조건에 따라 다른 서비스를 제공 할 수 있습니다. 이 약관은 사이트 이용에만 적용됩니다. + 회사는 다른 조건으로 다른 제품 및 서비스를 제공할 수 있습니다. 이 약관은 포럼 사용에만 적용됩니다. - 바로가기: + 건너뛰기: - [중요 용어](#heading--important-terms) - - [사이트 사용 권한](#heading--permission) - - [사이트 이용 조건](#heading--conditions) + - [포럼 이용 권한](#heading--permission) + - [포럼 이용 조건](#heading--conditions) - [허용되는 사용](#heading--acceptable-use) - [콘텐츠 표준](#heading--content-standards) - [Enforcement](#heading--enforcement) @@ -3580,51 +3553,51 @@ ko:

    중요 용어

    - ***이러한 약관에는 [면책 조항](#heading--disclaimers)의 면책 조항, [책임에 대한 제한](#heading--liability)의 책임 제한과 같이 사용자님의 권리와 책임에 영향을 미치는 여러 가지 중요한 조항이 포함됩니다.), [사용에 대한 책임](#heading--reponsibility)에서 사이트 이용을 오용하여 발생한 손해에 대해 배상하겠다는 사용자님의 동의 및 [분쟁](#heading--disputes)의 분쟁 중재에 대한 동의.*** + ***본 약관은 사용자의 권리와 책임에 영향을 주는 여러 중요 조항을 포함합니다. 예를 들면 다음과 같습니다. [면책 조항](#heading--disclaimers)의 면책 조항, [책임 제한](#heading--liability)의 사용자에 대한 회사의 책임 제한, [사용자의 사용에 대한 책임](#heading--responsibility)의 포럼 오용으로 인해 발생한 손해에 대해 회사에 보상하는 것에 동의, [분쟁](#heading--disputes)의 분쟁을 중재하기로 동의*** -

    사이트 사용 권한

    +

    포럼 이용 권한

    - 이 약관에 따라 우리는 사용자님에게 사이트 이용 권한을 부여합니다. 사이트를 이용하려면 모든 사람이 이 약관에 동의해야합니다. + 본 약관에 따라 회사는 사용자에게 포럼 이용 권한을 부여합니다. 포럼을 이용하려면 모든 사람이 이 약관에 동의해야 합니다. -

    사이트 이용 조건

    +

    포럼 이용 조건

    - 사이트 이용 권한은 다음 조건을 따릅니다: + 포럼 이용 권한에는 다음 조건이 적용됩니다. - 1. 13세 이상이어야합니다. + 1. 13세 이상이어야 합니다. - 2. 사이트가 사용자님에게 사이트 이용을 불허하면 더 이상 사이트를 이용할 수 없습니다. + 2. 회사가 사용자에게 직접 연락하여 이용 불가를 통지하면 더 이상 포럼을 이용할 수 없습니다. - 3. [허용되는 사용](#heading--acceptable-use) 및 [콘텐츠 기준](#heading--content-standards)에 따라 사이트를 이용해야합니다. + 3. [허용되는 사용](#heading--acceptable-use) 및 [콘텐츠 표준](#heading--content-standards)에 따라 포럼을 이용해야 합니다.

    허용되는 사용

    - 1. 사이트를 이용하여 법률을 위반할 수 없습니다. + 1. 포럼을 이용하여 법을 어길 수 없습니다. - 2. 사용자님은 특정 허가없이 사이트에서 다른 사람의 계정을 사용하거나 사용하려고 시도 할 수 없습니다. + 2. 특정 권한 없이 포럼에서 다른 사람의 계정을 사용하거나 사용하려고 시도할 수 없습니다. - 3. 사이트에서 사용자 이름이나 기타 고유 식별자를 구매, 판매 또는 거래 할 수 없습니다. + 3. 포럼에서 아이디 또는 기타 고유 ID를 구매, 판매 또는 거래할 수 없습니다. - 4. 사용자님은 사이트를 통해 광고, 스팸 메일 또는 기타 권유를 보내거나 사이트를 사용하여 상업용 메일 링리스트 또는 데이터베이스에 대한 주소 또는 기타 개인 데이터를 수집 할 수 없습니다. + 4. 포럼을 통해 광고, 행운의 편지 또는 기타 권유를 보내거나 상업적 메일링 리스트 또는 데이터베이스를 위한 주소 또는 기타 개인 데이터를 수집하기 위해 포럼을 사용할 수 없습니다. - 5. 웹 크롤러, 브라우저 플러그인 또는 애드온 또는 웹 브라우저가 아닌 기타 컴퓨터 프로그램을 사용하여 사이트에 대한 액세스를 자동화하거나 사이트를 모니터링 할 수 없습니다. 사이트를 크롤링하여 공개적으로 사용 가능한 검색 엔진을 사용하는 경우 색인을 생성 할 수 있습니다. + 5. 웹 크롤러, 브라우저 플러그인, 애드온 또는 웹 브라우저가 아닌 기타 컴퓨터 프로그램을 사용하여 포럼 액세스를 자동화하거나 포럼을 모니터링할 수 없습니다. 포럼을 크롤링하여 공개적으로 사용 가능한 검색 엔진을 위해 색인을 생성할 수는 있습니다. - 6. 사이트를 사용하여 배포 목록, 뉴스 그룹 또는 그룹 메일 별칭으로 전자 메일을 보낼 수 없습니다. + 6. 포럼을 사용하여 배포 목록, 뉴스그룹 또는 그룹 메일 별칭으로 이메일을 전송할 수 없습니다. - 7. 사용자님은 이 사이트와 제휴하거나 이 사이트의 보증을 받았다고 거짓으로 암시해서는 안됩니다. + 7. 이 회사와 제휴하거나 보증을 받는다고 허위로 암시할 수 없습니다. - 8. 다른 웹 페이지의 포럼에있는 이미지 또는 기타 하이퍼 텍스트가 아닌 콘텐츠에 하이퍼 링크를 사용할 수 없습니다. + 8. 다른 웹페이지의 포럼에 있는 이미지 또는 기타 비하이퍼텍스트 콘텐츠에 하이퍼링크할 수 없습니다. - 9. 포럼에서 다운로드 한 자료의 소유권을 나타내는 표시를 제거 할 수 없습니다. + 9. 포럼에서 다운로드한 자료의 소유권을 나타내는 표시를 제거할 수 없습니다. - 10. `