diff options
233 files changed, 3758 insertions, 2748 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index 4fcc8c618..b9228f996 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 orbs: - ruby: circleci/ruby@1.4.0 + ruby: circleci/ruby@1.4.1 node: circleci/node@5.0.1 executors: diff --git a/.codeclimate.yml b/.codeclimate.yml index c253bd95a..ee9022cda 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,4 +1,4 @@ -version: "2" +version: '2' checks: argument-count: enabled: false @@ -34,8 +34,8 @@ plugins: sass-lint: enabled: true exclude_patterns: -- spec/ -- vendor/asset/ + - spec/ + - vendor/asset/ -- app/javascript/mastodon/locales/**/*.json -- config/locales/**/*.yml + - app/javascript/mastodon/locales/**/*.json + - config/locales/**/*.yml diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 78e940763..628efc8ec 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,22 +5,22 @@ "workspaceFolder": "/workspaces/mastodon", // Set *default* container specific settings.json values on container create. - "settings": {}, + "settings": {}, // Add the IDs of extensions you want installed when the container is created. - "extensions": [ + "extensions": [ "EditorConfig.EditorConfig", "dbaeumer.vscode-eslint", - "rebornix.Ruby" - ], + "rebornix.Ruby" + ], // Use 'forwardPorts' to make a list of ports inside the container available locally. - // This can be used to network with other containers or the host. - "forwardPorts": [3000, 4000], + // This can be used to network with other containers or the host. + "forwardPorts": [3000, 4000], - // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "bundle install --path vendor/bundle && yarn install && ./bin/rails db:setup", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "bundle install --path vendor/bundle && yarn install && ./bin/rails db:setup", - // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - "remoteUser": "vscode" + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode" } diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 906fce430..538f6cccd 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -9,9 +9,9 @@ services: # Update 'VARIANT' to pick a version of Ruby: 3, 3.1, 3.0, 2, 2.7, 2.6 # Append -bullseye or -buster to pin to an OS version. # Use -bullseye variants on local arm64/Apple Silicon. - VARIANT: "3.0-bullseye" + VARIANT: '3.0-bullseye' # Optional Node.js version to install - NODE_VERSION: "14" + NODE_VERSION: '14' volumes: - ..:/workspaces/mastodon:cached environment: @@ -34,7 +34,6 @@ services: - internal_network user: vscode - db: image: postgres:14-alpine restart: unless-stopped diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..de7673eb6 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,78 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config and downloaded libraries. +/.bundle +/vendor/bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-journal + +# Ignore all logfiles and tempfiles. +.eslintcache +/log/* +!/log/.keep +/tmp +/coverage +/public/system +/public/assets +/public/packs +/public/packs-test +.env +.env.production +.env.development +/node_modules/ +/build/ + +# Ignore Vagrant files +.vagrant/ + +# Ignore Capistrano customizations +/config/deploy/* + +# Ignore IDE files +.vscode/ +.idea/ + +# Ignore postgres + redis + elasticsearch volume optionally created by docker-compose +/postgres +/postgres14 +/redis +/elasticsearch + +# ignore Helm dependency charts +/chart/charts/*.tgz + +# Ignore Apple files +.DS_Store + +# Ignore vim files +*~ +*.swp + +# Ignore npm debug log +npm-debug.log + +# Ignore yarn log files +yarn-error.log +yarn-debug.log + +# Ignore vagrant log files +*-cloudimg-console.log + +# Ignore Docker option files +docker-compose.override.yml + +# Ignore Helm files +/chart + +# Ignore emoji map file +/app/javascript/mastodon/features/emoji/emoji_map.json + +# Ignore locale files +/app/javascript/mastodon/locales +/config/locales diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 000000000..1d70813d5 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,3 @@ +module.exports = { + singleQuote: true +} diff --git a/.rubocop.yml b/.rubocop.yml index 4948aea5a..a76937426 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -5,17 +5,17 @@ AllCops: TargetRubyVersion: 2.5 NewCops: disable Exclude: - - 'spec/**/*' - - 'db/**/*' - - 'app/views/**/*' - - 'config/**/*' - - 'bin/*' - - 'Rakefile' - - 'node_modules/**/*' - - 'Vagrantfile' - - 'vendor/**/*' - - 'lib/json_ld/*' - - 'lib/templates/**/*' + - 'spec/**/*' + - 'db/**/*' + - 'app/views/**/*' + - 'config/**/*' + - 'bin/*' + - 'Rakefile' + - 'node_modules/**/*' + - 'Vagrantfile' + - 'vendor/**/*' + - 'lib/json_ld/*' + - 'lib/templates/**/*' Bundler/OrderedGems: Enabled: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 519c561a6..dd0ccc5f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,10 @@ Changelog All notable changes to this project will be documented in this file. -## Unreleased +## [3.5.0] - 2022-03-30 ### Added -- **Add support for post editing** ([Gargron](https://github.com/mastodon/mastodon/pull/16697), [Gargron](https://github.com/mastodon/mastodon/pull/17727), [Gargron](https://github.com/mastodon/mastodon/pull/17728), [Gargron](https://github.com/mastodon/mastodon/pull/17320), [Gargron](https://github.com/mastodon/mastodon/pull/17404), [Gargron](https://github.com/mastodon/mastodon/pull/17390), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17335), [Gargron](https://github.com/mastodon/mastodon/pull/17696), [Gargron](https://github.com/mastodon/mastodon/pull/17745), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17740), [Gargron](https://github.com/mastodon/mastodon/pull/17697), [Gargron](https://github.com/mastodon/mastodon/pull/17648), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17531), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17499), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17498), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17380), [Gargron](https://github.com/mastodon/mastodon/pull/17373), [Gargron](https://github.com/mastodon/mastodon/pull/17334), [Gargron](https://github.com/mastodon/mastodon/pull/17333), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17699), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17748)) +- **Add support for incoming edited posts** ([Gargron](https://github.com/mastodon/mastodon/pull/16697), [Gargron](https://github.com/mastodon/mastodon/pull/17727), [Gargron](https://github.com/mastodon/mastodon/pull/17728), [Gargron](https://github.com/mastodon/mastodon/pull/17320), [Gargron](https://github.com/mastodon/mastodon/pull/17404), [Gargron](https://github.com/mastodon/mastodon/pull/17390), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17335), [Gargron](https://github.com/mastodon/mastodon/pull/17696), [Gargron](https://github.com/mastodon/mastodon/pull/17745), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17740), [Gargron](https://github.com/mastodon/mastodon/pull/17697), [Gargron](https://github.com/mastodon/mastodon/pull/17648), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17531), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17499), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17498), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17380), [Gargron](https://github.com/mastodon/mastodon/pull/17373), [Gargron](https://github.com/mastodon/mastodon/pull/17334), [Gargron](https://github.com/mastodon/mastodon/pull/17333), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17699), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17748)) - Previous versions remain available for perusal and comparison - People who reblogged a post are notified when it's edited - New REST APIs: @@ -14,7 +14,7 @@ All notable changes to this project will be documented in this file. - `GET /api/v1/statuses/:id/history` - `GET /api/v1/statuses/:id/source` - New streaming API event: - - `update` + - `status.update` - **Add appeals for moderator decisions** ([Gargron](https://github.com/mastodon/mastodon/pull/17364), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17725), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17566), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17652), [Gargron](https://github.com/mastodon/mastodon/pull/17616), [Gargron](https://github.com/mastodon/mastodon/pull/17615), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17554), [Gargron](https://github.com/mastodon/mastodon/pull/17523)) - All default moderator decisions now notify the affected user by e-mail - They now link to an appeal page instead of suggesting replying to the e-mail @@ -63,7 +63,7 @@ All notable changes to this project will be documented in this file. - Add `types` param to `GET /api/v1/notifications` in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17767)) - **Add notifications for moderators about new sign-ups** ([Gargron](https://github.com/mastodon/mastodon/pull/16953), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17629)) - When a new user confirms e-mail, moderators receive a notification - - New streaming API event: + - New notification type: - `admin.sign_up` - Add authentication history ([Gargron](https://github.com/mastodon/mastodon/pull/16408), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16428), [baby-gnu](https://github.com/mastodon/mastodon/pull/16654)) - Add ability to automatically delete old posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16529), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17691), [tribela](https://github.com/mastodon/mastodon/pull/16653)) @@ -81,6 +81,7 @@ All notable changes to this project will be documented in this file. - Add lazy loading for emoji picker in web UI ([mashirozx](https://github.com/mastodon/mastodon/pull/16907), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17011)) - Add single option votes tooltip in polls in web UI ([Brawaru](https://github.com/mastodon/mastodon/pull/16849)) - Add confirmation modal when closing media edit modal with unsaved changes in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16518)) +- Add hint about missing media attachment description in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17845)) - Add support for fetching Create and Announce activities by URI in ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16383)) - Add `S3_FORCE_SINGLE_REQUEST` environment variable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16866)) - Add `OMNIAUTH_ONLY` environment variable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17288), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17345)) @@ -130,6 +131,11 @@ All notable changes to this project will be documented in this file. ### Fixed +- Fix IDN domains not being rendered correctly in a few left-over places ([Gargron](https://github.com/mastodon/mastodon/pull/17848)) +- Fix Sanskrit translation not being used in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17820)) +- Fix Kurdish languages having the wrong language codes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17812)) +- Fix pghero making database schema suggestions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17807)) +- Fix encoding glitch in the OpenGraph description of a profile page ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17821)) - Fix web manifest not permitting PWA usage from alternate domains ([HolgerHuo](https://github.com/mastodon/mastodon/pull/16714)) - Fix not being able to edit media attachments for scheduled posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17690)) - Fix subscribed relay activities being recorded as boosts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17571)) @@ -191,6 +197,11 @@ All notable changes to this project will be documented in this file. - Fix hashtag autocomplete overriding user-typed case ([weex](https://github.com/mastodon/mastodon/pull/16460)) - Fix WebAuthn authentication setup to not prompt for PIN ([truongnmt](https://github.com/mastodon/mastodon/pull/16545)) +### Security + +- Fix being able to post URLs longer than 4096 characters ([Gargron](https://github.com/mastodon/mastodon/pull/17908)) +- Fix being able to bypass e-mail restrictions ([Gargron](https://github.com/mastodon/mastodon/pull/17909)) + ## [3.4.6] - 2022-02-03 ### Fixed diff --git a/Dockerfile b/Dockerfile index 0185ebfe9..da4fb964c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ SHELL ["/bin/bash", "-c"] RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections # Install Node v16 (LTS) -ENV NODE_VER="16.13.2" +ENV NODE_VER="16.14.2" RUN ARCH= && \ dpkgArch="$(dpkg --print-architecture)" && \ case "${dpkgArch##*-}" in \ diff --git a/Gemfile b/Gemfile index 2621b77a5..4c8cd2f5a 100644 --- a/Gemfile +++ b/Gemfile @@ -89,7 +89,7 @@ gem 'stoplight', '~> 2.2.1' gem 'strong_migrations', '~> 0.7' gem 'tty-prompt', '~> 0.23', require: false gem 'twitter-text', '~> 3.1.0' -gem 'tzinfo-data', '~> 1.2021' +gem 'tzinfo-data', '~> 1.2022' gem 'webpacker', '~> 5.4' gem 'webpush', '~> 0.3' gem 'webauthn', '~> 3.0.0.alpha1' @@ -131,15 +131,15 @@ group :development do gem 'better_errors', '~> 2.9' gem 'binding_of_caller', '~> 1.0' gem 'bullet', '~> 7.0' - gem 'letter_opener', '~> 1.7' + gem 'letter_opener', '~> 1.8' gem 'letter_opener_web', '~> 2.0' gem 'memory_profiler' - gem 'rubocop', '~> 1.25', require: false - gem 'rubocop-rails', '~> 2.13', require: false + gem 'rubocop', '~> 1.26', require: false + gem 'rubocop-rails', '~> 2.14', require: false gem 'brakeman', '~> 5.2', require: false gem 'bundler-audit', '~> 0.9', require: false - gem 'capistrano', '~> 3.16' + gem 'capistrano', '~> 3.17' gem 'capistrano-rails', '~> 1.6' gem 'capistrano-rbenv', '~> 2.2' gem 'capistrano-yarn', '~> 2.0' diff --git a/Gemfile.lock b/Gemfile.lock index 2275d9453..e784b81cf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -96,7 +96,7 @@ GEM aws-sigv4 (~> 1.4) aws-sigv4 (1.4.0) aws-eventstream (~> 1, >= 1.0.2) - bcrypt (3.1.16) + bcrypt (3.1.17) better_errors (2.9.1) coderay (>= 1.0.0) erubi (>= 1.0.0) @@ -121,7 +121,7 @@ GEM bundler (>= 1.2.0, < 3) thor (~> 1.0) byebug (11.1.3) - capistrano (3.16.0) + capistrano (3.17.0) airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) @@ -157,7 +157,7 @@ GEM climate_control (0.2.0) coderay (1.1.3) color_diff (0.1) - concurrent-ruby (1.1.9) + concurrent-ruby (1.1.10) connection_pool (2.2.5) cose (1.0.0) cbor (~> 0.5.9) @@ -174,11 +174,11 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) - devise-two-factor (4.0.1) - activesupport (< 6.2) + devise-two-factor (4.0.2) + activesupport (< 7.1) attr_encrypted (>= 1.3, < 4, != 2) devise (~> 4.0) - railties (< 6.2) + railties (< 7.1) rotp (~> 6.0) devise_pam_authenticatable2 (9.2.0) devise (>= 4.0.0) @@ -351,8 +351,8 @@ GEM terrapin (~> 0.6.0) launchy (2.5.0) addressable (~> 2.7) - letter_opener (1.7.0) - launchy (~> 2.2) + letter_opener (1.8.1) + launchy (>= 2.2, < 3) letter_opener_web (2.0.0) actionmailer (>= 5.2) letter_opener (~> 1.7) @@ -433,8 +433,8 @@ GEM openssl-signature_algorithm (0.4.0) orm_adapter (0.5.0) ox (2.14.10) - parallel (1.21.0) - parser (3.1.0.0) + parallel (1.22.1) + parser (3.1.1.0) ast (~> 2.4.1) parslet (2.0.0) pastel (0.8.0) @@ -527,7 +527,7 @@ GEM redis (4.5.1) redis-namespace (1.8.2) redis (>= 3.0.4) - regexp_parser (2.2.0) + regexp_parser (2.2.1) request_store (1.5.0) rack (>= 1.4) responders (3.0.1) @@ -562,18 +562,18 @@ GEM rspec-support (3.11.0) rspec_junit_formatter (0.5.1) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.25.1) + rubocop (1.26.1) parallel (~> 1.10) parser (>= 3.1.0.0) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml - rubocop-ast (>= 1.15.1, < 2.0) + rubocop-ast (>= 1.16.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.15.1) - parser (>= 3.0.1.1) - rubocop-rails (2.13.2) + rubocop-ast (1.16.0) + parser (>= 3.1.1.0) + rubocop-rails (2.14.2) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.7.0, < 2.0) @@ -669,7 +669,7 @@ GEM unf (~> 0.1.0) tzinfo (2.0.4) concurrent-ruby (~> 1.0) - tzinfo-data (1.2021.5) + tzinfo-data (1.2022.1) tzinfo (>= 1.0.0) unf (0.1.4) unf_ext @@ -735,7 +735,7 @@ DEPENDENCIES browser bullet (~> 7.0) bundler-audit (~> 0.9) - capistrano (~> 3.16) + capistrano (~> 3.17) capistrano-rails (~> 1.6) capistrano-rbenv (~> 2.2) capistrano-yarn (~> 2.0) @@ -774,7 +774,7 @@ DEPENDENCIES json-ld-preloaded (~> 3.2) kaminari (~> 1.2) kt-paperclip (~> 7.1) - letter_opener (~> 1.7) + letter_opener (~> 1.8) letter_opener_web (~> 2.0) link_header (~> 0.0) lograge (~> 0.11) @@ -819,8 +819,8 @@ DEPENDENCIES rspec-rails (~> 5.1) rspec-sidekiq (~> 3.1) rspec_junit_formatter (~> 0.5) - rubocop (~> 1.25) - rubocop-rails (~> 2.13) + rubocop (~> 1.26) + rubocop-rails (~> 2.14) ruby-progressbar (~> 1.11) sanitize (~> 6.0) scenic (~> 1.6) @@ -839,7 +839,7 @@ DEPENDENCIES thor (~> 1.2) tty-prompt (~> 0.23) twitter-text (~> 3.1.0) - tzinfo-data (~> 1.2021) + tzinfo-data (~> 1.2022) webauthn (~> 3.0.0.alpha1) webmock (~> 3.14) webpacker (~> 5.4) diff --git a/app.json b/app.json index 6b4365383..c694908c5 100644 --- a/app.json +++ b/app.json @@ -95,8 +95,5 @@ "scripts": { "postdeploy": "bundle exec rails db:migrate && bundle exec rails db:seed" }, - "addons": [ - "heroku-postgresql", - "heroku-redis" - ] + "addons": ["heroku-postgresql", "heroku-redis"] } diff --git a/app/chewy/statuses_index.rb b/app/chewy/statuses_index.rb index 65cbb6fcd..bfd61a048 100644 --- a/app/chewy/statuses_index.rb +++ b/app/chewy/statuses_index.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class StatusesIndex < Chewy::Index + include FormattingHelper + settings index: { refresh_interval: '15m' }, analysis: { filter: { english_stop: { @@ -57,7 +59,7 @@ class StatusesIndex < Chewy::Index field :id, type: 'long' field :account_id, type: 'long' - field :text, type: 'text', value: ->(status) { [status.spoiler_text, Formatter.instance.plaintext(status)].concat(status.ordered_media_attachments.map(&:description)).concat(status.preloadable_poll ? status.preloadable_poll.options : []).join("\n\n") } do + field :text, type: 'text', value: ->(status) { [status.spoiler_text, extract_status_plain_text(status)].concat(status.ordered_media_attachments.map(&:description)).concat(status.preloadable_poll ? status.preloadable_poll.options : []).join("\n\n") } do field :stemmed, type: 'text', analyzer: 'content' end diff --git a/app/controllers/activitypub/base_controller.rb b/app/controllers/activitypub/base_controller.rb index 4cbc3ab8f..196d85a32 100644 --- a/app/controllers/activitypub/base_controller.rb +++ b/app/controllers/activitypub/base_controller.rb @@ -2,6 +2,7 @@ class ActivityPub::BaseController < Api::BaseController skip_before_action :require_authenticated_user! + skip_around_action :set_locale private diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index 72c30dec7..d96285b44 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -15,8 +15,6 @@ class Api::BaseController < ApplicationController protect_from_forgery with: :null_session - skip_around_action :set_locale - rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e| render json: { error: e.to_s }, status: 422 end diff --git a/app/controllers/api/v1/admin/accounts_controller.rb b/app/controllers/api/v1/admin/accounts_controller.rb index 65330b8c8..4b6dab208 100644 --- a/app/controllers/api/v1/admin/accounts_controller.rb +++ b/app/controllers/api/v1/admin/accounts_controller.rb @@ -104,13 +104,27 @@ class Api::V1::Admin::AccountsController < Api::BaseController end def filtered_accounts - AccountFilter.new(filter_params).results + AccountFilter.new(translated_filter_params).results end def filter_params params.permit(*FILTER_PARAMS) end + def translated_filter_params + translated_params = { origin: 'local', status: 'active' }.merge(filter_params.slice(*AccountFilter::KEYS)) + + translated_params[:origin] = 'remote' if params[:remote].present? + + %i(active pending disabled silenced suspended).each do |status| + translated_params[:status] = status.to_s if params[status].present? + end + + translated_params[:permissions] = 'staff' if params[:staff].present? + + translated_params + end + def insert_pagination_headers set_pagination_headers(next_path, prev_path) end diff --git a/app/controllers/api/v1/trends/links_controller.rb b/app/controllers/api/v1/trends/links_controller.rb index ad20e7f8b..b1cde5a4b 100644 --- a/app/controllers/api/v1/trends/links_controller.rb +++ b/app/controllers/api/v1/trends/links_controller.rb @@ -3,6 +3,10 @@ class Api::V1::Trends::LinksController < Api::BaseController before_action :set_links + after_action :insert_pagination_headers + + DEFAULT_LINKS_LIMIT = 10 + def index render json: @links, each_serializer: REST::Trends::LinkSerializer end @@ -20,6 +24,26 @@ class Api::V1::Trends::LinksController < Api::BaseController end def links_from_trends - Trends.links.query.allowed.in_locale(content_locale).limit(limit_param(10)) + Trends.links.query.allowed.in_locale(content_locale).offset(offset_param).limit(limit_param(DEFAULT_LINKS_LIMIT)) + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def pagination_params(core_params) + params.slice(:limit).permit(:limit).merge(core_params) + end + + def next_path + api_v1_trends_links_url pagination_params(offset: offset_param + limit_param(DEFAULT_LINKS_LIMIT)) + end + + def prev_path + api_v1_trends_links_url pagination_params(offset: offset_param - limit_param(DEFAULT_LINKS_LIMIT)) if offset_param > limit_param(DEFAULT_LINKS_LIMIT) + end + + def offset_param + params[:offset].to_i end end diff --git a/app/controllers/api/v1/trends/statuses_controller.rb b/app/controllers/api/v1/trends/statuses_controller.rb index d4ec97ae5..4977803fb 100644 --- a/app/controllers/api/v1/trends/statuses_controller.rb +++ b/app/controllers/api/v1/trends/statuses_controller.rb @@ -3,6 +3,8 @@ class Api::V1::Trends::StatusesController < Api::BaseController before_action :set_statuses + after_action :insert_pagination_headers + def index render json: @statuses, each_serializer: REST::StatusSerializer end @@ -22,6 +24,26 @@ class Api::V1::Trends::StatusesController < Api::BaseController def statuses_from_trends scope = Trends.statuses.query.allowed.in_locale(content_locale) scope = scope.filtered_for(current_account) if user_signed_in? - scope.limit(limit_param(DEFAULT_STATUSES_LIMIT)) + scope.offset(offset_param).limit(limit_param(DEFAULT_STATUSES_LIMIT)) + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def pagination_params(core_params) + params.slice(:limit).permit(:limit).merge(core_params) + end + + def next_path + api_v1_trends_statuses_url pagination_params(offset: offset_param + limit_param(DEFAULT_STATUSES_LIMIT)) + end + + def prev_path + api_v1_trends_statuses_url pagination_params(offset: offset_param - limit_param(DEFAULT_STATUSES_LIMIT)) if offset_param > limit_param(DEFAULT_STATUSES_LIMIT) + end + + def offset_param + params[:offset].to_i end end diff --git a/app/controllers/api/v1/trends/tags_controller.rb b/app/controllers/api/v1/trends/tags_controller.rb index 1334b72d2..d77857871 100644 --- a/app/controllers/api/v1/trends/tags_controller.rb +++ b/app/controllers/api/v1/trends/tags_controller.rb @@ -3,6 +3,10 @@ class Api::V1::Trends::TagsController < Api::BaseController before_action :set_tags + after_action :insert_pagination_headers + + DEFAULT_TAGS_LIMIT = 10 + def index render json: @tags, each_serializer: REST::TagSerializer end @@ -12,10 +16,30 @@ class Api::V1::Trends::TagsController < Api::BaseController def set_tags @tags = begin if Setting.trends - Trends.tags.query.allowed.limit(limit_param(10)) + Trends.tags.query.allowed.limit(limit_param(DEFAULT_TAGS_LIMIT)) else [] end end end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def pagination_params(core_params) + params.slice(:limit).permit(:limit).merge(core_params) + end + + def next_path + api_v1_trends_tags_url pagination_params(offset: offset_param + limit_param(DEFAULT_TAGS_LIMIT)) + end + + def prev_path + api_v1_trends_tags_url pagination_params(offset: offset_param - limit_param(DEFAULT_TAGS_LIMIT)) if offset_param > limit_param(DEFAULT_TAGS_LIMIT) + end + + def offset_param + params[:offset].to_i + end end diff --git a/app/controllers/api/v2/admin/accounts_controller.rb b/app/controllers/api/v2/admin/accounts_controller.rb new file mode 100644 index 000000000..a89e6835e --- /dev/null +++ b/app/controllers/api/v2/admin/accounts_controller.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class Api::V2::Admin::AccountsController < Api::V1::Admin::AccountsController + FILTER_PARAMS = %i( + origin + status + permissions + username + by_domain + display_name + email + ip + invited_by + ).freeze + + PAGINATION_PARAMS = (%i(limit) + FILTER_PARAMS).freeze + + private + + def filtered_accounts + AccountFilter.new(filter_params).results + end + + def filter_params + params.permit(*FILTER_PARAMS) + end + + def pagination_params(core_params) + params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params) + end +end diff --git a/app/controllers/api/web/embeds_controller.rb b/app/controllers/api/web/embeds_controller.rb index 741ba910f..58f6345e6 100644 --- a/app/controllers/api/web/embeds_controller.rb +++ b/app/controllers/api/web/embeds_controller.rb @@ -15,7 +15,7 @@ class Api::Web::EmbedsController < Api::Web::BaseController return not_found if oembed.nil? begin - oembed[:html] = Formatter.instance.sanitize(oembed[:html], Sanitize::Config::MASTODON_OEMBED) + oembed[:html] = Sanitize.fragment(oembed[:html], Sanitize::Config::MASTODON_OEMBED) rescue ArgumentError return not_found end diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index bb2374c0e..f0becf8bd 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -2,10 +2,12 @@ module AccountsHelper def display_name(account, **options) + str = account.display_name.presence || account.username + if options[:custom_emojify] - Formatter.instance.format_display_name(account, **options) + prerender_custom_emojis(h(str), account.emojis) else - account.display_name.presence || account.username + str end end diff --git a/app/helpers/admin/trends/statuses_helper.rb b/app/helpers/admin/trends/statuses_helper.rb index d16e3dd12..214c1e2a6 100644 --- a/app/helpers/admin/trends/statuses_helper.rb +++ b/app/helpers/admin/trends/statuses_helper.rb @@ -12,9 +12,6 @@ module Admin::Trends::StatusesHelper return '' if text.blank? - html = Formatter.instance.send(:encode, text) - html = Formatter.instance.send(:encode_custom_emojis, html, status.emojis, prefers_autoplay?) - - html.html_safe # rubocop:disable Rails/OutputSafety + prerender_custom_emojis(h(text), status.emojis) end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index eace78af6..d482ad1a2 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -240,4 +240,8 @@ module ApplicationHelper end end.values end + + def prerender_custom_emojis(html, custom_emojis) + EmojiFormatter.new(html, custom_emojis, animate: prefers_autoplay?).to_s + end end diff --git a/app/helpers/formatting_helper.rb b/app/helpers/formatting_helper.rb new file mode 100644 index 000000000..2a622ae0b --- /dev/null +++ b/app/helpers/formatting_helper.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module FormattingHelper + def html_aware_format(text, local, options = {}) + HtmlAwareFormatter.new(text, local, options).to_s + end + + def linkify(text, options = {}) + TextFormatter.new(text, options).to_s + end + + def extract_status_plain_text(status) + PlainTextFormatter.new(status.text, status.local?).to_s + end + + def status_content_format(status) + html_aware_format(status.text, status.local?, preloaded_accounts: [status.account] + (status.respond_to?(:active_mentions) ? status.active_mentions.map(&:account) : []), content_type: status.content_type) + end + + def account_bio_format(account) + html_aware_format(account.note, account.local?) + end + + def account_field_value_format(field, with_rel_me: true) + html_aware_format(field.value, field.account.local?, with_rel_me: with_rel_me, with_domains: true, multiline: false) + end +end diff --git a/app/helpers/routing_helper.rb b/app/helpers/routing_helper.rb index fb24a1b28..f95f46a56 100644 --- a/app/helpers/routing_helper.rb +++ b/app/helpers/routing_helper.rb @@ -2,6 +2,7 @@ module RoutingHelper extend ActiveSupport::Concern + include Rails.application.routes.url_helpers include ActionView::Helpers::AssetTagHelper include Webpacker::Helper @@ -22,8 +23,6 @@ module RoutingHelper full_asset_url(asset_pack_path(source, **options)) end - private - def use_storage? Rails.configuration.x.use_s3 || Rails.configuration.x.use_swift end diff --git a/app/helpers/statuses_helper.rb b/app/helpers/statuses_helper.rb index d328f89b7..e92b4c839 100644 --- a/app/helpers/statuses_helper.rb +++ b/app/helpers/statuses_helper.rb @@ -113,20 +113,6 @@ module StatusesHelper end end - private - - def simplified_text(text) - text.dup.tap do |new_text| - URI.extract(new_text).each do |url| - new_text.gsub!(url, '') - end - - new_text.gsub!(Account::MENTION_RE, '') - new_text.gsub!(Tag::HASHTAG_RE, '') - new_text.gsub!(/\s+/, '') - end - end - def embedded_view? params[:controller] == EMBEDDED_CONTROLLER && params[:action] == EMBEDDED_ACTION end diff --git a/app/javascript/flavours/glitch/components/admin/Counter.js b/app/javascript/flavours/glitch/components/admin/Counter.js index ecb242950..a4d6cef41 100644 --- a/app/javascript/flavours/glitch/components/admin/Counter.js +++ b/app/javascript/flavours/glitch/components/admin/Counter.js @@ -33,6 +33,7 @@ export default class Counter extends React.PureComponent { label: PropTypes.string.isRequired, href: PropTypes.string, params: PropTypes.object, + target: PropTypes.string, }; state = { @@ -54,7 +55,7 @@ export default class Counter extends React.PureComponent { } render () { - const { label, href } = this.props; + const { label, href, target } = this.props; const { loading, data } = this.state; let content; @@ -100,7 +101,7 @@ export default class Counter extends React.PureComponent { if (href) { return ( - <a href={href} className='sparkline'> + <a href={href} className='sparkline' target={target}> {inner} </a> ); diff --git a/app/javascript/flavours/glitch/features/compose/components/upload.js b/app/javascript/flavours/glitch/features/compose/components/upload.js index 338bfca37..963b95c87 100644 --- a/app/javascript/flavours/glitch/features/compose/components/upload.js +++ b/app/javascript/flavours/glitch/features/compose/components/upload.js @@ -5,7 +5,6 @@ import Motion from 'flavours/glitch/util/optional_motion'; import spring from 'react-motion/lib/spring'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { FormattedMessage } from 'react-intl'; -import classNames from 'classnames'; import Icon from 'flavours/glitch/components/icon'; import { isUserTouching } from 'flavours/glitch/util/is_mobile'; @@ -44,10 +43,16 @@ export default class Upload extends ImmutablePureComponent { <Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12, }) }}> {({ scale }) => ( <div style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}> - <div className={classNames('composer--upload_form--actions', { active: true })}> + <div className='composer--upload_form--actions'> <button className='icon-button' onClick={this.handleUndoClick}><Icon id='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button> {!isEditingStatus && (<button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>)} </div> + + {(media.get('description') || '').length === 0 && ( + <div className='composer--upload_form--item__warning'> + <button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='info-circle' /> <FormattedMessage id='upload_form.description_missing' defaultMessage='No description added' /></button> + </div> + )} </div> )} </Motion> diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss index 40cd899b3..27be22f1b 100644 --- a/app/javascript/flavours/glitch/styles/admin.scss +++ b/app/javascript/flavours/glitch/styles/admin.scss @@ -1322,7 +1322,7 @@ a.sparkline { width: 50px; height: 21px; position: absolute; - bottom: 8px; + bottom: 0; right: 15px; background: linear-gradient(to left, $ui-base-color, transparent); pointer-events: none; diff --git a/app/javascript/flavours/glitch/styles/components/composer.scss b/app/javascript/flavours/glitch/styles/components/composer.scss index 937751d00..96ea096e1 100644 --- a/app/javascript/flavours/glitch/styles/components/composer.scss +++ b/app/javascript/flavours/glitch/styles/components/composer.scss @@ -425,54 +425,12 @@ background-repeat: no-repeat; overflow: hidden; - textarea { - display: block; - position: absolute; - box-sizing: border-box; - bottom: 0; - left: 0; - margin: 0; - border: 0; - padding: 10px; - width: 100%; - color: $secondary-text-color; - background: linear-gradient(0deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 80%, transparent); - font-size: 14px; - font-family: inherit; - font-weight: 500; - opacity: 0; - z-index: 2; - transition: opacity .1s ease; - - &:focus { color: $white } - - &::placeholder { - opacity: 0.54; - color: $secondary-text-color; - } - } - & > .close { mix-blend-mode: difference } } - &.active { - & > div { - textarea { opacity: 1 } - } - } -} - -.composer--upload_form--actions { - background: linear-gradient(180deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 80%, transparent); - display: flex; - align-items: flex-start; - justify-content: space-between; - opacity: 0; - transition: opacity .1s ease; - .icon-button { flex: 0 1 auto; - color: $ui-secondary-color; + color: $secondary-text-color; font-size: 14px; font-weight: 500; padding: 10px; @@ -481,15 +439,28 @@ &:hover, &:focus, &:active { - color: lighten($ui-secondary-color, 4%); + color: lighten($secondary-text-color, 7%); } } - &.active { - opacity: 1; + &__warning { + position: absolute; + z-index: 2; + bottom: 0; + left: 0; + right: 0; + box-sizing: border-box; + background: linear-gradient(0deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 80%, transparent); } } +.composer--upload_form--actions { + background: linear-gradient(180deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 80%, transparent); + display: flex; + align-items: flex-start; + justify-content: space-between; +} + .composer--upload_form--progress { display: flex; padding: 10px; diff --git a/app/javascript/flavours/glitch/styles/components/modal.scss b/app/javascript/flavours/glitch/styles/components/modal.scss index 7e6918356..61c292b19 100644 --- a/app/javascript/flavours/glitch/styles/components/modal.scss +++ b/app/javascript/flavours/glitch/styles/components/modal.scss @@ -609,6 +609,15 @@ color: $inverted-text-color; } + .status__content__spoiler-link { + color: $primary-text-color; + background: $ui-primary-color; + + &:hover { + background: lighten($ui-primary-color, 8%); + } + } + .dialog-option .poll__input { border-color: $inverted-text-color; color: $ui-secondary-color; diff --git a/app/javascript/flavours/glitch/styles/components/status.scss b/app/javascript/flavours/glitch/styles/components/status.scss index b9dd3107b..d39069410 100644 --- a/app/javascript/flavours/glitch/styles/components/status.scss +++ b/app/javascript/flavours/glitch/styles/components/status.scss @@ -198,7 +198,8 @@ .status__content__spoiler-link { background: lighten($ui-base-color, 30%); - &:hover { + &:hover, + &:focus { background: lighten($ui-base-color, 33%); text-decoration: none; } @@ -222,13 +223,13 @@ background: lighten($ui-base-color, 30%); border: 0; color: $inverted-text-color; - font-weight: 500; + font-weight: 700; font-size: 11px; padding: 0 5px; text-transform: uppercase; line-height: inherit; cursor: pointer; - vertical-align: bottom; + vertical-align: top; &:hover { background: lighten($ui-base-color, 33%); @@ -768,7 +769,8 @@ a.status__display-name, background: $ui-base-lighter-color; color: $inverted-text-color; - &:hover { + &:hover, + &:focus { background: lighten($ui-base-color, 29%); text-decoration: none; } diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss index 020d39aff..bb91abdac 100644 --- a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss +++ b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss @@ -165,14 +165,6 @@ } } -.composer--upload_form--item > div input { - color: lighten($white, 7%); - - &::placeholder { - color: lighten($white, 10%); - } -} - .dropdown-menu__separator, .dropdown-menu__item.edited-timestamp__history__item, .dropdown-menu__container__header, diff --git a/app/javascript/mastodon/components/admin/Counter.js b/app/javascript/mastodon/components/admin/Counter.js index 6edb7bcfc..5a5b2b869 100644 --- a/app/javascript/mastodon/components/admin/Counter.js +++ b/app/javascript/mastodon/components/admin/Counter.js @@ -33,6 +33,7 @@ export default class Counter extends React.PureComponent { label: PropTypes.string.isRequired, href: PropTypes.string, params: PropTypes.object, + target: PropTypes.string, }; state = { @@ -54,7 +55,7 @@ export default class Counter extends React.PureComponent { } render () { - const { label, href } = this.props; + const { label, href, target } = this.props; const { loading, data } = this.state; let content; @@ -100,7 +101,7 @@ export default class Counter extends React.PureComponent { if (href) { return ( - <a href={href} className='sparkline'> + <a href={href} className='sparkline' target={target}> {inner} </a> ); diff --git a/app/javascript/mastodon/features/compose/components/upload.js b/app/javascript/mastodon/features/compose/components/upload.js index 1289d6b94..706824dc7 100644 --- a/app/javascript/mastodon/features/compose/components/upload.js +++ b/app/javascript/mastodon/features/compose/components/upload.js @@ -5,7 +5,6 @@ import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { FormattedMessage } from 'react-intl'; -import classNames from 'classnames'; import Icon from 'mastodon/components/icon'; export default class Upload extends ImmutablePureComponent { @@ -43,10 +42,16 @@ export default class Upload extends ImmutablePureComponent { <Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}> {({ scale }) => ( <div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}> - <div className={classNames('compose-form__upload__actions', { active: true })}> + <div className='compose-form__upload__actions'> <button className='icon-button' onClick={this.handleUndoClick}><Icon id='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button> {!isEditingStatus && (<button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>)} </div> + + {(media.get('description') || '').length === 0 && ( + <div className='compose-form__upload__warning'> + <button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='info-circle' /> <FormattedMessage id='upload_form.description_missing' defaultMessage='No description added' /></button> + </div> + )} </div> )} </Motion> diff --git a/app/javascript/mastodon/features/explore/results.js b/app/javascript/mastodon/features/explore/results.js index ff900de08..339f883c5 100644 --- a/app/javascript/mastodon/features/explore/results.js +++ b/app/javascript/mastodon/features/explore/results.js @@ -24,15 +24,15 @@ const appendLoadMore = (id, list, onLoadMore) => { } }; -const renderAccounts = (results, onLoadMore) => appendLoadMore('accounts', results.get('accounts').map(item => ( +const renderAccounts = (results, onLoadMore) => appendLoadMore('accounts', results.get('accounts', ImmutableList()).map(item => ( <Account key={`account-${item}`} id={item} /> )), onLoadMore); -const renderHashtags = (results, onLoadMore) => appendLoadMore('hashtags', results.get('hashtags').map(item => ( +const renderHashtags = (results, onLoadMore) => appendLoadMore('hashtags', results.get('hashtags', ImmutableList()).map(item => ( <Hashtag key={`tag-${item.get('name')}`} hashtag={item} /> )), onLoadMore); -const renderStatuses = (results, onLoadMore) => appendLoadMore('statuses', results.get('statuses').map(item => ( +const renderStatuses = (results, onLoadMore) => appendLoadMore('statuses', results.get('statuses', ImmutableList()).map(item => ( <Status key={`status-${item}`} id={item} /> )), onLoadMore); diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 287fd0771..055732cfd 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -328,7 +328,7 @@ "notifications.column_settings.filter_bar.category": "Barra ràpida de filtres", "notifications.column_settings.filter_bar.show_bar": "Mostra la barra de filtres", "notifications.column_settings.follow": "Nous seguidors:", - "notifications.column_settings.follow_request": "Nova sol·licitud de seguiment:", + "notifications.column_settings.follow_request": "Noves sol·licituts de seguiment:", "notifications.column_settings.mention": "Mencions:", "notifications.column_settings.poll": "Resultats de l’enquesta:", "notifications.column_settings.push": "Notificacions push", @@ -353,7 +353,7 @@ "notifications.permission_denied_alert": "No es poden activar les notificacions del escriptori perquè el permís del navegador ha estat denegat abans", "notifications.permission_required": "Les notificacions d'escriptori no estan disponibles perquè el permís requerit no ha estat concedit.", "notifications_permission_banner.enable": "Activar les notificacions d’escriptori", - "notifications_permission_banner.how_to_control": "Per a rebre notificacions quan Mastodon no està obert cal activar les notificacions d’escriptori. Pots controlar amb precisió quins tipus d’interaccions generen notificacions d’escriptori després d’activar el botó {icon} de dalt.", + "notifications_permission_banner.how_to_control": "Per a rebre notificacions quan Mastodon no és obert cal activar les notificacions d’escriptori. Pots controlar amb precisió quins tipus d’interaccions generen notificacions d’escriptori després d’activar el botó {icon} de dalt.", "notifications_permission_banner.title": "Mai et perdis res", "picture_in_picture.restore": "Retorna’l", "poll.closed": "Finalitzada", @@ -376,7 +376,7 @@ "privacy.unlisted.short": "No llistat", "refresh": "Actualitza", "regeneration_indicator.label": "Carregant…", - "regeneration_indicator.sublabel": "S'està preparant la línia de temps Inici!", + "regeneration_indicator.sublabel": "S'està preparant la teva línia de temps Inici!", "relative_time.days": "fa {number} dies", "relative_time.full.days": "fa {number, plural, one {# dia} other {# dies}}", "relative_time.full.hours": "fa {number, plural, one {# hora} other {# hores}}", @@ -394,7 +394,7 @@ "report.categories.other": "Altres", "report.categories.spam": "Contingut brossa", "report.categories.violation": "El contingut viola una o més regles del servidor", - "report.category.subtitle": "Tria la millor combinació", + "report.category.subtitle": "Tria la millor coincidència", "report.category.title": "Digue'ns què està passant amb aquest {type}", "report.category.title_account": "perfil", "report.category.title_status": "publicació", @@ -410,7 +410,7 @@ "report.reasons.dislike_description": "Això no és quelcom que vulguis veure", "report.reasons.other": "Això és una altre cosa", "report.reasons.other_description": "El problema no encaixa en altres categories", - "report.reasons.spam": "Això és brossa", + "report.reasons.spam": "Això és contingut brossa", "report.reasons.spam_description": "Enllaços maliciosos, compromís falç o respostes repetitives", "report.reasons.violation": "Viola les regles del servidor", "report.reasons.violation_description": "Ets conscient que trenca regles especifiques", @@ -447,7 +447,7 @@ "status.cancel_reblog_private": "Desfer l'impuls", "status.cannot_reblog": "Aquesta publicació no pot ser impulsada", "status.copy": "Copia l'enllaç a l'estat", - "status.delete": "Esborrar", + "status.delete": "Esborra", "status.detailed_status": "Visualització detallada de la conversa", "status.direct": "Missatge directe @{name}", "status.edit": "Edita", @@ -465,17 +465,17 @@ "status.mute": "Silenciar @{name}", "status.mute_conversation": "Silenciar conversació", "status.open": "Ampliar aquest estat", - "status.pin": "Fixat en el perfil", + "status.pin": "Fixa en el perfil", "status.pinned": "Publicació fixada", "status.read_more": "Llegir més", "status.reblog": "Impuls", - "status.reblog_private": "Impulsar a l'audiència original", + "status.reblog_private": "Impulsar amb la visibilitat original", "status.reblogged_by": "{name} ha impulsat", "status.reblogs.empty": "Encara ningú no ha impulsat aquesta publicació. Quan algú ho faci, apareixeran aquí.", "status.redraft": "Esborrar i reescriure", "status.remove_bookmark": "Suprimeix el marcador", "status.reply": "Respondre", - "status.replyAll": "Respondre al tema", + "status.replyAll": "Respondre al fil", "status.report": "Informar sobre @{name}", "status.sensitive_warning": "Contingut sensible", "status.share": "Compartir", @@ -510,11 +510,11 @@ "units.short.million": "{count}M", "units.short.thousand": "{count}K", "upload_area.title": "Arrossega i deixa anar per a carregar", - "upload_button.label": "Afegir multimèdia (JPEG, PNG, GIF, WebM, MP4, MOV)", + "upload_button.label": "Afegir mèdia, un vídeo o un fitxer d'audio", "upload_error.limit": "S'ha superat el límit de càrrega d'arxius.", "upload_error.poll": "No es permet l'enviament de fitxers en les enquestes.", "upload_form.audio_description": "Descriviu per a les persones amb pèrdua auditiva", - "upload_form.description": "Descriure els problemes visuals", + "upload_form.description": "Descriure per els que tenen problemes visuals", "upload_form.edit": "Edita", "upload_form.thumbnail": "Canvia la miniatura", "upload_form.undo": "Esborra", @@ -523,7 +523,7 @@ "upload_modal.apply": "Aplica", "upload_modal.applying": "Aplicant…", "upload_modal.choose_image": "Tria imatge", - "upload_modal.description_placeholder": "Jove xef, porti whisky amb quinze glaçons d’hidrogen, coi!", + "upload_modal.description_placeholder": "Una ràpida guineu marró salta sobre el gos mandrós", "upload_modal.detect_text": "Detecta el text de l'imatge", "upload_modal.edit_media": "Editar multimèdia", "upload_modal.hint": "Fes clic o arrossega el cercle en la previsualització per escollir el punt focal que sempre serà visible de totes les miniatures.", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index d48780042..c6ffaa6f2 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -75,7 +75,7 @@ "column.domain_blocks": "Blokované domény", "column.favourites": "Oblíbené", "column.follow_requests": "Žádosti o sledování", - "column.home": "Domů", + "column.home": "Domovská časová osa", "column.lists": "Seznamy", "column.mutes": "Skrytí uživatelé", "column.notifications": "Oznámení", @@ -294,7 +294,7 @@ "navigation_bar.discover": "Objevujte", "navigation_bar.domain_blocks": "Blokované domény", "navigation_bar.edit_profile": "Upravit profil", - "navigation_bar.explore": "Explore", + "navigation_bar.explore": "Objevování", "navigation_bar.favourites": "Oblíbené", "navigation_bar.filters": "Skrytá slova", "navigation_bar.follow_requests": "Žádosti o sledování", @@ -318,7 +318,7 @@ "notification.poll": "Anketa, ve které jste hlasovali, skončila", "notification.reblog": "Uživatel {name} boostnul váš příspěvek", "notification.status": "Nový příspěvek od {name}", - "notification.update": "{name} edited a post", + "notification.update": "uživatel {name} upravil příspěvek", "notifications.clear": "Smazat oznámení", "notifications.clear_confirmation": "Opravdu chcete trvale smazat všechna vaše oznámení?", "notifications.column_settings.admin.sign_up": "New sign-ups:", @@ -338,7 +338,7 @@ "notifications.column_settings.status": "Nové příspěvky:", "notifications.column_settings.unread_notifications.category": "Nepřečtená oznámení", "notifications.column_settings.unread_notifications.highlight": "Zvýraznit nepřečtená oznámení", - "notifications.column_settings.update": "Edits:", + "notifications.column_settings.update": "Úpravy:", "notifications.filter.all": "Vše", "notifications.filter.boosts": "Boosty", "notifications.filter.favourites": "Oblíbení", @@ -380,7 +380,7 @@ "relative_time.days": "{number} d", "relative_time.full.days": "{number, plural, one {# day} other {# days}} ago", "relative_time.full.hours": "{number, plural, one {# hour} other {# hours}} ago", - "relative_time.full.just_now": "just now", + "relative_time.full.just_now": "právě teď", "relative_time.full.minutes": "{number, plural, one {# minute} other {# minutes}} ago", "relative_time.full.seconds": "{number, plural, one {# second} other {# seconds}} ago", "relative_time.hours": "{number} h", @@ -391,11 +391,11 @@ "reply_indicator.cancel": "Zrušit", "report.block": "Block", "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.", - "report.categories.other": "Other", + "report.categories.other": "Ostatní", "report.categories.spam": "Spam", - "report.categories.violation": "Content violates one or more server rules", - "report.category.subtitle": "Choose the best match", - "report.category.title": "Tell us what's going on with this {type}", + "report.categories.violation": "Obsah porušuje jedno nebo více pravidel serveru", + "report.category.subtitle": "Vyberte nejbližší možnost", + "report.category.title": "Povězte nám, proč chcete {type} nahlásit", "report.category.title_account": "profile", "report.category.title_status": "post", "report.close": "Done", @@ -404,20 +404,20 @@ "report.forward_hint": "Tento účet je z jiného serveru. Chcete na něj také poslat anonymizovanou kopii hlášení?", "report.mute": "Mute", "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.", - "report.next": "Next", + "report.next": "Dále", "report.placeholder": "Dodatečné komentáře", - "report.reasons.dislike": "I don't like it", - "report.reasons.dislike_description": "It is not something you want to see", - "report.reasons.other": "It's something else", - "report.reasons.other_description": "The issue does not fit into other categories", - "report.reasons.spam": "It's spam", - "report.reasons.spam_description": "Malicious links, fake engagement, or repetitive replies", - "report.reasons.violation": "It violates server rules", - "report.reasons.violation_description": "You are aware that it breaks specific rules", - "report.rules.subtitle": "Select all that apply", - "report.rules.title": "Which rules are being violated?", - "report.statuses.subtitle": "Select all that apply", - "report.statuses.title": "Are there any posts that back up this report?", + "report.reasons.dislike": "Nelíbí se mi", + "report.reasons.dislike_description": "Není to něco, co chcete vidět", + "report.reasons.other": "Jde o něco jiného", + "report.reasons.other_description": "Problém neodpovídá ostatním kategoriím", + "report.reasons.spam": "Je to spam", + "report.reasons.spam_description": "Škodlivé odkazy, falešné interakce nebo opakované odpovědi", + "report.reasons.violation": "Porušuje pravidla serveru", + "report.reasons.violation_description": "Máte za to, že porušuje konkrétní pravidla", + "report.rules.subtitle": "Vyberte všechna relevantní", + "report.rules.title": "Která pravidla porušuje?", + "report.statuses.subtitle": "Vyberte všechny relevantní", + "report.statuses.title": "Existují příspěvky dokládající toto hlášení?", "report.submit": "Odeslat", "report.target": "Nahlášení uživatele {target}", "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:", @@ -490,7 +490,7 @@ "suggestions.dismiss": "Odmítnout návrh", "suggestions.header": "Mohlo by vás zajímat…", "tabs_bar.federated_timeline": "Federovaná", - "tabs_bar.home": "Domů", + "tabs_bar.home": "Domovská", "tabs_bar.local_timeline": "Místní", "tabs_bar.notifications": "Oznámení", "tabs_bar.search": "Hledat", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 659336393..73a65ed78 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -3,53 +3,53 @@ "account.add_or_remove_from_list": "افزودن یا برداشتن از سیاههها", "account.badges.bot": "روبات", "account.badges.group": "گروه", - "account.block": "مسدود کردن @{name}", + "account.block": "مسدود کردن @{name}", "account.block_domain": "مسدود کردن دامنهٔ {domain}", "account.blocked": "مسدود", "account.browse_more_on_origin_server": "مرور بیشتر روی نمایهٔ اصلی", "account.cancel_follow_request": "لغو درخواست پیگیری", - "account.direct": "پیام مستقیم به @{name}", - "account.disable_notifications": "آگاهی به من هنگام فرستادنهای @{name} پایان یابد", + "account.direct": "پیام مستقیم به @{name}", + "account.disable_notifications": "آگاه کردن من هنگام فرستههای @{name} را متوقّف کن", "account.domain_blocked": "دامنه مسدود شد", "account.edit_profile": "ویرایش نمایه", - "account.enable_notifications": "هنگام فرستههای @{name} مرا آگاه کن", + "account.enable_notifications": "هنگام فرستههای @{name} مرا آگاه کن", "account.endorse": "معرّفی در نمایه", "account.follow": "پیگیری", "account.followers": "پیگیرندگان", "account.followers.empty": "هنوز کسی این کاربر را پیگیری نمیکند.", "account.followers_counter": "{count, plural, one {{counter} پیگیرنده} other {{counter} پیگیرنده}}", - "account.following": "Following", + "account.following": "پی میگیرید", "account.following_counter": "{count, plural, one {{counter} پیگرفته} other {{counter} پیگرفته}}", "account.follows.empty": "این کاربر هنوز پیگیر کسی نیست.", "account.follows_you": "پی میگیردتان", - "account.hide_reblogs": "نهفتن تقویتهای @{name}", + "account.hide_reblogs": "نهفتن تقویتهای @{name}", "account.joined": "پیوسته از {date}", "account.link_verified_on": "مالکیت این پیوند در {date} بررسی شد", "account.locked_info": "این حساب خصوصی است. صاحبش تصمیم میگیرد که چه کسی پیگیرش باشد.", "account.media": "رسانه", - "account.mention": "نامبردن از @{name}", + "account.mention": "نامبردن از @{name}", "account.moved_to": "{name} منتقل شده به:", - "account.mute": "خموشاندن @{name}", - "account.mute_notifications": "خموشاندن آگاهیها از @{name}", + "account.mute": "خموشاندن @{name}", + "account.mute_notifications": "خموشاندن آگاهیهای @{name}", "account.muted": "خموش", "account.posts": "فرسته", "account.posts_with_replies": "فرستهها و پاسخها", - "account.report": "گزارش @{name}", + "account.report": "گزارش @{name}", "account.requested": "منتظر پذیرش است. برای لغو درخواست پیگیری کلیک کنید", - "account.share": "همرسانی نمایهٔ @{name}", - "account.show_reblogs": "نمایش تقویتهای @{name}", + "account.share": "همرسانی نمایهٔ @{name}", + "account.show_reblogs": "نمایش تقویتهای @{name}", "account.statuses_counter": "{count, plural, one {{counter} فرسته} other {{counter} فرسته}}", - "account.unblock": "رفع مسدودیت @{name}", + "account.unblock": "رفع مسدودیت @{name}", "account.unblock_domain": "رفع مسدودیت دامنهٔ {domain}", - "account.unblock_short": "Unblock", + "account.unblock_short": "رفع مسدودیت", "account.unendorse": "معرّفی نکردن در نمایه", "account.unfollow": "ناپیگیری", - "account.unmute": "ناخموشی @{name}", - "account.unmute_notifications": "ناخموشی آگاهیها از @{name}", - "account.unmute_short": "Unmute", + "account.unmute": "ناخموشی @{name}", + "account.unmute_notifications": "ناخموشی آگاهیهای @{name}", + "account.unmute_short": "ناخموشی", "account_note.placeholder": "برای افزودن یادداشت کلیک کنید", - "admin.dashboard.daily_retention": "User retention rate by day after sign-up", - "admin.dashboard.monthly_retention": "User retention rate by month after sign-up", + "admin.dashboard.daily_retention": "نرخ حفظ کاربر در روز پس از ثبت نام", + "admin.dashboard.monthly_retention": "نرخ حفظ کاربر در ماه پس از ثبت نام", "admin.dashboard.retention.average": "میانگین", "admin.dashboard.retention.cohort": "ماه ثبتنام", "admin.dashboard.retention.cohort_size": "کاربران جدید", @@ -79,13 +79,13 @@ "column.lists": "سیاههها", "column.mutes": "کاربران خموش", "column.notifications": "آگاهیها", - "column.pins": "فرستههای سنجاقشده", + "column.pins": "فرستههای سنجاق شده", "column.public": "خط زمانی همگانی", "column_back_button.label": "بازگشت", "column_header.hide_settings": "نهفتن تنظیمات", "column_header.moveLeft_settings": "جابهجایی ستون به چپ", "column_header.moveRight_settings": "جابهجایی ستون به راست", - "column_header.pin": "سنجاقکردن", + "column_header.pin": "سنجاق کردن", "column_header.show_settings": "نمایش تنظیمات", "column_header.unpin": "برداشتن سنجاق", "column_subheading.settings": "تنظیمات", @@ -94,7 +94,7 @@ "community.column_settings.remote_only": "تنها دوردست", "compose_form.direct_message_warning": "این فرسته تنها به کاربرانی که از آنها نام برده شده فرستاده خواهد شد.", "compose_form.direct_message_warning_learn_more": "بیشتر بدانید", - "compose_form.hashtag_warning": "از آنجا که این فرسته فهرستنشده است، در نتایج جستوجوی برچسبها پیدا نخواهد شد. تنها فرستههای عمومی را میتوان با جستوجوی برچسب یافت.", + "compose_form.hashtag_warning": "از آنجا که این فرسته فهرست نشده است، در نتایج جستوجوی هشتگها پیدا نخواهد شد. تنها فرستههای عمومی را میتوان با جستوجوی هشتگ یافت.", "compose_form.lock_disclaimer": "حسابتان {locked} نیست. هر کسی میتواند پیگیرتان شده و فرستههای ویژهٔ پیگیرانتان را ببیند.", "compose_form.lock_disclaimer.lock": "قفلشده", "compose_form.placeholder": "تازه چه خبر؟", @@ -106,7 +106,7 @@ "compose_form.poll.switch_to_single": "تبدیل به نظرسنجی تکگزینهای", "compose_form.publish": "بوق", "compose_form.publish_loud": "{publish}!", - "compose_form.save_changes": "Save changes", + "compose_form.save_changes": "ذخیرهٔ تغییرات", "compose_form.sensitive.hide": "{count, plural, one {علامتگذاری رسانه به عنوان حساس} other {علامتگذاری رسانهها به عنوان حساس}}", "compose_form.sensitive.marked": "{count, plural, one {رسانه به عنوان حساس علامتگذاری شد} other {رسانهها به عنوان حساس علامتگذاری شدند}}", "compose_form.sensitive.unmarked": "{count, plural, one {رسانه به عنوان حساس علامتگذاری نشد} other {رسانهها به عنوان حساس علامتگذاری نشدند}}", @@ -144,7 +144,7 @@ "directory.local": "تنها از {domain}", "directory.new_arrivals": "تازهواردان", "directory.recently_active": "کاربران فعال اخیر", - "embed.instructions": "برای جاگذاری این فرسته در سایت خودتان، کد زیر را کپی کنید.", + "embed.instructions": "برای جاسازی این فرسته در سایت خودتان، کد زیر را رونوشت کنید.", "embed.preview": "این گونه دیده خواهد شد:", "emoji_button.activity": "فعالیت", "emoji_button.custom": "سفارشی", @@ -164,11 +164,11 @@ "empty_column.account_timeline": "هیچ فرستهای اینجا نیست!", "empty_column.account_unavailable": "نمایهٔ موجود نیست", "empty_column.blocks": "هنوز کسی را مسدود نکردهاید.", - "empty_column.bookmarked_statuses": "هنوز هیچ فرستهٔ نشانشدهای ندارید. هنگامی که فرستهای را نشانکنید، اینجا نشان داده خواهد شد.", + "empty_column.bookmarked_statuses": "هنوز هیچ فرستهٔ نشانهگذاری شدهای ندارید. هنگامی که فرستهای را نشانهگذاری کنید، اینجا نشان داده خواهد شد.", "empty_column.community": "خط زمانی محلّی خالی است. چیزی بنویسید تا چرخش بچرخد!", "empty_column.direct": "هنوز هیچ پیام مستقیمی ندارید. هنگامی که چنین پیامی بگیرید یا بفرستید اینجا نشان داده خواهد شد.", "empty_column.domain_blocks": "هنوز هیچ دامنهای مسدود نشده است.", - "empty_column.explore_statuses": "Nothing is trending right now. Check back later!", + "empty_column.explore_statuses": "الآن چیزی پرطرفدار نیست. بعداً دوباره بررسی کنید!", "empty_column.favourited_statuses": "شما هنوز هیچ فرستهای را نپسندیدهاید. هنگامی که فرستهای را بپسندید، اینجا نشان داده خواهد شد.", "empty_column.favourites": "هنوز هیچ کسی این فرسته را نپسندیده است. هنگامی که کسی آن را بپسندد، اینجا نشان داده خواهد شد.", "empty_column.follow_recommendations": "ظاهرا هیچ پیشنهادی برای شما نمیتوانیم تولید کنیم. میتوانید از امکان جستوجو برای یافتن افرادی که ممکن است بشناسید و یا کاوش میان برچسبهای داغ استفاده کنید.", @@ -187,12 +187,12 @@ "error.unexpected_crash.next_steps_addons": "لطفاً از کارشان انداخته و صفحه را نوسازی کنید. اگر کمکی نکرد، شاید همچنان بتوانید با مرورگری دیگر یا با کارهای بومی از ماستودون استفاده کنید.", "errors.unexpected_crash.copy_stacktrace": "رونوشت از جزئیات اشکال", "errors.unexpected_crash.report_issue": "گزارش مشکل", - "explore.search_results": "Search results", - "explore.suggested_follows": "For you", - "explore.title": "Explore", - "explore.trending_links": "News", - "explore.trending_statuses": "Posts", - "explore.trending_tags": "Hashtags", + "explore.search_results": "نتایج جستوجو", + "explore.suggested_follows": "برای شما", + "explore.title": "کاوش", + "explore.trending_links": "اخبار", + "explore.trending_statuses": "فرستهها", + "explore.trending_tags": "هشتگها", "follow_recommendations.done": "انجام شد", "follow_recommendations.heading": "افرادی را که میخواهید فرستههایشان را ببینید پیگیری کنید! اینها تعدادی پیشنهاد هستند.", "follow_recommendations.lead": "فرستههای افرادی که دنبال میکنید به ترتیب زمانی در خوراک خانهتان نشان داده خواهد شد. از اشتباه کردن نترسید. میتوانید به همین سادگی در هر زمانی از دنبال کردن افراد دست بکشید!", @@ -247,7 +247,7 @@ "keyboard_shortcuts.my_profile": "گشودن نمایهتان", "keyboard_shortcuts.notifications": "گشودن ستون آگاهیها", "keyboard_shortcuts.open_media": "گشودن رسانه", - "keyboard_shortcuts.pinned": "گشودن سیاههٔ فرستههای سنجاق شده", + "keyboard_shortcuts.pinned": "گشودن فهرست فرستههای سنجاق شده", "keyboard_shortcuts.profile": "گشودن نمایهٔ نویسنده", "keyboard_shortcuts.reply": "پاسخ به فرسته", "keyboard_shortcuts.requests": "گشودن سیاههٔ درخواستهای پیگیری", @@ -294,7 +294,7 @@ "navigation_bar.discover": "گشت و گذار", "navigation_bar.domain_blocks": "دامنههای مسدود شده", "navigation_bar.edit_profile": "ویرایش نمایه", - "navigation_bar.explore": "Explore", + "navigation_bar.explore": "کاوش", "navigation_bar.favourites": "پسندیدهها", "navigation_bar.filters": "واژههای خموش", "navigation_bar.follow_requests": "درخواستهای پیگیری", @@ -305,11 +305,11 @@ "navigation_bar.logout": "خروج", "navigation_bar.mutes": "کاربران خموشانده", "navigation_bar.personal": "شخصی", - "navigation_bar.pins": "فرستههای سنجاقشده", + "navigation_bar.pins": "فرستههای سنجاق شده", "navigation_bar.preferences": "ترجیحات", "navigation_bar.public_timeline": "خط زمانی همگانی", "navigation_bar.security": "امنیت", - "notification.admin.sign_up": "{name} signed up", + "notification.admin.sign_up": "{name} ثبت نام کرد", "notification.favourite": "{name} فرستهتان را پسندید", "notification.follow": "{name} پیگیرتان شد", "notification.follow_request": "{name} میخواهد پیگیر شما باشد", @@ -318,10 +318,10 @@ "notification.poll": "نظرسنجیای که در آن رأی دادید به پایان رسیده است", "notification.reblog": "{name} فرستهتان را تقویت کرد", "notification.status": "{name} چیزی فرستاد", - "notification.update": "{name} edited a post", + "notification.update": "{name} فرستهای را ویرایش کرد", "notifications.clear": "پاکسازی آگاهیها", "notifications.clear_confirmation": "مطمئنید میخواهید همهٔ آگاهیهایتان را برای همیشه پاک کنید؟", - "notifications.column_settings.admin.sign_up": "New sign-ups:", + "notifications.column_settings.admin.sign_up": "ثبت نامهای جدید:", "notifications.column_settings.alert": "آگاهیهای میزکار", "notifications.column_settings.favourite": "پسندیدهها:", "notifications.column_settings.filter_bar.advanced": "نمایش همۀ دستهها", @@ -338,7 +338,7 @@ "notifications.column_settings.status": "فرستههای جدید:", "notifications.column_settings.unread_notifications.category": "آگاهیهای خوانده نشده", "notifications.column_settings.unread_notifications.highlight": "پررنگ کردن آگاهیهای خوانده نشده", - "notifications.column_settings.update": "Edits:", + "notifications.column_settings.update": "ویرایشها:", "notifications.filter.all": "همه", "notifications.filter.boosts": "تقویتها", "notifications.filter.favourites": "پسندها", @@ -378,54 +378,54 @@ "regeneration_indicator.label": "در حال بار شدن…", "regeneration_indicator.sublabel": "خوراک خانگیان دارد آماده میشود!", "relative_time.days": "{number} روز", - "relative_time.full.days": "{number, plural, one {# day} other {# days}} ago", - "relative_time.full.hours": "{number, plural, one {# hour} other {# hours}} ago", - "relative_time.full.just_now": "just now", - "relative_time.full.minutes": "{number, plural, one {# minute} other {# minutes}} ago", - "relative_time.full.seconds": "{number, plural, one {# second} other {# seconds}} ago", + "relative_time.full.days": "{number, plural, one {# روز} other {# روز}} پیش", + "relative_time.full.hours": "{number, plural, one {# ساعت} other {# ساعت}} پیش", + "relative_time.full.just_now": "همين آلان", + "relative_time.full.minutes": "{number, plural, one {# دقیقه} other {# دقیقه}} پیش", + "relative_time.full.seconds": "{number, plural, one {# ثانیه} other {# ثانیه}} پیش", "relative_time.hours": "{number} ساعت", "relative_time.just_now": "حالا", "relative_time.minutes": "{number} دقیقه", "relative_time.seconds": "{number} ثانیه", "relative_time.today": "امروز", "reply_indicator.cancel": "لغو", - "report.block": "Block", - "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.", - "report.categories.other": "Other", - "report.categories.spam": "Spam", - "report.categories.violation": "Content violates one or more server rules", - "report.category.subtitle": "Choose the best match", - "report.category.title": "Tell us what's going on with this {type}", - "report.category.title_account": "profile", - "report.category.title_status": "post", - "report.close": "Done", - "report.comment.title": "Is there anything else you think we should know?", + "report.block": "مسدود کردن", + "report.block_explanation": "شما فرستههایشان را نخواهید دید. آنها نمیتوانند فرستههایتان را ببینند یا شما را پیبگیرند. آنها میتوانند بگویند که مسدود شدهاند.", + "report.categories.other": "غیره", + "report.categories.spam": "هرزنامه", + "report.categories.violation": "محتوا یک یا چند قانون کارساز را نقض میکند", + "report.category.subtitle": "منطبقترین را انتخاب کنید", + "report.category.title": "به ما بگویید با این {type} چه مشکلی دارید", + "report.category.title_account": "نمایه", + "report.category.title_status": "فرسته", + "report.close": "انجام شد", + "report.comment.title": "آیا چیز دیگری هست که فکر میکنید باید بدانیم؟", "report.forward": "فرستادن به {target}", "report.forward_hint": "این حساب در کارساز دیگری ثبت شده. آیا میخواهید رونوشتی ناشناس از این گزارش به آنجا هم فرستاده شود؟", - "report.mute": "Mute", - "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.", - "report.next": "Next", + "report.mute": "خموش", + "report.mute_explanation": "شما فرستههای آنها را نخواهید دید. آنها همچنان میتوانند شما را پیبگیرند و فرستههایتان را ببینند و نمیدانند که خموش شدهاند.", + "report.next": "بعدی", "report.placeholder": "توضیحات اضافه", - "report.reasons.dislike": "I don't like it", - "report.reasons.dislike_description": "It is not something you want to see", - "report.reasons.other": "It's something else", - "report.reasons.other_description": "The issue does not fit into other categories", - "report.reasons.spam": "It's spam", - "report.reasons.spam_description": "Malicious links, fake engagement, or repetitive replies", - "report.reasons.violation": "It violates server rules", - "report.reasons.violation_description": "You are aware that it breaks specific rules", - "report.rules.subtitle": "Select all that apply", - "report.rules.title": "Which rules are being violated?", - "report.statuses.subtitle": "Select all that apply", - "report.statuses.title": "Are there any posts that back up this report?", + "report.reasons.dislike": "من آن را دوست ندارم", + "report.reasons.dislike_description": "این چیزی نیست که بخواهید ببینید", + "report.reasons.other": "بخواطر چیز دیگری است", + "report.reasons.other_description": "این موضوع در دستهبندیهای دیگر نمیگنجد", + "report.reasons.spam": "این هرزنامه است", + "report.reasons.spam_description": "پیوندهای مخرب، تعامل جعلی یا پاسخهای تکراری", + "report.reasons.violation": "قوانین کارساز را نقض میکند", + "report.reasons.violation_description": "شما آگاه هستید که قوانین خاصی را زیر پا میگذارد", + "report.rules.subtitle": "همهٔ موارد انجام شده را برگزینید", + "report.rules.title": "کدام قوانین نقض شدهاند؟", + "report.statuses.subtitle": "همهٔ موارد انجام شده را برگزینید", + "report.statuses.title": "آیا فرستهای وجود دارد که از این گزارش پشتیبانی کند؟", "report.submit": "فرستادن", "report.target": "در حال گزارش {target}", - "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:", - "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:", - "report.thanks.title": "Don't want to see this?", - "report.thanks.title_actionable": "Thanks for reporting, we'll look into this.", - "report.unfollow": "Unfollow @{name}", - "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.", + "report.thanks.take_action": "در اینجا گزینههایی برای کنترل آنچه در ماستودون میبینید، وجود دارد:", + "report.thanks.take_action_actionable": "در حالی که ما این مورد را بررسی میکنیم، میتوانید علیه @{name} اقدام کنید:", + "report.thanks.title": "نمیخواهید این را ببینید؟", + "report.thanks.title_actionable": "ممنون بابت گزارش، ما آن را بررسی خواهیم کرد.", + "report.unfollow": "ناپیگیری @{name}", + "report.unfollow_explanation": "شما این حساب را پیگرفتهاید، برای اینکه دیگر فرستههایش را در خوراک خانهتان نبینید؛ آن را پینگیرید.", "search.placeholder": "جستوجو", "search_popout.search_format": "راهنمای جستوجوی پیشرفته", "search_popout.tips.full_text": "جستوجوی متنی ساده فرستههایی که نوشته، پسندیده، تقویتکرده یا در آنها نامبرده شدهاید را به علاوهٔ نامهای کاربری، نامهای نمایشی و برچسبها برمیگرداند.", @@ -434,39 +434,39 @@ "search_popout.tips.text": "جستوجوی متنی ساده برای نامها، نامهای کاربری، و برچسبها", "search_popout.tips.user": "کاربر", "search_results.accounts": "افراد", - "search_results.all": "All", + "search_results.all": "همه", "search_results.hashtags": "برچسبها", - "search_results.nothing_found": "Could not find anything for these search terms", + "search_results.nothing_found": "چیزی برای این عبارت جستوجو یافت نشد", "search_results.statuses": "فرستهها", - "search_results.statuses_fts_disabled": "جستوجوی محتوای فرستهها در این کارساز ماستودون فعال نشده است.", + "search_results.statuses_fts_disabled": "جستوجوی محتوای فرستهها در این کارساز ماستودون به کار انداخته نشده است.", "search_results.total": "{count, number} {count, plural, one {نتیجه} other {نتیجه}}", - "status.admin_account": "گشودن واسط مدیریت برای @{name}", + "status.admin_account": "گشودن واسط مدیریت برای @{name}", "status.admin_status": "گشودن این فرسته در واسط مدیریت", - "status.block": "مسدود کردن @{name}", + "status.block": "مسدود کردن @{name}", "status.bookmark": "نشانک", - "status.cancel_reblog_private": "لغو تقویت", + "status.cancel_reblog_private": "ناتقویت", "status.cannot_reblog": "این فرسته قابل تقویت نیست", - "status.copy": "رونویسی از نشانی فرسته", + "status.copy": "رونوشت پیوند فرسته", "status.delete": "حذف", "status.detailed_status": "نمایش کامل گفتگو", - "status.direct": "پیام مستقیم به @{name}", - "status.edit": "Edit", - "status.edited": "Edited {date}", - "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}", - "status.embed": "جاگذاری", + "status.direct": "پیام مستقیم به @{name}", + "status.edit": "ویرایش", + "status.edited": "ویرایش شده در {date}", + "status.edited_x_times": "{count, plural, one {{count} مرتبه} other {{count} مرتبه}} ویرایش شد", + "status.embed": "جاسازی", "status.favourite": "پسندیدن", "status.filtered": "پالوده", - "status.history.created": "{name} created {date}", - "status.history.edited": "{name} edited {date}", + "status.history.created": "توسط {name} در {date} ایجاد شد", + "status.history.edited": "توسط {name} در {date} ویرایش شد", "status.load_more": "بار کردن بیشتر", "status.media_hidden": "رسانهٔ نهفته", - "status.mention": "نامبردن از @{name}", + "status.mention": "نامبردن از @{name}", "status.more": "بیشتر", - "status.mute": "خموشاندن @{name}", + "status.mute": "خموشاندن @{name}", "status.mute_conversation": "خموشاندن گفتوگو", "status.open": "گسترش این فرسته", - "status.pin": "سنجاقکردن در نمایه", - "status.pinned": "فرستهٔ سنجاقشده", + "status.pin": "سنجاق کردن در نمایه", + "status.pinned": "فرستهٔ سنجاق شده", "status.read_more": "بیشتر بخوانید", "status.reblog": "تقویت", "status.reblog_private": "تقویت برای مخاطبان نخستین", @@ -476,7 +476,7 @@ "status.remove_bookmark": "برداشتن نشانک", "status.reply": "پاسخ", "status.replyAll": "پاسخ به رشته", - "status.report": "گزارش @{name}", + "status.report": "گزارش @{name}", "status.sensitive_warning": "محتوای حساس", "status.share": "همرسانی", "status.show_less": "نمایش کمتر", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 791b802a1..caef22ee9 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -229,7 +229,7 @@ "keyboard_shortcuts.blocked": "Ouvrir la liste des comptes bloqués", "keyboard_shortcuts.boost": "Partager le message", "keyboard_shortcuts.column": "Se placer dans une colonne", - "keyboard_shortcuts.compose": "se placer dans la zone de rédaction", + "keyboard_shortcuts.compose": "Se placer dans la zone de rédaction", "keyboard_shortcuts.description": "Description", "keyboard_shortcuts.direct": "Ouvrir la colonne des messages directs", "keyboard_shortcuts.down": "Descendre dans la liste", @@ -246,7 +246,7 @@ "keyboard_shortcuts.muted": "Ouvrir la liste des comptes masqués", "keyboard_shortcuts.my_profile": "Ouvrir votre profil", "keyboard_shortcuts.notifications": "Ouvrir la colonne de notifications", - "keyboard_shortcuts.open_media": "ouvrir le média", + "keyboard_shortcuts.open_media": "Ouvrir le média", "keyboard_shortcuts.pinned": "Ouvrir la liste des messages épinglés", "keyboard_shortcuts.profile": "Ouvrir le profil de l’auteur·rice", "keyboard_shortcuts.reply": "Répondre au message", diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json index aae73a23e..9ca41b2f6 100644 --- a/app/javascript/mastodon/locales/gd.json +++ b/app/javascript/mastodon/locales/gd.json @@ -18,7 +18,7 @@ "account.followers": "Luchd-leantainn", "account.followers.empty": "Chan eil neach sam bith a’ leantainn air a’ chleachdaiche seo fhathast.", "account.followers_counter": "{count, plural, one {{counter} neach-leantainn} two {{counter} neach-leantainn} few {{counter} luchd-leantainn} other {{counter} luchd-leantainn}}", - "account.following": "Following", + "account.following": "A’ leantainn", "account.following_counter": "{count, plural, one {A’ leantainn air {counter}} two {A’ leantainn air {counter}} few {A’ leantainn air {counter}} other {A’ leantainn air {counter}}}", "account.follows.empty": "Chan eil an cleachdaiche seo a’ leantainn air neach sam bith fhathast.", "account.follows_you": "’Gad leantainn", @@ -41,12 +41,12 @@ "account.statuses_counter": "{count, plural, one {{counter} phost} two {{counter} phost} few {{counter} postaichean} other {{counter} post}}", "account.unblock": "Dì-bhac @{name}", "account.unblock_domain": "Dì-bhac an àrainn {domain}", - "account.unblock_short": "Unblock", + "account.unblock_short": "Dì-bhac", "account.unendorse": "Na brosnaich air a’ phròifil", "account.unfollow": "Na lean tuilleadh", "account.unmute": "Dì-mhùch @{name}", "account.unmute_notifications": "Dì-mhùch na brathan o @{name}", - "account.unmute_short": "Unmute", + "account.unmute_short": "Dì-mhùch", "account_note.placeholder": "Briog airson nòta a chur ris", "admin.dashboard.daily_retention": "Reat glèidheadh nan cleachdaichean às dèidh an clàradh a-rèir latha", "admin.dashboard.monthly_retention": "Reat glèidheadh nan cleachdaichean às dèidh an clàradh a-rèir mìos", @@ -294,7 +294,7 @@ "navigation_bar.discover": "Fidir", "navigation_bar.domain_blocks": "Àrainnean bacte", "navigation_bar.edit_profile": "Deasaich a’ phròifil", - "navigation_bar.explore": "Explore", + "navigation_bar.explore": "Rùraich", "navigation_bar.favourites": "Na h-annsachdan", "navigation_bar.filters": "Faclan mùchte", "navigation_bar.follow_requests": "Iarrtasan leantainn", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 3fd164f85..8f6fe61d4 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -18,7 +18,7 @@ "account.followers": "フォロワー", "account.followers.empty": "まだ誰もフォローしていません。", "account.followers_counter": "{counter} フォロワー", - "account.following": "Following", + "account.following": "フォロー中", "account.following_counter": "{counter} フォロー", "account.follows.empty": "まだ誰もフォローしていません。", "account.follows_you": "フォローされています", @@ -41,12 +41,12 @@ "account.statuses_counter": "{counter} 投稿", "account.unblock": "@{name}さんのブロックを解除", "account.unblock_domain": "{domain}のブロックを解除", - "account.unblock_short": "Unblock", + "account.unblock_short": "ブロック解除", "account.unendorse": "プロフィールから外す", "account.unfollow": "フォロー解除", "account.unmute": "@{name}さんのミュートを解除", "account.unmute_notifications": "@{name}さんからの通知を受け取るようにする", - "account.unmute_short": "Unmute", + "account.unmute_short": "ミュート解除", "account_note.placeholder": "クリックしてメモを追加", "admin.dashboard.daily_retention": "サインアップ後の日ごとのユーザー継続率", "admin.dashboard.monthly_retention": "サインアップ後の月ごとのユーザー継続率", @@ -192,7 +192,7 @@ "errors.unexpected_crash.copy_stacktrace": "スタックトレースをクリップボードにコピー", "errors.unexpected_crash.report_issue": "問題を報告", "explore.search_results": "検索結果", - "explore.suggested_follows": "For you", + "explore.suggested_follows": "おすすめ", "explore.title": "エクスプローラー", "explore.trending_links": "ニュース", "explore.trending_statuses": "投稿", @@ -326,7 +326,7 @@ "notification.update": "{name} が投稿を編集しました", "notifications.clear": "通知を消去", "notifications.clear_confirmation": "本当に通知を消去しますか?", - "notifications.column_settings.admin.sign_up": "New sign-ups:", + "notifications.column_settings.admin.sign_up": "新規登録:", "notifications.column_settings.alert": "デスクトップ通知", "notifications.column_settings.favourite": "お気に入り:", "notifications.column_settings.filter_bar.advanced": "すべてのカテゴリを表示", @@ -395,7 +395,7 @@ "relative_time.today": "今日", "reply_indicator.cancel": "キャンセル", "report.block": "ブロック", - "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.", + "report.block_explanation": "相手の投稿が表示されなくなります。相手はあなたの投稿を見ることやフォローすることができません。相手はブロックされていることがわかります。", "report.categories.other": "その他", "report.categories.spam": "スパム", "report.categories.violation": "サーバーのルールに違反", @@ -404,11 +404,11 @@ "report.category.title_account": "プロフィール", "report.category.title_status": "投稿", "report.close": "完了", - "report.comment.title": "Is there anything else you think we should know?", + "report.comment.title": "その他に私たちに伝えておくべき事はありますか?", "report.forward": "{target} に転送する", "report.forward_hint": "このアカウントは別のサーバーに所属しています。通報内容を匿名で転送しますか?", "report.mute": "ミュート", - "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.", + "report.mute_explanation": "相手の投稿は表示されなくなります。相手は引き続きあなたをフォローして、あなたの投稿を表示することができますが、ミュートされていることはわかりません。", "report.next": "次へ", "report.placeholder": "追加コメント", "report.reasons.dislike": "興味がありません", @@ -426,9 +426,9 @@ "report.submit": "通報する", "report.target": "{target}さんを通報する", "report.thanks.take_action": "次のような方法はいかがでしょうか?", - "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:", + "report.thanks.take_action_actionable": "私達が確認している間でも、あなたは @{name} さんに対して対応することが出来ます:", "report.thanks.title": "見えないようにしたいですか?", - "report.thanks.title_actionable": "Thanks for reporting, we'll look into this.", + "report.thanks.title_actionable": "ご報告ありがとうございます、追って確認します。", "report.unfollow": "@{name}のフォローを解除", "report.unfollow_explanation": "このアカウントをフォローしています。ホームフィードに彼らの投稿を表示しないようにするには、彼らのフォローを外してください。", "search.placeholder": "検索", @@ -441,7 +441,7 @@ "search_results.accounts": "人々", "search_results.all": "すべて", "search_results.hashtags": "ハッシュタグ", - "search_results.nothing_found": "Could not find anything for these search terms", + "search_results.nothing_found": "この検索条件では何も見つかりませんでした", "search_results.statuses": "投稿", "search_results.statuses_fts_disabled": "このサーバーでは投稿本文の検索は利用できません。", "search_results.total": "{count, number}件の結果", diff --git a/app/javascript/mastodon/locales/ku.json b/app/javascript/mastodon/locales/ku.json index 0298c51ec..2bf8fc520 100644 --- a/app/javascript/mastodon/locales/ku.json +++ b/app/javascript/mastodon/locales/ku.json @@ -342,7 +342,7 @@ "notifications.filter.all": "Hemû", "notifications.filter.boosts": "Bilindkirî", "notifications.filter.favourites": "Bijarte", - "notifications.filter.follows": "Şopîner", + "notifications.filter.follows": "Dişopîne", "notifications.filter.mentions": "Qalkirin", "notifications.filter.polls": "Encamên rapirsiyê", "notifications.filter.statuses": "Ji kesên tu dişopînî re rojanekirin", @@ -501,7 +501,7 @@ "time_remaining.seconds": "{number, plural, one {# çirke} other {# çirke}} maye", "timeline_hint.remote_resource_not_displayed": "{resource} Ji rajekerên din nayê dîtin.", "timeline_hint.resources.followers": "Şopîner", - "timeline_hint.resources.follows": "Şopîner", + "timeline_hint.resources.follows": "Dişopîne", "timeline_hint.resources.statuses": "Şandiyên kevn", "trends.counter_by_accounts": "{count, plural, one {{counter} kes} other {{counter} kes}} diaxivin", "trends.trending_now": "Rojev", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index c77970f69..604589b06 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -9,44 +9,44 @@ "account.browse_more_on_origin_server": "Meer op het originele profiel bekijken", "account.cancel_follow_request": "Volgverzoek annuleren", "account.direct": "@{name} een direct bericht sturen", - "account.disable_notifications": "Geef geen melding meer wanneer @{name} toot", + "account.disable_notifications": "Geef geen melding meer wanneer @{name} een bericht plaatst", "account.domain_blocked": "Domein geblokkeerd", "account.edit_profile": "Profiel bewerken", - "account.enable_notifications": "Geef een melding wanneer @{name} toot", + "account.enable_notifications": "Geef een melding wanneer @{name} een bericht plaatst", "account.endorse": "Op profiel weergeven", "account.follow": "Volgen", "account.followers": "Volgers", "account.followers.empty": "Niemand volgt nog deze gebruiker.", "account.followers_counter": "{count, plural, one {{counter} volger} other {{counter} volgers}}", - "account.following": "Following", + "account.following": "Volgend", "account.following_counter": "{count, plural, one {{counter} volgend} other {{counter} volgend}}", "account.follows.empty": "Deze gebruiker volgt nog niemand.", "account.follows_you": "Volgt jou", "account.hide_reblogs": "Boosts van @{name} verbergen", "account.joined": "Geregistreerd in {date}", "account.link_verified_on": "Eigendom van deze link is gecontroleerd op {date}", - "account.locked_info": "De privacystatus van dit account is op besloten gezet. De eigenaar bepaalt handmatig wie hen kan volgen.", + "account.locked_info": "De privacystatus van dit account is op besloten gezet. De eigenaar bepaalt handmatig wie diegene kan volgen.", "account.media": "Media", "account.mention": "@{name} vermelden", "account.moved_to": "{name} is verhuisd naar:", "account.mute": "@{name} negeren", "account.mute_notifications": "Meldingen van @{name} negeren", "account.muted": "Genegeerd", - "account.posts": "Toots", - "account.posts_with_replies": "Toots en reacties", + "account.posts": "Berichten", + "account.posts_with_replies": "Berichten en reacties", "account.report": "@{name} rapporteren", "account.requested": "Wacht op goedkeuring. Klik om het volgverzoek te annuleren", "account.share": "Profiel van @{name} delen", "account.show_reblogs": "Boosts van @{name} tonen", - "account.statuses_counter": "{count, plural, one {{counter} toot} other {{counter} toots}}", + "account.statuses_counter": "{count, plural, one {{counter} bericht} other {{counter} berichten}}", "account.unblock": "@{name} deblokkeren", "account.unblock_domain": "{domain} niet langer verbergen", - "account.unblock_short": "Unblock", + "account.unblock_short": "Deblokkeren", "account.unendorse": "Niet op profiel weergeven", "account.unfollow": "Ontvolgen", "account.unmute": "@{name} niet langer negeren", "account.unmute_notifications": "Meldingen van @{name} niet langer negeren", - "account.unmute_short": "Unmute", + "account.unmute_short": "Niet langer negeren", "account_note.placeholder": "Klik om een opmerking toe te voegen", "admin.dashboard.daily_retention": "User retention rate by day after sign-up", "admin.dashboard.monthly_retention": "User retention rate by month after sign-up", @@ -79,7 +79,7 @@ "column.lists": "Lijsten", "column.mutes": "Genegeerde gebruikers", "column.notifications": "Meldingen", - "column.pins": "Vastgezette toots", + "column.pins": "Vastgezette berichten", "column.public": "Globale tijdlijn", "column_back_button.label": "Terug", "column_header.hide_settings": "Instellingen verbergen", @@ -92,10 +92,10 @@ "community.column_settings.local_only": "Alleen lokaal", "community.column_settings.media_only": "Alleen media", "community.column_settings.remote_only": "Alleen andere servers", - "compose_form.direct_message_warning": "Deze toot wordt alleen naar vermelde gebruikers verstuurd.", + "compose_form.direct_message_warning": "Dit bericht wordt alleen naar vermelde gebruikers verstuurd.", "compose_form.direct_message_warning_learn_more": "Meer leren", - "compose_form.hashtag_warning": "Deze toot valt niet onder een hashtag te bekijken, omdat deze niet op openbare tijdlijnen wordt getoond. Alleen openbare toots kunnen via hashtags gevonden worden.", - "compose_form.lock_disclaimer": "Jouw account is niet {locked}. Iedereen kan jou volgen en kan de toots zien die je alleen aan jouw volgers hebt gericht.", + "compose_form.hashtag_warning": "Dit bericht valt niet onder een hashtag te bekijken, omdat deze niet op openbare tijdlijnen wordt getoond. Alleen openbare berichten kunnen via hashtags gevonden worden.", + "compose_form.lock_disclaimer": "Jouw account is niet {locked}. Iedereen kan jou volgen en kan de berichten zien die je alleen aan jouw volgers hebt gericht.", "compose_form.lock_disclaimer.lock": "besloten", "compose_form.placeholder": "Wat wil je kwijt?", "compose_form.poll.add_option": "Keuze toevoegen", @@ -106,7 +106,7 @@ "compose_form.poll.switch_to_single": "Poll wijzigen om een enkele keuze toe te staan", "compose_form.publish": "Toot", "compose_form.publish_loud": "{publish}!", - "compose_form.save_changes": "Save changes", + "compose_form.save_changes": "Wijzigingen opslaan", "compose_form.sensitive.hide": "{count, plural, one {Media als gevoelig markeren} other {Media als gevoelig markeren}}", "compose_form.sensitive.marked": "{count, plural, one {Media is als gevoelig gemarkeerd} other {Media is als gevoelig gemarkeerd}}", "compose_form.sensitive.unmarked": "{count, plural, one {Media is niet als gevoelig gemarkeerd} other {Media is niet als gevoelig gemarkeerd}}", @@ -118,22 +118,22 @@ "confirmations.block.confirm": "Blokkeren", "confirmations.block.message": "Weet je het zeker dat je {name} wilt blokkeren?", "confirmations.delete.confirm": "Verwijderen", - "confirmations.delete.message": "Weet je het zeker dat je deze toot wilt verwijderen?", + "confirmations.delete.message": "Weet je het zeker dat je dit bericht wilt verwijderen?", "confirmations.delete_list.confirm": "Verwijderen", "confirmations.delete_list.message": "Weet je zeker dat je deze lijst definitief wilt verwijderen?", "confirmations.discard_edit_media.confirm": "Weggooien", "confirmations.discard_edit_media.message": "Je hebt niet-opgeslagen wijzigingen in de mediabeschrijving of voorvertonning, wil je deze toch weggooien?", "confirmations.domain_block.confirm": "Verberg alles van deze server", - "confirmations.domain_block.message": "Weet je het echt heel erg zeker dat je alles van {domain} wilt negeren? In de meeste gevallen is het blokkeren of negeren van een paar specifieke personen voldoende en beter. Je zult geen toots van deze server op openbare tijdlijnen zien of in jouw meldingen. Jouw volgers van deze server worden verwijderd.", + "confirmations.domain_block.message": "Weet je het echt heel erg zeker dat je alles van {domain} wilt negeren? In de meeste gevallen is het blokkeren of negeren van een paar specifieke personen voldoende en beter. Je zult geen berichten van deze server op openbare tijdlijnen zien of in jouw meldingen. Jouw volgers van deze server worden verwijderd.", "confirmations.logout.confirm": "Uitloggen", "confirmations.logout.message": "Weet je zeker dat je wilt uitloggen?", "confirmations.mute.confirm": "Negeren", - "confirmations.mute.explanation": "Dit verbergt toots van hen en toots waar hen in wordt vermeld, maar hen kan nog steeds jouw toots bekijken en jou volgen.", + "confirmations.mute.explanation": "Dit verbergt diens berichten en berichten waar diegene in wordt vermeld, maar diegene kan nog steeds jouw berichten bekijken en jou volgen.", "confirmations.mute.message": "Weet je het zeker dat je {name} wilt negeren?", "confirmations.redraft.confirm": "Verwijderen en herschrijven", - "confirmations.redraft.message": "Weet je zeker dat je deze toot wilt verwijderen en herschrijven? Je verliest wel de boosts en favorieten, en de reacties op de originele toot zitten niet meer aan de nieuwe toot vast.", + "confirmations.redraft.message": "Weet je zeker dat je dit bericht wilt verwijderen en herschrijven? Je verliest wel de boosts en favorieten, en de reacties op het originele bericht raak je kwijt.", "confirmations.reply.confirm": "Reageren", - "confirmations.reply.message": "Door nu te reageren overschrijf je de toot die je op dit moment aan het schrijven bent. Weet je zeker dat je verder wil gaan?", + "confirmations.reply.message": "Door nu te reageren overschrijf je het bericht dat je op dit moment aan het schrijven bent. Weet je zeker dat je verder wil gaan?", "confirmations.unfollow.confirm": "Ontvolgen", "confirmations.unfollow.message": "Weet je het zeker dat je {name} wilt ontvolgen?", "conversation.delete": "Gesprek verwijderen", @@ -144,7 +144,7 @@ "directory.local": "Alleen {domain}", "directory.new_arrivals": "Nieuwe accounts", "directory.recently_active": "Onlangs actief", - "embed.instructions": "Embed deze toot op jouw website, door de onderstaande code te kopiëren.", + "embed.instructions": "Embed dit bericht op jouw website door de onderstaande code te kopiëren.", "embed.preview": "Zo komt het eruit te zien:", "emoji_button.activity": "Activiteiten", "emoji_button.custom": "Lokale emoji’s", @@ -161,41 +161,41 @@ "emoji_button.symbols": "Symbolen", "emoji_button.travel": "Reizen en locaties", "empty_column.account_suspended": "Account opgeschort", - "empty_column.account_timeline": "Hier zijn geen toots!", + "empty_column.account_timeline": "Hier zijn geen berichten!", "empty_column.account_unavailable": "Profiel is niet beschikbaar", "empty_column.blocks": "Jij hebt nog geen enkele gebruiker geblokkeerd.", - "empty_column.bookmarked_statuses": "Jij hebt nog geen toots aan je bladwijzers toegevoegd. Wanneer je er een aan jouw bladwijzers toevoegt, valt deze hier te zien.", - "empty_column.community": "De lokale tijdlijn is nog leeg. Toot iets in het openbaar om de spits af te bijten!", + "empty_column.bookmarked_statuses": "Jij hebt nog geen berichten aan je bladwijzers toegevoegd. Wanneer je er een aan jouw bladwijzers toevoegt, valt deze hier te zien.", + "empty_column.community": "De lokale tijdlijn is nog leeg. Plaats een openbaar bericht om de spits af te bijten!", "empty_column.direct": "Je hebt nog geen directe berichten. Wanneer je er een verzend of ontvangt, zijn deze hier te zien.", "empty_column.domain_blocks": "Er zijn nog geen geblokkeerde domeinen.", - "empty_column.explore_statuses": "Nothing is trending right now. Check back later!", - "empty_column.favourited_statuses": "Jij hebt nog geen favoriete toots. Wanneer je er een aan jouw favorieten toevoegt, valt deze hier te zien.", - "empty_column.favourites": "Niemand heeft deze toot nog aan hun favorieten toegevoegd. Wanneer iemand dit doet, valt dat hier te zien.", + "empty_column.explore_statuses": "Momenteel zijn er geen trends. Kom later terug!", + "empty_column.favourited_statuses": "Jij hebt nog geen favoriete berichten. Wanneer je er een aan jouw favorieten toevoegt, valt deze hier te zien.", + "empty_column.favourites": "Niemand heeft dit bericht nog aan diens favorieten toegevoegd. Wanneer iemand dit doet, valt dat hier te zien.", "empty_column.follow_recommendations": "Het lijkt er op dat er geen aanbevelingen voor jou aangemaakt kunnen worden. Je kunt proberen te zoeken naar mensen die je wellicht kent, zoeken op hashtags, de lokale en globale tijdlijnen bekijken of de gebruikersgids doorbladeren.", "empty_column.follow_requests": "Jij hebt nog enkel volgverzoek ontvangen. Wanneer je er eentje ontvangt, valt dat hier te zien.", "empty_column.hashtag": "Er is nog niks te vinden onder deze hashtag.", "empty_column.home": "Deze tijdlijn is leeg! Volg meer mensen om het te vullen. {suggestions}", "empty_column.home.suggestions": "Enkele aanbevelingen bekijken", - "empty_column.list": "Er is nog niks te zien in deze lijst. Wanneer lijstleden nieuwe toots publiceren, zijn deze hier te zien.", + "empty_column.list": "Er is nog niks te zien in deze lijst. Wanneer lijstleden nieuwe berichten plaatsen, zijn deze hier te zien.", "empty_column.lists": "Jij hebt nog geen enkele lijst. Wanneer je er eentje hebt aangemaakt, valt deze hier te zien.", "empty_column.mutes": "Jij hebt nog geen gebruikers genegeerd.", "empty_column.notifications": "Je hebt nog geen meldingen. Begin met iemand een gesprek.", - "empty_column.public": "Er is hier helemaal niks! Toot iets in het openbaar of volg mensen van andere servers om het te vullen", + "empty_column.public": "Er is hier helemaal niks! Plaatst een openbaar bericht of volg mensen van andere servers om het te vullen", "error.unexpected_crash.explanation": "Als gevolg van een bug in onze broncode of als gevolg van een compatibiliteitsprobleem met jouw webbrowser, kan deze pagina niet goed worden weergegeven.", "error.unexpected_crash.explanation_addons": "Deze pagina kon niet correct geladen worden. Deze fout wordt waarschijnlijk door een browser-add-on of een automatische vertalingshulpmiddel veroorzaakt.", "error.unexpected_crash.next_steps": "Probeer deze pagina te vernieuwen. Wanneer dit niet helpt is het nog steeds mogelijk om Mastodon in een andere webbrowser of mobiele app te gebruiken.", "error.unexpected_crash.next_steps_addons": "Probeer deze uit te schakelen en de pagina te verversen. Wanneer dat niet helpt, kun je Mastodon nog altijd met een andere webbrowser of mobiele app gebruiken.", "errors.unexpected_crash.copy_stacktrace": "Stacktrace naar klembord kopiëren", "errors.unexpected_crash.report_issue": "Technisch probleem melden", - "explore.search_results": "Search results", - "explore.suggested_follows": "For you", - "explore.title": "Explore", - "explore.trending_links": "News", - "explore.trending_statuses": "Posts", + "explore.search_results": "Zoekresultaten", + "explore.suggested_follows": "Voor jou", + "explore.title": "Verkennen", + "explore.trending_links": "Nieuws", + "explore.trending_statuses": "Berichten", "explore.trending_tags": "Hashtags", "follow_recommendations.done": "Klaar", - "follow_recommendations.heading": "Volg mensen waarvan je graag toots wil zien! Hier zijn enkele aanbevelingen.", - "follow_recommendations.lead": "Toots van mensen die je volgt zullen in chronologische volgorde onder start verschijnen. Wees niet bang om hierin fouten te maken, want je kunt mensen op elk moment net zo eenvoudig ontvolgen!", + "follow_recommendations.heading": "Volg mensen waarvan je graag berichten wil zien! Hier zijn enkele aanbevelingen.", + "follow_recommendations.lead": "Berichten van mensen die je volgt zullen in chronologische volgorde onder start verschijnen. Wees niet bang om hierin fouten te maken, want je kunt mensen op elk moment net zo eenvoudig ontvolgen!", "follow_request.authorize": "Goedkeuren", "follow_request.reject": "Afkeuren", "follow_requests.unlocked_explanation": "Ook al is jouw account niet besloten, de medewerkers van {domain} denken dat jij misschien de volgende volgverzoeken handmatig wil controleren.", @@ -227,13 +227,13 @@ "intervals.full.minutes": "{number, plural, one {# minuut} other {# minuten}}", "keyboard_shortcuts.back": "Ga terug", "keyboard_shortcuts.blocked": "Geblokkeerde gebruikers tonen", - "keyboard_shortcuts.boost": "Toot boosten", + "keyboard_shortcuts.boost": "Bericht boosten", "keyboard_shortcuts.column": "Op één van de kolommen focussen", - "keyboard_shortcuts.compose": "Tekstveld voor toots focussen", + "keyboard_shortcuts.compose": "Tekstveld om een bericht te schrijven focussen", "keyboard_shortcuts.description": "Omschrijving", "keyboard_shortcuts.direct": "Jouw directe berichten tonen", "keyboard_shortcuts.down": "Naar beneden in de lijst bewegen", - "keyboard_shortcuts.enter": "Toot volledig tonen", + "keyboard_shortcuts.enter": "Volledig bericht tonen", "keyboard_shortcuts.favourite": "Aan jouw favorieten toevoegen", "keyboard_shortcuts.favourites": "Favorieten tonen", "keyboard_shortcuts.federated": "Globale tijdlijn tonen", @@ -247,7 +247,7 @@ "keyboard_shortcuts.my_profile": "Jouw profiel tonen", "keyboard_shortcuts.notifications": "Meldingen tonen", "keyboard_shortcuts.open_media": "Media openen", - "keyboard_shortcuts.pinned": "Jouw vastgezette toots tonen", + "keyboard_shortcuts.pinned": "Jouw vastgemaakte berichten tonen", "keyboard_shortcuts.profile": "Gebruikersprofiel auteur openen", "keyboard_shortcuts.reply": "Reageren", "keyboard_shortcuts.requests": "Jouw volgverzoeken tonen", @@ -256,7 +256,7 @@ "keyboard_shortcuts.start": "\"Aan de slag\" tonen", "keyboard_shortcuts.toggle_hidden": "Inhoudswaarschuwing tonen/verbergen", "keyboard_shortcuts.toggle_sensitivity": "Media tonen/verbergen", - "keyboard_shortcuts.toot": "Nieuwe toot schrijven", + "keyboard_shortcuts.toot": "Nieuw bericht schrijven", "keyboard_shortcuts.unfocus": "Tekst- en zoekveld ontfocussen", "keyboard_shortcuts.up": "Naar boven in de lijst bewegen", "lightbox.close": "Sluiten", @@ -289,12 +289,12 @@ "navigation_bar.blocks": "Geblokkeerde gebruikers", "navigation_bar.bookmarks": "Bladwijzers", "navigation_bar.community_timeline": "Lokale tijdlijn", - "navigation_bar.compose": "Nieuw toot schrijven", + "navigation_bar.compose": "Nieuw bericht schrijven", "navigation_bar.direct": "Directe berichten", "navigation_bar.discover": "Ontdekken", "navigation_bar.domain_blocks": "Geblokkeerde domeinen", "navigation_bar.edit_profile": "Profiel bewerken", - "navigation_bar.explore": "Explore", + "navigation_bar.explore": "Verkennen", "navigation_bar.favourites": "Favorieten", "navigation_bar.filters": "Filters", "navigation_bar.follow_requests": "Volgverzoeken", @@ -305,23 +305,23 @@ "navigation_bar.logout": "Uitloggen", "navigation_bar.mutes": "Genegeerde gebruikers", "navigation_bar.personal": "Persoonlijk", - "navigation_bar.pins": "Vastgezette toots", + "navigation_bar.pins": "Vastgemaakte berichten", "navigation_bar.preferences": "Instellingen", "navigation_bar.public_timeline": "Globale tijdlijn", "navigation_bar.security": "Beveiliging", - "notification.admin.sign_up": "{name} signed up", - "notification.favourite": "{name} voegde jouw toot als favoriet toe", + "notification.admin.sign_up": "{name} heeft zich aangemeld", + "notification.favourite": "{name} voegde jouw bericht als favoriet toe", "notification.follow": "{name} volgt jou nu", "notification.follow_request": "{name} wil jou graag volgen", "notification.mention": "{name} vermeldde jou", "notification.own_poll": "Jouw poll is beëindigd", "notification.poll": "Een poll waaraan jij hebt meegedaan is beëindigd", - "notification.reblog": "{name} boostte jouw toot", - "notification.status": "{name} heeft zojuist een toot geplaatst", - "notification.update": "{name} edited a post", + "notification.reblog": "{name} boostte jouw bericht", + "notification.status": "{name} heeft zojuist een bericht geplaatst", + "notification.update": "{name} heeft een bericht bewerkt", "notifications.clear": "Meldingen verwijderen", "notifications.clear_confirmation": "Weet je het zeker dat je al jouw meldingen wilt verwijderen?", - "notifications.column_settings.admin.sign_up": "New sign-ups:", + "notifications.column_settings.admin.sign_up": "Nieuwe aanmeldingen:", "notifications.column_settings.alert": "Desktopmeldingen", "notifications.column_settings.favourite": "Favorieten:", "notifications.column_settings.filter_bar.advanced": "Alle categorieën tonen", @@ -335,10 +335,10 @@ "notifications.column_settings.reblog": "Boosts:", "notifications.column_settings.show": "In kolom tonen", "notifications.column_settings.sound": "Geluid afspelen", - "notifications.column_settings.status": "Nieuwe toots:", + "notifications.column_settings.status": "Nieuwe berichten:", "notifications.column_settings.unread_notifications.category": "Ongelezen meldingen", "notifications.column_settings.unread_notifications.highlight": "Ongelezen meldingen markeren", - "notifications.column_settings.update": "Edits:", + "notifications.column_settings.update": "Bewerkingen:", "notifications.filter.all": "Alles", "notifications.filter.boosts": "Boosts", "notifications.filter.favourites": "Favorieten", @@ -365,7 +365,7 @@ "poll.votes": "{votes, plural, one {# stem} other {# stemmen}}", "poll_button.add_poll": "Poll toevoegen", "poll_button.remove_poll": "Poll verwijderen", - "privacy.change": "Zichtbaarheid van toot aanpassen", + "privacy.change": "Zichtbaarheid van bericht aanpassen", "privacy.direct.long": "Alleen aan vermelde gebruikers tonen", "privacy.direct.short": "Direct", "privacy.private.long": "Alleen aan volgers tonen", @@ -378,100 +378,100 @@ "regeneration_indicator.label": "Aan het laden…", "regeneration_indicator.sublabel": "Jouw tijdlijn wordt aangemaakt!", "relative_time.days": "{number}d", - "relative_time.full.days": "{number, plural, one {# day} other {# days}} ago", - "relative_time.full.hours": "{number, plural, one {# hour} other {# hours}} ago", - "relative_time.full.just_now": "just now", - "relative_time.full.minutes": "{number, plural, one {# minute} other {# minutes}} ago", - "relative_time.full.seconds": "{number, plural, one {# second} other {# seconds}} ago", + "relative_time.full.days": "{number, plural, one {# dag} other {# dagen}} geleden", + "relative_time.full.hours": "{number, plural, one {# uur} other {# uur}} geleden", + "relative_time.full.just_now": "zojuist", + "relative_time.full.minutes": "{number, plural, one {# minuut} other {# minuten}} geleden", + "relative_time.full.seconds": "{number, plural, one {# seconde} other {# seconden}} geleden", "relative_time.hours": "{number}u", "relative_time.just_now": "nu", "relative_time.minutes": "{number}m", "relative_time.seconds": "{number}s", "relative_time.today": "vandaag", "reply_indicator.cancel": "Annuleren", - "report.block": "Block", - "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.", - "report.categories.other": "Other", + "report.block": "Blokkeren", + "report.block_explanation": "Je kunt diens berichten niet zien. Je kunt door diegene niet gevolgd worden en jouw berichten zijn onzichtbaar. Diegene kan zien dat die door jou is geblokkeerd.", + "report.categories.other": "Overig", "report.categories.spam": "Spam", - "report.categories.violation": "Content violates one or more server rules", - "report.category.subtitle": "Choose the best match", - "report.category.title": "Tell us what's going on with this {type}", - "report.category.title_account": "profile", - "report.category.title_status": "post", - "report.close": "Done", - "report.comment.title": "Is there anything else you think we should know?", + "report.categories.violation": "De inhoud overtreedt een of meerdere serverregels", + "report.category.subtitle": "Kies wat het meeste overeenkomt", + "report.category.title": "Vertel ons wat er met dit {type} aan de hand is", + "report.category.title_account": "profiel", + "report.category.title_status": "bericht", + "report.close": "Klaar", + "report.comment.title": "Zijn er nog andere dingen waarvan je denkt dat wij dat moeten weten?", "report.forward": "Naar {target} doorsturen", "report.forward_hint": "Het account bevindt zich op een andere server. Wil je daar eveneens een geanonimiseerde kopie van deze rapportage naar toe sturen?", - "report.mute": "Mute", - "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.", - "report.next": "Next", + "report.mute": "Negeren", + "report.mute_explanation": "Je kunt diens berichten niet zien. Je kunt nog wel gevolgd worden en jouw berichten zijn nog zichtbaar, maar diegene kan niet zien dat die wordt genegeerd.", + "report.next": "Volgende", "report.placeholder": "Extra opmerkingen", - "report.reasons.dislike": "I don't like it", - "report.reasons.dislike_description": "It is not something you want to see", - "report.reasons.other": "It's something else", - "report.reasons.other_description": "The issue does not fit into other categories", - "report.reasons.spam": "It's spam", - "report.reasons.spam_description": "Malicious links, fake engagement, or repetitive replies", - "report.reasons.violation": "It violates server rules", - "report.reasons.violation_description": "You are aware that it breaks specific rules", - "report.rules.subtitle": "Select all that apply", - "report.rules.title": "Which rules are being violated?", - "report.statuses.subtitle": "Select all that apply", - "report.statuses.title": "Are there any posts that back up this report?", + "report.reasons.dislike": "Ik vind het niet leuk", + "report.reasons.dislike_description": "Het is iets wat je niet wilt zien", + "report.reasons.other": "Het is iets anders", + "report.reasons.other_description": "Het probleem past niet in een andere categorie", + "report.reasons.spam": "Het is spam", + "report.reasons.spam_description": "Schadelijke links, reclame, misleiding of herhalende antwoorden", + "report.reasons.violation": "Het schendt de serverregels", + "report.reasons.violation_description": "Je weet dat het specifieke regels schendt", + "report.rules.subtitle": "Selecteer wat van toepassing is", + "report.rules.title": "Welke regels worden geschonden?", + "report.statuses.subtitle": "Selecteer wat van toepassing is", + "report.statuses.title": "Zijn er berichten die deze rapportage ondersteunen?", "report.submit": "Verzenden", "report.target": "{target} rapporteren", - "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:", - "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:", - "report.thanks.title": "Don't want to see this?", - "report.thanks.title_actionable": "Thanks for reporting, we'll look into this.", - "report.unfollow": "Unfollow @{name}", - "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.", + "report.thanks.take_action": "Hier zijn jouw opties waarmee je kunt bepalen wat je in Mastodon wilt zien:", + "report.thanks.take_action_actionable": "Terwijl wij jouw rapportage beroordelen, kun je deze acties ondernemen tegen @{name}:", + "report.thanks.title": "Wil je dit niet zien?", + "report.thanks.title_actionable": "Dank je voor het rapporteren. Wij gaan er naar kijken.", + "report.unfollow": "@{name} ontvolgen", + "report.unfollow_explanation": "Je volgt dit account. Om diens berichten niet meer op jouw starttijdlijn te zien, kun je diegene ontvolgen.", "search.placeholder": "Zoeken", "search_popout.search_format": "Geavanceerd zoeken", - "search_popout.tips.full_text": "Gebruik gewone tekst om te zoeken in jouw toots, gebooste toots, favorieten en in toots waarin je bent vermeldt, en tevens naar gebruikersnamen, weergavenamen en hashtags.", + "search_popout.tips.full_text": "Gebruik gewone tekst om te zoeken in jouw berichten, gebooste berichten, favorieten en in berichten waarin je bent vermeldt, en tevens naar gebruikersnamen, weergavenamen en hashtags.", "search_popout.tips.hashtag": "hashtag", - "search_popout.tips.status": "toot", + "search_popout.tips.status": "bericht", "search_popout.tips.text": "Gebruik gewone tekst om te zoeken op weergavenamen, gebruikersnamen en hashtags", "search_popout.tips.user": "gebruiker", "search_results.accounts": "Gebruikers", - "search_results.all": "All", + "search_results.all": "Alles", "search_results.hashtags": "Hashtags", - "search_results.nothing_found": "Could not find anything for these search terms", - "search_results.statuses": "Toots", - "search_results.statuses_fts_disabled": "Het zoeken in toots is op deze Mastodon-server niet ingeschakeld.", + "search_results.nothing_found": "Deze zoektermen leveren geen resultaat op", + "search_results.statuses": "Berichten", + "search_results.statuses_fts_disabled": "Het zoeken in berichten is op deze Mastodon-server niet ingeschakeld.", "search_results.total": "{count, number} {count, plural, one {resultaat} other {resultaten}}", "status.admin_account": "Moderatie-omgeving van @{name} openen", - "status.admin_status": "Deze toot in de moderatie-omgeving openen", + "status.admin_status": "Dit bericht in de moderatie-omgeving openen", "status.block": "@{name} blokkeren", "status.bookmark": "Bladwijzer toevoegen", "status.cancel_reblog_private": "Niet langer boosten", - "status.cannot_reblog": "Deze toot kan niet geboost worden", - "status.copy": "Link naar toot kopiëren", + "status.cannot_reblog": "Dit bericht kan niet geboost worden", + "status.copy": "Link naar bericht kopiëren", "status.delete": "Verwijderen", "status.detailed_status": "Uitgebreide gespreksweergave", "status.direct": "@{name} een direct bericht sturen", - "status.edit": "Edit", - "status.edited": "Edited {date}", - "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}", + "status.edit": "Bewerken", + "status.edited": "Bewerkt op {date}", + "status.edited_x_times": "{count, plural, one {{count} keer} other {{count} keer}} bewerkt", "status.embed": "Insluiten", "status.favourite": "Favoriet", "status.filtered": "Gefilterd", - "status.history.created": "{name} created {date}", - "status.history.edited": "{name} edited {date}", + "status.history.created": "{name} plaatste dit {date}", + "status.history.edited": "{name} bewerkte dit {date}", "status.load_more": "Meer laden", "status.media_hidden": "Media verborgen", "status.mention": "@{name} vermelden", "status.more": "Meer", "status.mute": "@{name} negeren", "status.mute_conversation": "Negeer gesprek", - "status.open": "Volledige toot tonen", + "status.open": "Volledig bericht tonen", "status.pin": "Aan profielpagina vastmaken", - "status.pinned": "Vastgemaakte toot", + "status.pinned": "Vastgemaakt bericht", "status.read_more": "Meer lezen", "status.reblog": "Boosten", "status.reblog_private": "Boost naar oorspronkelijke ontvangers", "status.reblogged_by": "{name} boostte", - "status.reblogs.empty": "Niemand heeft deze toot nog geboost. Wanneer iemand dit doet, valt dat hier te zien.", + "status.reblogs.empty": "Niemand heeft dit bericht nog geboost. Wanneer iemand dit doet, valt dat hier te zien.", "status.redraft": "Verwijderen en herschrijven", "status.remove_bookmark": "Bladwijzer verwijderen", "status.reply": "Reageren", @@ -502,7 +502,7 @@ "timeline_hint.remote_resource_not_displayed": "{resource} van andere servers worden niet getoond.", "timeline_hint.resources.followers": "Volgers", "timeline_hint.resources.follows": "Volgend", - "timeline_hint.resources.statuses": "Oudere toots", + "timeline_hint.resources.statuses": "Oudere berichten", "trends.counter_by_accounts": "{count, plural, one {{counter} persoon} other {{counter} personen}} zijn aan het praten", "trends.trending_now": "Huidige trends", "ui.beforeunload": "Je concept gaat verloren wanneer je Mastodon verlaat.", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 18e429641..f620e02b5 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -18,7 +18,7 @@ "account.followers": "Seguidores", "account.followers.empty": "Nada aqui.", "account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}", - "account.following": "Following", + "account.following": "Seguindo", "account.following_counter": "{count, plural, one {segue {counter}} other {segue {counter}}}", "account.follows.empty": "Nada aqui.", "account.follows_you": "te segue", @@ -41,14 +41,14 @@ "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock": "Desbloquear @{name}", "account.unblock_domain": "Desbloquear domínio {domain}", - "account.unblock_short": "Unblock", + "account.unblock_short": "Desbloquear", "account.unendorse": "Remover", "account.unfollow": "Deixar de seguir", "account.unmute": "Dessilenciar @{name}", "account.unmute_notifications": "Mostrar notificações de @{name}", - "account.unmute_short": "Unmute", + "account.unmute_short": "Reativar", "account_note.placeholder": "Nota pessoal sobre este perfil aqui", - "admin.dashboard.daily_retention": "User retention rate by day after sign-up", + "admin.dashboard.daily_retention": "Taxa de retenção de usuários por dia, após a inscrição", "admin.dashboard.monthly_retention": "Taxa de retenção de usuários por mês, após a inscrição", "admin.dashboard.retention.average": "Média", "admin.dashboard.retention.cohort": "Mês de inscrição", @@ -168,7 +168,7 @@ "empty_column.community": "A linha local está vazia. Publique algo para começar!", "empty_column.direct": "Nada aqui. Quando você enviar ou receber toots diretos, eles aparecerão aqui.", "empty_column.domain_blocks": "Nada aqui.", - "empty_column.explore_statuses": "Nothing is trending right now. Check back later!", + "empty_column.explore_statuses": "Nada está em alta no momento. Volte mais tarde!", "empty_column.favourited_statuses": "Nada aqui. Quando você favoritar um toot, ele aparecerá aqui.", "empty_column.favourites": "Nada aqui. Quando alguém favoritar, o autor aparecerá aqui.", "empty_column.follow_recommendations": "Parece que não há sugestões para você. Tente usar a pesquisa para encontrar pessoas que você possa conhecer ou explorar hashtags.", @@ -294,7 +294,7 @@ "navigation_bar.discover": "Descobrir", "navigation_bar.domain_blocks": "Domínios bloqueados", "navigation_bar.edit_profile": "Editar perfil", - "navigation_bar.explore": "Explore", + "navigation_bar.explore": "Explorar", "navigation_bar.favourites": "Favoritos", "navigation_bar.filters": "Palavras filtradas", "navigation_bar.follow_requests": "Seguidores pendentes", @@ -390,42 +390,42 @@ "relative_time.today": "hoje", "reply_indicator.cancel": "Cancelar", "report.block": "Bloquear", - "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.", + "report.block_explanation": "Você não verá suas postagens. Eles não poderão ver suas postagens ou segui-lo. Eles serão capazes de perceber que estão bloqueados.", "report.categories.other": "Outro", "report.categories.spam": "Spam", "report.categories.violation": "O conteúdo viola uma ou mais regras do servidor", - "report.category.subtitle": "Choose the best match", - "report.category.title": "Tell us what's going on with this {type}", + "report.category.subtitle": "Escolha a alternativa de melhor correspondência", + "report.category.title": "Conte-nos o que está acontecendo com esse {type}", "report.category.title_account": "perfil", "report.category.title_status": "publicação", "report.close": "Concluído", - "report.comment.title": "Is there anything else you think we should know?", + "report.comment.title": "Há algo mais que você acredita que devemos saber?", "report.forward": "Encaminhar para {target}", "report.forward_hint": "A conta está em outra instância. Enviar uma cópia anônima da denúncia para lá?", "report.mute": "Silenciar", - "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.", + "report.mute_explanation": "Você não verá suas postagens. Eles ainda podem seguir você e ver suas postagens e não saberão que estão silenciados.", "report.next": "Próximo", "report.placeholder": "Comentários adicionais aqui", "report.reasons.dislike": "Eu não gosto disso", - "report.reasons.dislike_description": "It is not something you want to see", - "report.reasons.other": "It's something else", + "report.reasons.dislike_description": "Não é algo que você quer ver", + "report.reasons.other": "É outra coisa", "report.reasons.other_description": "O problema não se encaixa em outras categorias", "report.reasons.spam": "É spam", - "report.reasons.spam_description": "Malicious links, fake engagement, or repetitive replies", - "report.reasons.violation": "It violates server rules", + "report.reasons.spam_description": "Links maliciosos, envolvimento falso ou respostas repetitivas", + "report.reasons.violation": "Viola as regras do servidor", "report.reasons.violation_description": "Você está ciente de que isso quebra regras específicas", "report.rules.subtitle": "Selecione tudo que se aplica", - "report.rules.title": "Which rules are being violated?", + "report.rules.title": "Que regras estão sendo violadas?", "report.statuses.subtitle": "Selecione tudo que se aplica", - "report.statuses.title": "Are there any posts that back up this report?", + "report.statuses.title": "Existem postagens que respaldam esse relatório?", "report.submit": "Enviar", "report.target": "Denunciando {target}", - "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:", + "report.thanks.take_action": "Aqui estão suas opções para controlar o que você vê no Mastodon:", "report.thanks.take_action_actionable": "Enquanto revisamos isso, você pode tomar medidas contra @{name}:", "report.thanks.title": "Não quer ver isto?", "report.thanks.title_actionable": "Obrigado por reportar. Vamos analisar.", - "report.unfollow": "Unfollow @{name}", - "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.", + "report.unfollow": "Deixar de seguir @{name}", + "report.unfollow_explanation": "Você está seguindo esta conta. Para não mais ver os posts dele em sua página inicial, deixe de segui-lo.", "search.placeholder": "Pesquisar", "search_popout.search_format": "Formato de pesquisa avançada", "search_popout.tips.full_text": "Texto simples retorna toots que você escreveu, favoritou, deu boost, ou em que foi mencionado, assim como nomes de usuário e de exibição, e hashtags correspondentes.", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index bf3097dc0..7267fc99d 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -18,7 +18,7 @@ "account.followers": "Подписчики", "account.followers.empty": "На этого пользователя пока никто не подписан.", "account.followers_counter": "{count, plural, one {{counter} подписчик} many {{counter} подписчиков} other {{counter} подписчика}}", - "account.following": "Following", + "account.following": "Подписки", "account.following_counter": "{count, plural, one {{counter} подписка} many {{counter} подписок} other {{counter} подписки}}", "account.follows.empty": "Этот пользователь пока ни на кого не подписался.", "account.follows_you": "Подписан(а) на вас", @@ -95,7 +95,7 @@ "compose_form.direct_message_warning": "Адресованные посты отправляются и видны только упомянутым в них пользователям.", "compose_form.direct_message_warning_learn_more": "Подробнее", "compose_form.hashtag_warning": "Так как этот пост не публичный, он не отобразится в поиске по хэштегам.", - "compose_form.lock_disclaimer": "Ваша учётная запись не {locked}. Любой пользователь сможет подписаться на вас и просматривать посты для подписчиков.", + "compose_form.lock_disclaimer": "Ваша учётная запись {locked}. Любой пользователь сможет подписаться на вас и просматривать посты для подписчиков.", "compose_form.lock_disclaimer.lock": "не закрыта", "compose_form.placeholder": "О чём думаете?", "compose_form.poll.add_option": "Добавить вариант", @@ -390,42 +390,42 @@ "relative_time.today": "сегодня", "reply_indicator.cancel": "Отмена", "report.block": "Заблокировать", - "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.", + "report.block_explanation": "В перестаните видеть посты этого пользователя, а он(а) больше не сможет подписаться на вас и читать ваши посты. Он(а) сможет понять что вы заблокировали его/её.", "report.categories.other": "Другое", "report.categories.spam": "Спам", "report.categories.violation": "Содержимое нарушает одно или несколько правил узла", "report.category.subtitle": "Выберите наиболее подходящее", - "report.category.title": "Расскажите нам, что происходит с {type}", - "report.category.title_account": "профиль", - "report.category.title_status": "пост", + "report.category.title": "Расскажите нам, что не так с {type}", + "report.category.title_account": "этим профилем", + "report.category.title_status": "этим постом", "report.close": "Готово", - "report.comment.title": "Есть что-нибудь еще, что мы должны знать?", - "report.forward": "Переслать в {target}", + "report.comment.title": "Есть ли что-нибудь ещё, что нам стоит знать?", + "report.forward": "Переслать на {target}", "report.forward_hint": "Эта учётная запись расположена на другом узле. Отправить туда анонимную копию вашей жалобы?", - "report.mute": "Mute", + "report.mute": "Игнорировать", "report.mute_explanation": "Вы не будете видеть их посты. Они по-прежнему могут подписываться на вас и видеть ваши посты, но не будут знать, что они в списке игнорируемых.", "report.next": "Далее", - "report.placeholder": "Комментарий", + "report.placeholder": "Дополнительные комментарии", "report.reasons.dislike": "Мне не нравится", "report.reasons.dislike_description": "Не хотел(а) бы видеть такой контент", "report.reasons.other": "Другое", - "report.reasons.other_description": "Проблема не подпадает под другие категории", + "report.reasons.other_description": "Проблема не попадает ни под одну из категорий", "report.reasons.spam": "Это спам", - "report.reasons.spam_description": "Вредоносные ссылки, поддельные действия или повторяющиеся ответы", + "report.reasons.spam_description": "Вредоносные ссылки, фальшивое взаимодействие или повторяющиеся ответы", "report.reasons.violation": "Нарушаются правила сервера", "report.reasons.violation_description": "Вы знаете, что подобное нарушает определенные правила", "report.rules.subtitle": "Выберите все подходящие варианты", "report.rules.title": "Какие правила нарушены?", "report.statuses.subtitle": "Выберите все подходящие варианты", - "report.statuses.title": "Есть ли сообщения, подтверждающие основания этой жалобы?", + "report.statuses.title": "Выберите посты, которые относятся к вашей жалобе.", "report.submit": "Отправить", "report.target": "Жалоба на {target}", - "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:", - "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:", + "report.thanks.take_action": "Вот несколько опций управления тем, что вы видите в Mastodon:", + "report.thanks.take_action_actionable": "Пока мы рассматриваем его, вот действия, которые вы можете предпринять лично против @{name}:", "report.thanks.title": "Не хотите видеть это?", "report.thanks.title_actionable": "Спасибо за обращение, мы его рассмотрим.", "report.unfollow": "Отписаться от @{name}", - "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.", + "report.unfollow_explanation": "Вы подписаны на этого пользователя. Чтобы не видеть его/её посты в своей домашней ленте, отпишитесь от него/неё.", "search.placeholder": "Поиск", "search_popout.search_format": "Продвинутый формат поиска", "search_popout.tips.full_text": "Поиск по простому тексту отобразит посты, которые вы написали, добавили в избранное, продвинули или в которых были упомянуты, а также подходящие имена пользователей и хэштеги.", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 60b513aa1..860e65413 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -389,7 +389,7 @@ "relative_time.seconds": "{number}sek", "relative_time.today": "dnes", "reply_indicator.cancel": "Zrušiť", - "report.block": "Block", + "report.block": "Blokuj", "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.", "report.categories.other": "Other", "report.categories.spam": "Spam", @@ -424,7 +424,7 @@ "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:", "report.thanks.title": "Nechceš to vidieť?", "report.thanks.title_actionable": "Thanks for reporting, we'll look into this.", - "report.unfollow": "Unfollow @{name}", + "report.unfollow": "Nesleduj @{name}", "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.", "search.placeholder": "Hľadaj", "search_popout.search_format": "Pokročilé vyhľadávanie", @@ -434,7 +434,7 @@ "search_popout.tips.text": "Vráti jednoduchý textový výpis zhodujúcich sa mien, prezývok a haštagov", "search_popout.tips.user": "užívateľ", "search_results.accounts": "Ľudia", - "search_results.all": "All", + "search_results.all": "Všetky", "search_results.hashtags": "Haštagy", "search_results.nothing_found": "Could not find anything for these search terms", "search_results.statuses": "Príspevky", @@ -451,7 +451,7 @@ "status.detailed_status": "Podrobný náhľad celej konverzácie", "status.direct": "Priama správa pre @{name}", "status.edit": "Uprav", - "status.edited": "Edited {date}", + "status.edited": "Upravené {date}", "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}", "status.embed": "Vložiť", "status.favourite": "Páči sa mi", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index d1047f5da..ce3cdabd0 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -18,7 +18,7 @@ "account.followers": "Ndjekës", "account.followers.empty": "Këtë përdorues ende s’e ndjek kush.", "account.followers_counter": "{count, plural, one {{counter} Ndjekës} other {{counter} Ndjekës}}", - "account.following": "Following", + "account.following": "Ndjekje", "account.following_counter": "{count, plural, one {{counter} i Ndjekur} other {{counter} të Ndjekur}}", "account.follows.empty": "Ky përdorues ende s’ndjek kënd.", "account.follows_you": "Ju ndjek", @@ -41,12 +41,12 @@ "account.statuses_counter": "{count, plural, one {{counter} Mesazh} other {{counter} Mesazhe}}", "account.unblock": "Zhbllokoje @{name}", "account.unblock_domain": "Zhblloko përkatësinë {domain}", - "account.unblock_short": "Unblock", + "account.unblock_short": "Zhbllokoje", "account.unendorse": "Mos e përfshi në profil", "account.unfollow": "Resht së ndjekuri", "account.unmute": "Ktheji zërin @{name}", "account.unmute_notifications": "Hiqua ndalimin e shfaqjes njoftimeve nga @{name}", - "account.unmute_short": "Unmute", + "account.unmute_short": "Çheshtoje", "account_note.placeholder": "Klikoni për të shtuar shënim", "admin.dashboard.daily_retention": "Shkallë mbajtjeje përdoruesi, në ditë, pas regjistrimit", "admin.dashboard.monthly_retention": "Shkallë mbajtjeje përdoruesi, në muaj, pas regjistrimit", @@ -294,7 +294,7 @@ "navigation_bar.discover": "Zbuloni", "navigation_bar.domain_blocks": "Përkatësi të bllokuara", "navigation_bar.edit_profile": "Përpunoni profilin", - "navigation_bar.explore": "Explore", + "navigation_bar.explore": "Eksploroni", "navigation_bar.favourites": "Të parapëlqyer", "navigation_bar.filters": "Fjalë të heshtuara", "navigation_bar.follow_requests": "Kërkesa për ndjekje", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index f7eddd11b..f8477e8fd 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -128,7 +128,7 @@ "confirmations.logout.confirm": "ออกจากระบบ", "confirmations.logout.message": "คุณแน่ใจหรือไม่ว่าต้องการออกจากระบบ?", "confirmations.mute.confirm": "ซ่อน", - "confirmations.mute.explanation": "นี่จะซ่อนโพสต์จากเขาและโพสต์ที่กล่าวถึงเขา แต่จะยังอนุญาตให้เขาเห็นโพสต์ของคุณและติดตามคุณ", + "confirmations.mute.explanation": "นี่จะซ่อนโพสต์จากเขาและโพสต์ที่กล่าวถึงเขา แต่จะยังคงอนุญาตให้เขาเห็นโพสต์ของคุณและติดตามคุณ", "confirmations.mute.message": "คุณแน่ใจหรือไม่ว่าต้องการซ่อน {name}?", "confirmations.redraft.confirm": "ลบแล้วร่างใหม่", "confirmations.redraft.message": "คุณแน่ใจหรือไม่ว่าต้องการลบโพสต์นี้แล้วร่างโพสต์ใหม่? รายการโปรดและการดันจะหายไป และการตอบกลับโพสต์ดั้งเดิมจะไม่มีความเกี่ยวพัน", @@ -403,7 +403,7 @@ "report.forward": "ส่งต่อไปยัง {target}", "report.forward_hint": "บัญชีมาจากเซิร์ฟเวอร์อื่น ส่งสำเนาของรายงานที่ไม่ระบุตัวตนไปที่นั่นด้วย?", "report.mute": "ซ่อน", - "report.mute_explanation": "คุณจะไม่เห็นโพสต์ของเขา เขายังสามารถติดตามคุณและเห็นโพสต์ของคุณและจะไม่ทราบว่ามีการซ่อนเขา", + "report.mute_explanation": "คุณจะไม่เห็นโพสต์ของเขา เขายังคงสามารถติดตามคุณและเห็นโพสต์ของคุณและจะไม่ทราบว่ามีการซ่อนเขา", "report.next": "ถัดไป", "report.placeholder": "ความคิดเห็นเพิ่มเติม", "report.reasons.dislike": "ฉันไม่ชอบโพสต์", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 06bb94307..e2e1386e6 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -18,7 +18,7 @@ "account.followers": "Підписники", "account.followers.empty": "Ніхто ще не підписався на цього користувача.", "account.followers_counter": "{count, plural, one {{counter} Підписник} few {{counter} Підписники} many {{counter} Підписників} other {{counter} Підписники}}", - "account.following": "Following", + "account.following": "Стежите", "account.following_counter": "{count, plural, one {{counter} Підписка} few {{counter} Підписки} many {{counter} Підписок} other {{counter} Підписки}}", "account.follows.empty": "Цей користувач ще ні на кого не підписався.", "account.follows_you": "Підписаний(-а) на вас", @@ -41,7 +41,7 @@ "account.statuses_counter": "{count, plural, one {{counter} Пост} few {{counter} Пости} many {{counter} Постів} other {{counter} Пости}}", "account.unblock": "Розблокувати @{name}", "account.unblock_domain": "Розблокувати {domain}", - "account.unblock_short": "Unblock", + "account.unblock_short": "Розблокувати", "account.unendorse": "Не публікувати у профілі", "account.unfollow": "Відписатися", "account.unmute": "Зняти глушення з @{name}", @@ -187,7 +187,7 @@ "error.unexpected_crash.next_steps_addons": "Спробуйте їх вимкнути та оновити сторінку. Якщо це не допомагає, ви можете використовувати Mastodon через інший браузер або окремий застосунок.", "errors.unexpected_crash.copy_stacktrace": "Скопіювати трасування стека у буфер обміну", "errors.unexpected_crash.report_issue": "Повідомити про проблему", - "explore.search_results": "Search results", + "explore.search_results": "Результати пошуку", "explore.suggested_follows": "Для вас", "explore.title": "Огляд", "explore.trending_links": "Новини", @@ -309,7 +309,7 @@ "navigation_bar.preferences": "Налаштування", "navigation_bar.public_timeline": "Глобальна стрічка", "navigation_bar.security": "Безпека", - "notification.admin.sign_up": "{name} signed up", + "notification.admin.sign_up": "{name} приєднується", "notification.favourite": "{name} вподобав(-ла) ваш допис", "notification.follow": "{name} підписався(-лась) на вас", "notification.follow_request": "{name} відправив(-ла) запит на підписку", @@ -321,7 +321,7 @@ "notification.update": "{name} змінює допис", "notifications.clear": "Очистити сповіщення", "notifications.clear_confirmation": "Ви впевнені, що хочете назавжди видалити всі сповіщеня?", - "notifications.column_settings.admin.sign_up": "New sign-ups:", + "notifications.column_settings.admin.sign_up": "Нові реєстрації:", "notifications.column_settings.alert": "Сповіщення на комп'ютері", "notifications.column_settings.favourite": "Вподобане:", "notifications.column_settings.filter_bar.advanced": "Показати всі категорії", @@ -389,7 +389,7 @@ "relative_time.seconds": "{number}с", "relative_time.today": "сьогодні", "reply_indicator.cancel": "Відмінити", - "report.block": "Block", + "report.block": "Заблокувати", "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.", "report.categories.other": "Інше", "report.categories.spam": "Спам", @@ -402,7 +402,7 @@ "report.comment.title": "Is there anything else you think we should know?", "report.forward": "Надіслати до {target}", "report.forward_hint": "Це акаунт з іншого серверу. Відправити анонімізовану копію скарги і туди?", - "report.mute": "Mute", + "report.mute": "Заглушити", "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.", "report.next": "Далі", "report.placeholder": "Додаткові коментарі", @@ -415,8 +415,8 @@ "report.reasons.violation": "It violates server rules", "report.reasons.violation_description": "You are aware that it breaks specific rules", "report.rules.subtitle": "Select all that apply", - "report.rules.title": "Which rules are being violated?", - "report.statuses.subtitle": "Select all that apply", + "report.rules.title": "Які правила порушено?", + "report.statuses.subtitle": "Виберіть усі варіанти, що підходять", "report.statuses.title": "Are there any posts that back up this report?", "report.submit": "Відправити", "report.target": "Скаржимося на {target}", @@ -424,7 +424,7 @@ "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:", "report.thanks.title": "Don't want to see this?", "report.thanks.title_actionable": "Thanks for reporting, we'll look into this.", - "report.unfollow": "Unfollow @{name}", + "report.unfollow": "Відписатися від @{name}", "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.", "search.placeholder": "Пошук", "search_popout.search_format": "Розширений формат пошуку", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index b6db3c14b..d47033881 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -8,7 +8,7 @@ "account.blocked": "Đã chặn", "account.browse_more_on_origin_server": "Truy cập trang của người này", "account.cancel_follow_request": "Hủy yêu cầu theo dõi", - "account.direct": "Nhắn tin @{name}", + "account.direct": "Nhắn riêng @{name}", "account.disable_notifications": "Không thông báo khi @{name} đăng tút", "account.domain_blocked": "Người đã chặn", "account.edit_profile": "Chỉnh sửa trang cá nhân", @@ -49,9 +49,9 @@ "account.unmute_short": "Bỏ ẩn", "account_note.placeholder": "Nhấn để thêm", "admin.dashboard.daily_retention": "Tỉ lệ người dùng sau đăng ký ở lại theo ngày", - "admin.dashboard.monthly_retention": "Tỉ lệ người dùng sau đăng ký ở lại theo tháng", + "admin.dashboard.monthly_retention": "Tỉ lệ người dùng ở lại sau khi đăng ký", "admin.dashboard.retention.average": "Trung bình", - "admin.dashboard.retention.cohort": "Đăng ký tháng", + "admin.dashboard.retention.cohort": "Tháng đăng ký", "admin.dashboard.retention.cohort_size": "Người dùng mới", "alert.rate_limited.message": "Vui lòng thử lại sau {retry_time, time, medium}.", "alert.rate_limited.title": "Vượt giới hạn", @@ -179,7 +179,7 @@ "empty_column.list": "Chưa có tút. Khi những người trong danh sách này đăng tút mới, chúng sẽ xuất hiện ở đây.", "empty_column.lists": "Bạn chưa tạo danh sách nào.", "empty_column.mutes": "Bạn chưa ẩn bất kỳ ai.", - "empty_column.notifications": "Bạn chưa có thông báo nào. Hãy thử theo dõi hoặc nhắn tin cho một ai đó.", + "empty_column.notifications": "Bạn chưa có thông báo nào. Hãy thử theo dõi hoặc nhắn riêng cho một ai đó.", "empty_column.public": "Trống trơn! Bạn hãy viết gì đó hoặc bắt đầu theo dõi những người khác", "error.unexpected_crash.explanation": "Trang này có thể không hiển thị chính xác do lỗi lập trình Mastodon hoặc vấn đề tương thích trình duyệt.", "error.unexpected_crash.explanation_addons": "Trang này không thể hiển thị do xung khắc với add-on của trình duyệt hoặc công cụ tự động dịch ngôn ngữ.", @@ -188,7 +188,7 @@ "errors.unexpected_crash.copy_stacktrace": "Sao chép stacktrace vào clipboard", "errors.unexpected_crash.report_issue": "Báo cáo lỗi", "explore.search_results": "Kết quả tìm kiếm", - "explore.suggested_follows": "Đề xuất cho bạn", + "explore.suggested_follows": "Dành cho bạn", "explore.title": "Khám phá", "explore.trending_links": "Tin tức", "explore.trending_statuses": "Tút", @@ -294,7 +294,7 @@ "navigation_bar.discover": "Khám phá", "navigation_bar.domain_blocks": "Máy chủ đã ẩn", "navigation_bar.edit_profile": "Trang cá nhân", - "navigation_bar.explore": "Khám phá", + "navigation_bar.explore": "Xu hướng", "navigation_bar.favourites": "Thích", "navigation_bar.filters": "Bộ lọc từ ngữ", "navigation_bar.follow_requests": "Yêu cầu theo dõi", @@ -309,7 +309,7 @@ "navigation_bar.preferences": "Cài đặt", "navigation_bar.public_timeline": "Thế giới", "navigation_bar.security": "Bảo mật", - "notification.admin.sign_up": "{name} vừa đăng ký", + "notification.admin.sign_up": "{name} đăng ký máy chủ của bạn", "notification.favourite": "{name} thích tút của bạn", "notification.follow": "{name} theo dõi bạn", "notification.follow_request": "{name} yêu cầu theo dõi bạn", @@ -367,7 +367,7 @@ "poll_button.remove_poll": "Hủy cuộc bình chọn", "privacy.change": "Thay đổi quyền riêng tư", "privacy.direct.long": "Chỉ người được nhắc đến mới thấy", - "privacy.direct.short": "Tin nhắn", + "privacy.direct.short": "Nhắn riêng", "privacy.private.long": "Dành riêng cho người theo dõi", "privacy.private.short": "Riêng tư", "privacy.public.long": "Hiện trên bảng tin máy chủ", @@ -449,7 +449,7 @@ "status.copy": "Sao chép URL", "status.delete": "Xóa", "status.detailed_status": "Xem chi tiết thêm", - "status.direct": "Nhắn tin @{name}", + "status.direct": "Nhắn riêng @{name}", "status.edit": "Sửa", "status.edited": "Đã sửa {date}", "status.edited_x_times": "Đã sửa {count, plural, other {{count} lần}}", @@ -483,7 +483,7 @@ "status.show_less_all": "Thu gọn toàn bộ", "status.show_more": "Xem thêm", "status.show_more_all": "Hiển thị tất cả", - "status.show_thread": "Toàn chủ đề", + "status.show_thread": "Xem chuỗi tút này", "status.uncached_media_warning": "Uncached", "status.unmute_conversation": "Quan tâm", "status.unpin": "Bỏ ghim trên trang cá nhân", diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index 40cd899b3..27be22f1b 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -1322,7 +1322,7 @@ a.sparkline { width: 50px; height: 21px; position: absolute; - bottom: 8px; + bottom: 0; right: 15px; background: linear-gradient(to left, $ui-base-color, transparent); pointer-events: none; diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 295b0ddfb..442ffd2c0 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -596,30 +596,24 @@ display: flex; align-items: flex-start; justify-content: space-between; - opacity: 0; - transition: opacity .1s ease; + } - .icon-button { - flex: 0 1 auto; - color: $secondary-text-color; - font-size: 14px; - font-weight: 500; - padding: 10px; - font-family: inherit; - - &:hover, - &:focus, - &:active { - color: lighten($secondary-text-color, 7%); - } - } + .icon-button { + flex: 0 1 auto; + color: $secondary-text-color; + font-size: 14px; + font-weight: 500; + padding: 10px; + font-family: inherit; - &.active { - opacity: 1; + &:hover, + &:focus, + &:active { + color: lighten($secondary-text-color, 7%); } } - &-description { + &__warning { position: absolute; z-index: 2; bottom: 0; @@ -627,34 +621,6 @@ right: 0; box-sizing: border-box; background: linear-gradient(0deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 80%, transparent); - padding: 10px; - opacity: 0; - transition: opacity .1s ease; - - textarea { - background: transparent; - color: $secondary-text-color; - border: 0; - padding: 0; - margin: 0; - width: 100%; - font-family: inherit; - font-size: 14px; - font-weight: 500; - - &:focus { - color: $white; - } - - &::placeholder { - opacity: 0.75; - color: $secondary-text-color; - } - } - - &.active { - opacity: 1; - } } } @@ -870,7 +836,8 @@ .status__content__spoiler-link { background: $action-button-color; - &:hover { + &:hover, + &:focus { background: lighten($action-button-color, 7%); text-decoration: none; } @@ -982,7 +949,7 @@ text-transform: uppercase; line-height: 20px; cursor: pointer; - vertical-align: middle; + vertical-align: top; } .status__wrapper--filtered { @@ -1072,7 +1039,8 @@ color: $primary-text-color; background: $ui-primary-color; - &:hover { + &:hover, + &:focus { background: lighten($ui-primary-color, 8%); } } @@ -1646,7 +1614,8 @@ a.account__display-name { background: $ui-base-lighter-color; color: $inverted-text-color; - &:hover { + &:hover, + &:focus { background: lighten($ui-base-lighter-color, 7%); text-decoration: none; } @@ -5158,6 +5127,15 @@ a.status-card.compact:hover { color: $inverted-text-color; } + .status__content__spoiler-link { + color: $primary-text-color; + background: $ui-primary-color; + + &:hover { + background: lighten($ui-primary-color, 8%); + } + } + .dialog-option .poll__input { border-color: $inverted-text-color; color: $ui-secondary-color; diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index cf31b6ff6..1ac509f18 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ActivityPub::Activity::Create < ActivityPub::Activity + include FormattingHelper + def perform dereference_object! @@ -367,7 +369,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity end def converted_text - Formatter.instance.linkify([@status_parser.title.presence, @status_parser.spoiler_text.presence, @status_parser.url || @status_parser.uri].compact.join("\n\n")) + linkify([@status_parser.title.presence, @status_parser.spoiler_text.presence, @status_parser.url || @status_parser.uri].compact.join("\n\n")) end def unsupported_media_type?(mime_type) diff --git a/app/lib/activitypub/parser/media_attachment_parser.rb b/app/lib/activitypub/parser/media_attachment_parser.rb index 1798e58a4..30bea1f0e 100644 --- a/app/lib/activitypub/parser/media_attachment_parser.rb +++ b/app/lib/activitypub/parser/media_attachment_parser.rb @@ -27,7 +27,9 @@ class ActivityPub::Parser::MediaAttachmentParser end def description - @json['summary'].presence || @json['name'].presence + str = @json['summary'].presence || @json['name'].presence + str = str.strip[0...MediaAttachment::MAX_DESCRIPTION_LENGTH] if str.present? + str end def focus diff --git a/app/lib/admin/system_check.rb b/app/lib/admin/system_check.rb index afb20cb47..877a42ef6 100644 --- a/app/lib/admin/system_check.rb +++ b/app/lib/admin/system_check.rb @@ -5,6 +5,7 @@ class Admin::SystemCheck Admin::SystemCheck::DatabaseSchemaCheck, Admin::SystemCheck::SidekiqProcessCheck, Admin::SystemCheck::RulesCheck, + Admin::SystemCheck::ElasticsearchCheck, ].freeze def self.perform diff --git a/app/lib/admin/system_check/elasticsearch_check.rb b/app/lib/admin/system_check/elasticsearch_check.rb new file mode 100644 index 000000000..1b48a5415 --- /dev/null +++ b/app/lib/admin/system_check/elasticsearch_check.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +class Admin::SystemCheck::ElasticsearchCheck < Admin::SystemCheck::BaseCheck + def pass? + return true unless Chewy.enabled? + + running_version.present? && compatible_version? + end + + def message + if running_version.present? + Admin::SystemCheck::Message.new(:elasticsearch_version_check, I18n.t('admin.system_checks.elasticsearch_version_check.version_comparison', running_version: running_version, required_version: required_version)) + else + Admin::SystemCheck::Message.new(:elasticsearch_running_check) + end + end + + private + + def running_version + @running_version ||= begin + Chewy.client.info['version']['number'] + rescue Faraday::ConnectionFailed + nil + end + end + + def required_version + '7.x' + end + + def compatible_version? + Gem::Version.new(running_version) >= Gem::Version.new(required_version) + end + + def missing_queues + @missing_queues ||= Sidekiq::ProcessSet.new.reduce(SIDEKIQ_QUEUES) { |queues, process| queues - process['queues'] } + end +end diff --git a/app/lib/advanced_text_formatter.rb b/app/lib/advanced_text_formatter.rb new file mode 100644 index 000000000..728400819 --- /dev/null +++ b/app/lib/advanced_text_formatter.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +class AdvancedTextFormatter < TextFormatter + class HTMLRenderer < Redcarpet::Render::HTML + def initialize(options, &block) + super(options) + @format_link = block + end + + def block_code(code, _language) + <<~HTML.squish + <pre><code>#{ERB::Util.h(code).gsub("\n", '<br/>')}</code></pre> + HTML + end + + def autolink(link, link_type) + return link if link_type == :email + @format_link.call(link) + end + end + + # @param [String] text + # @param [Hash] options + # @option options [Boolean] :multiline + # @option options [Boolean] :with_domains + # @option options [Boolean] :with_rel_me + # @option options [Array<Account>] :preloaded_accounts + # @option options [String] :content_type + def initialize(text, options = {}) + content_type = options.delete(:content_type) + super(text, options) + + @text = format_markdown(text) if content_type == 'text/markdown' + end + + # Differs from TextFormatter by not messing with newline after parsing + def to_s + return ''.html_safe if text.blank? + + html = rewrite do |entity| + if entity[:url] + link_to_url(entity) + elsif entity[:hashtag] + link_to_hashtag(entity) + elsif entity[:screen_name] + link_to_mention(entity) + end + end + + html.html_safe # rubocop:disable Rails/OutputSafety + end + + # Differs from `TextFormatter` by skipping HTML tags and entities + def entities + @entities ||= begin + gaps = [] + total_offset = 0 + + escaped = text.gsub(/<[^>]*>|&#[0-9]+;/) do |match| + total_offset += match.length - 1 + end_offset = Regexp.last_match.end(0) + gaps << [end_offset - total_offset, total_offset] + ' ' + end + + Extractor.extract_entities_with_indices(escaped, extract_url_without_protocol: false).map do |entity| + start_pos, end_pos = entity[:indices] + offset_idx = gaps.rindex { |gap| gap.first <= start_pos } + offset = offset_idx.nil? ? 0 : gaps[offset_idx].last + entity.merge(indices: [start_pos + offset, end_pos + offset]) + end + end + end + + private + + # Differs from `TextFormatter` in that it keeps HTML; but it sanitizes at the end to remain safe + def rewrite + entities.sort_by! do |entity| + entity[:indices].first + end + + result = ''.dup + + last_index = entities.reduce(0) do |index, entity| + indices = entity[:indices] + result << text[index...indices.first] + result << yield(entity) + indices.last + end + + result << text[last_index..-1] + + Sanitize.fragment(result, Sanitize::Config::MASTODON_OUTGOING) + end + + def format_markdown(html) + html = markdown_formatter.render(html) + html.delete("\r").delete("\n") + end + + def markdown_formatter + extensions = { + autolink: true, + no_intra_emphasis: true, + fenced_code_blocks: true, + disable_indented_code_blocks: true, + strikethrough: true, + lax_spacing: true, + space_after_headers: true, + superscript: true, + underline: true, + highlight: true, + footnotes: false, + } + + renderer = HTMLRenderer.new({ + filter_html: false, + escape_html: false, + no_images: true, + no_styles: true, + safe_links_only: true, + hard_wrap: true, + link_attributes: { target: '_blank', rel: 'nofollow noopener' }, + }) do |url| + link_to_url({ url: url }) + end + + Redcarpet::Markdown.new(renderer, extensions) + end +end diff --git a/app/lib/emoji_formatter.rb b/app/lib/emoji_formatter.rb new file mode 100644 index 000000000..f808f3a22 --- /dev/null +++ b/app/lib/emoji_formatter.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +class EmojiFormatter + include RoutingHelper + + DISALLOWED_BOUNDING_REGEX = /[[:alnum:]:]/.freeze + + attr_reader :html, :custom_emojis, :options + + # @param [ActiveSupport::SafeBuffer] html + # @param [Array<CustomEmoji>] custom_emojis + # @param [Hash] options + # @option options [Boolean] :animate + def initialize(html, custom_emojis, options = {}) + raise ArgumentError unless html.html_safe? + + @html = html + @custom_emojis = custom_emojis + @options = options + end + + def to_s + return html if custom_emojis.empty? || html.blank? + + i = -1 + tag_open_index = nil + inside_shortname = false + shortname_start_index = -1 + invisible_depth = 0 + last_index = 0 + result = ''.dup + + while i + 1 < html.size + i += 1 + + if invisible_depth.zero? && inside_shortname && html[i] == ':' + inside_shortname = false + shortcode = html[shortname_start_index + 1..i - 1] + char_after = html[i + 1] + + next unless (char_after.nil? || !DISALLOWED_BOUNDING_REGEX.match?(char_after)) && (emoji = emoji_map[shortcode]) + + result << html[last_index..shortname_start_index - 1] if shortname_start_index.positive? + result << image_for_emoji(shortcode, emoji) + last_index = i + 1 + elsif tag_open_index && html[i] == '>' + tag = html[tag_open_index..i] + tag_open_index = nil + + if invisible_depth.positive? + invisible_depth += count_tag_nesting(tag) + elsif tag == '<span class="invisible">' + invisible_depth = 1 + end + elsif html[i] == '<' + tag_open_index = i + inside_shortname = false + elsif !tag_open_index && html[i] == ':' && (i.zero? || !DISALLOWED_BOUNDING_REGEX.match?(html[i - 1])) + inside_shortname = true + shortname_start_index = i + end + end + + result << html[last_index..-1] + + result.html_safe # rubocop:disable Rails/OutputSafety + end + + private + + def emoji_map + @emoji_map ||= custom_emojis.each_with_object({}) { |e, h| h[e.shortcode] = [full_asset_url(e.image.url), full_asset_url(e.image.url(:static))] } + end + + def count_tag_nesting(tag) + if tag[1] == '/' + -1 + elsif tag[-2] == '/' + 0 + else + 1 + end + end + + def image_for_emoji(shortcode, emoji) + original_url, static_url = emoji + + if animate? + image_tag(original_url, draggable: false, class: 'emojione', alt: ":#{shortcode}:", title: ":#{shortcode}:") + else + image_tag(original_url, draggable: false, class: 'emojione custom-emoji', alt: ":#{shortcode}:", title: ":#{shortcode}:", data: { original: original_url, static: static_url }) + end + end + + def animate? + @options[:animate] + end +end diff --git a/app/lib/extractor.rb b/app/lib/extractor.rb index 8020aa916..aea60dae5 100644 --- a/app/lib/extractor.rb +++ b/app/lib/extractor.rb @@ -1,22 +1,44 @@ # frozen_string_literal: true module Extractor + MAX_DOMAIN_LENGTH = 253 + extend Twitter::TwitterText::Extractor module_function - # :yields: username, list_slug, start, end + def extract_entities_with_indices(text, options = {}, &block) + entities = begin + extract_urls_with_indices(text, options) + + extract_hashtags_with_indices(text, check_url_overlap: false) + + extract_mentions_or_lists_with_indices(text) + + extract_extra_uris_with_indices(text) + end + + return [] if entities.empty? + + entities = remove_overlapping_entities(entities) + entities.each(&block) if block_given? + entities + end + def extract_mentions_or_lists_with_indices(text) - return [] unless Twitter::TwitterText::Regex[:at_signs].match?(text) + return [] unless text && Twitter::TwitterText::Regex[:at_signs].match?(text) possible_entries = [] - text.to_s.scan(Account::MENTION_RE) do |screen_name, _| + text.scan(Account::MENTION_RE) do |screen_name, _| match_data = $LAST_MATCH_INFO - after = $' + after = $' + unless Twitter::TwitterText::Regex[:end_mention_match].match?(after) + _, domain = screen_name.split('@') + + next if domain.present? && domain.length > MAX_DOMAIN_LENGTH + start_position = match_data.char_begin(1) - 1 - end_position = match_data.char_end(1) + end_position = match_data.char_end(1) + possible_entries << { screen_name: screen_name, indices: [start_position, end_position], @@ -29,36 +51,70 @@ module Extractor yield mention[:screen_name], mention[:indices].first, mention[:indices].last end end + possible_entries end - def extract_hashtags_with_indices(text, **) - return [] unless /#/.match?(text) + def extract_hashtags_with_indices(text, _options = {}) + return [] unless text&.index('#') + + possible_entries = [] - tags = [] text.scan(Tag::HASHTAG_RE) do |hash_text, _| - match_data = $LAST_MATCH_INFO + match_data = $LAST_MATCH_INFO start_position = match_data.char_begin(1) - 1 - end_position = match_data.char_end(1) - after = $' + end_position = match_data.char_end(1) + after = $' + if %r{\A://}.match?(after) hash_text.match(/(.+)(https?\Z)/) do |matched| - hash_text = matched[1] + hash_text = matched[1] end_position -= matched[2].codepoint_length end end - tags << { + possible_entries << { hashtag: hash_text, indices: [start_position, end_position], } end - tags.each { |tag| yield tag[:hashtag], tag[:indices].first, tag[:indices].last } if block_given? - tags + if block_given? + possible_entries.each do |tag| + yield tag[:hashtag], tag[:indices].first, tag[:indices].last + end + end + + possible_entries end def extract_cashtags_with_indices(_text) - [] # always returns empty array + [] + end + + def extract_extra_uris_with_indices(text) + return [] unless text&.index(':') + + possible_entries = [] + + text.scan(Twitter::TwitterText::Regex[:valid_extended_uri]) do + valid_uri_match_data = $LAST_MATCH_INFO + + start_position = valid_uri_match_data.char_begin(3) + end_position = valid_uri_match_data.char_end(3) + + possible_entries << { + url: valid_uri_match_data[3], + indices: [start_position, end_position], + } + end + + if block_given? + possible_entries.each do |url| + yield url[:url], url[:indices].first, url[:indices].last + end + end + + possible_entries end end diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index efc9da34b..6994f00ae 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -5,6 +5,7 @@ require 'singleton' class FeedManager include Singleton include Redisable + include FormattingHelper # Maximum number of items stored in a single feed MAX_ITEMS = 400 @@ -503,7 +504,7 @@ class FeedManager status = status.reblog if status.reblog? combined_text = [ - Formatter.instance.plaintext(status), + extract_status_plain_text(status), status.spoiler_text, status.preloadable_poll ? status.preloadable_poll.options.join("\n\n") : nil, status.ordered_media_attachments.map(&:description).join("\n\n"), diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb deleted file mode 100644 index dfa493ed5..000000000 --- a/app/lib/formatter.rb +++ /dev/null @@ -1,382 +0,0 @@ -# frozen_string_literal: true - -require 'singleton' - -class HTMLRenderer < Redcarpet::Render::HTML - def block_code(code, language) - "<pre><code>#{encode(code).gsub("\n", "<br/>")}</code></pre>" - end - - def autolink(link, link_type) - return link if link_type == :email - Formatter.instance.link_url(link) - rescue Addressable::URI::InvalidURIError, IDN::Idna::IdnaError - encode(link) - end - - private - - def html_entities - @html_entities ||= HTMLEntities.new - end - - def encode(html) - html_entities.encode(html) - end -end - -class Formatter - include Singleton - include RoutingHelper - - include ActionView::Helpers::TextHelper - - def format(status, **options) - if status.respond_to?(:reblog?) && status.reblog? - prepend_reblog = status.reblog.account.acct - status = status.proper - else - prepend_reblog = false - end - - raw_content = status.text - - if options[:inline_poll_options] && status.preloadable_poll - raw_content = raw_content + "\n\n" + status.preloadable_poll.options.map { |title| "[ ] #{title}" }.join("\n") - end - - return '' if raw_content.blank? - - unless status.local? - html = reformat(raw_content) - html = encode_custom_emojis(html, status.emojis, options[:autoplay]) if options[:custom_emojify] - return html.html_safe # rubocop:disable Rails/OutputSafety - end - - linkable_accounts = status.respond_to?(:active_mentions) ? status.active_mentions.map(&:account) : [] - linkable_accounts << status.account - - html = raw_content - html = "RT @#{prepend_reblog} #{html}" if prepend_reblog - html = format_markdown(html) if status.content_type == 'text/markdown' - html = encode_and_link_urls(html, linkable_accounts, keep_html: %w(text/markdown text/html).include?(status.content_type)) - html = reformat(html, true) if %w(text/markdown text/html).include?(status.content_type) - html = encode_custom_emojis(html, status.emojis, options[:autoplay]) if options[:custom_emojify] - - unless %w(text/markdown text/html).include?(status.content_type) - html = simple_format(html, {}, sanitize: false) - html = html.delete("\n") - end - - html.html_safe # rubocop:disable Rails/OutputSafety - end - - def format_markdown(html) - html = markdown_formatter.render(html) - html.delete("\r").delete("\n") - end - - def reformat(html, outgoing = false) - sanitize(html, Sanitize::Config::MASTODON_STRICT.merge(outgoing: outgoing)) - rescue ArgumentError - '' - end - - def plaintext(status) - return status.text if status.local? - - text = status.text.gsub(/(<br \/>|<br>|<\/p>)+/) { |match| "#{match}\n" } - strip_tags(text) - end - - def simplified_format(account, **options) - return '' if account.note.blank? - - html = account.local? ? linkify(account.note) : reformat(account.note) - html = encode_custom_emojis(html, account.emojis, options[:autoplay]) if options[:custom_emojify] - html.html_safe # rubocop:disable Rails/OutputSafety - end - - def sanitize(html, config) - Sanitize.fragment(html, config) - end - - def format_spoiler(status, **options) - html = encode(status.spoiler_text) - html = encode_custom_emojis(html, status.emojis, options[:autoplay]) - html.html_safe # rubocop:disable Rails/OutputSafety - end - - def format_poll_option(status, option, **options) - html = encode(option.title) - html = encode_custom_emojis(html, status.emojis, options[:autoplay]) - html.html_safe # rubocop:disable Rails/OutputSafety - end - - def format_display_name(account, **options) - html = encode(account.display_name.presence || account.username) - html = encode_custom_emojis(html, account.emojis, options[:autoplay]) if options[:custom_emojify] - html.html_safe # rubocop:disable Rails/OutputSafety - end - - def format_field(account, str, **options) - html = account.local? ? encode_and_link_urls(str, me: true, with_domain: true) : reformat(str) - html = encode_custom_emojis(html, account.emojis, options[:autoplay]) if options[:custom_emojify] - html.html_safe # rubocop:disable Rails/OutputSafety - end - - def linkify(text) - html = encode_and_link_urls(text) - html = simple_format(html, {}, sanitize: false) - html = html.delete("\n") - - html.html_safe # rubocop:disable Rails/OutputSafety - end - - def link_url(url) - "<a href=\"#{encode(url)}\" target=\"blank\" rel=\"nofollow noopener noreferrer\">#{link_html(url)}</a>" - end - - private - - def markdown_formatter - extensions = { - autolink: true, - no_intra_emphasis: true, - fenced_code_blocks: true, - disable_indented_code_blocks: true, - strikethrough: true, - lax_spacing: true, - space_after_headers: true, - superscript: true, - underline: true, - highlight: true, - footnotes: false, - } - - renderer = HTMLRenderer.new({ - filter_html: false, - escape_html: false, - no_images: true, - no_styles: true, - safe_links_only: true, - hard_wrap: true, - link_attributes: { target: '_blank', rel: 'nofollow noopener' }, - }) - - Redcarpet::Markdown.new(renderer, extensions) - end - - def html_entities - @html_entities ||= HTMLEntities.new - end - - def encode(html) - html_entities.encode(html) - end - - def encode_and_link_urls(html, accounts = nil, options = {}) - if accounts.is_a?(Hash) - options = accounts - accounts = nil - end - - entities = options[:keep_html] ? html_friendly_extractor(html) : utf8_friendly_extractor(html, extract_url_without_protocol: false) - - rewrite(html.dup, entities, options[:keep_html]) do |entity| - if entity[:url] - link_to_url(entity, options) - elsif entity[:hashtag] - link_to_hashtag(entity) - elsif entity[:screen_name] - link_to_mention(entity, accounts, options) - end - end - end - - def count_tag_nesting(tag) - if tag[1] == '/' then -1 - elsif tag[-2] == '/' then 0 - else 1 - end - end - - # rubocop:disable Metrics/BlockNesting - def encode_custom_emojis(html, emojis, animate = false) - return html if emojis.empty? - - emoji_map = emojis.each_with_object({}) { |e, h| h[e.shortcode] = [full_asset_url(e.image.url), full_asset_url(e.image.url(:static))] } - - i = -1 - tag_open_index = nil - inside_shortname = false - shortname_start_index = -1 - invisible_depth = 0 - - while i + 1 < html.size - i += 1 - - if invisible_depth.zero? && inside_shortname && html[i] == ':' - shortcode = html[shortname_start_index + 1..i - 1] - emoji = emoji_map[shortcode] - - if emoji - original_url, static_url = emoji - replacement = begin - if animate - image_tag(original_url, draggable: false, class: 'emojione', alt: ":#{shortcode}:", title: ":#{shortcode}:") - else - image_tag(original_url, draggable: false, class: 'emojione custom-emoji', alt: ":#{shortcode}:", title: ":#{shortcode}:", data: { original: original_url, static: static_url }) - end - end - before_html = shortname_start_index.positive? ? html[0..shortname_start_index - 1] : '' - html = before_html + replacement + html[i + 1..-1] - i += replacement.size - (shortcode.size + 2) - 1 - else - i -= 1 - end - - inside_shortname = false - elsif tag_open_index && html[i] == '>' - tag = html[tag_open_index..i] - tag_open_index = nil - if invisible_depth.positive? - invisible_depth += count_tag_nesting(tag) - elsif tag == '<span class="invisible">' - invisible_depth = 1 - end - elsif html[i] == '<' - tag_open_index = i - inside_shortname = false - elsif !tag_open_index && html[i] == ':' - inside_shortname = true - shortname_start_index = i - end - end - - html - end - # rubocop:enable Metrics/BlockNesting - - def rewrite(text, entities, keep_html = false) - text = text.to_s - - # Sort by start index - entities = entities.sort_by do |entity| - indices = entity.respond_to?(:indices) ? entity.indices : entity[:indices] - indices.first - end - - result = [] - - last_index = entities.reduce(0) do |index, entity| - indices = entity.respond_to?(:indices) ? entity.indices : entity[:indices] - result << (keep_html ? text[index...indices.first] : encode(text[index...indices.first])) - result << yield(entity) - indices.last - end - - result << (keep_html ? text[last_index..-1] : encode(text[last_index..-1])) - - result.flatten.join - end - - def utf8_friendly_extractor(text, options = {}) - # Note: I couldn't obtain list_slug with @user/list-name format - # for mention so this requires additional check - special = Extractor.extract_urls_with_indices(text, options) - standard = Extractor.extract_entities_with_indices(text, options) - extra = Extractor.extract_extra_uris_with_indices(text, options) - - Extractor.remove_overlapping_entities(special + standard + extra) - end - - def html_friendly_extractor(html, options = {}) - gaps = [] - total_offset = 0 - - escaped = html.gsub(/<[^>]*>|&#[0-9]+;/) do |match| - total_offset += match.length - 1 - end_offset = Regexp.last_match.end(0) - gaps << [end_offset - total_offset, total_offset] - "\u200b" - end - - entities = Extractor.extract_hashtags_with_indices(escaped, :check_url_overlap => false) + - Extractor.extract_mentions_or_lists_with_indices(escaped) - Extractor.remove_overlapping_entities(entities).map do |extract| - pos = extract[:indices].first - offset_idx = gaps.rindex { |gap| gap.first <= pos } - offset = offset_idx.nil? ? 0 : gaps[offset_idx].last - next extract.merge( - :indices => [extract[:indices].first + offset, extract[:indices].last + offset] - ) - end - end - - def link_to_url(entity, options = {}) - url = Addressable::URI.parse(entity[:url]) - html_attrs = { target: '_blank', rel: 'nofollow noopener noreferrer' } - - html_attrs[:rel] = "me #{html_attrs[:rel]}" if options[:me] - - Twitter::TwitterText::Autolink.send(:link_to_text, entity, link_html(entity[:url]), url, html_attrs) - rescue Addressable::URI::InvalidURIError, IDN::Idna::IdnaError - encode(entity[:url]) - end - - def link_to_mention(entity, linkable_accounts, options = {}) - acct = entity[:screen_name] - - return link_to_account(acct, options) unless linkable_accounts - - same_username_hits = 0 - account = nil - username, domain = acct.split('@') - domain = nil if TagManager.instance.local_domain?(domain) - - linkable_accounts.each do |item| - same_username = item.username.casecmp(username).zero? - same_domain = item.domain.nil? ? domain.nil? : item.domain.casecmp(domain)&.zero? - - if same_username && !same_domain - same_username_hits += 1 - elsif same_username && same_domain - account = item - end - end - - account ? mention_html(account, with_domain: same_username_hits.positive? || options[:with_domain]) : "@#{encode(acct)}" - end - - def link_to_account(acct, options = {}) - username, domain = acct.split('@') - - domain = nil if TagManager.instance.local_domain?(domain) - account = EntityCache.instance.mention(username, domain) - - account ? mention_html(account, with_domain: options[:with_domain]) : "@#{encode(acct)}" - end - - def link_to_hashtag(entity) - hashtag_html(entity[:hashtag]) - end - - def link_html(url) - url = Addressable::URI.parse(url).to_s - prefix = url.match(/\A(https?:\/\/(www\.)?|xmpp:)/).to_s - text = url[prefix.length, 30] - suffix = url[prefix.length + 30..-1] - cutoff = url[prefix.length..-1].length > 30 - - "<span class=\"invisible\">#{encode(prefix)}</span><span class=\"#{cutoff ? 'ellipsis' : ''}\">#{encode(text)}</span><span class=\"invisible\">#{encode(suffix)}</span>" - end - - def hashtag_html(tag) - "<a href=\"#{encode(tag_url(tag))}\" class=\"mention hashtag\" rel=\"tag\">#<span>#{encode(tag)}</span></a>" - end - - def mention_html(account, with_domain: false) - "<span class=\"h-card\"><a href=\"#{encode(ActivityPub::TagManager.instance.url_for(account))}\" class=\"u-url mention\">@<span>#{encode(with_domain ? account.pretty_acct : account.username)}</span></a></span>" - end -end diff --git a/app/lib/html_aware_formatter.rb b/app/lib/html_aware_formatter.rb new file mode 100644 index 000000000..7a1cd0340 --- /dev/null +++ b/app/lib/html_aware_formatter.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +class HtmlAwareFormatter + attr_reader :text, :local, :options + + alias local? local + + # @param [String] text + # @param [Boolean] local + # @param [Hash] options + def initialize(text, local, options = {}) + @text = text + @local = local + @options = options + end + + def to_s + return ''.html_safe if text.blank? + + if local? + linkify + else + reformat.html_safe # rubocop:disable Rails/OutputSafety + end + rescue ArgumentError + ''.html_safe + end + + private + + def reformat + Sanitize.fragment(text, Sanitize::Config::MASTODON_STRICT) + end + + def linkify + if %w(text/markdown text/html).include?(@options[:content_type]) + AdvancedTextFormatter.new(text, options).to_s + else + TextFormatter.new(text, options).to_s + end + end +end diff --git a/app/lib/link_details_extractor.rb b/app/lib/link_details_extractor.rb index fabbd244d..b0c4e4f42 100644 --- a/app/lib/link_details_extractor.rb +++ b/app/lib/link_details_extractor.rb @@ -208,7 +208,7 @@ class LinkDetailsExtractor end def valid_url_or_nil(str, same_origin_only: false) - return if str.blank? + return if str.blank? || str == 'null' url = @original_url + Addressable::URI.parse(str) diff --git a/app/lib/plain_text_formatter.rb b/app/lib/plain_text_formatter.rb new file mode 100644 index 000000000..08aa29696 --- /dev/null +++ b/app/lib/plain_text_formatter.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class PlainTextFormatter + include ActionView::Helpers::TextHelper + + NEWLINE_TAGS_RE = /(<br \/>|<br>|<\/p>)+/.freeze + + attr_reader :text, :local + + alias local? local + + def initialize(text, local) + @text = text + @local = local + end + + def to_s + if local? + text + else + strip_tags(insert_newlines).chomp + end + end + + private + + def insert_newlines + text.gsub(NEWLINE_TAGS_RE) { |match| "#{match}\n" } + end +end diff --git a/app/lib/rss/serializer.rb b/app/lib/rss/serializer.rb index 7e3ed1f17..d44e94221 100644 --- a/app/lib/rss/serializer.rb +++ b/app/lib/rss/serializer.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class RSS::Serializer + include FormattingHelper + private def render_statuses(builder, statuses) @@ -9,7 +11,7 @@ class RSS::Serializer item.title(status_title(status)) .link(ActivityPub::TagManager.instance.url_for(status)) .pub_date(status.created_at) - .description(status.spoiler_text.presence || Formatter.instance.format(status, inline_poll_options: true).to_str) + .description(status_description(status)) status.ordered_media_attachments.each do |media| item.enclosure(full_asset_url(media.file.url(:original, false)), media.file.content_type, media.file.size) @@ -19,9 +21,8 @@ class RSS::Serializer end def status_title(status) - return "#{status.account.acct} deleted status" if status.destroyed? - preview = status.proper.spoiler_text.presence || status.proper.text + if preview.length > 30 || preview[0, 30].include?("\n") preview = preview[0, 30] preview = preview[0, preview.index("\n").presence || 30] + '…' @@ -35,4 +36,20 @@ class RSS::Serializer "#{status.account.acct}: #{preview}" end end + + def status_description(status) + if status.proper.spoiler_text? + status.proper.spoiler_text + else + html = status_content_format(status.proper).to_str + after_html = '' + + if status.proper.preloadable_poll + poll_options_html = status.proper.preloadable_poll.options.map { |o| "[ ] #{o}" }.join('<br />') + after_html = "<p>#{poll_options_html}</p>" + end + + "#{html}#{after_html}" + end + end end diff --git a/app/lib/text_formatter.rb b/app/lib/text_formatter.rb new file mode 100644 index 000000000..48e2fc233 --- /dev/null +++ b/app/lib/text_formatter.rb @@ -0,0 +1,158 @@ +# frozen_string_literal: true + +class TextFormatter + include ActionView::Helpers::TextHelper + include ERB::Util + include RoutingHelper + + URL_PREFIX_REGEX = /\A(https?:\/\/(www\.)?|xmpp:)/.freeze + + DEFAULT_REL = %w(nofollow noopener noreferrer).freeze + + DEFAULT_OPTIONS = { + multiline: true, + }.freeze + + attr_reader :text, :options + + # @param [String] text + # @param [Hash] options + # @option options [Boolean] :multiline + # @option options [Boolean] :with_domains + # @option options [Boolean] :with_rel_me + # @option options [Array<Account>] :preloaded_accounts + def initialize(text, options = {}) + @text = text + @options = DEFAULT_OPTIONS.merge(options) + end + + def entities + @entities ||= Extractor.extract_entities_with_indices(text, extract_url_without_protocol: false) + end + + def to_s + return ''.html_safe if text.blank? + + html = rewrite do |entity| + if entity[:url] + link_to_url(entity) + elsif entity[:hashtag] + link_to_hashtag(entity) + elsif entity[:screen_name] + link_to_mention(entity) + end + end + + html = simple_format(html, {}, sanitize: false).delete("\n") if multiline? + + html.html_safe # rubocop:disable Rails/OutputSafety + end + + private + + def rewrite + entities.sort_by! do |entity| + entity[:indices].first + end + + result = ''.dup + + last_index = entities.reduce(0) do |index, entity| + indices = entity[:indices] + result << h(text[index...indices.first]) + result << yield(entity) + indices.last + end + + result << h(text[last_index..-1]) + + result + end + + def link_to_url(entity) + url = Addressable::URI.parse(entity[:url]).to_s + rel = with_rel_me? ? (DEFAULT_REL + %w(me)) : DEFAULT_REL + + prefix = url.match(URL_PREFIX_REGEX).to_s + display_url = url[prefix.length, 30] + suffix = url[prefix.length + 30..-1] + cutoff = url[prefix.length..-1].length > 30 + + <<~HTML.squish + <a href="#{h(url)}" target="_blank" rel="#{rel.join(' ')}"><span class="invisible">#{h(prefix)}</span><span class="#{cutoff ? 'ellipsis' : ''}">#{h(display_url)}</span><span class="invisible">#{h(suffix)}</span></a> + HTML + rescue Addressable::URI::InvalidURIError, IDN::Idna::IdnaError + h(entity[:url]) + end + + def link_to_hashtag(entity) + hashtag = entity[:hashtag] + url = tag_url(hashtag) + + <<~HTML.squish + <a href="#{h(url)}" class="mention hashtag" rel="tag">#<span>#{h(hashtag)}</span></a> + HTML + end + + def link_to_mention(entity) + username, domain = entity[:screen_name].split('@') + domain = nil if local_domain?(domain) + account = nil + + if preloaded_accounts? + same_username_hits = 0 + + preloaded_accounts.each do |other_account| + same_username = other_account.username.casecmp(username).zero? + same_domain = other_account.domain.nil? ? domain.nil? : other_account.domain.casecmp(domain)&.zero? + + if same_username && !same_domain + same_username_hits += 1 + elsif same_username && same_domain + account = other_account + end + end + else + account = entity_cache.mention(username, domain) + end + + return "@#{h(entity[:screen_name])}" if account.nil? + + url = ActivityPub::TagManager.instance.url_for(account) + display_username = same_username_hits&.positive? || with_domains? ? account.pretty_acct : account.username + + <<~HTML.squish + <span class="h-card"><a href="#{h(url)}" class="u-url mention">@<span>#{h(display_username)}</span></a></span> + HTML + end + + def entity_cache + @entity_cache ||= EntityCache.instance + end + + def tag_manager + @tag_manager ||= TagManager.instance + end + + delegate :local_domain?, to: :tag_manager + + def multiline? + options[:multiline] + end + + def with_domains? + options[:with_domains] + end + + def with_rel_me? + options[:with_rel_me] + end + + def preloaded_accounts + options[:preloaded_accounts] + end + + def preloaded_accounts? + preloaded_accounts.present? + end +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index cc585c3b7..a37682eca 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -5,6 +5,7 @@ class ApplicationMailer < ActionMailer::Base helper :application helper :instance + helper :formatting protected diff --git a/app/models/account.rb b/app/models/account.rb index dfbe0b8bc..1966c5a48 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -132,13 +132,13 @@ class Account < ApplicationRecord :approved?, :pending?, :disabled?, + :unconfirmed?, :unconfirmed_or_pending?, :role, :admin?, :moderator?, :staff?, :locale, - :hides_network?, :shows_application?, to: :user, prefix: true, diff --git a/app/models/account_filter.rb b/app/models/account_filter.rb index 9da1522dd..ec309ce09 100644 --- a/app/models/account_filter.rb +++ b/app/models/account_filter.rb @@ -80,6 +80,10 @@ class AccountFilter accounts_with_users.merge(User.pending) when 'suspended' Account.suspended + when 'disabled' + accounts_with_users.merge(User.disabled) + when 'silenced' + Account.silenced else raise "Unknown status: #{value}" end diff --git a/app/models/concerns/status_snapshot_concern.rb b/app/models/concerns/status_snapshot_concern.rb new file mode 100644 index 000000000..c728db7c3 --- /dev/null +++ b/app/models/concerns/status_snapshot_concern.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module StatusSnapshotConcern + extend ActiveSupport::Concern + + included do + has_many :edits, class_name: 'StatusEdit', inverse_of: :status, dependent: :destroy + end + + def edited? + edited_at.present? + end + + def build_snapshot(account_id: nil, at_time: nil, rate_limit: true) + # We don't use `edits#new` here to avoid it having saved when the + # status is saved, since we want to control that manually + + StatusEdit.new( + status_id: id, + text: text, + spoiler_text: spoiler_text, + sensitive: sensitive, + ordered_media_attachment_ids: ordered_media_attachment_ids&.dup || media_attachments.pluck(:id), + media_descriptions: ordered_media_attachments.map(&:description), + poll_options: preloadable_poll&.options&.dup, + account_id: account_id || self.account_id, + content_type: content_type, + created_at: at_time || edited_at, + rate_limit: rate_limit + ) + end + + def snapshot!(**options) + build_snapshot(**options).save! + end +end diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 4b38d729e..a5ce1e837 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -185,7 +185,7 @@ class MediaAttachment < ApplicationRecord remotable_attachment :thumbnail, IMAGE_LIMIT, suppress_errors: true, download_on_assign: false validates :account, presence: true - validates :description, length: { maximum: MAX_DESCRIPTION_LENGTH }, if: :local? + validates :description, length: { maximum: MAX_DESCRIPTION_LENGTH } validates :file, presence: true, if: :local? validates :thumbnail, absence: true, if: -> { local? && !audio_or_video? } @@ -258,7 +258,6 @@ class MediaAttachment < ApplicationRecord after_commit :enqueue_processing, on: :create after_commit :reset_parent_cache, on: :update - before_create :prepare_description, unless: :local? before_create :set_unknown_type before_create :set_processing @@ -306,10 +305,6 @@ class MediaAttachment < ApplicationRecord self.type = :unknown if file.blank? && !type_changed? end - def prepare_description - self.description = description.strip[0...MAX_DESCRIPTION_LENGTH] unless description.nil? - end - def set_type_and_extension self.type = begin if VIDEO_MIME_TYPES.include?(file_content_type) diff --git a/app/models/status.rb b/app/models/status.rb index b979252b3..62f9e5831 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -37,6 +37,7 @@ class Status < ApplicationRecord include Paginable include Cacheable include StatusThreadingConcern + include StatusSnapshotConcern include RateLimitable rate_limit by: :account, family: :statuses @@ -61,8 +62,6 @@ class Status < ApplicationRecord belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies, optional: true belongs_to :reblog, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblogs, optional: true - has_many :edits, class_name: 'StatusEdit', inverse_of: :status, dependent: :destroy - has_many :favourites, inverse_of: :status, dependent: :destroy has_many :bookmarks, inverse_of: :status, dependent: :destroy has_many :reblogs, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblog, dependent: :destroy @@ -217,25 +216,6 @@ class Status < ApplicationRecord public_visibility? || unlisted_visibility? end - def snapshot!(account_id: nil, at_time: nil, rate_limit: true) - edits.create!( - text: text, - spoiler_text: spoiler_text, - sensitive: sensitive, - ordered_media_attachment_ids: ordered_media_attachment_ids || media_attachments.pluck(:id), - media_descriptions: ordered_media_attachments.map(&:description), - poll_options: preloadable_poll&.options, - account_id: account_id || self.account_id, - content_type: content_type, - created_at: at_time || edited_at, - rate_limit: rate_limit - ) - end - - def edited? - edited_at.present? - end - alias sign? distributable? def with_media? diff --git a/app/models/trends/query.rb b/app/models/trends/query.rb index 64a4c0c1f..231b65228 100644 --- a/app/models/trends/query.rb +++ b/app/models/trends/query.rb @@ -37,7 +37,7 @@ class Trends::Query end def offset!(value) - @offset = value + @offset = value.to_i self end @@ -46,7 +46,7 @@ class Trends::Query end def limit!(value) - @limit = value + @limit = value.to_i self end diff --git a/app/models/user.rb b/app/models/user.rb index f657f1b27..76ad7d1b2 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -91,11 +91,11 @@ class User < ApplicationRecord validates :invite_request, presence: true, on: :create, if: :invite_text_required? validates :locale, inclusion: I18n.available_locales.map(&:to_s), if: :locale? - validates_with BlacklistedEmailValidator, on: :create + validates_with BlacklistedEmailValidator, if: -> { !confirmed? } validates_with EmailMxValidator, if: :validate_email_dns? validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create - # Those are honeypot/antispam fields + # Honeypot/anti-spam fields attr_accessor :registration_form_time, :website, :confirm_password validates_with RegistrationFormTimeValidator, on: :create @@ -208,8 +208,12 @@ class User < ApplicationRecord confirmed? && approved? && !disabled? && !account.suspended? && !account.memorial? end + def unconfirmed? + !confirmed? + end + def unconfirmed_or_pending? - !(confirmed? && approved?) + unconfirmed? || pending? end def inactive_message diff --git a/app/serializers/activitypub/actor_serializer.rb b/app/serializers/activitypub/actor_serializer.rb index 48707aa16..e6dd8040e 100644 --- a/app/serializers/activitypub/actor_serializer.rb +++ b/app/serializers/activitypub/actor_serializer.rb @@ -2,6 +2,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer include RoutingHelper + include FormattingHelper context :security @@ -102,7 +103,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer end def summary - object.suspended? ? '' : Formatter.instance.simplified_format(object) + object.suspended? ? '' : account_bio_format(object) end def icon @@ -185,6 +186,8 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer end class Account::FieldSerializer < ActivityPub::Serializer + include FormattingHelper + attributes :type, :name, :value def type @@ -192,7 +195,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer end def value - Formatter.instance.format_field(object.account, object.value) + account_field_value_format(object) end end diff --git a/app/serializers/activitypub/note_serializer.rb b/app/serializers/activitypub/note_serializer.rb index 05f2ee14f..ca067ed9b 100644 --- a/app/serializers/activitypub/note_serializer.rb +++ b/app/serializers/activitypub/note_serializer.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ActivityPub::NoteSerializer < ActivityPub::Serializer + include FormattingHelper + context_extensions :atom_uri, :conversation, :sensitive, :voters_count, :direct_message attributes :id, :type, :summary, @@ -50,11 +52,11 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer end def content - Formatter.instance.format(object) + status_content_format(object) end def content_map - { object.language => Formatter.instance.format(object) } + { object.language => content } end def replies diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb index 36886181f..113e0cca7 100644 --- a/app/serializers/rest/account_serializer.rb +++ b/app/serializers/rest/account_serializer.rb @@ -2,6 +2,7 @@ class REST::AccountSerializer < ActiveModel::Serializer include RoutingHelper + include FormattingHelper attributes :id, :username, :acct, :display_name, :locked, :bot, :discoverable, :group, :created_at, :note, :url, :avatar, :avatar_static, :header, :header_static, @@ -14,10 +15,12 @@ class REST::AccountSerializer < ActiveModel::Serializer attribute :suspended, if: :suspended? class FieldSerializer < ActiveModel::Serializer + include FormattingHelper + attributes :name, :value, :verified_at def value - Formatter.instance.format_field(object.account, object.value) + account_field_value_format(object) end end @@ -32,7 +35,7 @@ class REST::AccountSerializer < ActiveModel::Serializer end def note - object.suspended? ? '' : Formatter.instance.simplified_format(object) + object.suspended? ? '' : account_bio_format(object) end def url diff --git a/app/serializers/rest/announcement_serializer.rb b/app/serializers/rest/announcement_serializer.rb index 9343b97d2..23b2fa514 100644 --- a/app/serializers/rest/announcement_serializer.rb +++ b/app/serializers/rest/announcement_serializer.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class REST::AnnouncementSerializer < ActiveModel::Serializer + include FormattingHelper + attributes :id, :content, :starts_at, :ends_at, :all_day, :published_at, :updated_at @@ -25,7 +27,7 @@ class REST::AnnouncementSerializer < ActiveModel::Serializer end def content - Formatter.instance.linkify(object.text) + linkify(object.text) end def reactions diff --git a/app/serializers/rest/status_edit_serializer.rb b/app/serializers/rest/status_edit_serializer.rb index 05ccd5e94..f7a48797d 100644 --- a/app/serializers/rest/status_edit_serializer.rb +++ b/app/serializers/rest/status_edit_serializer.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class REST::StatusEditSerializer < ActiveModel::Serializer + include FormattingHelper + has_one :account, serializer: REST::AccountSerializer attributes :content, :spoiler_text, :sensitive, :created_at @@ -11,7 +13,7 @@ class REST::StatusEditSerializer < ActiveModel::Serializer attribute :poll, if: -> { object.poll_options.present? } def content - Formatter.instance.format(object) + status_content_format(object) end def poll diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb index 0a00ed77e..daa7de7ea 100644 --- a/app/serializers/rest/status_serializer.rb +++ b/app/serializers/rest/status_serializer.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class REST::StatusSerializer < ActiveModel::Serializer + include FormattingHelper + attributes :id, :created_at, :in_reply_to_id, :in_reply_to_account_id, :sensitive, :spoiler_text, :visibility, :language, :uri, :url, :replies_count, :reblogs_count, @@ -73,7 +75,7 @@ class REST::StatusSerializer < ActiveModel::Serializer end def content - Formatter.instance.format(object) + status_content_format(object) end def url diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index 47a788c30..6dc14d8c2 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -4,6 +4,8 @@ class ActivityPub::ProcessStatusUpdateService < BaseService include JsonLdHelper def call(status, json) + raise ArgumentError, 'Status has unsaved changes' if status.changed? + @json = json @status_parser = ActivityPub::Parser::StatusParser.new(@json) @uri = @status_parser.uri @@ -17,16 +19,19 @@ class ActivityPub::ProcessStatusUpdateService < BaseService last_edit_date = status.edited_at.presence || status.created_at + # Since we rely on tracking of previous changes, ensure clean slate + status.clear_changes_information + # Only allow processing one create/update per status at a time RedisLock.acquire(lock_options) do |lock| if lock.acquired? Status.transaction do - create_previous_edit! + record_previous_edit! update_media_attachments! update_poll! update_immediate_attributes! update_metadata! - create_edit! + create_edits! end queue_poll_notifications! @@ -216,19 +221,14 @@ class ActivityPub::ProcessStatusUpdateService < BaseService { redis: Redis.current, key: "create:#{@uri}", autorelease: 15.minutes.seconds } end - def create_previous_edit! - # We only need to create a previous edit when no previous edits exist, e.g. - # when the status has never been edited. For other cases, we always create - # an edit, so the step can be skipped - - return if @status.edits.any? - - @status.snapshot!(at_time: @status.created_at, rate_limit: false) + def record_previous_edit! + @previous_edit = @status.build_snapshot(at_time: @status.created_at, rate_limit: false) if @status.edits.empty? end - def create_edit! + def create_edits! return unless significant_changes? + @previous_edit&.save! @status.snapshot!(account_id: @account.id, rate_limit: false) end diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index 239ab9b93..9c8b5ea20 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -134,7 +134,7 @@ class FetchLinkCardService < BaseService when 'video' @card.width = embed[:width].presence || 0 @card.height = embed[:height].presence || 0 - @card.html = Formatter.instance.sanitize(embed[:html], Sanitize::Config::MASTODON_OEMBED) + @card.html = Sanitize.fragment(embed[:html], Sanitize::Config::MASTODON_OEMBED) @card.image_remote_url = (url + embed[:thumbnail_url]).to_s if embed[:thumbnail_url].present? when 'rich' # Most providers rely on <script> tags, which is a no-no diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index b1f9fd755..a90f17cfd 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -48,47 +48,23 @@ class NotifyService < BaseService return false if @notification.target_status.in_reply_to_id.nil? # Using an SQL CTE to avoid unneeded back-and-forth with SQL server in case of long threads - !Status.count_by_sql([<<-SQL.squish, id: @notification.target_status.in_reply_to_id, recipient_id: @recipient.id, sender_id: @notification.from_account.id]).zero? - WITH RECURSIVE ancestors(id, in_reply_to_id, replying_to_sender, path) AS ( - SELECT - s.id, - s.in_reply_to_id, - (CASE - WHEN s.account_id = :recipient_id THEN - EXISTS ( - SELECT * - FROM mentions m - WHERE m.silent = FALSE AND m.account_id = :sender_id AND m.status_id = s.id - ) - ELSE - FALSE - END), - ARRAY[s.id] + !Status.count_by_sql([<<-SQL.squish, id: @notification.target_status.in_reply_to_id, recipient_id: @recipient.id, sender_id: @notification.from_account.id, depth_limit: 100]).zero? + WITH RECURSIVE ancestors(id, in_reply_to_id, mention_id, path, depth) AS ( + SELECT s.id, s.in_reply_to_id, m.id, ARRAY[s.id], 0 FROM statuses s + LEFT JOIN mentions m ON m.silent = FALSE AND m.account_id = :sender_id AND m.status_id = s.id WHERE s.id = :id UNION ALL - SELECT - s.id, - s.in_reply_to_id, - (CASE - WHEN s.account_id = :recipient_id THEN - EXISTS ( - SELECT * - FROM mentions m - WHERE m.silent = FALSE AND m.account_id = :sender_id AND m.status_id = s.id - ) - ELSE - FALSE - END), - st.path || s.id + SELECT s.id, s.in_reply_to_id, m.id, st.path || s.id, st.depth + 1 FROM ancestors st JOIN statuses s ON s.id = st.in_reply_to_id - WHERE st.replying_to_sender IS FALSE AND NOT s.id = ANY(path) + LEFT JOIN mentions m ON m.silent = FALSE AND m.account_id = :sender_id AND m.status_id = s.id + WHERE st.mention_id IS NULL AND NOT s.id = ANY(path) AND st.depth < :depth_limit ) SELECT COUNT(*) FROM ancestors st JOIN statuses s ON s.id = st.id - WHERE st.replying_to_sender IS TRUE AND s.visibility = 3 + WHERE st.mention_id IS NOT NULL AND s.visibility = 3 SQL end diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb index f5155a2f5..cc4ec670d 100644 --- a/app/services/update_status_service.rb +++ b/app/services/update_status_service.rb @@ -4,6 +4,8 @@ class UpdateStatusService < BaseService include Redisable include LanguagesHelper + class NoChangesSubmittedError < StandardError; end + # @param [Status] status # @param [Integer] account_id # @param [Hash] options @@ -18,6 +20,8 @@ class UpdateStatusService < BaseService @status = status @options = options @account_id = account_id + @media_attachments_changed = false + @poll_changed = false Status.transaction do create_previous_edit! @@ -33,18 +37,24 @@ class UpdateStatusService < BaseService broadcast_updates! @status + rescue NoChangesSubmittedError + # For calls that result in no changes, swallow the error + # but get back to the original state + + @status.reload end private def update_media_attachments! - previous_media_attachments = @status.media_attachments.to_a + previous_media_attachments = @status.ordered_media_attachments.to_a next_media_attachments = validate_media! added_media_attachments = next_media_attachments - previous_media_attachments MediaAttachment.where(id: added_media_attachments.map(&:id)).update_all(status_id: @status.id) @status.ordered_media_attachment_ids = (@options[:media_ids] || []).map(&:to_i) & next_media_attachments.map(&:id) + @media_attachments_changed = previous_media_attachments.map(&:id) != @status.ordered_media_attachment_ids @status.media_attachments.reload end @@ -70,20 +80,23 @@ class UpdateStatusService < BaseService # If for some reasons the options were changed, it invalidates all previous # votes, so we need to remove them - poll_changed = true if @options[:poll][:options] != poll.options || ActiveModel::Type::Boolean.new.cast(@options[:poll][:multiple]) != poll.multiple + @poll_changed = true if @options[:poll][:options] != poll.options || ActiveModel::Type::Boolean.new.cast(@options[:poll][:multiple]) != poll.multiple poll.options = @options[:poll][:options] poll.hide_totals = @options[:poll][:hide_totals] || false poll.multiple = @options[:poll][:multiple] || false poll.expires_in = @options[:poll][:expires_in] - poll.reset_votes! if poll_changed + poll.reset_votes! if @poll_changed poll.save! @status.poll_id = poll.id elsif previous_poll.present? previous_poll.destroy + @poll_changed = true @status.poll_id = nil end + + @poll_changed = true if @previous_expires_at != @status.preloadable_poll&.expires_at end def update_immediate_attributes! @@ -92,8 +105,11 @@ class UpdateStatusService < BaseService @status.sensitive = @options[:sensitive] || @options[:spoiler_text].present? if @options.key?(:sensitive) || @options.key?(:spoiler_text) @status.language = valid_locale_cascade(@options[:language], @status.language, @status.account.user&.preferred_posting_language, I18n.default_locale) @status.content_type = @options[:content_type] || @status.content_type - @status.edited_at = Time.now.utc + # We raise here to rollback the entire transaction + raise NoChangesSubmittedError unless significant_changes? + + @status.edited_at = Time.now.utc @status.save! end @@ -139,4 +155,8 @@ class UpdateStatusService < BaseService def create_edit! @status.snapshot!(account_id: @account_id) end + + def significant_changes? + @status.changed? || @poll_changed || @media_attachments_changed + end end diff --git a/app/validators/status_length_validator.rb b/app/validators/status_length_validator.rb index 2a3ac8862..f93450ba6 100644 --- a/app/validators/status_length_validator.rb +++ b/app/validators/status_length_validator.rb @@ -3,35 +3,57 @@ class StatusLengthValidator < ActiveModel::Validator MAX_CHARS = (ENV['MAX_TOOT_CHARS'] || 500).to_i URL_PLACEHOLDER_CHARS = 23 - URL_PLACEHOLDER = "\1#{'x' * URL_PLACEHOLDER_CHARS}" + URL_PLACEHOLDER = 'x' * 23 def validate(status) return unless status.local? && !status.reblog? - @status = status - status.errors.add(:text, I18n.t('statuses.over_character_limit', max: MAX_CHARS)) if too_long? + status.errors.add(:text, I18n.t('statuses.over_character_limit', max: MAX_CHARS)) if too_long?(status) end private - def too_long? - countable_length > MAX_CHARS + def too_long?(status) + countable_length(combined_text(status)) > MAX_CHARS end - def countable_length - total_text.mb_chars.grapheme_length + def countable_length(str) + str.mb_chars.grapheme_length end - def total_text - [@status.spoiler_text, countable_text].join + def combined_text(status) + [status.spoiler_text, countable_text(status.text)].join end - def countable_text - return '' if @status.text.nil? + def countable_text(str) + return '' if str.blank? - @status.text.dup.tap do |new_text| - new_text.gsub!(FetchLinkCardService::URL_PATTERN, URL_PLACEHOLDER) - new_text.gsub!(Account::MENTION_RE, '@\2') + # To ensure that we only give length concessions to entities that + # will be correctly parsed during formatting, we go through full + # entity extraction + + entities = Extractor.remove_overlapping_entities(Extractor.extract_urls_with_indices(str, extract_url_without_protocol: false) + Extractor.extract_mentions_or_lists_with_indices(str)) + + rewrite_entities(str, entities) do |entity| + if entity[:url] + URL_PLACEHOLDER + elsif entity[:screen_name] + "@#{entity[:screen_name].split('@').first}" + end end end + + def rewrite_entities(str, entities) + entities.sort_by! { |entity| entity[:indices].first } + result = ''.dup + + last_index = entities.reduce(0) do |index, entity| + result << str[index...entity[:indices].first] + result << yield(entity) + entity[:indices].last + end + + result << str[last_index..-1] + result + end end diff --git a/app/views/accounts/_bio.html.haml b/app/views/accounts/_bio.html.haml index e8a49a1aa..e2539b1d4 100644 --- a/app/views/accounts/_bio.html.haml +++ b/app/views/accounts/_bio.html.haml @@ -5,17 +5,17 @@ .account__header__fields - fields.each do |field| %dl - %dt.emojify{ title: field.name }= Formatter.instance.format_field(account, field.name, custom_emojify: true) + %dt.emojify{ title: field.name }= prerender_custom_emojis(h(field.name), account.emojis) %dd{ title: field.value, class: custom_field_classes(field) } - if field.verified? %span.verified__mark{ title: t('accounts.link_verified_on', date: l(field.verified_at)) } = fa_icon 'check' - = Formatter.instance.format_field(account, field.value, custom_emojify: true) + = prerender_custom_emojis(account_field_value_format(field), account.emojis) = account_badge(account) - if account.note.present? - .account__header__content.emojify= Formatter.instance.simplified_format(account, custom_emojify: true) + .account__header__content.emojify= prerender_custom_emojis(account_bio_format(account), account.emojis) .public-account-bio__extra = t 'accounts.joined', date: l(account.created_at, format: :month) diff --git a/app/views/accounts/_moved.html.haml b/app/views/accounts/_moved.html.haml index 4f71b062d..2f46e0dd0 100644 --- a/app/views/accounts/_moved.html.haml +++ b/app/views/accounts/_moved.html.haml @@ -3,7 +3,7 @@ .moved-account-widget .moved-account-widget__message = fa_icon 'suitcase' - = t('accounts.moved_html', name: content_tag(:bdi, content_tag(:strong, display_name(account, custom_emojify: true), class: :emojify)), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), ActivityPub::TagManager.instance.url_for(moved_to_account), class: 'mention')) + = t('accounts.moved_html', name: content_tag(:bdi, content_tag(:strong, display_name(account, custom_emojify: true), class: :emojify)), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.pretty_acct)])), ActivityPub::TagManager.instance.url_for(moved_to_account), class: 'mention')) .moved-account-widget__card = link_to ActivityPub::TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'me noopener noreferrer' do @@ -17,4 +17,4 @@ %span.display-name %bdi %strong.emojify= display_name(moved_to_account, custom_emojify: true) - %span @#{moved_to_account.acct} + %span @#{moved_to_account.pretty_acct} diff --git a/app/views/admin/account_actions/new.html.haml b/app/views/admin/account_actions/new.html.haml index ca4f9663f..c7bb618df 100644 --- a/app/views/admin/account_actions/new.html.haml +++ b/app/views/admin/account_actions/new.html.haml @@ -1,11 +1,11 @@ - content_for :page_title do - = t('admin.account_actions.title', acct: @account.acct) + = t('admin.account_actions.title', acct: @account.pretty_acct) = simple_form_for @account_action, url: admin_account_action_path(@account.id) do |f| = f.input :report_id, as: :hidden .fields-group - = f.input :type, as: :radio_buttons, collection: Admin::AccountAction.types_for_account(@account), include_blank: false, wrapper: :with_block_label, label_method: ->(type) { safe_join([I18n.t("simple_form.labels.admin_account_action.types.#{type}"), content_tag(:span, I18n.t("simple_form.hints.admin_account_action.types.#{type}"), class: 'hint')])}, hint: t('simple_form.hints.admin_account_action.type_html', acct: @account.acct) + = f.input :type, as: :radio_buttons, collection: Admin::AccountAction.types_for_account(@account), include_blank: false, wrapper: :with_block_label, label_method: ->(type) { safe_join([I18n.t("simple_form.labels.admin_account_action.types.#{type}"), content_tag(:span, I18n.t("simple_form.hints.admin_account_action.types.#{type}"), class: 'hint')])}, hint: t('simple_form.hints.admin_account_action.type_html', acct: @account.pretty_acct) - if @account.local? %hr.spacer/ diff --git a/app/views/admin/account_warnings/_account_warning.html.haml b/app/views/admin/account_warnings/_account_warning.html.haml index 1462e76d0..030635185 100644 --- a/app/views/admin/account_warnings/_account_warning.html.haml +++ b/app/views/admin/account_warnings/_account_warning.html.haml @@ -5,7 +5,7 @@ = fa_icon 'warning' .log-entry__content .log-entry__title - = t(account_warning.action, scope: 'admin.strikes.actions', name: content_tag(:span, account_warning.account.username, class: 'username'), target: content_tag(:span, account_warning.target_account.acct, class: 'target')).html_safe + = t(account_warning.action, scope: 'admin.strikes.actions', name: content_tag(:span, account_warning.account.username, class: 'username'), target: content_tag(:span, account_warning.target_account.pretty_acct, class: 'target')).html_safe .log-entry__timestamp %time.formatted{ datetime: account_warning.created_at.iso8601 } = l(account_warning.created_at) diff --git a/app/views/admin/accounts/_account.html.haml b/app/views/admin/accounts/_account.html.haml index 2df91301e..82dd8dfb2 100644 --- a/app/views/admin/accounts/_account.html.haml +++ b/app/views/admin/accounts/_account.html.haml @@ -1,4 +1,4 @@ -.batch-table__row{ class: [!account.suspended? && account.user_pending? && 'batch-table__row--attention', account.suspended? && 'batch-table__row--muted'] } +.batch-table__row{ class: [!account.suspended? && account.user_pending? && 'batch-table__row--attention', (account.suspended? || account.user_unconfirmed?) && 'batch-table__row--muted'] } %label.batch-table__row__select.batch-table__row__select--aligned.batch-checkbox = f.check_box :account_ids, { multiple: true, include_hidden: false }, account.id .batch-table__row__content.batch-table__row__content--unpadded diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml index fc667b376..0290df7de 100644 --- a/app/views/admin/accounts/index.html.haml +++ b/app/views/admin/accounts/index.html.haml @@ -33,7 +33,7 @@ = hidden_field_tag key, params[key] - %i(username by_domain display_name email ip).each do |key| - - unless key == :by_domain && params[:remote].blank? + - unless key == :by_domain && params[:origin] != 'remote' .input.string.optional = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.accounts.#{key}") diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index 9a1f07a06..1230294fe 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -1,5 +1,5 @@ - content_for :page_title do - = @account.acct + = @account.pretty_acct - if @account.instance_actor? .flash-message.notice @@ -16,16 +16,16 @@ .account__header__fields - fields.each do |field| %dl - %dt.emojify{ title: field.name }= Formatter.instance.format_field(account, field.name, custom_emojify: true) + %dt.emojify{ title: field.name }= prerender_custom_emojis(h(field.name), account.emojis) %dd{ title: field.value, class: custom_field_classes(field) } - if field.verified? %span.verified__mark{ title: t('accounts.link_verified_on', date: l(field.verified_at)) } = fa_icon 'check' - = Formatter.instance.format_field(account, field.value, custom_emojify: true) + = prerender_custom_emojis(account_field_value_format(field, with_rel_me: false), account.emojis) - if account.note.present? %div - .account__header__content.emojify= Formatter.instance.simplified_format(account, custom_emojify: true) + .account__header__content.emojify= prerender_custom_emojis(account_bio_format(account), account.emojis) .dashboard__counters.admin-account-counters %div diff --git a/app/views/admin/change_emails/show.html.haml b/app/views/admin/change_emails/show.html.haml index 6ff0d785e..bc00d6114 100644 --- a/app/views/admin/change_emails/show.html.haml +++ b/app/views/admin/change_emails/show.html.haml @@ -1,5 +1,5 @@ - content_for :page_title do - = t('admin.accounts.change_email.title', username: @account.acct) + = t('admin.accounts.change_email.title', username: @account.username) = simple_form_for @user, url: admin_account_change_email_path(@account.id) do |f| .fields-group diff --git a/app/views/admin/disputes/appeals/_appeal.html.haml b/app/views/admin/disputes/appeals/_appeal.html.haml index 02b8777e1..3f6efb856 100644 --- a/app/views/admin/disputes/appeals/_appeal.html.haml +++ b/app/views/admin/disputes/appeals/_appeal.html.haml @@ -4,7 +4,7 @@ = image_tag appeal.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar' .log-entry__content .log-entry__title - = t(appeal.strike.action, scope: 'admin.strikes.actions', name: content_tag(:span, appeal.strike.account.username, class: 'username'), target: content_tag(:span, appeal.account.acct, class: 'target')).html_safe + = t(appeal.strike.action, scope: 'admin.strikes.actions', name: content_tag(:span, appeal.strike.account.username, class: 'username'), target: content_tag(:span, appeal.account.username, class: 'target')).html_safe .log-entry__timestamp %time.formatted{ datetime: appeal.strike.created_at.iso8601 } = l(appeal.strike.created_at) diff --git a/app/views/admin/instances/_instance.html.haml b/app/views/admin/instances/_instance.html.haml index 8a4396002..93f9bd418 100644 --- a/app/views/admin/instances/_instance.html.haml +++ b/app/views/admin/instances/_instance.html.haml @@ -1,7 +1,7 @@ .directory__tag = link_to admin_instance_path(instance) do %h4 - = fa_icon 'warning fw' if instance.failing? + = fa_icon 'warning fw', title: t('admin.instances.availability.warning') if instance.failing? = instance.domain %small diff --git a/app/views/admin/instances/show.html.haml b/app/views/admin/instances/show.html.haml index 9b2a46e7f..e8cc1c400 100644 --- a/app/views/admin/instances/show.html.haml +++ b/app/views/admin/instances/show.html.haml @@ -84,7 +84,8 @@ - else %span.negative-hint = t('admin.instances.availability.failures_recorded', count: @instance.delivery_failure_tracker.days) - = link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } unless @instance.exhausted_deliveries_days.empty? + %span= link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } unless @instance.exhausted_deliveries_days.empty? + %span= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } - if @instance.purgeable? %p= t('admin.instances.purge_description_html') diff --git a/app/views/admin/relationships/index.html.haml b/app/views/admin/relationships/index.html.haml index 60b9b5b25..f82cf26a3 100644 --- a/app/views/admin/relationships/index.html.haml +++ b/app/views/admin/relationships/index.html.haml @@ -1,5 +1,5 @@ - content_for :page_title do - = t('admin.relationships.title', acct: @account.acct) + = t('admin.relationships.title', acct: @account.pretty_acct) .filters .filter-subset diff --git a/app/views/admin/reports/_status.html.haml b/app/views/admin/reports/_status.html.haml index 7538cfd54..392fc8f81 100644 --- a/app/views/admin/reports/_status.html.haml +++ b/app/views/admin/reports/_status.html.haml @@ -4,12 +4,12 @@ .batch-table__row__content .status__content>< - if status.proper.spoiler_text.blank? - = Formatter.instance.format(status.proper, custom_emojify: true) + = prerender_custom_emojis(status_content_format(status.proper), status.proper.emojis) - else %details< %summary>< - %strong> Content warning: #{Formatter.instance.format_spoiler(status.proper)} - = Formatter.instance.format(status.proper, custom_emojify: true) + %strong> Content warning: #{prerender_custom_emojis(h(status.proper.spoiler_text), status.proper.emojis)} + = prerender_custom_emojis(status_content_format(status.proper), status.proper.emojis) - unless status.proper.ordered_media_attachments.empty? - if status.proper.ordered_media_attachments.first.video? diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml index 209fbb698..e5ea56779 100644 --- a/app/views/admin/reports/show.html.haml +++ b/app/views/admin/reports/show.html.haml @@ -23,7 +23,7 @@ = fa_icon('lock') if @report.target_account.locked? - if @report.target_account.note.present? .account-card__bio.emojify - = Formatter.instance.simplified_format(@report.target_account, custom_emojify: true) + = prerender_custom_emojis(account_bio_format(@report.target_account), @report.target_account.emojis) .account-card__actions .account-card__counters .account-card__counters__item diff --git a/app/views/admin/settings/edit.html.haml b/app/views/admin/settings/edit.html.haml index a287e52ff..a47cb2a88 100644 --- a/app/views/admin/settings/edit.html.haml +++ b/app/views/admin/settings/edit.html.haml @@ -87,7 +87,7 @@ = f.input :trendable_by_default, as: :boolean, wrapper: :with_label, label: t('admin.settings.trendable_by_default.title'), hint: t('admin.settings.trendable_by_default.desc_html') .fields-group - = f.input :trending_status_cw, as: :boolean, wrapper: :with_label, label: t('admin.settings.trending_status_cw.title'), hint: t('trending_status_cw.desc_html') + = f.input :trending_status_cw, as: :boolean, wrapper: :with_label, label: t('admin.settings.trending_status_cw.title'), hint: t('admin.settings.trending_status_cw.desc_html') .fields-group = f.input :noindex, as: :boolean, wrapper: :with_label, label: t('admin.settings.default_noindex.title'), hint: t('admin.settings.default_noindex.desc_html') diff --git a/app/views/admin/statuses/index.html.haml b/app/views/admin/statuses/index.html.haml index 865464c72..9163dee79 100644 --- a/app/views/admin/statuses/index.html.haml +++ b/app/views/admin/statuses/index.html.haml @@ -1,7 +1,7 @@ - content_for :page_title do = t('admin.statuses.title') \- - = "@#{@account.acct}" + = "@#{@account.pretty_acct}" .filters .filter-subset diff --git a/app/views/admin/tags/show.html.haml b/app/views/admin/tags/show.html.haml index c41ce2fc2..5ac57e1f2 100644 --- a/app/views/admin/tags/show.html.haml +++ b/app/views/admin/tags/show.html.haml @@ -8,7 +8,7 @@ .dashboard .dashboard__item - = react_admin_component :counter, measure: 'tag_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_accounts_measure') + = react_admin_component :counter, measure: 'tag_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_accounts_measure'), href: tag_url(@tag), target: '_blank' .dashboard__item = react_admin_component :counter, measure: 'tag_uses', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_uses_measure') .dashboard__item diff --git a/app/views/admin_mailer/new_report.text.erb b/app/views/admin_mailer/new_report.text.erb index d6c7d6bab..f8a5224a1 100644 --- a/app/views/admin_mailer/new_report.text.erb +++ b/app/views/admin_mailer/new_report.text.erb @@ -1,5 +1,5 @@ <%= raw t('application_mailer.salutation', name: display_name(@me)) %> -<%= raw(@report.account.local? ? t('admin_mailer.new_report.body', target: @report.target_account.acct, reporter: @report.account.acct) : t('admin_mailer.new_report.body_remote', target: @report.target_account.acct, domain: @report.account.domain)) %> +<%= raw(@report.account.local? ? t('admin_mailer.new_report.body', target: @report.target_account.pretty_acct, reporter: @report.account.pretty_acct) : t('admin_mailer.new_report.body_remote', target: @report.target_account.acct, domain: @report.account.domain)) %> <%= raw t('application_mailer.view')%> <%= admin_report_url(@report) %> diff --git a/app/views/auth/registrations/_status.html.haml b/app/views/auth/registrations/_status.html.haml index 68954a5da..759bbc41c 100644 --- a/app/views/auth/registrations/_status.html.haml +++ b/app/views/auth/registrations/_status.html.haml @@ -7,7 +7,7 @@ = t('auth.status.pending') - elsif @user.account.moved_to_account_id.present? .flash-message.warning - = t('auth.status.redirecting_to', acct: @user.account.moved_to_account.acct) + = t('auth.status.redirecting_to', acct: @user.account.moved_to_account.pretty_acct) = link_to t('migrations.cancel'), settings_migration_path %h3= t('auth.status.account_status') diff --git a/app/views/authorize_interactions/show.html.haml b/app/views/authorize_interactions/show.html.haml index 42c874134..2b4d2ed62 100644 --- a/app/views/authorize_interactions/show.html.haml +++ b/app/views/authorize_interactions/show.html.haml @@ -1,5 +1,5 @@ - content_for :page_title do - = t('authorize_follow.title', acct: @resource.acct) + = t('authorize_follow.title', acct: @resource.pretty_acct) .form-container .follow-prompt diff --git a/app/views/authorize_interactions/success.html.haml b/app/views/authorize_interactions/success.html.haml index 47fd09767..86fa55eac 100644 --- a/app/views/authorize_interactions/success.html.haml +++ b/app/views/authorize_interactions/success.html.haml @@ -1,5 +1,5 @@ - content_for :page_title do - = t('authorize_follow.title', acct: @resource.acct) + = t('authorize_follow.title', acct: @resource.pretty_acct) .form-container .follow-prompt diff --git a/app/views/directories/index.html.haml b/app/views/directories/index.html.haml index 2ac700fe6..4872432d4 100644 --- a/app/views/directories/index.html.haml +++ b/app/views/directories/index.html.haml @@ -34,7 +34,7 @@ = fa_icon('lock') if account.locked? - if account.note.present? .account-card__bio.emojify - = Formatter.instance.simplified_format(account, custom_emojify: true) + = prerender_custom_emojis(account_bio_format(account), account.emojis) - else .flex-spacer .account-card__actions diff --git a/app/views/disputes/strikes/show.html.haml b/app/views/disputes/strikes/show.html.haml index 0fc32b918..0b71e14a3 100644 --- a/app/views/disputes/strikes/show.html.haml +++ b/app/views/disputes/strikes/show.html.haml @@ -26,7 +26,7 @@ %p= t "user_mailer.warning.explanation.#{@strike.action}", instance: Rails.configuration.x.local_domain - unless @strike.text.blank? - = Formatter.instance.linkify(@strike.text) + = linkify(@strike.text) - if @strike.report && !@strike.report.other? %p diff --git a/app/views/notification_mailer/_status.html.haml b/app/views/notification_mailer/_status.html.haml index f520208e1..444b06fe6 100644 --- a/app/views/notification_mailer/_status.html.haml +++ b/app/views/notification_mailer/_status.html.haml @@ -23,15 +23,15 @@ = image_tag full_asset_url(status.account.avatar.url), alt:'' %td{ align: 'left' } %bdi= display_name(status.account) - = "@#{status.account.acct}" + = "@#{status.account.pretty_acct}" - if status.spoiler_text? %div.auto-dir %p - = Formatter.instance.format_spoiler(status) + = status.spoiler_text %div.auto-dir - = Formatter.instance.format(status) + = status_content_format(status) - if status.ordered_media_attachments.size > 0 %p diff --git a/app/views/notification_mailer/_status.text.erb b/app/views/notification_mailer/_status.text.erb index c43f32d9f..1dc8de739 100644 --- a/app/views/notification_mailer/_status.text.erb +++ b/app/views/notification_mailer/_status.text.erb @@ -3,6 +3,6 @@ > ---- > <% end %> -> <%= raw word_wrap(Formatter.instance.plaintext(status), break_sequence: "\n> ") %> +> <%= raw word_wrap(extract_status_plain_text(status), break_sequence: "\n> ") %> <%= raw t('application_mailer.view')%> <%= web_url("statuses/#{status.id}") %> diff --git a/app/views/notification_mailer/digest.text.erb b/app/views/notification_mailer/digest.text.erb index b2c85a9e3..0f84a4ef0 100644 --- a/app/views/notification_mailer/digest.text.erb +++ b/app/views/notification_mailer/digest.text.erb @@ -3,9 +3,9 @@ <%= raw t('notification_mailer.digest.body', since: l(@me.user_current_sign_in_at || @since), instance: root_url) %> <% @notifications.each do |notification| %> -* <%= raw t('notification_mailer.digest.mention', name: notification.from_account.acct) %> +* <%= raw t('notification_mailer.digest.mention', name: notification.from_account.pretty_acct) %> - <%= raw Formatter.instance.plaintext(notification.target_status) %> + <%= raw extract_status_plain_text(notification.target_status) %> <%= raw t('application_mailer.view')%> <%= web_url("statuses/#{notification.target_status.id}") %> <% end %> diff --git a/app/views/notification_mailer/favourite.html.haml b/app/views/notification_mailer/favourite.html.haml index a715d615c..ebc5c29c7 100644 --- a/app/views/notification_mailer/favourite.html.haml +++ b/app/views/notification_mailer/favourite.html.haml @@ -20,7 +20,7 @@ = image_tag full_pack_url('media/images/mailer/icon_grade.png'), alt:'' %h1= t 'notification_mailer.favourite.title' - %p.lead= t('notification_mailer.favourite.body', name: @account.acct) + %p.lead= t('notification_mailer.favourite.body', name: @account.pretty_acct) = render 'status', status: @status diff --git a/app/views/notification_mailer/favourite.text.erb b/app/views/notification_mailer/favourite.text.erb index 2581b4909..f4f869656 100644 --- a/app/views/notification_mailer/favourite.text.erb +++ b/app/views/notification_mailer/favourite.text.erb @@ -1,5 +1,5 @@ <%= raw t('application_mailer.salutation', name: display_name(@me)) %> -<%= raw t('notification_mailer.favourite.body', name: @account.acct) %> +<%= raw t('notification_mailer.favourite.body', name: @account.pretty_acct) %> <%= render 'status', status: @status %> diff --git a/app/views/notification_mailer/follow.html.haml b/app/views/notification_mailer/follow.html.haml index cd84f7858..a59ef8835 100644 --- a/app/views/notification_mailer/follow.html.haml +++ b/app/views/notification_mailer/follow.html.haml @@ -20,7 +20,7 @@ = image_tag full_pack_url('media/images/mailer/icon_person_add.png'), alt: '' %h1= t 'notification_mailer.follow.title' - %p.lead= t('notification_mailer.follow.body', name: @account.acct) + %p.lead= t('notification_mailer.follow.body', name: @account.pretty_acct) %table.email-table{ cellspacing: 0, cellpadding: 0 } %tbody diff --git a/app/views/notification_mailer/follow.text.erb b/app/views/notification_mailer/follow.text.erb index cbe46f552..016a0a4cf 100644 --- a/app/views/notification_mailer/follow.text.erb +++ b/app/views/notification_mailer/follow.text.erb @@ -1,5 +1,5 @@ <%= raw t('application_mailer.salutation', name: display_name(@me)) %> -<%= raw t('notification_mailer.follow.body', name: @account.acct) %> +<%= raw t('notification_mailer.follow.body', name: @account.pretty_acct) %> <%= raw t('application_mailer.view')%> <%= web_url("accounts/#{@account.id}") %> diff --git a/app/views/notification_mailer/follow_request.html.haml b/app/views/notification_mailer/follow_request.html.haml index a63e27a90..4c32c831e 100644 --- a/app/views/notification_mailer/follow_request.html.haml +++ b/app/views/notification_mailer/follow_request.html.haml @@ -20,7 +20,7 @@ = image_tag full_pack_url('media/images/mailer/icon_person_add.png'), alt: '' %h1= t 'notification_mailer.follow_request.title' - %p.lead= t('notification_mailer.follow_request.body', name: @account.acct) + %p.lead= t('notification_mailer.follow_request.body', name: @account.pretty_acct) %table.email-table{ cellspacing: 0, cellpadding: 0 } %tbody diff --git a/app/views/notification_mailer/follow_request.text.erb b/app/views/notification_mailer/follow_request.text.erb index a018394b8..66aa97fe3 100644 --- a/app/views/notification_mailer/follow_request.text.erb +++ b/app/views/notification_mailer/follow_request.text.erb @@ -1,5 +1,5 @@ <%= raw t('application_mailer.salutation', name: display_name(@me)) %> -<%= raw t('notification_mailer.follow_request.body', name: @account.acct) %> +<%= raw t('notification_mailer.follow_request.body', name: @account.pretty_acct) %> <%= raw t('application_mailer.view')%> <%= web_url("follow_requests") %> diff --git a/app/views/notification_mailer/mention.html.haml b/app/views/notification_mailer/mention.html.haml index 619873cfa..cfb7465c1 100644 --- a/app/views/notification_mailer/mention.html.haml +++ b/app/views/notification_mailer/mention.html.haml @@ -20,7 +20,7 @@ = image_tag full_pack_url('media/images/mailer/icon_reply.png'), alt: '' %h1= t 'notification_mailer.mention.title' - %p.lead= t('notification_mailer.mention.body', name: @status.account.acct) + %p.lead= t('notification_mailer.mention.body', name: @status.account.pretty_acct) = render 'status', status: @status diff --git a/app/views/notification_mailer/mention.text.erb b/app/views/notification_mailer/mention.text.erb index 03f53813b..f104d5f92 100644 --- a/app/views/notification_mailer/mention.text.erb +++ b/app/views/notification_mailer/mention.text.erb @@ -1,5 +1,5 @@ <%= raw t('application_mailer.salutation', name: display_name(@me)) %> -<%= raw t('notification_mailer.mention.body', name: @status.account.acct) %> +<%= raw t('notification_mailer.mention.body', name: @status.account.pretty_acct) %> <%= render 'status', status: @status %> diff --git a/app/views/notification_mailer/reblog.html.haml b/app/views/notification_mailer/reblog.html.haml index a2811be23..c528536ec 100644 --- a/app/views/notification_mailer/reblog.html.haml +++ b/app/views/notification_mailer/reblog.html.haml @@ -20,7 +20,7 @@ = image_tag full_pack_url('media/images/mailer/icon_cached.png'), alt: '' %h1= t 'notification_mailer.reblog.title' - %p.lead= t('notification_mailer.reblog.body', name: @account.acct) + %p.lead= t('notification_mailer.reblog.body', name: @account.pretty_acct) = render 'status', status: @status diff --git a/app/views/notification_mailer/reblog.text.erb b/app/views/notification_mailer/reblog.text.erb index 8fc841bf6..73a3b3945 100644 --- a/app/views/notification_mailer/reblog.text.erb +++ b/app/views/notification_mailer/reblog.text.erb @@ -1,5 +1,5 @@ <%= raw t('application_mailer.salutation', name: display_name(@me)) %> -<%= raw t('notification_mailer.reblog.body', name: @account.acct) %> +<%= raw t('notification_mailer.reblog.body', name: @account.pretty_acct) %> <%= render 'status', status: @status %> diff --git a/app/views/settings/aliases/index.html.haml b/app/views/settings/aliases/index.html.haml index 5df0c9669..c618a82f1 100644 --- a/app/views/settings/aliases/index.html.haml +++ b/app/views/settings/aliases/index.html.haml @@ -29,5 +29,5 @@ - else - @aliases.each do |account_alias| %tr - %td= account_alias.acct + %td= account_alias.pretty_acct %td= table_link_to 'trash', t('aliases.remove'), settings_alias_path(account_alias), data: { method: :delete } diff --git a/app/views/settings/migrations/show.html.haml b/app/views/settings/migrations/show.html.haml index 078eaebc6..492f6fe12 100644 --- a/app/views/settings/migrations/show.html.haml +++ b/app/views/settings/migrations/show.html.haml @@ -8,7 +8,7 @@ = render 'application/card', account: current_account.moved_to_account .fields-row__column.fields-group.fields-row__column-6 %p.hint - %span.positive-hint= t('migrations.redirecting_to', acct: current_account.moved_to_account.acct) + %span.positive-hint= t('migrations.redirecting_to', acct: current_account.moved_to_account.pretty_acct) %p.hint= t('migrations.cancel_explanation') @@ -76,7 +76,7 @@ - if migration.target_account.present? = compact_account_link_to migration.target_account - else - = migration.acct + = migration.pretty_acct %td= number_with_delimiter migration.followers_count diff --git a/app/views/statuses/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml index fd7e034b1..1d0e5a38c 100644 --- a/app/views/statuses/_detailed_status.html.haml +++ b/app/views/statuses/_detailed_status.html.haml @@ -18,10 +18,11 @@ .status__content.emojify{ :data => ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }< - if status.spoiler_text? %p< - %span.p-summary> #{Formatter.instance.format_spoiler(status, autoplay: prefers_autoplay?)} + %span.p-summary> #{prerender_custom_emojis(h(status.spoiler_text), status.emojis)} %button.status__content__spoiler-link= t('statuses.show_more') .e-content - = Formatter.instance.format(status, custom_emojify: true, autoplay: prefers_autoplay?) + = prerender_custom_emojis(status_content_format(status), status.emojis) + - if status.preloadable_poll = render_poll_component(status) diff --git a/app/views/statuses/_poll.html.haml b/app/views/statuses/_poll.html.haml index 3546a923e..d0f264095 100644 --- a/app/views/statuses/_poll.html.haml +++ b/app/views/statuses/_poll.html.haml @@ -12,7 +12,7 @@ %span.poll__number>< = "#{percent.round}%" %span.poll__option__text - = Formatter.instance.format_poll_option(status, option, autoplay: prefers_autoplay?) + = prerender_custom_emojis(h(option.title), status.emojis) - if own_votes.include?(index) %span.poll__voted %i.poll__voted__mark.fa.fa-check @@ -23,7 +23,7 @@ %label.poll__option>< %span.poll__input{ class: poll.multiple? ? 'checkbox' : nil}>< %span.poll__option__text - = Formatter.instance.format_poll_option(status, option, autoplay: prefers_autoplay?) + = prerender_custom_emojis(h(option.title), status.emojis) .poll__footer - unless show_results %button.button.button-secondary{ disabled: true } diff --git a/app/views/statuses/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml index a41656323..7b672bda7 100644 --- a/app/views/statuses/_simple_status.html.haml +++ b/app/views/statuses/_simple_status.html.haml @@ -30,10 +30,11 @@ .status__content.emojify{ :data => ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }< - if status.spoiler_text? %p< - %span.p-summary> #{Formatter.instance.format_spoiler(status, autoplay: prefers_autoplay?)} + %span.p-summary> #{prerender_custom_emojis(h(status.spoiler_text), status.emojis)} %button.status__content__spoiler-link= t('statuses.show_more') .e-content< - = Formatter.instance.format(status, custom_emojify: true, autoplay: prefers_autoplay?) + = prerender_custom_emojis(status_content_format(status), status.emojis) + - if status.preloadable_poll = render_poll_component(status) diff --git a/app/views/user_mailer/warning.html.haml b/app/views/user_mailer/warning.html.haml index b308e18f7..fff61fa90 100644 --- a/app/views/user_mailer/warning.html.haml +++ b/app/views/user_mailer/warning.html.haml @@ -40,7 +40,7 @@ %p= t "user_mailer.warning.explanation.#{@warning.action}", instance: @instance - unless @warning.text.blank? - = Formatter.instance.linkify(@warning.text) + = linkify(@warning.text) - if @warning.report && !@warning.report.other? %p diff --git a/app/workers/scheduler/user_cleanup_scheduler.rb b/app/workers/scheduler/user_cleanup_scheduler.rb index 750d2127b..d1f00c47f 100644 --- a/app/workers/scheduler/user_cleanup_scheduler.rb +++ b/app/workers/scheduler/user_cleanup_scheduler.rb @@ -27,7 +27,7 @@ class Scheduler::UserCleanupScheduler end def clean_discarded_statuses! - Status.discarded.where('deleted_at <= ?', 30.days.ago).find_in_batches do |statuses| + Status.unscoped.discarded.where('deleted_at <= ?', 30.days.ago).find_in_batches do |statuses| RemovalWorker.push_bulk(statuses) do |status| [status.id, { 'immediate' => true }] end diff --git a/boxfile.yml b/boxfile.yml index c1d89bb15..27166cec9 100644 --- a/boxfile.yml +++ b/boxfile.yml @@ -43,20 +43,19 @@ run.config: fs_watch: true - deploy.config: extra_steps: - NODE_ENV=production bundle exec rake assets:precompile transform: - - "envsubst < /app/.env.nanobox > /app/.env.production" + - 'envsubst < /app/.env.nanobox > /app/.env.production' - |- - if [ -z "$LOCAL_DOMAIN" ] - then - . /app/.env.production - export LOCAL_DOMAIN - fi - erb /app/nanobox/nginx-web.conf.erb > /app/nanobox/nginx-web.conf - erb /app/nanobox/nginx-stream.conf.erb > /app/nanobox/nginx-stream.conf + if [ -z "$LOCAL_DOMAIN" ] + then + . /app/.env.production + export LOCAL_DOMAIN + fi + erb /app/nanobox/nginx-web.conf.erb > /app/nanobox/nginx-web.conf + erb /app/nanobox/nginx-stream.conf.erb > /app/nanobox/nginx-stream.conf - touch /app/log/production.log before_live: web.web: @@ -65,11 +64,10 @@ deploy.config: after_live: worker.sidekiq: - |- - if [[ "${ES_ENABLED}" != "false" ]] - then - bin/tootctl search deploy - fi - + if [[ "${ES_ENABLED}" != "false" ]] + then + bin/tootctl search deploy + fi web.web: start: @@ -89,7 +87,6 @@ web.web: data.storage: - public/system - web.stream: start: nginx: nginx -c /app/nanobox/nginx-stream.conf @@ -103,7 +100,6 @@ web.stream: writable_dirs: - tmp - worker.sidekiq: start: default: bundle exec sidekiq -c 5 -q default -L /app/log/sidekiq.log @@ -123,7 +119,6 @@ worker.sidekiq: data.storage: - public/system - data.db: image: nanobox/postgresql:9.6 @@ -145,7 +140,6 @@ data.db: curl -k -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/${file} -X DELETE done - data.elastic: image: nanobox/elasticsearch:5 @@ -171,7 +165,6 @@ data.elastic: curl -k -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/${file} -X DELETE done - data.redis: image: nanobox/redis:4.0 @@ -191,7 +184,6 @@ data.redis: curl -k -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/${file} -X DELETE done - data.storage: image: nanobox/unfs:0.9 diff --git a/config/brakeman.ignore b/config/brakeman.ignore index c24146da4..80c5f6d4e 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -7,7 +7,7 @@ "check_name": "SQL", "message": "Possible SQL injection", "file": "app/models/status.rb", - "line": 105, + "line": 106, "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", "code": "result.joins(\"INNER JOIN statuses_tags t#{id} ON t#{id}.status_id = statuses.id AND t#{id}.tag_id = #{id}\")", "render_path": null, @@ -27,7 +27,7 @@ "check_name": "SQL", "message": "Possible SQL injection", "file": "app/models/trends/query.rb", - "line": 60, + "line": 76, "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", "code": "klass.joins(\"join unnest(array[#{ids.join(\",\")}]) with ordinality as x (id, ordering) on #{klass.table_name}.id = x.id\")", "render_path": null, @@ -61,6 +61,36 @@ "note": "" }, { + "warning_type": "Cross-Site Scripting", + "warning_code": 2, + "fingerprint": "71cf98c8235b5cfa9946b5db8fdc1a2f3a862566abb34e4542be6f3acae78233", + "check_name": "CrossSiteScripting", + "message": "Unescaped model attribute", + "file": "app/views/admin/disputes/appeals/_appeal.html.haml", + "line": 7, + "link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting", + "code": "t((Unresolved Model).new.strike.action, :scope => \"admin.strikes.actions\", :name => content_tag(:span, (Unresolved Model).new.strike.account.username, :class => \"username\"), :target => content_tag(:span, (Unresolved Model).new.account.username, :class => \"target\"))", + "render_path": [ + { + "type": "template", + "name": "admin/disputes/appeals/index", + "line": 20, + "file": "app/views/admin/disputes/appeals/index.html.haml", + "rendered": { + "name": "admin/disputes/appeals/_appeal", + "file": "app/views/admin/disputes/appeals/_appeal.html.haml" + } + } + ], + "location": { + "type": "template", + "template": "admin/disputes/appeals/_appeal" + }, + "user_input": "(Unresolved Model).new.strike", + "confidence": "Weak", + "note": "" + }, + { "warning_type": "SQL Injection", "warning_code": 0, "fingerprint": "75fcd147b7611763ab6915faf8c5b0709e612b460f27c05c72d8b9bd0a6a77f8", @@ -121,33 +151,23 @@ "note": "" }, { - "warning_type": "Cross-Site Scripting", - "warning_code": 2, - "fingerprint": "afad51718ae373b2f19d2513029fd2afccf58b9148e475934bc6a162ee33c352", - "check_name": "CrossSiteScripting", - "message": "Unescaped model attribute", - "file": "app/views/admin/disputes/appeals/_appeal.html.haml", - "line": 7, - "link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting", - "code": "t((Unresolved Model).new.strike.action, :scope => \"admin.strikes.actions\", :name => content_tag(:span, (Unresolved Model).new.strike.account.username, :class => \"username\"), :target => content_tag(:span, (Unresolved Model).new.account.acct, :class => \"target\"))", - "render_path": [ - { - "type": "template", - "name": "admin/disputes/appeals/index", - "line": 20, - "file": "app/views/admin/disputes/appeals/index.html.haml", - "rendered": { - "name": "admin/disputes/appeals/_appeal", - "file": "app/views/admin/disputes/appeals/_appeal.html.haml" - } - } - ], + "warning_type": "Mass Assignment", + "warning_code": 105, + "fingerprint": "ab5035dd1a9f8c3a8d92fb2c37e8fe86fede4f87c91b71aa32e89c9eede602fc", + "check_name": "PermitAttributes", + "message": "Potentially dangerous key allowed for mass assignment", + "file": "app/controllers/api/v1/notifications_controller.rb", + "line": 81, + "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/", + "code": "params.permit(:account_id, :types => ([]), :exclude_types => ([]))", + "render_path": null, "location": { - "type": "template", - "template": "admin/disputes/appeals/_appeal" + "type": "method", + "class": "Api::V1::NotificationsController", + "method": "browserable_params" }, - "user_input": "(Unresolved Model).new.strike", - "confidence": "Weak", + "user_input": ":account_id", + "confidence": "High", "note": "" }, { @@ -184,7 +204,7 @@ { "type": "template", "name": "admin/trends/links/index", - "line": 45, + "line": 49, "file": "app/views/admin/trends/links/index.html.haml", "rendered": { "name": "admin/trends/links/_preview_card", @@ -207,7 +227,7 @@ "check_name": "PermitAttributes", "message": "Potentially dangerous key allowed for mass assignment", "file": "app/controllers/api/v1/reports_controller.rb", - "line": 36, + "line": 26, "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/", "code": "params.permit(:account_id, :comment, :category, :forward, :status_ids => ([]), :rule_ids => ([]))", "render_path": null, @@ -221,6 +241,6 @@ "note": "" } ], - "updated": "2022-02-15 03:48:53 +0100", + "updated": "2022-03-22 07:48:32 +0100", "brakeman_version": "5.2.1" } diff --git a/config/database.yml b/config/database.yml index 9b8d096e9..127a78abf 100644 --- a/config/database.yml +++ b/config/database.yml @@ -32,4 +32,3 @@ production: host: <%= ENV['DB_HOST'] || 'localhost' %> port: <%= ENV['DB_PORT'] || 5432 %> prepared_statements: <%= ENV['PREPARED_STATEMENTS'] || 'true' %> - diff --git a/config/deploy.rb b/config/deploy.rb index f642e6e59..8a2316b57 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -lock '3.16.0' +lock '3.17.0' set :repo_url, ENV.fetch('REPO', 'https://github.com/mastodon/mastodon.git') set :branch, ENV.fetch('BRANCH', 'master') diff --git a/config/environments/production.rb b/config/environments/production.rb index 1d9063cd6..4446a9152 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -87,11 +87,13 @@ Rails.application.configure do # E-mails outgoing_email_address = ENV.fetch('SMTP_FROM_ADDRESS', 'notifications@localhost') - outgoing_mail_domain = Mail::Address.new(outgoing_email_address).domain + outgoing_email_domain = Mail::Address.new(outgoing_email_address).domain + config.action_mailer.default_options = { from: outgoing_email_address, reply_to: ENV['SMTP_REPLY_TO'], - 'Message-ID': -> { "<#{Mail.random_tag}@#{outgoing_mail_domain}>" }, + return_path: ENV['SMTP_RETURN_PATH'], + message_id: -> { "<#{Mail.random_tag}@#{outgoing_email_domain}>" }, } config.action_mailer.smtp_settings = { diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 84f5d6666..017bd1a70 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -17,8 +17,8 @@ data: search: paths: - - app/ - - config/navigation.rb + - app/ + - config/navigation.rb relative_roots: - app/controllers diff --git a/config/initializers/twitter_regex.rb b/config/initializers/twitter_regex.rb index d2ea5f974..6a7723fd2 100644 --- a/config/initializers/twitter_regex.rb +++ b/config/initializers/twitter_regex.rb @@ -75,30 +75,4 @@ module Twitter::TwitterText ) }iox end - - module Extractor - # Extracts a list of all XMPP and magnet URIs included in the Toot <tt>text</tt> along - # with the indices. If the <tt>text</tt> is <tt>nil</tt> or contains no - # XMPP or magnet URIs an empty array will be returned. - # - # If a block is given then it will be called for each XMPP URI. - def extract_extra_uris_with_indices(text, _options = {}) # :yields: uri, start, end - return [] unless text && text.index(":") - urls = [] - - text.to_s.scan(Twitter::TwitterText::Regex[:valid_extended_uri]) do - valid_uri_match_data = $~ - - start_position = valid_uri_match_data.char_begin(3) - end_position = valid_uri_match_data.char_end(3) - - urls << { - :url => valid_uri_match_data[3], - :indices => [start_position, end_position] - } - end - urls.each{|url| yield url[:url], url[:indices].first, url[:indices].last} if block_given? - urls - end - end end diff --git a/config/locales/activerecord.ku.yml b/config/locales/activerecord.ku.yml index 3a3a1d843..340b7a777 100644 --- a/config/locales/activerecord.ku.yml +++ b/config/locales/activerecord.ku.yml @@ -9,7 +9,7 @@ ku: agreement: Peymana karûbarê email: Navnîşana E-nameyê locale: Herêmî - password: Pêborîn + password: Borînpeyv user/account: username: Navê bikarhêneriyê user/invite_request: diff --git a/config/locales/activerecord.nl.yml b/config/locales/activerecord.nl.yml index 6bbdc5b40..b5a122001 100644 --- a/config/locales/activerecord.nl.yml +++ b/config/locales/activerecord.nl.yml @@ -24,7 +24,7 @@ nl: status: attributes: reblog: - taken: van toot bestaat al + taken: van bericht bestaat al user: attributes: email: diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 4ccadab8b..ba66c5749 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -474,9 +474,6 @@ ar: delivery_error_days: أيام أخطاء التوصيل delivery_error_hint: إذا كان التوصيل غير ممكناً لـ%{count} يوم، فستوضع عليها علامة {غير قابلة للتسليم} تلقائياً. empty: لم يتم العثور على نطاقات. - known_accounts: - one: "%{count} حساب معروف" - other: "%{count} حسابات معروفة" moderation: all: كافتها limited: محدود diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 460feb037..d7a8a4858 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -1,7 +1,7 @@ --- ca: about: - about_hashtag_html: Aquests són tuts públics etiquetats amb <strong>#%{hashtag}</strong>. Pots interactuar amb elles si tens un compte a qualsevol lloc del fedivers. + about_hashtag_html: Aquests són publicacions públiques etiquetades amb <strong>#%{hashtag}</strong>. Pots interactuar amb elles si tens un compte a qualsevol lloc del fedivers. about_mastodon_html: 'La xarxa social del futur: sense anuncis, sense vigilància corporativa, disseny ètic i descentralització. Posseeix les teves dades amb Mastodon!' about_this: Quant a active_count_after: actiu @@ -25,7 +25,7 @@ ca: instance_actor_flash: | Aquest compte és un actor virtual utilitzat per a representar al propi servidor i no cap usuari individual. S'utilitza per a propòsits de federació i no ha de ser bloquejat si no voleu bloquejar tota la instància, en aquest cas hauríeu d'utilitzar un bloqueig de domini. - learn_more: Més informació + learn_more: Aprèn més logged_in_as_html: Actualment has iniciat sessió com a %{username}. logout_before_registering: Ja has iniciat sessió. privacy_policy: Política de privadesa @@ -35,12 +35,12 @@ ca: server_stats: 'Estadístiques del servidor:' source_code: Codi font status_count_after: - one: estat - other: tuts - status_count_before: Que han escrit + one: publicació + other: publicacions + status_count_before: Que han publicat tagline: Segueix els teus amics i descobreix-ne de nous terms: Termes del servei - unavailable_content: Contingut no disponible + unavailable_content: Servidors moderats unavailable_content_description: domain: Servidor reason: Raó @@ -78,10 +78,10 @@ ca: pin_errors: following: Has d'estar seguint la persona que vulguis avalar posts: - one: Tut - other: Tuts - posts_tab_heading: Tuts - posts_with_replies: Tuts i respostes + one: Publicació + other: Publicacions + posts_tab_heading: Publicacions + posts_with_replies: Publicacions i respostes roles: admin: Administrador bot: Bot @@ -98,7 +98,7 @@ ca: created_msg: La nota de moderació s'ha creat correctament! destroyed_msg: Nota de moderació destruïda amb èxit! accounts: - add_email_domain_block: Afegir el domini de correu a la llista negra + add_email_domain_block: Bloquejar el domini de l'adreça de correu electrònic approve: Aprova approved_msg: L’aplicació del registre de %{username} s’ha aprovat amb èxit are_you_sure: N'estàs segur? @@ -168,7 +168,6 @@ ca: previous_strikes_description_html: one: Aquest compte té <strong>una</strong> acció. other: Aquest compte té <strong>%{count}</strong> accions. - zero: Aquest compte està <strong>al dia</strong>. promote: Promociona protocol: Protocol public: Públic @@ -490,6 +489,7 @@ ca: other: Intents fallits en %{count} diferents dies. no_failures_recorded: Sense errors registrats. title: Disponibilitat + warning: El darrer intent de connectar a aquest servidor no ha tingut èxit back_to_all: Totes back_to_limited: Limitades back_to_warning: Avís @@ -529,7 +529,6 @@ ca: known_accounts: one: "%{count} compte conegut" other: "%{count} comptes coneguts" - zero: Cap compte conegut moderation: all: Totes limited: Limitades @@ -774,6 +773,11 @@ ca: system_checks: database_schema_check: message_html: Hi ha pendents migracions de la base de dades. Si us plau executa-les per a assegurar que l'aplicació es comporta com s'espera + elasticsearch_running_check: + message_html: No s'ha pogut connectar a Elasticsearch. Si us plau verifica que estigui funcionant o desactiva la cerca de text complet + elasticsearch_version_check: + message_html: 'Versió incompatible de Elasticsearch: %{value}' + version_comparison: Elasticsearch %{running_version} està funcionant mentre %{required_version} és requerida rules_check: action: Gestiona les normes del servidor message_html: No has definit cap norma del servidor. @@ -794,9 +798,8 @@ ca: disallow: No permetre l'enllaç disallow_provider: No permetre el mitjà shared_by_over_week: - one: Compartit per un usuari en la darrera setmana - other: Compartit per %{count} usuaris en la darrera setmana - zero: Compartit per ningú en la darrera setmana + one: Compartit per una persona en la darrera setmana + other: Compartit per %{count} persones en la darrera setmana title: Enllaços en tendència usage_comparison: Compartit %{today} vegades avui, comparat amb %{yesterday} d'ahir pending_review: Revisió pendent @@ -837,9 +840,8 @@ ca: usable: Pot ser emprat usage_comparison: Usat %{today} vegades avui, comparat amb %{yesterday} d'ahir used_by_over_week: - one: Emprat per un usuari en la darrera setmana - other: Emprat per %{count} usuaris en la darrera setmana - zero: Emprat per ningú en la darrera setmana + one: Emprat per una persona en la darrera setmana + other: Emprat per %{count} persones en la darrera setmana title: Tendència warning_presets: add_new: Afegir-ne un de nou diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 8eda24b4f..107aa9a0b 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -168,6 +168,11 @@ cs: not_subscribed: Neodebírá pending: Čeká na posouzení perform_full_suspension: Pozastavit + previous_strikes_description_html: + few: Tento účet má <strong>%{count}</strong> strajky. + many: Tento účet má <strong>%{count}</strong> strajků. + one: Tento účet má <strong>jeden</strong> strajk. + other: Tento účet má <strong>%{count}</strong> strajků. promote: Povýšit protocol: Protokol public: Veřejný @@ -366,6 +371,7 @@ cs: enable: Povolit enabled: Povoleno enabled_msg: Emoji bylo úspěšně povoleno + image_hint: PNG nebo GIF do %{size} list: Uvést listed: Uvedeno new: @@ -446,6 +452,8 @@ cs: title: Doporučená sledování unsuppress: Obnovit doporučení sledování instances: + availability: + warning: Poslední pokus o připojení k tomuto serveru byl neúspěšný back_to_all: Vše back_to_limited: Omezený back_to_warning: Varování @@ -527,12 +535,15 @@ cs: one: "%{count} poznámka" other: "%{count} poznámek" action_taken_by: Akci vykonal uživatel - are_you_sure: Opravu? + are_you_sure: Jste si jisti? assign_to_self: Přidělit ke mně assigned: Přiřazený moderátor by_target_domain: Doména nahlášeného účtu + category: Kategorie + category_description_html: Důvod nahlášení tohoto účtu a/nebo obsahu bude uveden v komunikaci s nahlášeným účtem comment: none: Žádné + comment_description_html: 'Pro upřesnění uživatel %{name} napsal:' created_at: Nahlášené forwarded: Přeposláno forwarded_to: Přeposláno na %{domain} @@ -544,13 +555,19 @@ cs: create_and_unresolve: Znovu otevřít s poznámkou delete: Smazat placeholder: Popište, jaké akce byly vykonány, nebo jakékoliv jiné související aktuality… + title: Poznámky + notes_description_html: Zobrazit a zanechat poznámky pro ostatní moderátory i sebe v budoucnu + remote_user_placeholder: vzdálený uživatel z %{instance} reopen: Znovu otevřít hlášení report: 'Nahlásit #%{id}' reported_account: Nahlášený účet reported_by: Nahlášeno uživatelem resolved: Vyřešeno resolved_msg: Hlášení úspěšně vyřešeno! + skip_to_actions: Přeskočit k akcím status: Stav + statuses: Nahlášený obsah + statuses_description_html: Obsah porušující pravidla bude uveden v komunikaci s nahlášeným účtem target_origin: Původ nahlášeného účtu title: Hlášení unassign: Odebrat @@ -666,6 +683,11 @@ cs: system_checks: database_schema_check: message_html: Na spuštění čekají databázové migrace. Nechte je prosím proběhnout pro zajištění očekávaného chování aplikace + elasticsearch_running_check: + message_html: Nelze se připojit k Elasticsearch. Prosím zkontrolujte, že běží, nebo vypněte fulltextové vyhledávání + elasticsearch_version_check: + message_html: 'Nekompatibilní verze Elasticsearch: %{value}' + version_comparison: Je spuštěn Elasticsearch %{running_version} místo vyžadovaného %{required_version} rules_check: action: Spravovat pravidla serveru message_html: Nedefinovali jste žádná pravidla serveru. @@ -1041,6 +1063,9 @@ cs: carry_mutes_over_text: Tento účet se přesunul z %{acct}, který jste skryli. copy_account_note_text: 'Tento účet se přesunul z %{acct}, zde byly Vaše předchozí poznámky o něm:' notification_mailer: + admin: + sign_up: + subject: Uživatel %{name} se zaregistroval digest: action: Zobrazit všechna oznámení body: Zde najdete stručný souhrn zpráv, které jste zmeškali od vaší poslední návštěvy %{since} @@ -1082,6 +1107,8 @@ cs: title: Nový boost status: subject: Nový příspěvek od %{name} + update: + subject: Uživatel %{name} upravil příspěvek notifications: email_events: Události pro e-mailová oznámení email_events_hint: 'Vyberte události, pro které chcete dostávat oznámení:' @@ -1163,6 +1190,9 @@ cs: reply: proceed: Pokračovat k odpovědi prompt: 'Chcete odpovědět na tento příspěvek:' + reports: + errors: + invalid_rules: neodkazuje na platná pravidla scheduled_statuses: over_daily_limit: Překročili jste limit %{limit} příspěvků naplánovaných na tento den over_total_limit: Překročili jste limit %{limit} naplánovaných příspěvků @@ -1251,6 +1281,7 @@ cs: other: "%{count} videí" boosted_from_html: Boostnuto z %{acct_link} content_warning: 'Varování o obsahu: %{warning}' + default_language: Stejný jako jazyk rozhraní disallowed_hashtags: few: 'obsahoval nepovolené hashtagy: %{tags}' many: 'obsahoval nepovolené hashtagy: %{tags}' @@ -1450,6 +1481,8 @@ cs: subject: Potvrďte prosím pokus o přihlášení title: Pokus o přihlášení warning: + explanation: + delete_statuses: Bylo shledáno, že některé vaše příspěvky porušují jednu nebo více zásad komunity a následně byly odstraněny moderátory %{instance}. subject: disable: Váš účet %{acct} byl zmrazen none: Varování pro %{acct} diff --git a/config/locales/da.yml b/config/locales/da.yml index 34e56ded4..d3182ad7f 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -166,9 +166,8 @@ da: perform_full_suspension: Suspendér previous_strikes: Tidligere anmeldelser (strikes) previous_strikes_description_html: - one: Denne konto har <strong>et</strong> anmeldelse. + one: Denne konto har <strong>en</strong> anmeldelse. other: Denne konto har <strong>%{count}</strong> anmeldelser. - zero: Denne konto er <strong>på god fod</strong>. promote: Forfrem protocol: Protokol public: Offentlig @@ -490,6 +489,7 @@ da: other: Mislykkede forsøg på %{count} forskellige dage. no_failures_recorded: Ingen fejl noteret. title: Tilgængelighed + warning: Seneste forsøg på at oprette forbindelse til denne server mislykkedes back_to_all: Alle back_to_limited: Begrænset back_to_warning: Advarsel @@ -529,7 +529,6 @@ da: known_accounts: one: "%{count} kendt konto" other: "%{count} kendte konti" - zero: Ingen kendt konto moderation: all: Alle limited: Begrænset @@ -774,6 +773,11 @@ da: system_checks: database_schema_check: message_html: Databasemigreringer afventer. Kør dem for at sikre den forventede adfærd fra applikationen + elasticsearch_running_check: + message_html: Kunne ikke oprette forbindelse til Elasticsearch. Tjek, at den kører, eller deaktivér fuldtekstsøgning + elasticsearch_version_check: + message_html: 'Inkompatibel Elasticsearch-version: %{value}' + version_comparison: Elasticsearch %{running_version} kører, men %{required_version} kræves rules_check: action: Håndtér serverregler message_html: Ingen serverregler defineret. @@ -794,9 +798,8 @@ da: disallow: Tillad ikke link disallow_provider: Tillad ikke udgiver shared_by_over_week: - one: Delt af én person i løbet af den seneste uge - other: Delt af %{count} personer i løbet af den seneste uge - zero: Ikke delt af nogen i løbet af den seneste uge + one: Delt af én person den seneste uge + other: Delt af %{count} personer den seneste uge title: Populære links usage_comparison: Delt %{today} gange i dag, sammenlignet med %{yesterday} i går pending_review: Afventer revision @@ -837,9 +840,8 @@ da: usable: Kan anvendes usage_comparison: Anvendt %{today} gange i dag, sammenlignet med %{yesterday} i går used_by_over_week: - one: Anvendt af én person i løbet af den seneste uge - other: Anvendt af %{count} personer i løbet af den seneste uge - zero: Ikke anvendt af nogen i løbet af den seneste uge + one: Brugt af én person den seneste uge + other: Brugt af %{count} personer den seneste uge title: Trends warning_presets: add_new: Tilføj ny diff --git a/config/locales/de.yml b/config/locales/de.yml index 4768f4e80..78ba2c440 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -165,10 +165,6 @@ de: pending: In Warteschlange perform_full_suspension: Verbannen previous_strikes: Vorherige Strikes - previous_strikes_description_html: - one: Dieses Konto hat <strong>einen</strong> Strike. - other: Dieses Konto hat <strong>%{count}</strong> Strikes. - zero: Dieses Konto ist <strong>in gutem Stand</strong>. promote: Befördern protocol: Protokoll public: Öffentlich @@ -373,6 +369,7 @@ de: enable: Aktivieren enabled: Aktiviert enabled_msg: Das Emoji wurde aktiviert + image_hint: PNG oder GIF bis %{size} list: Liste listed: Gelistet new: @@ -489,6 +486,7 @@ de: other: Fehlgeschlagener Versuch am %{count}. Tag. no_failures_recorded: Keine Fehler bei der Aufzeichnung. title: Verfügbarkeit + warning: Der letzte Versuch, sich mit diesem Server zu verbinden, war nicht erfolgreich back_to_all: Alle back_to_limited: Beschränkt back_to_warning: Warnung @@ -525,10 +523,6 @@ de: delivery_error_hint: Wenn eine Lieferung für %{count} Tage nicht möglich ist, wird sie automatisch als nicht lieferbar markiert. destroyed_msg: Daten von %{domain} sind nun in der Warteschlange für die bevorstehende Löschung. empty: Keine Domains gefunden. - known_accounts: - one: "%{count} bekanntes Konto" - other: "%{count} bekannte Konten" - zero: Kein bekanntes Konto moderation: all: Alle limited: Beschränkt @@ -792,10 +786,6 @@ de: description_html: Dies sind Links, die derzeit von Konten geteilt werden, von denen dein Server Beiträge sieht. Es kann deinen Benutzern helfen, herauszufinden, was in der Welt vor sich geht. Es werden keine Links öffentlich angezeigt, bis du den Publisher genehmigst. Du kannst auch einzelne Links zulassen oder ablehnen. disallow: Verbiete Link disallow_provider: Verbiete Herausgeber - shared_by_over_week: - one: In der letzten Woche geteilt von einer Person - other: In der letzten Woche geteilt von %{count} Personen - zero: Geteilt von niemandem in der letzten Woche title: Angesagte Links usage_comparison: Heute %{today} mal geteilt, gestern %{yesterday} mal pending_review: Überprüfung ausstehend @@ -835,10 +825,6 @@ de: trending_rank: 'Trend #%{rank}' usable: Kann verwendet werden usage_comparison: Heute %{today} mal genutzt, gestern %{yesterday} mal - used_by_over_week: - one: In der letzten Woche genutzt von einer Person - other: In der letzten Woche genutzt von %{count} Personen - zero: Genutzt von niemandem in der letzten Woche title: Trends warning_presets: add_new: Neu hinzufügen @@ -1436,6 +1422,7 @@ de: disallowed_hashtags: one: 'enthält einen verbotenen Hashtag: %{tags}' other: 'enthält verbotene Hashtags: %{tags}' + edited_at_html: Bearbeitet %{date} errors: in_reply_not_found: Der Beitrag, auf den du antworten möchtest, scheint nicht zu existieren. open_in_web: Im Web öffnen diff --git a/config/locales/devise.ca.yml b/config/locales/devise.ca.yml index ff7836711..4c58c432f 100644 --- a/config/locales/devise.ca.yml +++ b/config/locales/devise.ca.yml @@ -25,7 +25,7 @@ ca: explanation: Has creat un compte a %{host} amb aquesta adreça de correu electrònic. Estàs a un sol clic de l'activació. Si no fos així, ignora aquest correu electrònic. explanation_when_pending: Has sol·licitat una invitació a %{host} amb aquesta adreça de correu electrònic. Un cop confirmis la teva adreça de correu electrònic revisarem la teva sol·licitud. No es pot iniciar la sessió fins llavors. Si la teva sol·licitud és rebutjada les teves dades s’eliminaran, de manera que no s’exigirà cap altra acció. Si no has estat tu qui ha fet aquest sol·licitud si us plau ignora aquest correu electrònic. extra_html: Si us plau consulta també <a href="%{terms_path}"> les regles del servidor</a> i <a href="%{policy_path}"> les nostres condicions de servei</a>. - subject: 'Mastodon: Instruccions de confirmació de %{instance}' + subject: 'Mastodon: Instruccions de confirmació per a %{instance}' title: Verifica l'adreça de correu email_changed: explanation: 'L''adreça de correu del teu compte s''està canviant a:' @@ -34,7 +34,7 @@ ca: title: Adreça de correu electrònic nova password_change: explanation: S'ha canviat la contrasenya del teu compte. - extra: Si no has canviat el teu correu electrònic, és probable que algú hagi accedit al teu compte. Si us plau, canvia la contrasenya immediatament o posa't en contacte amb l'administrador del servidor si no pots accedir al teu compte. + extra: Si no has canviat la teva contrasenya, és probable que algú hagi accedit al teu compte. Si us plau, canvia la contrasenya immediatament o posa't en contacte amb l'administrador del servidor si no pots accedir al teu compte. subject: 'Mastodon: Contrasenya canviada' title: Contrasenya canviada reconfirmation_instructions: @@ -61,7 +61,7 @@ ca: subject: 'Mastodon: codis de recuperació de Dos factors regenerats' title: 2FA codis de recuperació canviats unlock_instructions: - subject: 'Mastodon: Instruccions per a desbloquejar' + subject: 'Mastodon: Instruccions de desbloqueig' webauthn_credential: added: explanation: La següent clau de seguretat s'ha afegit al teu compte @@ -84,34 +84,34 @@ ca: success: Autenticat amb èxit des del compte %{kind}. passwords: no_token: No pots accedir a aquesta pàgina sense provenir des del correu de restabliment de la contrasenya. Si vens des del correu de restabliment de contrasenya, assegura't que estàs emprant l'adreça completa proporcionada. - send_instructions: Si el teu correu electrònic existeix en la nostra base de dades, rebràs en pocs minuts un enllaç de restabliment de contrasenya en l'adreça de correu. Si us plau verifica la teva carpeta de correu brossa if no rebut aquest correu. - send_paranoid_instructions: Si el seu correu electrònic existeix en la nostra base de dades, rebràs un enllaç de restabliment de contrasenya en l'adreça de correu en pocs minuts. + send_instructions: Si el teu correu electrònic existeix en la nostra base de dades, rebràs en pocs minuts un enllaç de restabliment de contrasenya en l'adreça de correu. Si us plau verifica la teva carpeta de correu brossa si no has rebut aquest correu. + send_paranoid_instructions: Si el teu correu electrònic existeix en la nostra base de dades, rebràs un enllaç de restabliment de contrasenya en l'adreça de correu en pocs minuts. Si us plau verifica la carpeta de correu brossa si no reps aquest correu. updated: La contrasenya s'ha canviat correctament. Ara ja estàs registrat. updated_not_active: La contrasenya s'ha canviat correctament. registrations: - destroyed: Adéu! el compte s'ha cancel·lat amb èxit. Desitgem veure't de nou aviat. + destroyed: Adéu! el compte s'ha cancel·lat amb èxit. Desitgem veure't de nou ben aviat. signed_up: Benvingut! T'has registrat amb èxit. - signed_up_but_inactive: T´has registrat amb èxit. No obstant, no podem identificar-te perquè el compte encara no s'ha activat. - signed_up_but_locked: T´has registrat amb èxit. No obstant, no podem identificar-te perquè el compte està blocat. + signed_up_but_inactive: T´has registrat amb èxit. No obstant, no podem iniciar la teva sessió perquè el teu compte encara no s'ha activat. + signed_up_but_locked: T´has registrat amb èxit. No obstant, no podem iniciar la teva sessió perquè el teu compte està bloquejat. signed_up_but_pending: S'ha enviat un missatge amb un enllaç de confirmació a la teva adreça de correu electrònic. Després que hagis fet clic a l'enllaç, revisarem la sol·licitud. Se't notificarà si s'aprova. - signed_up_but_unconfirmed: S'ha enviat per correu electrònic un missatge amb un enllaç de confirmació. Fes clic a l'enllaç per a activar el compte. - update_needs_confirmation: Ha actualitzat el seu compte amb èxit, però necessitem verificar la nova adreça de correu. Si us plau comprovi el correu i segueixi l'enllaç per confirmar la nova adreça de correu. - updated: El seu compte ha estat actualitzat amb èxit. + signed_up_but_unconfirmed: S'ha enviat per correu electrònic un missatge amb un enllaç de confirmació. Fes clic a l'enllaç per a activar el compte. Si us plau verifica la teva carpeta de correu brossa si no reps aquest correu. + update_needs_confirmation: Has actualitzat el teu compte amb èxit, però necessitem verificar la teva nova adreça de correu. Si us plau comprova el correu i segueixi l'enllaç per confirmar la nova adreça de correu. Si us plau verifica la teva carpeta de correu brossa si no reps aquest correu. + updated: El teu compte ha estat actualitzat amb èxit. sessions: already_signed_out: Has tancat la sessió amb èxit. signed_in: T'has registrat amb èxit. signed_out: Has tancat la sessió amb èxit. unlocks: send_instructions: En pocs minuts rebràs un correu electrònic amb instruccions sobre com desbloquejar el teu compte. Si us plau verifica la teva carpeta de correu brossa si no has rebut aquest correu. - send_paranoid_instructions: Si el compte existeix, rebràs en pocs minuts un correu electrònic amb instruccions sobre com desbloquejar-lo. Verifica la carpeta de correu brossa si no has rebut aquest correu. - unlocked: El compte s'ha desblocat correctament. Inicia sessió per a continuar. + send_paranoid_instructions: Si el teu compte existeix, rebràs en pocs minuts un correu electrònic amb instruccions sobre com desbloquejar-lo. Verifica la carpeta de correu brossa si no has rebut aquest correu. + unlocked: El compte s'ha desbloquejat correctament. Inicia sessió per a continuar. errors: messages: already_confirmed: ja està confirmat. Intenta d'iniciar sessió - confirmation_period_expired: calia fer la confirmació dins de %{period}, torna a sol·licitar-la - expired: ha expirat, demana'n una altra + confirmation_period_expired: cal fer la confirmació dins de %{period}, si us plau sol·licita-ho de nou + expired: ha expirat, si us plau demana'n una altra not_found: no s'ha trobat not_locked: no està bloquejada not_saved: one: '1 error ha impedit desar aquest %{resource}:' - other: "%{count} errors hab impedit desar aquest %{resource}:" + other: "%{count} errors han impedit desar aquest %{resource}:" diff --git a/config/locales/devise.da.yml b/config/locales/devise.da.yml index 6e4d5ad62..18aa43162 100644 --- a/config/locales/devise.da.yml +++ b/config/locales/devise.da.yml @@ -37,21 +37,21 @@ da: title: Adgangskode skiftet reconfirmation_instructions: explanation: Bekræft den nye adresse for at skifte din e-mail. - extra: Er denne ændring ikke foranlediget af dig, så ignorér denne e-mail. Mastodon-kontoens e-mailadresse skiftes ikke, før linket ovenfor benyttes. + extra: Er denne ændring ikke foranlediget af dig, så ignorér denne e-mail. Mastodon-kontoens e-mailadresse kan kun skiftes vha. linket ovenfor. subject: 'Mastodon: Bekræft e-mail for %{instance}' title: Bekræft e-mailadresse reset_password_instructions: action: Skift adgangskode explanation: Du har anmodet om en ny kontoadgangskode. - extra: Har du ikke anmodet om dette, så ignorér denne e-mail. Din adgangskode skiftes først, når linket ovenfor er benyttet til at oprette en ny. - subject: 'Mastodon: Nulstil adgangskode-instruktioner' + extra: Har du ikke anmodet om dette, så ignorér denne e-mail. Din adgangskode skiftes først, når en ny er oprettet vha. linket ovenfor. + subject: 'Mastodon: Instruktioner til adgangskodenulstilling' title: Adgangskodenulstilling two_factor_disabled: - explanation: Tofaktorgodkendelse for din konto er blevet deaktiveret. Indlogning er nu kun mulig via email og adgangskode. + explanation: Tofaktorgodkendelse for kontoen er blevet deaktiveret. Indlogning er nu kun mulig via email og adgangskode. subject: 'Mastodon: Tofaktorgodkendelse deaktiveret' title: 2FA deaktiveret two_factor_enabled: - explanation: Tofaktorgodkendelse er blevet aktiveret for din konto. Et login-token genereret af den parrede TOTP-app vil være nødvendig. + explanation: Tofaktorgodkendelse er blevet aktiveret for kontoen. Indlogning vil kærve et token genereret af den parrede TOTP-app. subject: 'Mastodon: Tofaktorgodkendelse aktiveret' title: 2FA aktiveret two_factor_recovery_codes_changed: @@ -70,38 +70,38 @@ da: subject: 'Mastodon: Sikkerhedsnøgle slettet' title: En af dine sikkerhedsnøgler er blevet slettet webauthn_disabled: - explanation: Godkendelse med sikkerhedsnøgler er blevet deaktiveret for din konto. Indlogning er nu kun mulig via token genereret af den parrede TOTP-app. + explanation: Godkendelse med sikkerhedsnøgler er blevet deaktiveret for kontoen. Indlogning er nu kun mulig via token genereret af den parrede TOTP-app. subject: 'Mastodon: Godkendelse med sikkerhedsnøgler deaktiveret' title: Sikkerhedsnøgler deaktiveret webauthn_enabled: - explanation: Sikkerhedsnøglegodkendelse er aktiveret for din konto. Din sikkerhedsnøgle kan nu bruges til indlogning. + explanation: Sikkerhedsnøglegodkendelse er aktiveret for kontoen. Din sikkerhedsnøgle kan nu bruges til indlogning. subject: 'Mastodon: Sikkerhedsnøglegodkendelse aktiveret' title: Sikkerhedsnøgler aktiveret omniauth_callbacks: failure: Kunne ikke godkende dig fra %{kind} fordi "%{reason}". success: Godkendt fra %{kind}-konto. passwords: - no_token: Denne side er kun tilgængelig via linket fra en adgangskodenulstillings e-mail. Husk i den forbindelse at benytte den fuldstændige URL fra e-mailen. + no_token: Denne side er kun tilgængelig via linket fra en e-mail til adgangskodenulstillings. Husk i den forbindelse at benytte den fuldstændige URL fra e-mailen. send_instructions: Er din e-mailadresse allerede registreret, e-mailes du et link til adgangskodenulstilling. Tjek spammappen, hvis e-mailen ikke ses i indbakken indenfor få minutter. - send_paranoid_instructions: Er din e-mail-adresse allerede registreret, e-mailes du et link til adgangskodegendannelse. Tjek spammappen, hvis e-mailen ikke ses i indbakken indenfor få minutter. + send_paranoid_instructions: Er din e-mailadresse allerede registreret, e-mailes du et link til adgangskodenulstilling. Tjek spammappen, hvis e-mailen ikke ses i indbakken indenfor få minutter. updated: Din adgangskode er skiftet, og du er nu logget ind. updated_not_active: Din adgangskode er skiftet. registrations: destroyed: Farvel! Din konto er nu annulleret. Vi håber snart at se dig igen. - signed_up: Velkommen! Du har nu tilmeldt dig. - signed_up_but_inactive: Du har nu oprettet dig. Da din konto endnu ikke er aktiveret, kan du dog pt. ikke logge ind. - signed_up_but_locked: Du har nu oprettet dig. Da din konto er låst, kan du pt. ikke logge ind. - signed_up_but_pending: En besked med et bekræftelseslink er e-mailet til dig. Når du har klikket på linket, gennemgår vi din ansøgning, og du får besked, hvis den godkendes. - signed_up_but_unconfirmed: En besked med et bekræftelseslink er e-mailet til dig. Følg linket for at aktivere din konto. Tjek din spammappe, hvis du ikke ser denne e-mail i din indbakke. - update_needs_confirmation: Du har opdateret din konto. Din nye e-mailadresse skal dog bekræftes. For at gøre dette, tjek din e-mail og følg bekræftelseslinket. Tjek din spammappe, hvis du ikke ser denne e-mail i din indbakke indenfor få minutter. + signed_up: Velkommen! Du er nu tilmeldt. + signed_up_but_inactive: Du har nu oprettet dig. Da din konto endnu ikke er aktiveret, kan du dog ikke logge ind med det samme. + signed_up_but_locked: Du har nu oprettet dig. Da din konto er låst, kan du ikke logge ind med det samme. + signed_up_but_pending: Et bekræftelseslink er e-mailet til dig. Når du har klikket på linket, gennemgår vi din ansøgning, og du får besked, hvis den godkendes. + signed_up_but_unconfirmed: Et bekræftelseslink er e-mailet til dig. Følg linket for at aktivere din konto. Tjek spammappen, hvis e-mailen ikke dukker op i indbakken. + update_needs_confirmation: Du har opdateret din konto. Din nye e-mailadresse skal nu bekræftes. Til dette formål er du blevet e-mailet et bekræftelseslink, så følg dette for at bekræfte den nye e-mailadresse. Ser du ikke e-mailen i din indbakke snarest, så tjek Spam-mappen. updated: Din konto er nu opdateret. sessions: already_signed_out: Du er nu logget ud. signed_in: Du er nu logget ind. signed_out: Du er nu logget ud. unlocks: - send_instructions: Instruktioner mailes til dig om, hvordan du oplåser din konto. Er denne e-mail ikke er i din indbakke inden for få minutter, så tjek spammappe. - send_paranoid_instructions: Findes din konto, mailes du instrukser om, hvordan du oplåser den. Ser du ikke denne e-mail i din indbakke undenfor få minutter, så tjek spammappen. + send_instructions: Instruktioner e-mailes til dig om, hvordan du oplåser din konto. Er e-mailen ikke er i din indbakke inden for få minutter, så tjek i Spam. + send_paranoid_instructions: Findes din konto, e-mailes du instrukser om, hvordan du oplåser den. Er e-mailen i din indbakke indenfor få minutter, så tjek i Spam. unlocked: Din konto er nu oplåst. Log ind for at fortsætte. errors: messages: diff --git a/config/locales/devise.ku.yml b/config/locales/devise.ku.yml index 9ae76dab2..18187a156 100644 --- a/config/locales/devise.ku.yml +++ b/config/locales/devise.ku.yml @@ -8,10 +8,10 @@ ku: failure: already_authenticated: Jixwe te berê têketin kiriye. inactive: Ajimêra te hîn nehatiye çalakkirin. - invalid: Nederbasdar %{authentication_keys} an jî şîfre. + invalid: "%{authentication_keys} an jî borînpeyv nederbasdar e." last_attempt: Peşiya kilît kirina ajimêra te carek din jî biceribîne. locked: Ajimêra ye hat kilît kirin. - not_found_in_database: Nederbasdar %{authentication_keys} an jî şîfre. + not_found_in_database: "%{authentication_keys} an jî borînpeyv nederbasdar e." pending: Ajimêra te hîn tê vekolandin. timeout: Danişîna te qedîya. Ji kerema xwe ji bo berdewamiyê dîsa têkeve. unauthenticated: Peşiya berdewamiya te têketina xwe bike an jî xwe tomar bike. @@ -33,10 +33,10 @@ ku: subject: 'Mastodon: E-name hate guhertin' title: Navnîşana e-nameya nû password_change: - explanation: Pêborîna ajimêra te hate guhertin. + explanation: Borînpeyva ajimêra te hate guhertin. extra: Heke te ajimêra xwe ne guhertiye. Ew tê wateya ku kesek ketiye ajimêrê te. Jkx pêborîna xwe zû biguherîne an jî bi rêveberiya rajekar re têkeve têkiliyê heke tu êdî nikare ajimêra xwe bi kar bînî. subject: 'Mastodon: pêborîn hate guhertin' - title: Pêborîn hate guhertin + title: Borînpeyv hate guhertin reconfirmation_instructions: explanation: Navnîşana nû piştrast bike da ku tu e-nameya xwe biguherînî. extra: |- @@ -45,13 +45,13 @@ ku: subject: 'Mastodon: E-nameyê piştrast bike bo %{instance}' title: Navnîşana e-nameyê piştrast bike reset_password_instructions: - action: Pêborînê biguherîne + action: Borînpeyvê biguherîne explanation: Te ji bo ajimêra xwe daxwaza pêborîneke nû kiriye. - extra: Heke te ev daxwaz nekir, jkx guh nede vê e-nameyê. Pêborîna te wê neyê guhertin heya ku tu li girêdana Jêrin bitikînî û yeka nû çê bikî. + extra: Heke te ev daxwaz nekir, jkx guh nede vê e-nameyê. Borînpeyva te wê neyê guhertin heya ku tu li girêdana Jêrin bitikînî û yeka nû çê bikî. subject: 'Mastodon: rêwerzên jê birina pêborîn' - title: Pêborîn ji nû ve saz bike + title: Borînpeyv ji nû ve saz bike two_factor_disabled: - explanation: Ji bo ajimêrê te piştrastkirina du-faktorî hat asteng kirin. Niha tu tenê bi navnîşana e-name û şîfre ya xwe dikarî têketin bikî. + explanation: Ji bo ajimêrê te piştrastkirina du-faktorî hat asteng kirin. Niha tu tenê bi navnîşana e-name û borînpeyva xwe dikarî têketinê bikî. subject: 'Mastodon: piştrastkirina du- faktorî neçalak bike' title: 2FA Neçalak e two_factor_enabled: @@ -85,11 +85,11 @@ ku: failure: Nikare ji %{kind} rastandinê bikê ji bo " %{reason}". success: Ji ajimêra %{kind} bi serkeftî hate rastandin. passwords: - no_token: Tu nikarî xwe bigihînî vê rûpelê bêyî ku tu ji e-nameya ji nû ve sazkirina pêborînê wernegerî. Heke tu ji e-nameya ji nû ve sazkirina pêborînê tê, ji kerema xwe pê ewle be ku tu girêdanê ya tevahî bi kar tînî. - send_instructions: Heke navnîşana te ya e-nameyê di danegeha me da hebê, tu yê di navnîşana xwe ya e-nameyê da girêdana rizgarkirina pêborînê bistînî. Heke te ev e-name wernegirtibe, ji kerema xwe peldanka xwe ya spamê kontrol bike. - send_paranoid_instructions: Heke navnîşana te ya e-nameyê di danegeha me da hebê, tu yê di navnîşana xwe ya e-nameyê da girêdana rizgarkirina pêborînê bistînî di hundir çend xulkan de. Heke te ev e-name wernegirtibe, ji kerema xwe peldanka xwe ya spamê kontrol bike. - updated: Pêborîna te bi serkeftî hate guhertin. Niha tu têketî ye. - updated_not_active: Pêborîna te bi serkeftî hate guhertin. + no_token: Tu nikarî xwe bigihînî vê rûpelê bêyî ku tu ji e-nameya ji nû ve sazkirina borînpeyvê wernegerî. Heke tu ji e-nameya ji nû ve sazkirina borînpeyvê tê, ji kerema xwe pê ewle be ku tu girêdanê ya tevahî bi kar tînî. + send_instructions: Heke navnîşana te ya e-nameyê di danegeha me da hebê, tu yê di navnîşana xwe ya e-nameyê da girêdana rizgarkirina borînpeyvê bistînî. Heke te ev e-name wernegirtibe, ji kerema xwe peldanka xwe ya spamê kontrol bike. + send_paranoid_instructions: Heke navnîşana te ya e-nameyê di danegeha me da hebê, tu yê di navnîşana xwe ya e-nameyê da girêdana rizgarkirina borînpeyvê bistînî di hundir çend xulkan de. Heke te ev e-name wernegirtibe, ji kerema xwe peldanka xwe ya spamê kontrol bike. + updated: Borînpeyva te bi serkeftî hate guhertin. Niha tu têketî ye. + updated_not_active: Borînpeyva te bi serkeftî hate guhertin. registrations: destroyed: Xatirê te! Ajimêra te bi serkeftî hate pûçkirin. Em hêvî dikin ku tu di nêzîk de te dîsa bibînin. signed_up: Bi xêr hatî! Te bi serkeftî tomarkirin kir. diff --git a/config/locales/devise.th.yml b/config/locales/devise.th.yml index 14f99f2c3..287ea49c5 100644 --- a/config/locales/devise.th.yml +++ b/config/locales/devise.th.yml @@ -12,7 +12,7 @@ th: last_attempt: คุณลองได้อีกหนึ่งครั้งก่อนที่บัญชีของคุณจะถูกล็อค locked: บัญชีของคุณถูกล็อค not_found_in_database: "%{authentication_keys} หรือรหัสผ่านไม่ถูกต้อง" - pending: บัญชีของคุณยังอยู่ระหว่างการตรวจทาน + pending: บัญชีของคุณยังคงอยู่ระหว่างการตรวจทาน timeout: เซสชันของคุณหมดอายุแล้ว โปรดลงชื่อเข้าอีกครั้งเพื่อดำเนินการต่อ unauthenticated: คุณจำเป็นต้องลงชื่อเข้าหรือลงทะเบียนก่อนดำเนินการต่อ unconfirmed: คุณต้องยืนยันที่อยู่อีเมลของคุณก่อนดำเนินการต่อ diff --git a/config/locales/doorkeeper.ca.yml b/config/locales/doorkeeper.ca.yml index a4d37f417..9725efe6c 100644 --- a/config/locales/doorkeeper.ca.yml +++ b/config/locales/doorkeeper.ca.yml @@ -13,9 +13,9 @@ ca: attributes: redirect_uri: fragment_present: no pot contenir un fragment. - invalid_uri: ha de ser un URI válid. - relative_uri: ha de ser un URI absoluta. - secured_uri: ha de ser un URI HTTPS/SSL. + invalid_uri: ha de ser una URI vàlida. + relative_uri: ha de ser una URI absoluta. + secured_uri: ha de ser una URI HTTPS/SSL. doorkeeper: applications: buttons: @@ -82,9 +82,9 @@ ca: messages: access_denied: El propietari del recurs o servidor d'autorizació ha denegat la petició. credential_flow_not_configured: Les credencials de contrasenya del propietari del recurs han fallat degut a que Doorkeeper.configure.resource_owner_from_credentials està sense configurar. - invalid_client: La autentificació del client ha fallat perquè és un client desconegut o no està inclòs l'autentificació del client o el mètode d'autenticació no està confirmat. - invalid_grant: La concessió d'autorizació oferida és invàlida, ha vençut, s'ha revocat, no coincideix amb l'URI de redirecció utilizada en la petició d'autorizació, o fou emesa per a un altre client. - invalid_redirect_uri: L'URI de redirecció inclòs no és vàlid. + invalid_client: La autentificació del client ha fallat perquè és un client desconegut o no està inclòsa l'autentificació del client o el mètode d'autenticació no està confirmat. + invalid_grant: La concessió d'autorizació oferta és invàlida, ha vençut, s'ha revocat, no coincideix amb l'URI de redirecció utilizada en la petició d'autorizació, o fou emesa per a un altre client. + invalid_redirect_uri: L'uri de redirecció inclòsa no és vàlida. invalid_request: missing_param: 'Falta paràmetre requerit: %{value}.' request_not_authorized: La petició ha de ser autoritzada. Falta o és invàlid un paràmetre requerit per l'autorització de la petició. @@ -154,7 +154,7 @@ ca: admin:write:accounts: fer l'acció de moderació en els comptes admin:write:reports: fer l'acció de moderació en els informes crypto: usa xifrat d'extrem a extrem - follow: seguir, blocar, desblocar i deixar de seguir comptes + follow: modificar relacions dels comptes push: rebre notificacions push del teu compte read: llegir les dades del teu compte read:accounts: veure informació dels comptes @@ -168,13 +168,13 @@ ca: read:notifications: veure les teves notificacions read:reports: veure els teus informes read:search: cerca en nom teu - read:statuses: veure tots els tuts - write: publicar en el teu nom + read:statuses: veure tots les publicacions + write: modificar totes les dades del teu compte write:accounts: modifica el teu perfil write:blocks: bloqueja comptes i dominis write:bookmarks: publicacions a marcadors write:conversations: silencia i esborra converses - write:favourites: afavoreix tuts + write:favourites: afavoreix publicacions write:filters: crear filtres write:follows: seguir usuaris write:lists: crear llistes @@ -182,4 +182,4 @@ ca: write:mutes: silencia usuaris i converses write:notifications: esborra les teves notificacions write:reports: informe d’altres persones - write:statuses: publicar tuts + write:statuses: publicar publicacions diff --git a/config/locales/doorkeeper.da.yml b/config/locales/doorkeeper.da.yml index 19f4307f6..094faedba 100644 --- a/config/locales/doorkeeper.da.yml +++ b/config/locales/doorkeeper.da.yml @@ -4,7 +4,7 @@ da: attributes: doorkeeper/application: name: Applikationsnavn - redirect_uri: Link + redirect_uri: Omdirigerings-URI scopes: Områder website: Applikationswebsted errors: @@ -13,7 +13,7 @@ da: attributes: redirect_uri: fragment_present: kan ikke indeholde et fragment. - invalid_uri: skal være en gyldigt URI. + invalid_uri: skal være en gyldig URI. relative_uri: skal være en absolut URI. secured_uri: skal være en HTTPS-/SSL-URI. doorkeeper: @@ -33,7 +33,7 @@ da: help: native_redirect_uri: Brug %{native_redirect_uri} til lokale tests redirect_uri: Brug én linje pr. URI - scopes: Adskil omfang med mellemrum. Lad være tomt for standardomfang. + scopes: Adskil omfang med mellemrum. Lad stå tomt for standardomfang. index: application: Applikation callback_url: Callback-URL @@ -60,9 +60,9 @@ da: error: title: En fejl opstod new: - prompt_html: "%{client_name} ønsker tilladelse til at tilgå din konto. Den er en tredjepartsapplikation. <strong>Er der ikke tillid til den, bør den ikke godkendes.</strong>" + prompt_html: "%{client_name} ønsker tilladelse til at tilgå din konto. Den er en tredjepartsapplikation. <strong>Har du ikke tillid til den, bør den ikke godkendes.</strong>" review_permissions: Gennemgå tilladelser - title: Godkendelse krævet + title: Godkendelse kræves show: title: Kopiér og indsæt denne godkendelseskode i applikationen. authorized_applications: @@ -72,7 +72,7 @@ da: revoke: Sikker? index: authorized_at: Godkendt pr. %{date} - description_html: Disse er applikationer, som kan tilgå din konto vha. API'en. Er der applikationer her, som ikke genkendes eller udviser mærkelig adfærd, kan deres adgang tilbagekaldes. + description_html: Disse er applikationer, som kan tilgå din konto vha. API'en. Er her applikationer, som ikke genkendes eller udviser mærkværdig adfærd, kan deres adgangstilladelse ophæves. last_used_at: Senest brugt pr. %{date} never_used: Aldrig brugt scopes: Tilladelser @@ -81,25 +81,25 @@ da: errors: messages: access_denied: Ressourceejeren eller godkendelsesserveren afviste anmodningen. - credential_flow_not_configured: Ressourceejeradgangskodeakkreditiv flow mislykkedes grundet ikke-opsat Doorkeeper.configure.resource_owner_from_credentials. - invalid_client: Klientbekræftelse mislykkedes grundet en ukendt klient, ingen klientbekræftelse inkluderet, eller uunderstøttet bekræftelsesmetode. - invalid_grant: Den leverede godkendelse er ugyldig, udløbet, tilbagekaldt, matcher ikke omdirigerings-URI brugt i godkendelsesanmodningen, eller er udstedt til en anden klient. + credential_flow_not_configured: Ressourceejeradgangskodeakkreditiver-flow mislykkedes grundet ikke-opsat Doorkeeper.configure.resource_owner_from_credentials. + invalid_client: Klientgodkendelse mislykkedes grundet en ukendt klient, ingen inkluderet klientgodkendelse eller uunderstøttet godkendelsesmetode. + invalid_grant: Den leverede godkendelse er ugyldig, udløbet, ophævet, matcher ikke omdirigerings-URI'en brugt i godkendelsesanmodningen eller er udstedt til en anden klient. invalid_redirect_uri: Inkluderede ormdirigerings-URI er ugyldig. invalid_request: - missing_param: 'Mangler krævet parameter: %{value}.' - request_not_authorized: Anmodning skal godkendes. Krævet parameter til godkendelse af anmodning mangler eller er ugyldig. - unknown: Anmodningen mangler en krævet parametre, inkluderer en uunderstøttet parametre værdi eller er på anden vis fejlbehæftet. - invalid_resource_owner: De angivne ressourceejerakkreditiver er ugyldige, eller ressourceejer kunne ikke findes - invalid_scope: Det anmodede omfang er ugyldigt, ukendt eller fejlbehæftet. + missing_param: 'Mangler obligatoriske parameter: %{value}.' + request_not_authorized: Anmodning kræver godkendelse. Obligatorisk parameter til godkendelse af anmodning mangler eller er ugyldig. + unknown: Anmodningen mangler en obligatorisk parameter, indeholder en uunderstøttet parameterværdi eller er på anden vis fejlbehæftet. + invalid_resource_owner: De angivne ressourceejerakkreditiver er ugyldige, eller ressourceejer kan ikke findes + invalid_scope: Det anmodede omfang er ugyldigt, ukendt eller forkert udformet. invalid_token: expired: Adgangstoken er udløbet - revoked: Adgangstoken er tilbagekaldt - unknown: Adgangstoken er ugyldig + revoked: Adgangstoken er ophævet + unknown: Adgangstoken er ugyldigt resource_owner_authenticator_not_configured: Ressourceejer kunne ikke findes grundet ikke-opsat Doorkeeper.configure.resource_owner_authenticator. server_error: Godkejdelsesserveren stødte på en uventet betingelse, der forhindrede den i at imødekomme anmodningen. temporarily_unavailable: Godkendelsesserveren kan pt. ikke håndtere anmodningen grundet midlertidig overbelastning eller servervedligehold. - unauthorized_client: Klienten er ikke godkendt til at udføre denne anmodning via denne metode. - unsupported_grant_type: Godkendelsestypen understøttes ikke af godkendelsesserveren. + unauthorized_client: Klienten er ikke godkendt til at udføre denne anmodning vha. denne metode. + unsupported_grant_type: Godkendelsestildelingstypen understøttes ikke af godkendelsesserveren. unsupported_response_type: Godkendelsesserveren understøtter ikke denne svartype. flash: applications: @@ -111,7 +111,7 @@ da: notice: Applikation opdateret. authorized_applications: destroy: - notice: Applikation tilbagekaldt. + notice: Applikation ophævet. grouped_scopes: access: read: Skrivebeskyttet adgang @@ -133,7 +133,7 @@ da: follows: Følger lists: Lister media: Medievedhæftninger - mutes: Tavsgjorte + mutes: Tavsgørelser notifications: Notifikationer push: Push-notifikationer reports: Anmeldelser @@ -143,43 +143,43 @@ da: admin: nav: applications: Applikationer - oauth2_provider: OAuth-udbyder + oauth2_provider: OAuth2-leverandør application: - title: OAuth-godkendelse krævet + title: OAuth-godkendelse obligatorisk scopes: - admin:read: læs al data på serveren + admin:read: læs alle data på serveren admin:read:accounts: læs sensitiv information fra alle konti admin:read:reports: læs sensitiv information fra alle anmeldelser og anmeldte konti - admin:write: redigér al data på serveren + admin:write: redigér alle data på serveren admin:write:accounts: udfør modereringshandlinger på konti admin:write:reports: udfør modereringshandlinger på anmeldelser crypto: benyt ende-til-ende kryptering follow: ændre kontorelationer - push: modtage dine push-notifikationer - read: læse alle dine kontodata + push: modtag dine push-notifikationer + read: læs alle dine kontodata read:accounts: se kontooplysninger read:blocks: se dine blokeringer read:bookmarks: se dine bogmærker read:favourites: se dine favoritter read:filters: se dine filtre - read:follows: se, hvem du følger + read:follows: se dine følger read:lists: se dine lister read:mutes: se dine tavsgørelser read:notifications: se dine notifikationer read:reports: se dine anmeldelser - read:search: søge på dine vegne - read:statuses: se alle statusser + read:search: søg på dine vegne + read:statuses: se alle indlæg write: ændre alle dine kontodata write:accounts: ændre din profil write:blocks: blokere konti og domæner - write:bookmarks: bogmærke statusser - write:conversations: tavsgør og slet konversationer - write:favourites: favoritmarkerede indlæg + write:bookmarks: bogmærke indlæg + write:conversations: tavsgøre og slette konversationer + write:favourites: favoritmarkere indlæg write:filters: oprette filtre write:follows: følge personer write:lists: oprette lister - write:media: uploade multimediefiler + write:media: uploade mediefiler write:mutes: tavsgøre personer og konversationer write:notifications: rydde dine notifikationer write:reports: anmelde personer - write:statuses: udgive statusser + write:statuses: udgive indlæg diff --git a/config/locales/doorkeeper.fa.yml b/config/locales/doorkeeper.fa.yml index cc479fbc1..9f455e64b 100644 --- a/config/locales/doorkeeper.fa.yml +++ b/config/locales/doorkeeper.fa.yml @@ -29,7 +29,7 @@ fa: edit: title: ویرایش برنامه form: - error: اوخ! ببینید چیزی را اشتباهی در فرم وارد نکردهاید؟ + error: اوخ! ببینید چیزی را اشتباهی در فرم وارد نکردهاید help: native_redirect_uri: برای آزمایشهای محلی %{native_redirect_uri} را به کار ببرید redirect_uri: هر URI را در یک سطر جدا بنویسید @@ -60,6 +60,7 @@ fa: error: title: خطایی رخ داد new: + review_permissions: بازبینی اجازهها title: نیاز به اجازه دادن show: title: این کد مجوز را کپی کرده و در برنامه وارد کنید. @@ -69,6 +70,7 @@ fa: confirmations: revoke: آیا مطمئن هستید؟ index: + scopes: اجازهها title: برنامههای مجاز errors: messages: @@ -104,6 +106,29 @@ fa: authorized_applications: destroy: notice: برنامه فسخ شد. + grouped_scopes: + access: + read: فقط دسترسی خواندن + read/write: دسترسی خواندن و نوشتن + write: فقط دسترسی نوشتن + title: + accounts: حسابها + all: همه چیز + blocks: مسدودها + bookmarks: نشانکها + conversations: گفتوگوها + crypto: رمزگذاری سرتاسری + favourites: پسندیدهها + filters: پالایهها + follows: پیگرفتگان + lists: سیاههها + media: پیوستهای رسانهای + mutes: خموشها + notifications: آگاهیها + push: آگاهیهای ارسالی + reports: گزارشها + search: جستوجو + statuses: فرستهها layouts: admin: nav: @@ -118,11 +143,12 @@ fa: admin:write: تغییر تمام دادهها روی کارساز admin:write:accounts: انجام کنش مدیریتی روی حسابها admin:write:reports: انجام کنش مدیریتی روی گزارشها + crypto: از رمزگذاری سرتاسر استفاده کنید follow: پیگیری، مسدودسازی، لغو مسدودسازی، و لغو پیگیری حسابها push: دریافت آگاهیای ارسالیتان read: خواندن اطلاعات حساب شما read:accounts: دیدن اطّلاعات حساب - read:blocks: دیدن انسدادهایتان + read:blocks: دیدن مسدودهایتان read:bookmarks: دیدن نشانکهایتان read:favourites: دیدن برگزیدههایتان read:filters: دیدن پالایههایتان @@ -137,6 +163,7 @@ fa: write:accounts: تغییر نمایهتان write:blocks: انسداد حسابها و دامنهها write:bookmarks: نشانکگذاری وضعیتها + write:conversations: مکالمات را بیصدا و حذف کنید write:favourites: برگزیدن وضعیتها write:filters: ایحاد پالایشها write:follows: پیگیری افراد diff --git a/config/locales/doorkeeper.gd.yml b/config/locales/doorkeeper.gd.yml index 217dca738..c5a830fc7 100644 --- a/config/locales/doorkeeper.gd.yml +++ b/config/locales/doorkeeper.gd.yml @@ -60,6 +60,8 @@ gd: error: title: Thachair mearachd new: + prompt_html: Bu mhiann le %{client_name} cead gus an cunntas agad inntrigeadh. Seo aplacaid threas-phàrtaidh. <strong>Mur eil earbsa agad ann, na ùghdarraich e.</strong> + review_permissions: Thoir sùil air na ceadan title: Tha feum air ùghdarrachadh show: title: Dèan lethbhreac dhen chòd ùghdarrachaidh seo ’s cuir san aplacaid e. @@ -69,6 +71,12 @@ gd: confirmations: revoke: A bheil thu cinnteach? index: + authorized_at: Air ùghdarrachadh %{date} + description_html: Seo na h-aplacaidean as urrainn dhaibh an cunntas agad inntrigeadh leis an API. Ma tha aplacaid an-seo nach aithne dhut no ma tha droch-ghiùlan air aplacaid, ’s urrainn dhut an t-inntrigeadh aice a chùl-ghairm. + last_used_at: Air a chleachdadh %{date} an turas mu dheireadh + never_used: Cha deach a chleachdadh a-riamh + scopes: Ceadan + superapp: Inntearnail title: Na h-aplacaidean ùghdarraichte agad errors: messages: @@ -104,6 +112,33 @@ gd: authorized_applications: destroy: notice: Chaidh an t-iarrtas a chùl-ghairm. + grouped_scopes: + access: + read: Inntrigeadh leughaidh a-mhàin + read/write: Inntrigeadh leughaidh is sgrìobhaidh + write: Inntrigeadh sgrìobhaidh a-mhàin + title: + accounts: Cunntasan + admin/accounts: Rianachd nan cunntas + admin/all: Gach gleus na rianachd + admin/reports: Rianachd nan gearan + all: A h-uile rud + blocks: Bacaidhean + bookmarks: Comharran-lìn + conversations: Còmhraidhean + crypto: Crioptachadh o cheann gu ceann + favourites: Annsachdan + filters: Criathragan + follow: Dàimhean + follows: Leantainn + lists: Liostaichean + media: Ceanglachain mheadhanan + mutes: Mùchaidhean + notifications: Brathan + push: Brathan putaidh + reports: Gearanan + search: Lorg + statuses: Postaichean layouts: admin: nav: @@ -118,6 +153,7 @@ gd: admin:write: dàta sam bith atharrachadh air an fhrithealaiche admin:write:accounts: gnìomhan na maorsainneachd a ghabhail air cunntasan admin:write:reports: gnìomhan na maorsainneachd a ghabhail air gearanan + crypto: crioptachadh o cheann gu ceann a chleachdadh follow: dàimhean chunntasan atharrachadh push: na brathan putaidh agad fhaighinn read: dàta sam bith a’ cunntais agad a leughadh @@ -137,6 +173,7 @@ gd: write:accounts: a’ phròifil agad atharrachadh write:blocks: cunntasan is àrainnean a bhacadh write:bookmarks: comharran-lìn a dhèanamh de phostaichean + write:conversations: còmhraidhean a mhùchadh is a sguabadh às write:favourites: postaichean a chur ris na h-annsachdan write:filters: criathragan a chruthachadh write:follows: leantainn air daoine diff --git a/config/locales/doorkeeper.id.yml b/config/locales/doorkeeper.id.yml index 050d97dc5..9a3fed94d 100644 --- a/config/locales/doorkeeper.id.yml +++ b/config/locales/doorkeeper.id.yml @@ -73,6 +73,10 @@ id: index: authorized_at: Diberi hak otorisasi pada %{date} description_html: Ini adalah aplikasi yang dapat mengakses akun Anda menggunakan API. Jika ada aplikasi yang tidak Anda kenal di sini, atau aplikasi yang berperilaku aneh, Anda dapat mencabut hak aksesnya. + last_used_at: Terakhir dipakai pada %{date} + never_used: Tidak pernah dipakai + scopes: Hak akses + superapp: Internal title: Aplikasi yang anda izinkan errors: messages: @@ -108,6 +112,33 @@ id: authorized_applications: destroy: notice: Aplikasi dicabut. + grouped_scopes: + access: + read: Akses baca-saja + read/write: Akses baca dan tulis + write: Akses tulis-saja + title: + accounts: Akun + admin/accounts: Administrasi akun + admin/all: Semua fungsi administratif + admin/reports: Administrasi laporan + all: Segalanya + blocks: Blokir + bookmarks: Markah + conversations: Percakapan + crypto: Enkripsi end-to-end + favourites: Favorit + filters: Saringan + follow: Hubungan + follows: Mengikuti + lists: Daftar + media: Lampiran media + mutes: Bisukan + notifications: Notifikasi + push: Notifikasi dorong + reports: Laporan + search: Pencarian + statuses: Kiriman layouts: admin: nav: @@ -122,6 +153,7 @@ id: admin:write: ubah semua data di server admin:write:accounts: lakukan aksi moderasi akun admin:write:reports: lakukan aksi moderasi laporan + crypto: menggunakan enkripsi end-to-end follow: mengikuti, blokir, menghapus blokir, dan berhenti mengikuti akun push: terima notifikasi dorong read: membaca data pada akun anda @@ -141,6 +173,7 @@ id: write:accounts: ubah profil Anda write:blocks: blokir akun dan domain write:bookmarks: status markah + write:conversations: bisukan dan hapus percakapan write:favourites: status favorit write:filters: buat saringan write:follows: ikuti orang diff --git a/config/locales/doorkeeper.ku.yml b/config/locales/doorkeeper.ku.yml index 3a98486e3..f92a228d1 100644 --- a/config/locales/doorkeeper.ku.yml +++ b/config/locales/doorkeeper.ku.yml @@ -31,7 +31,7 @@ ku: form: error: Wey li min! kontrol bikeku form çewtî tê de tune help: - native_redirect_uri: Bo testên herêmî %{native_redirect_uri} bikar bîne + native_redirect_uri: Bo testên herêmî %{native_redirect_uri} bi kar bîne redirect_uri: Serê URl de rêzek bikarbînin scopes: Berfirehî bi valahîyan re veqetîne. Bo bikaranîna berfirehî ya standard vala bihêle. index: @@ -81,7 +81,7 @@ ku: errors: messages: access_denied: Xwedîyê çavkanîyê an jî destûrmendê rajeker daxwazî red kirin. - credential_flow_not_configured: Herikîna pêborînê bawername ya xwediyê çavkaniyê, ji ber Doorkeeper.configure.resource_owner_from_credentials nehat pevsazkirin. + credential_flow_not_configured: Herikîna borînpeyvê bawername ya xwediyê çavkaniyê, ji ber Doorkeeper.configure.resource_owner_from_credentials nehat pevsazkirin. invalid_client: Erêkirina nasnameyê rajegir ji ber rajegirê nediyar têk çû, erêkirina nasnameyê rajegir di nav da tinne an jî rêbaza erêkirinê ne piştgirêdayî ye. invalid_grant: Mafê ku hatiye peyda kirin ne derbasdar e, qediya ye, pûç e, girêdana ya ku di daxwaza mafê de tê bikaranîn li hev nagire an jî rajegirekî din hildaye. invalid_redirect_uri: Girêdan beralîkirî ya di nav da ne derbasdar e. @@ -130,7 +130,7 @@ ku: favourites: Bijarte filters: Parzûn follow: Pêwendî - follows: Şopîner + follows: Dişopîne lists: Rêzok media: Pêvekên medya mutes: Bêdengkirin @@ -162,7 +162,7 @@ ku: read:bookmarks: şûnpelên xwe bibîne read:favourites: bijarteyên xwe bibîne read:filters: parzûnûn xwe bibîne - read:follows: şopînerên xwe bibîne + read:follows: ên tu dişopînî bibîne read:lists: rêzoka xwe bibîne read:mutes: ajimêrên bêdeng kirî bibîne read:notifications: agahdariyên xwe bibîne diff --git a/config/locales/doorkeeper.nl.yml b/config/locales/doorkeeper.nl.yml index cb0c70aab..76f3b88c3 100644 --- a/config/locales/doorkeeper.nl.yml +++ b/config/locales/doorkeeper.nl.yml @@ -60,6 +60,8 @@ nl: error: title: Er is een fout opgetreden new: + prompt_html: "%{client_name} heeft toestemming nodig om toegang te krijgen tot jouw account. Het betreft een third-party-toepassing.<strong>Als je dit niet vertrouwt, moet je geen toestemming verlenen.</strong>" + review_permissions: Toestemmingen beoordelen title: Autorisatie vereist show: title: Kopieer deze autorisatiecode en plak het in de toepassing. @@ -69,6 +71,11 @@ nl: confirmations: revoke: Weet je het zeker? index: + authorized_at: Toestemming verleent op %{date} + last_used_at: Voor het laatst gebruikt op %{date} + never_used: Nooit gebruikt + scopes: Toestemmingen + superapp: Intern title: Jouw geautoriseerde toepassingen errors: messages: @@ -104,6 +111,33 @@ nl: authorized_applications: destroy: notice: Toepassing ingetrokken. + grouped_scopes: + access: + read: Alleen leestoegang + read/write: Lees- en schrijftoegang + write: Alleen schrijftoegang + title: + accounts: Accounts + admin/accounts: Accountbeheer + admin/all: Alle beheerfuncties + admin/reports: Rapportagebeheer + all: Alles + blocks: Blokkeren + bookmarks: Bladwijzers + conversations: Gesprekken + crypto: End-to-end-encryptie + favourites: Favorieten + filters: Filters + follow: Relaties + follows: Volgend + lists: Lijsten + media: Mediabijlagen + mutes: Negeren + notifications: Meldingen + push: Pushmeldingen + reports: Rapportages + search: Zoeken + statuses: Berichten layouts: admin: nav: @@ -118,6 +152,7 @@ nl: admin:write: wijzig alle gegevens op de server admin:write:accounts: moderatieacties op accounts uitvoeren admin:write:reports: moderatieacties op rapportages uitvoeren + crypto: end-to-end-encryptie gebruiken follow: relaties tussen accounts bewerken push: jouw pushmeldingen ontvangen read: alle gegevens van jouw account lezen @@ -130,14 +165,15 @@ nl: read:lists: jouw lijsten bekijken read:mutes: jouw genegeerde gebruikers bekijken read:notifications: jouw meldingen bekijken - read:reports: jouw gerapporteerde toots bekijken + read:reports: jouw gerapporteerde berichten bekijken read:search: namens jou zoeken - read:statuses: alle toots bekijken + read:statuses: alle berichten bekijken write: alle gegevens van jouw account bewerken write:accounts: jouw profiel bewerken write:blocks: accounts en domeinen blokkeren - write:bookmarks: toots aan bladwijzers toevoegen - write:favourites: toots als favoriet markeren + write:bookmarks: berichten aan bladwijzers toevoegen + write:conversations: gespreken negeren en verwijderen + write:favourites: berichten als favoriet markeren write:filters: filters aanmaken write:follows: mensen volgen write:lists: lijsten aanmaken @@ -145,4 +181,4 @@ nl: write:mutes: mensen en gesprekken negeren write:notifications: meldingen verwijderen write:reports: andere mensen rapporteren - write:statuses: toots publiceren + write:statuses: berichten plaatsen diff --git a/config/locales/doorkeeper.pt-BR.yml b/config/locales/doorkeeper.pt-BR.yml index 7c77af88b..93cd0c55a 100644 --- a/config/locales/doorkeeper.pt-BR.yml +++ b/config/locales/doorkeeper.pt-BR.yml @@ -113,6 +113,7 @@ pt-BR: accounts: Contas all: Tudo blocks: Blocos + bookmarks: Salvos conversations: Conversas crypto: Criptografia de ponta a ponta favourites: Favoritos diff --git a/config/locales/doorkeeper.sk.yml b/config/locales/doorkeeper.sk.yml index 3f92a67ae..3e29a3332 100644 --- a/config/locales/doorkeeper.sk.yml +++ b/config/locales/doorkeeper.sk.yml @@ -101,6 +101,7 @@ sk: notice: Oprávnenia aplikácie zrušené. grouped_scopes: title: + blocks: Blokovania mutes: Nevšímané layouts: admin: diff --git a/config/locales/doorkeeper.uk.yml b/config/locales/doorkeeper.uk.yml index 44562f4b8..e9000cf46 100644 --- a/config/locales/doorkeeper.uk.yml +++ b/config/locales/doorkeeper.uk.yml @@ -60,6 +60,7 @@ uk: error: title: Сталася помилка new: + review_permissions: Переглянути дозволи title: Необхідна авторизація show: title: Скопіюйте цей код авторизації та вставте його у додаток. @@ -69,8 +70,11 @@ uk: confirmations: revoke: Ви впевнені? index: + authorized_at: Авторизовано %{date} + last_used_at: Востаннє використано %{date} never_used: Ніколи не використовувалися scopes: Дозволи + superapp: Внутрішній title: Ваші авторизовані додатки errors: messages: @@ -107,13 +111,27 @@ uk: destroy: notice: Авторизацію додатка відкликано. grouped_scopes: + access: + read: Доступ без права внесення змін + read/write: Доступ до читання і запису + write: Доступ лише для запису title: accounts: Облікові записи + admin/accounts: Адміністрація облікових записів + admin/all: Усі адміністративні функції + admin/reports: Адміністрація звітів all: Усе + blocks: Блокування + bookmarks: Закладки + conversations: Бесіди crypto: Наскрізне шифрування + favourites: Вподобане filters: Фільтри + follow: Взаємозв'язки + follows: Підписки lists: Списки media: Мультимедійні вкладення + mutes: Заглушені notifications: Сповіщення push: Push-сповіщення reports: Скарги @@ -153,6 +171,7 @@ uk: write:accounts: змінювати ваш профіль write:blocks: блокувати облікові записи і домени write:bookmarks: додавати пости в закладки + write:conversations: заглушити і видалити розмови write:favourites: вподобані статуси write:filters: створювати фільтри write:follows: підписуйтесь на людей diff --git a/config/locales/doorkeeper.vi.yml b/config/locales/doorkeeper.vi.yml index 4acfd9977..ecd5cfc4c 100644 --- a/config/locales/doorkeeper.vi.yml +++ b/config/locales/doorkeeper.vi.yml @@ -71,13 +71,13 @@ vi: confirmations: revoke: Bạn có chắc không? index: - authorized_at: Cấp quyền vào %{date} + authorized_at: Cho phép vào %{date} description_html: Đây là những ứng dụng có thể truy cập tài khoản của bạn bằng API. Nếu có ứng dụng bạn không nhận ra ở đây hoặc ứng dụng hoạt động sai, bạn có thể thu hồi quyền truy cập của ứng dụng đó. - last_used_at: Dùng gần nhất vào %{date} - never_used: Chưa dùng bao giờ + last_used_at: Dùng lần cuối %{date} + never_used: Chưa dùng scopes: Quyền cho phép superapp: Đang dùng - title: Các ứng dụng đang cho phép + title: Các ứng dụng đang dùng errors: messages: access_denied: Chủ sở hữu tài nguyên hoặc máy chủ đã từ chối yêu cầu. diff --git a/config/locales/en.yml b/config/locales/en.yml index d4a42e867..829cd61d0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -168,7 +168,6 @@ en: previous_strikes_description_html: one: This account has <strong>one</strong> strike. other: This account has <strong>%{count}</strong> strikes. - zero: This account is <strong>in good standing</strong>. promote: Promote protocol: Protocol public: Public @@ -490,6 +489,7 @@ en: other: Failed attempts on %{count} different days. no_failures_recorded: No failures on record. title: Availability + warning: The last attempt to connect to this server has been unsuccessful back_to_all: All back_to_limited: Limited back_to_warning: Warning @@ -529,7 +529,6 @@ en: known_accounts: one: "%{count} known account" other: "%{count} known accounts" - zero: No known account moderation: all: All limited: Limited @@ -774,6 +773,11 @@ en: system_checks: database_schema_check: message_html: There are pending database migrations. Please run them to ensure the application behaves as expected + elasticsearch_running_check: + message_html: Could not connect to Elasticsearch. Please check that it is running, or disable full-text search + elasticsearch_version_check: + message_html: 'Incompatible Elasticsearch version: %{value}' + version_comparison: Elasticsearch %{running_version} is running while %{required_version} is required rules_check: action: Manage server rules message_html: You haven't defined any server rules. @@ -796,7 +800,6 @@ en: shared_by_over_week: one: Shared by one person over the last week other: Shared by %{count} people over the last week - zero: Shared by noone over the last week title: Trending links usage_comparison: Shared %{today} times today, compared to %{yesterday} yesterday pending_review: Pending review @@ -839,7 +842,6 @@ en: used_by_over_week: one: Used by one person over the last week other: Used by %{count} people over the last week - zero: Used by noone over the last week title: Trends warning_presets: add_new: Add new diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml index 7dee30a27..36b46eb47 100644 --- a/config/locales/es-AR.yml +++ b/config/locales/es-AR.yml @@ -168,7 +168,6 @@ es-AR: previous_strikes_description_html: one: Esta cuenta tiene <strong>un</strong> incumplimiento. other: Esta cuenta tiene <strong>%{count}</strong> incumplimientos. - zero: Esta cuenta está <strong>en buen estado</strong>. promote: Promover protocol: Protocolo public: Pública @@ -490,6 +489,7 @@ es-AR: other: Intentos fallidos en %{count} días. no_failures_recorded: No hay fallos en el registro. title: Disponibilidad + warning: El último intento de conexión a este servidor no fue exitoso back_to_all: Todos back_to_limited: Limitados back_to_warning: Advertencia @@ -529,7 +529,6 @@ es-AR: known_accounts: one: "%{count} cuenta conocida" other: "%{count} cuentas conocidas" - zero: Ninguna cuenta conocida moderation: all: Todas limited: Limitadas @@ -774,6 +773,11 @@ es-AR: system_checks: database_schema_check: message_html: Hay migraciones pendientes de la base de datos. Por favor, ejecutalas para asegurarte de que la aplicación funciona según lo esperado + elasticsearch_running_check: + message_html: No se pudo conectar a Elasticsearch. Por favor, revisá que se esté ejecutando, o deshabilitá la búsqueda de texto completo + elasticsearch_version_check: + message_html: 'Versión incompatible de Elasticsearch: %{value}' + version_comparison: Se está ejecutando la versión %{running_version} de Elasticsearch, mientras que la versión requerida es la %{required_version} rules_check: action: Administrar reglas del servidor message_html: No definiste ninguna regla del servidor. @@ -794,9 +798,8 @@ es-AR: disallow: Rechazar enlace disallow_provider: Rechazar medio shared_by_over_week: - one: Compartido por una persona en la última semana - other: Compartido por %{count} personas en la última semana - zero: Compartido por nadie en la última semana + one: Compartido por una persona durante la última semana + other: Compartido por %{count} personas durante la última semana title: Enlaces en tendencia usage_comparison: Compartido %{today} veces hoy, comparado con la/s %{yesterday} vez/veces de ayer pending_review: Revisión pendiente @@ -837,9 +840,8 @@ es-AR: usable: Pueden usarse usage_comparison: Usadas %{today} veces hoy, comparado con la/s %{yesterday} vez/veces de ayer used_by_over_week: - one: Usada por una persona en la última semana - other: Usada por %{count} personas en la última semana - zero: Usada por nadie en la última semana + one: Usada por una persona durante la última semana + other: Usada por %{count} personas durante la última semana title: Tendencias warning_presets: add_new: Agregar nuevo diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index da321d7ee..17af40f2c 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -165,10 +165,6 @@ es-MX: pending: Revisión pendiente perform_full_suspension: Suspender previous_strikes: Amonestaciones anteriores - previous_strikes_description_html: - one: Esta cuenta tiene <strong>una</strong> amonestación. - other: Esta cuenta tiene <strong>%{count}</strong> amonestaciones. - zero: Esta cuenta está <strong>en buen estado</strong>. promote: Promocionar protocol: Protocolo public: Público @@ -490,6 +486,7 @@ es-MX: other: Intentos fallidos en %{count} días diferentes. no_failures_recorded: No hay fallos en el registro. title: Disponibilidad + warning: El último intento de conexión a este servidor no ha tenido éxito back_to_all: Todos back_to_limited: Limitados back_to_warning: Advertencia @@ -526,10 +523,6 @@ es-MX: delivery_error_hint: Si la entrega no es posible a lo largo de %{count} días, se marcará automáticamente como no entregable. destroyed_msg: Los datos de %{domain} están ahora en cola para su inminente eliminación. empty: No se encontraron dominios. - known_accounts: - one: "%{count} cuenta conocida" - other: "%{count} cuentas conocidas" - zero: Ninguna cuenta conocida moderation: all: Todos limited: Limitado @@ -774,6 +767,11 @@ es-MX: system_checks: database_schema_check: message_html: Hay migraciones pendientes de la base de datos. Por favor, ejecútalas para asegurarte de que la aplicación funciona como debería + elasticsearch_running_check: + message_html: No se pudo conectar a Elasticsearch. Por favor, comprueba que está ejecutándose, o desactiva la búsqueda de texto completo + elasticsearch_version_check: + message_html: 'Versión incompatible de Elasticsearch: %{value}' + version_comparison: Elasticsearch %{running_version} se está ejecutando pero se necesita Elasticsearch %{required_version} rules_check: action: Administrar reglas del servidor message_html: No ha definido ninguna regla del servidor. @@ -793,10 +791,6 @@ es-MX: description_html: Estos son enlaces que actualmente están siendo compartidos mucho por las cuentas desde las que tu servidor ve los mensajes. Pueden ayudar a tus usuarios a averiguar qué está pasando en el mundo. Ningún enlace se muestren públicamente hasta que autorice al dominio. También puede permitir o rechazar enlaces individuales. disallow: Rechazar enlace disallow_provider: Rechazar editor - shared_by_over_week: - one: Compartido por una persona en la última semana - other: Compartido por %{count} personas durante la última semana - zero: Compartido por nadie en la última semana title: Enlaces en tendencia usage_comparison: Compartido %{today} veces hoy, comparado a %{yesterday} ayer pending_review: Revisión pendiente @@ -836,10 +830,6 @@ es-MX: trending_rank: Tendencia n.º %{rank} usable: Pueden usarse usage_comparison: Usada %{today} veces hoy, comparado con %{yesterday} ayer - used_by_over_week: - one: Usada por una persona durante la última semana - other: Usada por %{count} personas durante la última semana - zero: Usada por nadie en la última semana title: Tendencias warning_presets: add_new: Añadir nuevo diff --git a/config/locales/es.yml b/config/locales/es.yml index bcce44e20..2ac09ea44 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -168,7 +168,6 @@ es: previous_strikes_description_html: one: Esta cuenta tiene <strong>una</strong> amonestación. other: Esta cuenta tiene <strong>%{count}</strong> amonestaciones. - zero: Esta cuenta está <strong>en buen estado</strong>. promote: Promocionar protocol: Protocolo public: Público @@ -490,6 +489,7 @@ es: other: Intentos fallidos en %{count} días diferentes. no_failures_recorded: No hay fallos en el registro. title: Disponibilidad + warning: El último intento de conexión a este servidor no ha tenido éxito back_to_all: Todos back_to_limited: Limitados back_to_warning: Advertencia @@ -529,7 +529,6 @@ es: known_accounts: one: "%{count} cuenta conocida" other: "%{count} cuentas conocidas" - zero: Ninguna cuenta conocida moderation: all: Todos limited: Limitado @@ -774,6 +773,11 @@ es: system_checks: database_schema_check: message_html: Hay migraciones pendientes de la base de datos. Por favor, ejecútalas para asegurarte de que la aplicación funciona como debería + elasticsearch_running_check: + message_html: No se pudo conectar a Elasticsearch. Por favor, comprueba que está ejecutándose, o desactiva la búsqueda de texto completo + elasticsearch_version_check: + message_html: 'Versión incompatible de Elasticsearch: %{value}' + version_comparison: Elasticsearch %{running_version} se está ejecutando pero se necesita Elasticsearch %{required_version} rules_check: action: Administrar reglas del servidor message_html: No ha definido ninguna regla del servidor. @@ -794,9 +798,8 @@ es: disallow: Rechazar enlace disallow_provider: Rechazar medio shared_by_over_week: - one: Compartido por una persona en la última semana + one: Compartido por una persona durante la última semana other: Compartido por %{count} personas durante la última semana - zero: Compartido por nadie en la última semana title: Enlaces en tendencia usage_comparison: Compartido %{today} veces hoy, comparado con %{yesterday} ayer pending_review: Revisión pendiente @@ -839,7 +842,6 @@ es: used_by_over_week: one: Usada por una persona durante la última semana other: Usada por %{count} personas durante la última semana - zero: Usada por nadie en la última semana title: Tendencias warning_presets: add_new: Añadir nuevo diff --git a/config/locales/eu.yml b/config/locales/eu.yml index d6f49058e..a41a77baf 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -163,10 +163,6 @@ eu: pending: Berrikusketa egiteke perform_full_suspension: Kanporatu previous_strikes: Aurreko abisuak - previous_strikes_description_html: - one: Kontu honek abisu <strong>bat</strong> dauka. - other: Kontu honek <strong>%{count}</strong> abisu dauzka. - zero: Kontu honek <strong>ez dauka abisurik</strong>. promote: Sustatu protocol: Protokoloa public: Publikoa @@ -497,10 +493,6 @@ eu: delivery_error_hint: Banaketa ezin bada %{count} egunean egin, banaezin bezala markatuko da automatikoki. destroyed_msg: "%{domain} domeinuko datuak berehala ezabatzeko ilaran daude orain." empty: Ez da domeinurik aurkitu. - known_accounts: - one: Kontu ezagun %{count} - other: "%{count} kontu ezagun" - zero: Kontu ezagunik ez moderation: all: Denak limited: Mugatua diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 1776505ba..2379e63da 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -16,6 +16,7 @@ fa: contact: تماس contact_missing: تنظیم نشده contact_unavailable: موجود نیست + continue_to_web: در کارهٔ وب ادامه دهید discover_users: یافتن کاربران documentation: مستندات federation_hint_html: با حسابی روی %{instance} میتوانید افراد روی هر کارساز ماستودون و بیش از آن را پی بگیرید. @@ -25,6 +26,8 @@ fa: این حساب، بازیگری مجازی به نمایندگی خود کارساز بوده و کاربری واقعی نیست. این حساب برای مقاصد خودگردانی به کار میرفته و نباید مسدود شود؛ مگر این که بخواهید کل نمونه را مسدود کنید که در آن صورت نیز باید از انسداد دامنه استفاده کنید. learn_more: بیشتر بدانید + logged_in_as_html: شما هماکنون به عنوان %{username} وارد شدهاید. + logout_before_registering: شما هماکنون وارد شدهاید. privacy_policy: سیاست رازداری rules: قوانین کارساز rules_html: 'در زیر خلاصهای از قوانینی که در صورت علاقه به داشتن حسابی روی این کارساز ماستودون، باید رعایت کنید آمده است:' @@ -75,10 +78,10 @@ fa: pin_errors: following: باید کاربری که میخواهید پیشنهاد دهید را دنبال کرده باشید posts: - one: بوق - other: بوق - posts_tab_heading: بوقها - posts_with_replies: بوقها و پاسخها + one: فرسته + other: فرستهها + posts_tab_heading: فرستهها + posts_with_replies: فرستهها و پاسخها roles: admin: مدیر bot: ربات @@ -161,6 +164,7 @@ fa: not_subscribed: مشترک نیست pending: در انتظار بررسی perform_full_suspension: تعلیق + previous_strikes: اخطارهای پیشین promote: ترفیعدادن protocol: پروتکل public: عمومی @@ -202,8 +206,9 @@ fa: silence: خموشاندن silenced: خموشانده statuses: نوشتهها - strikes: اخطار های پیشین + strikes: اخطارهای پیشین subscribe: اشتراک + suspend: تعلیق suspended: تعلیقشده suspension_irreversible: دادههای این حساب به صورت بیبازگشت حذف شد. میتوانید برای قابل استفاده کردنش، آن را نامعلّق کنید، ولی این کار هیچ دادهای را که از پیش داده، برنخواهد گرداند. suspension_reversible_hint_html: حساب معلّق شد و دادهها به صورت کامل در %{date} برداشته خواهند شد. تا آن زمان، حساب میتواند بی هیچ عوارضی بازگردانده شود. اگر میخواهید فوراً همهٔ دادههای حساب را بردارید، میتوانید در پایین این کار را بکنید. @@ -224,6 +229,7 @@ fa: whitelisted: فهرست مجاز action_logs: action_types: + approve_appeal: پذیرش درخواست تجدیدنظر approve_user: تایید کاربر assigned_to_self_report: واگذاری گزارش change_email_user: تغییر رایانامه برای کاربر @@ -255,6 +261,7 @@ fa: enable_user: به کار انداختن کاربر memorialize_account: یادسپاری حساب promote_user: ترفیع کاربر + reject_appeal: رد کردن درخواست تجدیدنظر reject_user: رد کاربر remove_avatar_user: برداشتن تصویر نمایه reopen_report: بازگشایی گزارش @@ -273,6 +280,7 @@ fa: update_domain_block: بهروزرسانی مسدودسازی دامنه update_status: بهروز رسانی وضعیت actions: + approve_appeal_html: "%{name} درخواست تجدیدنظر تصمیم مدیر را از %{target} پذیرفت" approve_user_html: "%{name} ثبت نام %{target} را تایید کرد" assigned_to_self_report_html: "%{name} رسیدگی به گزارش %{target} را به عهده گرفت" change_email_user_html: "%{name} نشانی رایانامهٔ کاربر %{target} را عوض کرد" @@ -304,6 +312,7 @@ fa: enable_user_html: "%{name} ورود را برای کاربر %{target} فعال کرد" memorialize_account_html: "%{name} حساب %{target} را تبدیل به صفحهٔ یادمان کرد" promote_user_html: "%{name} کاربر %{target} را ترفیع داد" + reject_appeal_html: "%{name} درخواست تجدیدنظر تصمیم مدیر را از %{target} رد کرد" reject_user_html: "%{name} ثبت نام %{target} را رد کرد" remove_avatar_user_html: "%{name} تصویر نمایهٔ %{target} را حذف کرد" reopen_report_html: "%{name} گزارش %{target} را دوباره به جریان انداخت" @@ -381,6 +390,18 @@ fa: media_storage: ذخیرهساز رسانه new_users: کاربران جدید opened_reports: گزارش باز شده + pending_appeals_html: + one: "<strong>%{count}</strong> درخواست تجدیدنظر در انتظار" + other: "<strong>%{count}</strong> درخواست تجدیدنظر در انتظار" + pending_reports_html: + one: "<strong>%{count}</strong> گزارش در انتظار" + other: "<strong>%{count}</strong> گزارش در انتظار" + pending_tags_html: + one: "<strong>%{count}</strong> هشتگ در انتظار" + other: "<strong>%{count}</strong> هشتگ در انتظار" + pending_users_html: + one: "<strong>%{count}</strong> کاربر در انتظار" + other: "<strong>%{count}</strong> کاربر در انتظار" resolved_reports: گزارش حل شده software: نرمافزار sources: منابع ثبتنام @@ -389,6 +410,10 @@ fa: top_languages: زبانهای فعّالتر top_servers: کاربران فعّالتر website: پایگاه وب + disputes: + appeals: + empty: هیچ درخواست تجدیدنظری یافت نشد + title: درخواستهای تجدیدنظر domain_allows: add_new: مجاز کردن دامنه created_msg: دامنه با موفقیت مجاز شد @@ -497,11 +522,11 @@ fa: relays: add_new: افزودن رلهٔ تازه delete: حذف - description_html: یک <strong>رلهٔ میانسروری</strong> (federation relay) یک سرور میانجی است که حجم زیادی از بوقهای عمومی را بین سرورهای گوناگونی که عضوش میشوند جابهجا میکند. <strong>رلهها به سرورهای کوچک و متوسط کمک میکنند تا مطالب عمومی بیشتری را بیابند.</strong> اگر رله نباشد، این مطالب عمومی تنها وقتی پیدا میشوند که کاربران محلی خودشان پیگیر کاربران روی سرورهای دیگر شوند. + description_html: یک <strong>رلهٔ میانسروری</strong> (federation relay) یک سرور میانجی است که حجم زیادی از فرستههای عمومی را بین سرورهای گوناگونی که عضوش میشوند جابهجا میکند. <strong>رلهها به سرورهای کوچک و متوسط کمک میکنند تا مطالب عمومی بیشتری را بیابند.</strong> اگر رله نباشد، این مطالب عمومی تنها وقتی پیدا میشوند که کاربران محلی خودشان پیگیر کاربران روی سرورهای دیگر شوند. disable: از کار انداختن disabled: از کار افتاده enable: به کار انداختن - enable_hint: اگر فعال باشد، کارساز شما عضو همهٔ بوقهای عمومیای را که از این رله میآید میگیرد، و بوقهای عمومی این کارساز را به آن میفرستند. + enable_hint: اگر فعال باشد، کارساز شما عضو همهٔ فرستههای عمومیای را که از این رله میآید میگیرد، و فرستههای عمومی این کارساز را به آن میفرستند. enabled: فعال inbox_url: نشانی رله pending: در انتظار پذیرش رله @@ -567,10 +592,10 @@ fa: title: قوانین کارساز settings: activity_api_enabled: - desc_html: تعداد بوقهای محلی، کاربران فعال، و کاربران تازه در هر هفته + desc_html: تعداد فرستههای محلی، کاربران فعال، و کاربران تازه در هر هفته title: انتشار آمار تجمیعی دربارهٔ فعالیت کاربران bootstrap_timeline_accounts: - desc_html: نامهای کاربری را با ویرگول از هم جدا کنید. تنها حسابهای محلی و قفلنشده کار میکنند. اگر اینجا را خالی بگذارید، به طور پیشفرض همهٔ مدیرهای این سرور پیگرفته خواهند شد. + desc_html: نامهای کاربری را با ویرگول از هم جدا کنید. این حسابها تضمین میشوند که در پیشنهادهای پیگیری نشان داده شوند title: پیگیریهای پیشفرض برای کاربران تازه contact_information: email: ایمیل کاری @@ -584,7 +609,7 @@ fa: domain_blocks: all: برای همه disabled: برای هیچکدام - title: نمایش دامینهای مسدودشده + title: نمایش دامنههای مسدود شده users: برای کاربران محلی واردشده domain_blocks_rationale: title: دیدن دلیل @@ -623,7 +648,7 @@ fa: open: همه میتوانند ثبت نام کنند title: شرایط ثبت نام show_known_fediverse_at_about_page: - desc_html: اگر انتخاب شود، بوقهای همهٔ سرورهای دیگر نیز در پیشنمایش این سرور نمایش مییابد. وگرنه فقط بوقهای محلی نشان داده میشوند. + desc_html: اگر از کار انداخته شود، خطزمانی همگانی را محدود میکند؛ تا فقط محتوای محلّی را نمایش دهد. title: نمایش سرورهای دیگر در پیشنمایش این سرور show_staff_badge: desc_html: نمایش علامت همکار روی صفحهٔ کاربر @@ -653,7 +678,7 @@ fa: title: بگذارید که برچسبهای پرطرفدار بدون بازبینی قبلی نمایش داده شوند trends: desc_html: برچسبهای عمومی که پیشتر بازبینی شدهاند و هماینک پرطرفدارند - title: برچسبهای پرطرفدار + title: پرطرفدارها site_uploads: delete: پرونده بارگذاری شده را پاک کنید destroyed_msg: بارگذاری پایگاه با موفقیت حذف شد! @@ -666,9 +691,12 @@ fa: deleted: پاکشده media: title: رسانه - no_status_selected: هیچ بوقی تغییری نکرد زیرا هیچکدام از آنها انتخاب نشده بودند + no_status_selected: هیچ فرستهای تغییری نکرد زیرا هیچکدام از آنها انتخاب نشده بودند title: نوشتههای حساب with_media: دارای عکس یا ویدیو + strikes: + appeal_approved: درخواست تجدیدنظر کرد + appeal_pending: درخواست تجدیدنظر در انتظار system_checks: database_schema_check: message_html: تعداد مهاجرت پایگاه داده در انتظار انجام هستند. لطفا آنها را اجرا کنید تا اطمینان یابید که برنامه مطابق انتظار رفتار خواهد کرد @@ -707,6 +735,7 @@ fa: not_listable: پیشنهاد نخواهد شد not_usable: غیر قابل استفاده title: برچسبهای پرطرفدار + trending_rank: 'پرطرفدار #%{rank}' usable: قابل استفاده title: پرطرفدار warning_presets: @@ -716,6 +745,10 @@ fa: empty: هنز هیچ پیشتنظیم هشداری را تعریف نکردهاید. title: مدیریت هشدارهای پیشفرض admin_mailer: + new_appeal: + actions: + none: یک هشدار + silence: برای محدود کردن حساب آنها new_pending_account: body: جزئیات حساب تازه اینجاست. شما میتوانید آن را تأیید یا رد کنید. subject: حساب تازهای در %{instance} نیازمند بررسی است (%{username}) @@ -723,6 +756,9 @@ fa: body: کاربر %{reporter} کاربر %{target} را گزارش داد body_remote: کسی از %{domain} گزارش %{target} را فرستاده subject: گزارش تازهای برای %{instance} (#%{id}) + new_trends: + new_trending_links: + no_approved_links: در حال حاضر هیچ پیوند پرطرفداری پذیرفته نشده است. aliases: add_new: ساختن نام مستعار created_msg: نام مستعار تازه با موفقیت ساخته شد. الان میتوانید انتقال از حساب قدیمی را آغاز کنید. @@ -741,7 +777,7 @@ fa: guide_link: https://crowdin.com/project/mastodon guide_link_text: همه میتوانند کمک کنند. sensitive_content: محتوای حساس - toot_layout: آرایش بوق + toot_layout: آرایش فرسته application_mailer: notification_preferences: تغییر ترجیحات ایمیل salutation: "%{name}،" @@ -861,6 +897,18 @@ fa: directory: شاخهٔ نمایه explanation: کاربران را بر اساس علاقهمندیهایشان بیابید explore_mastodon: گشت و گذار در %{title} + disputes: + strikes: + appeal: درخواست تجدیدنظر + appeal_rejected: درخواست تجدیدنظر رد شده است + appeal_submitted_at: درخواست تجدیدنظر فرستاده شد + appeals: + submit: فرستادن درخواست تجدیدنظر + title_actions: + none: هشدار + your_appeal_approved: درخواست تجدیدنظر شما پذیرفته شد + your_appeal_pending: شما یک درخواست تجدیدنظر فرستادید + your_appeal_rejected: درخواست تجدیدنظر شما رد شد domain_validator: invalid_domain: نام دامین معتبر نیست errors: @@ -892,7 +940,7 @@ fa: blocks: حسابهای مسدودشده bookmarks: نشانکها csv: CSV - domain_blocks: دامینهای مسدودشده + domain_blocks: دامنههای مسدود شده lists: سیاههها mutes: حسابهای بیصداشده storage: تصویرهای ذخیرهشده @@ -998,7 +1046,7 @@ fa: not_ready: پروندههایی که پردازش را تمام نکردهاند نمیتوانند پیوست شوند. یکبار دیگر امتحان کنید! too_many: نمیتوان بیشتر از ۴ تصویر بارگذاری کرد migrations: - acct: username@domain حساب تازه + acct: جابهجایی به cancel: لغو انتقال cancel_explanation: با لغو انتقال، حساب شما دوباره فعال میشود، ولی این کار پیگیران شما را که به حساب دیگر منتقل شدهاند برنمیگرداند. cancelled_msg: انتقال حساب با موفقیت لغو شد. @@ -1067,9 +1115,9 @@ fa: poll: subject: نظرسنجیای از %{name} پایان یافت reblog: - body: "%{name} نوشتهٔ شما را بازبوقید:" - subject: "%{name} نوشتهٔ شما را بازبوقید" - title: بازبوق تازه + body: "%{name} فرستهٔ شما را تقویت کرد:" + subject: "%{name} فرستهٔ شما را تقویت کرد" + title: تقویت تازه status: subject: "%{name} چیزی فرستاد" notifications: @@ -1145,17 +1193,17 @@ fa: reason_html: "<strong>چرا این گام ضروریست؟</strong> ممکن است <code>%{instance}</code> کارسازی نباشد که شما رویش حساب دارید؛ پس لازم است پیش از هرچیز، به کارساز خودتان هدایتتان کنیم." remote_interaction: favourite: - proceed: به سمت پسندیدن این بوق - prompt: 'شما میخواهید این بوق را بپسندید:' + proceed: به سمت پسندیدن + prompt: 'شما میخواهید این فرسته را بپسندید:' reblog: - proceed: به سمت بازبوقیدن - prompt: 'شما میخواهید این بوق را بازببوقید:' + proceed: به سمت تقویت + prompt: 'شما میخواهید این فرسته را تقویت کنید:' reply: proceed: به سمت پاسخدادن - prompt: 'شما میخواهید به این بوق پاسخ دهید:' + prompt: 'شما میخواهید به این فرسته پاسخ دهید:' scheduled_statuses: - over_daily_limit: شما از حد مجاز %{limit} بوق زمانبندیشده در آن روز فراتر رفتهاید - over_total_limit: شما از حد مجاز %{limit} بوق زمانبندیشده فراتر رفتهاید + over_daily_limit: شما از حد مجاز %{limit} فرسته زمانبندیشده در آن روز فراتر رفتهاید + over_total_limit: شما از حد مجاز %{limit} فرسته زمانبندیشده فراتر رفتهاید too_soon: زمان تعیینشده باید در آینده باشد sessions: activity: آخرین فعالیت @@ -1233,19 +1281,19 @@ fa: video: one: "%{count} ویدیو" other: "%{count} ویدیو" - boosted_from_html: بازبوقیده از طرف %{acct_link} + boosted_from_html: تقویت شده از طرف %{acct_link} content_warning: 'هشدا محتوا: %{warning}' disallowed_hashtags: one: 'دارای هشتگ غیرمجاز: %{tags}' other: 'دارای هشتگهای غیرمجاز: %{tags}' errors: in_reply_not_found: به نظر نمیرسد وضعیتی که میخواهید به آن پاسخ دهید، وجود داشته باشد. - open_in_web: بازکردن در وب + open_in_web: گشودن در وب over_character_limit: از حد مجاز %{max} حرف فراتر رفتید pin_errors: limit: از این بیشتر نمیشود نوشتههای ثابت داشت ownership: نوشتههای دیگران را نمیتوان ثابت کرد - reblog: بازبوقها را نمیتوان ثابت کرد + reblog: تقویت را نمیتوان سنجاق کرد poll: total_people: one: "%{count} نفر" @@ -1295,17 +1343,17 @@ fa: '2629746': ۱ ماه '31556952': ۱ سال '5259492': ۲ ماه - '604800': 1 week + '604800': ۱ هفته '63113904': ۲ سال '7889238': ۳ ماه min_age_label: کرانهٔ سن min_favs: نگه داشتن فرستههایی با برگزینش بیش از min_favs_hint: هیچ یک از فرستههایتان را که بیش از این تعداد برگزیده شده باشند، حذف نمیکند. برای حذف فرستهها فارغ از تعداد برگزینشهایشان، خالی بگذارید min_reblogs: نگه داشتن فرستههایی با تقویت بیش از - min_reblogs_hint: هیچ یک از فرستههایتان را که بیش از این تعداد تق. یت شده باشند، حذف نمیکند. برای حذف فرستهها فارغ از تعداد تقویتهایشان، خالی بگذارید + min_reblogs_hint: هیچ یک از فرستههایتان را که بیش از این تعداد تقویت شده باشند، حذف نمیکند. برای حذف فرستهها فارغ از تعداد تقویتهایشان، خالی بگذارید stream_entries: pinned: نوشتههای ثابت - reblogged: بازبوقید + reblogged: تقویت شده sensitive_content: محتوای حساس tags: does_not_match_previous_name: با نام پیشین مطابق نیست @@ -1417,6 +1465,15 @@ fa: recovery_instructions_html: اگر تلفن خود را گم کردید، میتوانید با یکی از کدهای بازیابی زیر کنترل حساب خود را به دست بگیرید. <strong>این کدها را در جای امنی نگه دارید.</strong> مثلاً آنها را چاپ کنید و کنار سایر مدارک مهم خود قرار دهید. webauthn: کلیدهای امنیتی user_mailer: + appeal_approved: + action: به حساب خودتان بروید + explanation: درخواست تجدیدنظر اخطار علیه حساب شما در %{strike_date} که در %{appeal_date} ارسال کردهاید، پذیرفته شده است. حساب شما بار دیگر در وضعیت خوبی قرار دارد. + subject: درخواست تجدیدنظر شما در %{date} پذیرفته شد + title: درخواست تجدیدنظر پذیرفته شد + appeal_rejected: + explanation: درخواست تجدیدنظر اخطار علیه حساب شما در %{strike_date} که در %{appeal_date} ارسال کردهاید، رد شده است. + subject: درخواست تجدیدنظر شما در %{date} رد شده است + title: درخواست تجدیدنظر رد شد backup_ready: explanation: شما یک نسخهٔ پشتیبان کامل از حساب خود را درخواست کردید. این پشتیبان الان آمادهٔ بارگیری است! subject: بایگانی شما آمادهٔ دریافت است @@ -1428,6 +1485,8 @@ fa: subject: لطفاً تلاش برای ورود را تأیید کنید title: تلاش برای ورود warning: + appeal: فرستادن یک درخواست تجدیدنظر + appeal_description: اگر فکر میکنید این یک خطا است، میتوانید یک درخواست تجدیدنظر به کارکنان %{instance} ارسال کنید. categories: spam: هرزنامه reason: 'دلیل:' diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 918c505b1..1cdaed6ef 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -165,10 +165,6 @@ fi: pending: Odottaa tarkistusta perform_full_suspension: Siirrä kokonaan jäähylle previous_strikes: Aiemmat varoitukset - previous_strikes_description_html: - one: Tällä tilillä on <strong>yksi</strong> varoitus. - other: Tällä tilillä on <strong>%{count}</strong> varoitusta. - zero: Tämä tili on <strong>hyvässä kunnossa</strong>. promote: Ylennä protocol: Protokolla public: Julkinen @@ -495,10 +491,6 @@ fi: delivery_error_hint: Jos toimitus ei ole mahdollista %{count} päivän aikana, se merkitään automaattisesti toimittamattomaksi. destroyed_msg: Tiedot %{domain} on nyt jonossa välitöntä poistoa varten. empty: Verkkotunnuksia ei löytynyt. - known_accounts: - one: "%{count} tunnettu tili" - other: "%{count} tunnettua tiliä" - zero: Ei tunnettua tiliä moderation: all: Kaikki limited: Rajoitettu @@ -760,10 +752,6 @@ fi: description_html: Nämä ovat linkkejä, joita jaetaan tällä hetkellä paljon tileillä, joilta palvelimesi näkee viestejä. Se voi auttaa käyttäjiäsi saamaan selville, mitä maailmassa tapahtuu. Linkkejä ei näytetä julkisesti, ennen kuin hyväksyt julkaisijan. Voit myös sallia tai hylätä yksittäiset linkit. disallow: Hylkää linkki disallow_provider: Estä julkaisija - shared_by_over_week: - one: Jakanut yksi henkilö viimeisen viikon aikana - other: Jakanut %{count} henkilöä viimeisen viikon aikana - zero: Kukaan ei ole jakanut viimeisen viikon aikana title: Suositut linkit usage_comparison: Jaettu %{today} kertaa tänään verrattuna eilen %{yesterday} pending_review: Odottaa tarkistusta @@ -803,10 +791,6 @@ fi: trending_rank: 'Nousussa #%{rank}' usable: Voidaan käyttää usage_comparison: Käytetty %{today} kertaa tänään, verrattuna %{yesterday} eiliseen - used_by_over_week: - one: Yhden henkilön käyttämä viimeisen viikon aikana - other: Käyttänyt %{count} henkilöä viimeisen viikon aikana - zero: Ei kenenkään käytössä viimeisen viikon aikana title: Trendit warning_presets: add_new: Lisää uusi diff --git a/config/locales/fr.yml b/config/locales/fr.yml index e3879be0a..bc1902cf8 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -166,9 +166,8 @@ fr: perform_full_suspension: Suspendre previous_strikes: Sanctions précédentes previous_strikes_description_html: - one: Ce compte a reçu <strong>une</strong> sanction. + one: Ce compte a reçu <strong>%{count}</strong> sanction. other: Ce compte a reçu <strong>%{count}</strong> sanctions. - zero: Ce compte est <strong>en règle</strong>. promote: Promouvoir protocol: Protocole public: Publique @@ -482,8 +481,12 @@ fr: instances: availability: failure_threshold_reached: Le seuil de défaillance a été atteint le %{date}. + failures_recorded: + one: Tentative échouée pendant %{count} jour. + other: Tentatives échouées pendant %{count} jours différents. no_failures_recorded: Pas d'échec enregistré. title: Disponibilité + warning: La dernière tentative de connexion à ce serveur a échoué back_to_all: Tout back_to_limited: Limité back_to_warning: Avertissement @@ -523,7 +526,6 @@ fr: known_accounts: one: "%{count} compte connu" other: "%{count} comptes connus" - zero: Pas de compte connu moderation: all: Tout limited: Limité @@ -768,6 +770,11 @@ fr: system_checks: database_schema_check: message_html: Vous avez des migrations de base de données en attente. Veuillez les exécuter pour vous assurer que l'application se comporte comme prévu + elasticsearch_running_check: + message_html: Impossible de se connecter à Elasticsearch. Veuillez vérifier qu’il est en cours d’exécution ou désactiver la recherche en plein texte + elasticsearch_version_check: + message_html: 'Version d’Elasticsearch incompatible : %{value}' + version_comparison: Elasticsearch %{running_version} est en cours d’exécution alors que %{required_version} est requise rules_check: action: Gérer les règles du serveur message_html: Vous n'avez pas défini de règles pour le serveur. @@ -788,9 +795,8 @@ fr: disallow: Interdire le lien disallow_provider: Interdire l'éditeur shared_by_over_week: - one: Partagé par une personne au cours de la semaine dernière - other: Partagé par %{count} personnes au cours de la semaine dernière - zero: Non partagé au cours de la semaine dernière + one: Partagé par %{count} personne au cours de la dernière semaine + other: Partagé par %{count} personnes au cours de la dernière semaine title: Liens tendances usage_comparison: Partagé %{today} fois aujourd'hui, comparé à %{yesterday} hier pending_review: En attente de révision @@ -831,9 +837,8 @@ fr: usable: Peut être utilisé usage_comparison: Utilisé %{today} fois aujourd'hui, comparé à %{yesterday} hier used_by_over_week: - one: Utilisé par une personne au cours de la semaine dernière - other: Utilisé par %{count} personnes au cours de la semaine dernière - zero: Non utilisé au cours de la semaine dernière + one: Utilisé par %{count} personne au cours de la dernière semaine + other: Utilisé par %{count} personnes au cours de la dernière semaine title: Tendances warning_presets: add_new: Ajouter un nouveau @@ -1431,6 +1436,7 @@ fr: disallowed_hashtags: one: 'contient un hashtag désactivé : %{tags}' other: 'contient les hashtags désactivés : %{tags}' + edited_at_html: Édité le %{date} errors: in_reply_not_found: Le message auquel vous essayez de répondre ne semble pas exister. open_in_web: Ouvrir sur le web diff --git a/config/locales/gd.yml b/config/locales/gd.yml index 6729b0443..0f6524fbd 100644 --- a/config/locales/gd.yml +++ b/config/locales/gd.yml @@ -173,10 +173,6 @@ gd: pending: A’ feitheamh air lèirmheas perform_full_suspension: Cuir à rèim previous_strikes: Rabhaidhean roimhe - previous_strikes_description_html: - one: Fhuair an cunntas seo <strong>aon</strong> rabhadh. - other: Fhuair an cunntas seo <strong>%{count}</strong> rabhaidhean. - zero: Tha <strong>deagh chliù</strong> aig a’ chunntas seo. promote: Àrdaich protocol: Pròtacal public: Poblach @@ -381,6 +377,7 @@ gd: enable: Cuir an comas enabled: Chaidh a chur an comas enabled_msg: Chaidh an t-Emoji sin a chur an comas + image_hint: PNG no GIF suas ri %{size} list: Liosta listed: Liostaichte new: @@ -485,6 +482,7 @@ gd: resolve: Fuasgail an àrainn title: Bac àrainn puist-d ùr no_email_domain_block_selected: Cha deach bacadh àrainn puist-d sam bith atharrachadh o nach deach gin dhiubh a thaghadh + resolved_dns_records_hint_html: Thèid ainm na h-àrainne fhuasgladh nan àrainnean MX a leanas agus an urra riutha-san gun gabh iad ri post-d. Ma bhacas tu àrainn MX, bacaidh seo an clàradh o sheòladh puist-d sam bith a chleachdas an aon àrainn MX fiù ’s ma bhios ainm àrainne eadar-dhealaichte ’ga sealltainn. <strong>Thoir an aire nach bac thu solaraichean puist-d mòra.</strong> resolved_through_html: Chaidh fuasgladh slighe %{domain} title: Àrainnean puist-d ’gam bacadh follow_recommendations: @@ -496,11 +494,46 @@ gd: title: Molaidhean leantainn unsuppress: Aisig am moladh leantainn instances: + availability: + description_html: + few: Ma dh’fhàilligeas an lìbhrigeadh dhan àrainn fad <strong>%{count} làithean</strong>, chan fheuch sinn a-rithist leis an lìbhrigeadh ach às dèidh lìbhrigeadh fhaighinn <em>on àrainn ud fhèin</em>. + one: Ma dh’fhàilligeas an lìbhrigeadh dhan àrainn fad <strong>%{count} latha</strong>, chan fheuch sinn a-rithist leis an lìbhrigeadh ach às dèidh lìbhrigeadh fhaighinn <em>on àrainn ud fhèin</em>. + other: Ma dh’fhàilligeas an lìbhrigeadh dhan àrainn fad <strong>%{count} latha</strong>, chan fheuch sinn a-rithist leis an lìbhrigeadh ach às dèidh lìbhrigeadh fhaighinn <em>on àrainn ud fhèin</em>. + two: Ma dh’fhàilligeas an lìbhrigeadh dhan àrainn fad <strong>%{count} latha</strong>, chan fheuch sinn a-rithist leis an lìbhrigeadh ach às dèidh lìbhrigeadh fhaighinn <em>on àrainn ud fhèin</em>. + failure_threshold_reached: Chaidh stairsneach an fhàilligidh a ruigsinn %{date}. + failures_recorded: + few: Oidhirp a dh’fhàillig rè %{count} làithean. + one: Oidhirp a dh’fhàillig rè %{count} latha. + other: Oidhirp a dh’fhàillig rè %{count} latha. + two: Oidhirp a dh’fhàillig rè %{count} latha. + no_failures_recorded: Cha deach fàilligeadh sam bith a chlàradh. + title: Faotainneachd + warning: Cha deach leis an oidhirp mu dheireadh air ceangal ris an fhrithealaiche seo back_to_all: Na h-uile back_to_limited: Cuingichte back_to_warning: Rabhadh by_domain: Àrainn confirm_purge: A bheil thu cinnteach gu bheil thu airson an dàta on àrainn seo a sguabadh às gu buan? + content_policies: + comment: Nòta taobh a-staigh + description_html: "’S urrainn dhut poileasaidhean susbainte a mhìneachadh a thèid a chur an sàs air a h-uile cunntas on àrainn seo ’s a fo-àrainnean-se." + policies: + reject_media: Diùlt meadhanan + reject_reports: Diùlt gearanan + silence: Cuingich + suspend: Cuir à rèim + policy: Poileasaidh + reason: Adhbhar poblach + title: Poileasaidhean susbainte + dashboard: + instance_accounts_dimension: Cunntasan ’gan leantainn as trice + instance_accounts_measure: cunntasan ’gan stòradh + instance_followers_measure: an luchd-leantainn againne thall + instance_follows_measure: an luchd-leantainn acasan an-seo + instance_languages_dimension: Brod nan cànan + instance_media_attachments_measure: ceanglachain mheadhanan ’gan stòradh + instance_reports_measure: gearanan mun dèidhinn + instance_statuses_measure: postaichean ’gan stòradh delivery: all: Na h-uile clear: Falamhaich na mearachdan lìbhrigidh @@ -512,10 +545,6 @@ gd: delivery_error_hint: Mura gabh a lìbhrigeadh fad %{count} là(ithean), thèid comharra a chur ris gu fèin-obrachail a dh’innseas nach gabh a lìbhrigeadh. destroyed_msg: Tha an dàta o %{domain} air ciutha an sguabaidh às aithghearr. empty: Cha deach àrainn a lorg. - known_accounts: - one: "%{count} chunntas as aithne dhuinn" - other: "%{count} cunntas(an) as aithne dhuinn" - zero: Gun chunntas as aithne dhuinn moderation: all: Na h-uile limited: Cuingichte @@ -523,12 +552,14 @@ gd: private_comment: Beachd prìobhaideachd public_comment: Beachd poblach purge: Purgaidich + purge_description_html: Ma tha thu dhen bheachd gu bheil an àrainn seo far loidhne gu buan, ’s urrainn dhut a h-uile clàr cunntais ’s an dàta co-cheangailte on àrainn ud a sguabadh às san stòras agad. Dh’fhaoidte gun doir sin greis mhath. title: Co-nasgadh total_blocked_by_us: "‘Ga bhacadh leinne" total_followed_by_them: "’Ga leantainn leotha-san" total_followed_by_us: "’Ga leantainn leinne" total_reported: Gearanan mun dèidhinn total_storage: Ceanglachain mheadhanan + totals_time_period_hint_html: Gabhaidh na h-iomlanan gu h-ìosal a-staigh an dàta o chian nan cian. invites: deactivate_all: Cuir na h-uile à gnìomh filter: @@ -584,9 +615,13 @@ gd: action_log: Sgrùd an loga action_taken_by: Chaidh an gnìomh a ghabhail le actions: + delete_description_html: Thèid na postaichean le gearan orra a sguabadh às agus rabhadh a chlàradh gus do chuideachadh ach am bi thu nas teinne le droch-ghiùlan on aon chunntas sam àm ri teachd. + mark_as_sensitive_description_html: Thèid comharra an fhrionasachd a chur ris na meadhanan sna postaichean le gearan orra agus rabhadh a chlàradh gus do chuideachadh ach am bi thu nas teinne le droch-ghiùlan on aon chunntas sam àm ri teachd. other_description_html: Seall barrachd roghainnean airson giùlan a’ chunntais a stiùireadh agus an conaltradh leis a’ chunntas a chaidh gearan a dhèanamh mu dhèidhinn a ghnàthachadh. + resolve_description_html: Cha dèid gnìomh sam bith a ghabhail an aghaidh a’ chunntais le gearan air agus thèid an gearan a dhùnadh gun rabhadh a chlàradh. silence_description_html: Chan fhaic ach an fheadhainn a tha a’ leantainn oirre mu thràth no a lorgas a làimh i a’ phròifil seo agus cuingichidh seo uiread nan daoine a ruigeas i gu mòr. Gabhaidh seo a neo-dhèanamh uair sam bith. suspend_description_html: Cha ghabh a’ phròifil seo agus an t-susbaint gu leòr aice inntrigeadh gus an dèid a sguabadh às air deireadh na sgeòil. Cha ghabh eadar-ghabhail a dhèanamh leis a’ chunntas. Gabhaidh seo a neo-dhèanamh am broinn 30 latha. + actions_description_html: Cuir romhad dè an gnìomh a ghabhas tu gus an gearan seo fhuasgladh. Ma chuireas tu peanas air a’ chunntas le gearan air, gheibh iad brath air a’ phost-d mura tagh thu an roinn-seòrsa <strong>Spama</strong>. add_to_report: Cuir barrachd ris a’ ghearan are_you_sure: A bheil thu cinnteach? assign_to_self: Iomruin dhomh-sa @@ -756,6 +791,11 @@ gd: system_checks: database_schema_check: message_html: Tha imrichean stòir-dhàta ri dhèiligeadh ann. Ruith iad a dhèanamh cinnteach gum bi giùlan na h-aplacaid mar a bhiodhte ’n dùil + elasticsearch_running_check: + message_html: Cha b’ urrainn dhuinn ceangal ri Elasticsearch. Dearbh thu bheil e a’ ruith no cuir an lorg làn-teacsa à comas + elasticsearch_version_check: + message_html: 'Tionndadh Elasticsearch nach eil co-chòrdail: %{value}' + version_comparison: Tha Elasticsearch %{running_version} a ruith ach tha feum air %{required_version} rules_check: action: Stiùirich riaghailtean an fhrithealaiche message_html: Cha do mhìnich thu riaghailtean an fhrithealaiche fhathast. @@ -772,23 +812,22 @@ gd: links: allow: Ceadaich an ceangal allow_provider: Ceadaich am foillsichear + description_html: Seo na ceanglaichean a tha ’gan co-roinneadh le iomadh cunntas on a chì am frithealaiche agad na postaichean. Faodaidh iad a bhith ’nan cuideachadh dhan luchd-cleachdaidh ach am faigh iad a-mach dè tha tachairt air an t-saoghal. Cha dèid ceanglaichean a shealltainn gu poblach gus an aontaich thu ris an fhoillsichear. ’S urrainn dhut ceanglaichean àraidh a cheadachadh no a dhiùltadh cuideachd. disallow: Na ceadaich an ceangal disallow_provider: Na ceadaich am foillsichear - shared_by_over_week: - one: Chaidh a cho-roinneadh le aonar rè na seachdain seo chaidh - other: Chaidh a cho-roinneadh le %{count} rè na seachdain seo chaidh - zero: Cha deach a cho-roinneadh rè na seachdain seo chaidh title: Ceanglaichean a’ treandadh usage_comparison: Chaidh a cho-roinneadh %{today} tura(i)s an-diugh an coimeas ri %{yesterday} an-dè pending_review: A’ feitheamh air lèirmheas preview_card_providers: allowed: Faodaidh ceanglaichean on fhoillsichear seo treandadh + description_html: Seo na h-àrainnean on a thèid ceanglaichean a cho-roinneadh air an fhrithealaiche agad gu tric. Cha bhi ceanglaichean a’ treandadh mura dh’aontaich thu ri àrainn a’ cheangail. Gabhaidh d’ aonta (no do dhiùltadh) a-staigh na fo-àrainnean. rejected: Cha treandaich ceanglaichean on fhoillsichear seo title: Foillsichearan rejected: Air a dhiùltadh statuses: allow: Ceadaich am post allow_account: Ceadaich an t-ùghdar + description_html: Seo na postaichean air a bheil am frithealaiche agad eòlach ’s a tha ’gan co-roinneadh is ’nan annsachd gu tric aig an àm seo. Faodaidh iad a bhith ’nan cuideachadh dhan luchd-cleachdaidh ùr no a thill ach an lorg iad daoine airson leantainn orra. Cha dèid postaichean a shealltainn gu poblach gus an gabh thu ris an ùghdar agus gus an aontaich an t-ùghdar gun dèid an cunntas aca a mholadh do dhaoine eile. ’S urrainn dhut postaichean àraidh a cheadachadh no a dhiùltadh cuideachd. disallow: Na ceadaich am post disallow_account: Na ceadaich an t-ùghdar not_discoverable: Cha do chuir an t-ùghdar roimhe gun gabh a lorg @@ -806,6 +845,7 @@ gd: tag_servers_dimension: Brod nam frithealaichean tag_servers_measure: frithealaichean eadar-dhealaichte tag_uses_measure: cleachdaidhean iomlan + description_html: Seo na tagaichean hais a nochdas ann an grunn phostaichean a chì am frithealaiche agad aig an àm seo. Faodaidh iad a bhith ’nan cuideachadh dhan luchd-cleachdaidh agad ach am faigh iad a-mach cò air a tha daoine a’ bruidhinn nas trice aig an àm seo. Cha dèid tagaichean hais a shealltainn gu poblach gus an aontaich thu riutha. listable: Gabhaidh a mholadh not_listable: Cha dèid a mholadh not_trendable: Cha nochd e am measg nan treandaichean @@ -816,10 +856,6 @@ gd: trending_rank: 'A’ treandadh #%{rank}' usable: Gabhaidh a chleachdadh usage_comparison: Chaidh a chleachdadh %{today} tura(i)s an-diugh an coimeas ri %{yesterday} an-dè - used_by_over_week: - one: Chaidh a chleachdadh le aonar rè na seachdain seo chaidh - other: Chaidh a chleachdadh le %{count} rè na seachdain seo chaidh - zero: Cha deach a chleachdadh rè na seachdain seo chaidh title: Treandaichean warning_presets: add_new: Cuir fear ùr ris @@ -851,12 +887,15 @@ gd: body: 'Tha na nithean seo feumach air lèirmheas mus nochd iad gu poblach:' new_trending_links: no_approved_links: Chan eil ceangal a’ treandadh le aontachadh ann. + requirements: "’S urrainn do ghin dhe na tagraichean seo dol thairis air #%{rank} a tha aig a’ cheangal “%{lowest_link_title}” a’ treandadh as ìsle le aontachadh agus sgòr de %{lowest_link_score} air." title: Ceanglaichean a’ treandadh new_trending_statuses: no_approved_statuses: Chan eil post a’ treandadh le aontachadh ann. + requirements: "’S urrainn do ghin dhe na tagraichean seo dol thairis air #%{rank} a tha aig a’ phost %{lowest_status_url} a’ treandadh as ìsle le aontachadh agus sgòr de %{lowest_status_score} air." title: Postaichean a’ treandadh new_trending_tags: no_approved_tags: Chan eil taga hais a’ treandadh le aontachadh ann. + requirements: "’S urrainn do ghin dhe na tagraichean seo dol thairis air #%{rank} a tha aig an taga hais #%{lowest_tag_name} a’ treandadh as ìsle le aontachadh agus sgòr de %{lowest_tag_score} air." title: Tagaichean hais a’ treandadh subject: Tha treandaichean ùra a’ feitheamh air lèirmheas air %{instance} aliases: @@ -1011,6 +1050,19 @@ gd: submit: Cuir a-null an t-ath-thagradh associated_report: An gearan co-cheangailte created_at: Ceann-là + description_html: Seo na gnìomhan a chaidh a ghabhail an aghaidh a’ chunntais agad agus na rabhaidhean a chaidh a chur thugad le luchd-obrach %{instance}. + recipient: Faightear + status: 'Post #%{id}' + status_removed: Chaidh am post a thoirt air falbh on t-siostam mu thràth + title: "%{action} o %{date}" + title_actions: + delete_statuses: Toirt air falbh puist + disable: Reòthadh cunntais + mark_statuses_as_sensitive: Comharra na frionasachd air postaichean + none: Rabhadh + sensitive: Comharra na frionasachd air cunntais + silence: Cuingeachadh cunntais + suspend: Cur à rèim cunntais your_appeal_approved: Chaidh aontachadh ris an ath-thagradh agad your_appeal_pending: Chuir thu ath-thagradh a-null your_appeal_rejected: Chaidh an t-ath-thagradh agad a dhiùltadh @@ -1192,6 +1244,9 @@ gd: carry_mutes_over_text: Chaidh an cleachdaiche seo imrich o %{acct} a b’ àbhaist dhut a mhùchadh. copy_account_note_text: 'Da cleachdaiche air gluasad o %{acct}, seo na nòtaichean a bh’ agad mu dhèidhinn roimhe:' notification_mailer: + admin: + sign_up: + subject: Chlàraich %{name} digest: action: Seall a h-uile brath body: Seo geàrr-chunntas air na h-atharraichean nach fhaca thu on tadhal mu dheireadh agad %{since} @@ -1233,6 +1288,8 @@ gd: title: Brosnachadh ùr status: subject: Tha %{name} air post a sgrìobhadh + update: + subject: Dheasaich %{name} post notifications: email_events: Tachartasan nam brathan puist-d email_events_hint: 'Tagh na tachartasan dhan a bheil thu airson brathan fhaighinn:' @@ -1314,6 +1371,9 @@ gd: reply: proceed: Lean air adhart gus freagairt prompt: 'Tha thu airson freagairt dhan phost seo:' + reports: + errors: + invalid_rules: gun iomradh air riaghailtean dligheach scheduled_statuses: over_daily_limit: Chaidh thu thar na crìoch de %{limit} post(aichean) sgeidealaichte an-diugh over_total_limit: Chaidh thu thar na crìoch de %{limit} post(aichean) sgeidealaichte @@ -1380,6 +1440,7 @@ gd: profile: Pròifil relationships: Dàimhean leantainn statuses_cleanup: Sguabadh às fèin-obrachail phostaichean + strikes: Rabhaidhean na maorsainneachd two_factor_authentication: Dearbhadh dà-cheumnach webauthn_authentication: Iuchraichean tèarainteachd statuses: @@ -1402,11 +1463,13 @@ gd: two: "%{count} video" boosted_from_html: Brosnachadh o %{acct_link} content_warning: 'Rabhadh susbainte: %{warning}' + default_language: Co-ionnan ri cànan na h-eadar-aghaidh disallowed_hashtags: few: "– bha na tagaichean hais toirmisgte seo ann: %{tags}" one: "– bha na tagaichean hais toirmisgte seo ann: %{tags}" other: "– bha na tagaichean hais toirmisgte seo ann: %{tags}" two: "– bha na tagaichean hais toirmisgte seo ann: %{tags}" + edited_at_html: Air a dheasachadh %{date} errors: in_reply_not_found: Tha coltas nach eil am post dhan a tha thu airson freagairt ann. open_in_web: Fosgail air an lìon @@ -1469,7 +1532,7 @@ gd: '2629746': Mìos '31556952': Bliadhna '5259492': 2 mhìos - '604800': 1 week + '604800': Seachdain '63113904': 2 bhliadhna '7889238': 3 mìosan min_age_label: Stairsneach aoise @@ -1484,7 +1547,7 @@ gd: tags: does_not_match_previous_name: "– chan eil seo a-rèir an ainm roimhe" terms: - body_html: '<h2>Poileasaidh prìobhaideachd</h2> <h3 id="collect">Dè am fiosrachadh a chruinnicheas sinn?</h3> <ul> <li><em>Fiosrachadh bunasach a’ cunntais</em>: Ma chlàraicheas tu leis an fhrithealaiche seo, dh’fhaoidte gun dèid iarraidh ort gun cuir thu a-steach ainm-cleachdaiche, seòladh puist-d agus facal-faire. Faodaidh tu barrachd fiosrachaidh a chur ris a’ phròifil agad ma thogras tu, can ainm-taisbeanaidh agus teacsa mu do dhèidhinn agus dealbhan pròifile ’s banna-chinn a luchdadh suas. Thèid an t-ainm-cleachdaiche, an t-ainm-taisbeanaidh, an teacsa mu do dhèidhinn agus dealbhan na pròifile ’s a bhanna-chinn a shealltainn gu poblach an-còmhnaidh.</li> <li><em>Postaichean, luchd-leantainn agus fiosrachadh poblach eile</em>: Tha liosta nan daoine air a leanas tu poblach mar a tha i dhan luchd-leantainn agad. Nuair a chuireas tu a-null teachdaireachd, thèid an t-àm ’s an ceann-latha a stòradh cho math ris an aplacaid leis an do chuir thu am foirm a-null. Faodaidh ceanglachain meadhain a bhith am broinn teachdaireachdan, can dealbhan no videothan. Tha postaichean poblach agus postaichean falaichte o liostaichean ri ’m faighinn gu poblach. Nuair a bhrosnaicheas tu post air a’ phròifil agad, ’s e fiosrachadh poblach a tha sin cuideachd. Thèid na postaichean agad a lìbhrigeadh dhan luchd-leantainn agad agus is ciall dha seo gun dèid an lìbhrigeadh gu frithealaichean eile aig amannan is gun dèid lethbhreacan dhiubh a stòradh thall. Nuair a sguabas tu às post, thèid sin a lìbhrigeadh dhan luchd-leantainn agad cuideachd. Tha ath-bhlogachadh no dèanamh annsachd de phost eile poblach an-còmhnaidh.</li> <li><em>Postaichean dìreach is dhan luchd-leantainn a-mhàin</em>: Thèid a h-uile post a stòradh ’s a phròiseasadh air an fhrithealaiche. Thèid na postaichean dhan luchd-leantainn a-mhàin a lìbhrigeadh dhan luchd-leantainn agad agus dhan luchd-chleachdaidh a chaidh iomradh a dhèanamh orra sa phost. Thèid postaichean dìreach a lìbhrigeadh dhan luchd-chleachdaidh a chaidh iomradh a dhèanamh orra sa phost a-mhàin. Is ciall dha seo gun dèid an lìbhrigeadh gu frithealaichean eile aig amannan is gun dèid lethbhreacan dhiubh a stòradh thall. Nì sinn ar dìcheall gun cuingich sinn an t-inntrigeadh dha na postaichean air na daoine a fhuair ùghdarrachadh dhaibh ach dh’fhaoidte nach dèan frithealaichean eile seo. Mar sin dheth, tha e cudromach gun doir thu sùil air na frithealaichean dhan a bhuineas an luchd-leantainn agad. Faodaidh tu roghainn a chur air no dheth a leigeas leat aontachadh ri luchd-leantainn ùra no an diùltadh a làimh. <em>Thoir an aire gum faic rianairean an fhrithealaiche agus frithealaiche sam bith a gheibh am fiosrachadh na teachdaireachdan dhen leithid</em> agus gur urrainn dha na faightearan glacaidhean-sgrìn no lethbhreacan dhiubh a dhèanamh no an cho-roinneadh air dòighean eile. <em>Na co-roinn fiosrachadh cunnartach air Mastodon idir.</em></li> <li><em>IPan is meata-dàta eile</em>: Nuair a nì thu clàradh a-steach, clàraidh sinn an seòladh IP on a rinn thu clàradh a-steach cuide ri ainm aplacaid a’ bhrabhsair agad. Bidh a h-uile seisean clàraidh a-steach ri làimh dhut airson an lèirmheas agus an cùl-ghairm sna roghainnean. Thèid an seòladh IP as ùire a chleachd thu a stòradh suas ri 12 mhìos. Faodaidh sinn cuideachd logaichean an fhrithealaiche a chumail a ghabhas a-steach seòladh IP aig a h-uile iarrtas dhan fhrithealaiche againn.</li> </ul> <hr class="spacer" /> <h3 id="use">Dè na h-adhbharan air an cleachd sinn am fiosrachadh agad?</h3> <p>Seo na dòighean air an cleachd sinn fiosrachadh sam bith a chruinnich sinn uat ma dh’fhaoidte:</p> <ul> <li>Airson bun-ghleusan Mhastodon a lìbhrigeadh. Chan urrainn dhut conaltradh le susbaint càich no an t-susbaint agad fhèin a phostadh ach nuair a bhios tu air do chlàradh a-steach. Mar eisimpleir, faodaidh tu leantainn air càch ach am faic thu na postaichean aca còmhla air loidhne-ama pearsanaichte na dachaigh agad.</li> <li>Airson cuideachadh le maorsainneachd na coimhearsnachd, can airson coimeas a dhèanamh eadar an seòladh IP agad ri feadhainn eile feuch am mothaich sinn do sheachnadh toirmisg no briseadh eile nan riaghailtean.</li> <li>Faodaidh sinn an seòladh puist-d agad a chleachdadh airson fiosrachadh no brathan mu chonaltraidhean càich leis an t-susbaint agad no teachdaireachdan a chur thugad, airson freagairt ri ceasnachaidhean agus/no iarrtasan no ceistean eile.</li> </ul> <hr class="spacer" /> <h3 id="protect">Ciamar a dhìonas sinn am fiosrachadh agad?</h3> <p>Cuiridh sinn iomadh gleus tèarainteachd an sàs ach an glèidheadh sinn sàbhailteachd an fhiosrachaidh phearsanta agad nuair a chuireas tu gin a-steach, nuair a chuireas tu a-null e no nuair a nì thu inntrigeadh air. Am measg gleusan eile, thèid seisean a’ bhrabhsair agad cuide ris an trafaig eadar na h-aplacaidean agad ’s an API a dhìon le SSL agus thèid hais a dhèanamh dhen fhacal-fhaire agad le algairim aon-shligheach làidir. Faodaidh tu dearbhadh dà-cheumnach a chur an comas airson barrachd tèarainteachd a chur ris an inntrigeadh dhan chunntas agad.</p> <hr class="spacer" /> <h3 id="data-retention">Dè am poileasaidh cumail dàta againn?</h3> <p>Nì sinn ar dìcheall:</p> <ul> <li>Nach cùm sinn logaidhean an fhrithealaiche sa bheil seòlaidhean IP nan iarrtasan uile dhan fhrithealaiche seo nas fhaide na 90 latha ma chumas sinn logaichean dhen leithid idir.</li> <li>Nach cùm sinn na seòlaidhean IP a tha co-cheangailte ri cleachdaichean clàraichte nas fhaide na 12 mhìos.</li> </ul> <p>’S urrainn dhut tasg-lann iarraidh dhen t-susbaint agad ’s a luchdadh a-nuas is gabhaidh seo a-staigh na postaichean, na ceanglachain meadhain, dealbh na pròifil agus dealbh a’ bhanna-chinn agad.</p> <p>’S urrainn dhut an cunntas agad a sguabadh às gu buan uair sam bith.</p> <hr class="spacer"/> <h3 id="cookies">An cleachd sinn briosgaidhean?</h3> <p>Cleachdaidh. ’S e faidhlichean beaga a tha sna briosgaidean a thar-chuireas làrach no solaraiche seirbheise gu clàr-cruaidh a’ choimpiutair agad leis a’ bhrabhsair-lìn agad (ma cheadaicheas tu sin). Bheir na briosgaidean sin comas dhan làrach gun aithnich i am brabhsair agad agus ma tha cunntas clàraichte agad, gun co-cheangail i ris a’ chunntas chlàraichte agad e.</p> <p>Cleachdaidh sinn briosgaidean airson na roghainnean agad a thuigsinn ’s a ghlèidheadh gus an tadhail thu oirnn san àm ri teachd.</p> <hr class="spacer" /> <h3 id="disclose">Am foillsich sinn fiosrachadh sam bith gu pàrtaidhean air an taobh a-muigh?</h3> <p>Cha reic, malairt no tar-chuir sinn fiosrachadh air a dh’aithnichear thu fhèin gu pàrtaidh sam bith air an taobh a-muigh. Cha ghabh seo a-staigh treas-phàrtaidhean earbsach a chuidicheas leinn le ruith na làraich againn, le obrachadh a’ ghnìomhachais againn no gus an t-seirbheis a thoirt leat cho fada ’s a dh’aontaicheas na treas-phàrtaidhean sin gun cùm iad am fiosrachadh dìomhair. Faodaidh sinn am fiosrachadh agad fhoillseachadh cuideachd nuair a bhios sinn dhen bheachd gu bheil am foillseachadh sin iomchaidh airson gèilleadh dhan lagh, poileasaidhean na làraich againn èigneachadh no na còraichean, an sealbh no an t-sàbhailteachd againn fhèin no aig càch a dhìon.</p> <p>Dh’fhaoidte gun dèid an t-susbaint phoblach agad a luchdadh a-nuas le frithealaichean eile san lìonra. Thèid na postaichean poblach agad ’s an fheadhainn dhan luchd-leantainn a-mhàin a lìbhrigeadh dha na frithealaichean far a bheil an luchd-leantainn agad a’ còmhnaidh agus thèid na teachdaireachdan dìreach a lìbhrigeadh gu frithealaichean nam faightearan nuair a bhios iad a’ còmhnaidh air frithealaiche eile.</p> <p>Nuair a dh’ùghdarraicheas tu aplacaid gun cleachd i an cunntas agad, a-rèir sgòp nan ceadan a dh’aontaicheas tu riutha, faodaidh i fiosrachadh poblach na pròifil agad, liosta na feadhna air a bhios tu a’ leantainn, an luchd-leantainn agad, na liostaichean agad, na postaichean agad uile ’s na h-annsachdan agad inntrigeadh. Chan urrainn do dh’aplacaidean an seòladh puist-d no am facal-faire agad inntrigeadh idir.</p> <hr class="spacer" /> <h3 id="children">Cleachdadh na làraich leis a’ chloinn</h3> <p>Ma tha am frithealaiche seo san Aonadh Eòrpach (AE) no san Roinn Eaconomach na h-Eòrpa (EEA): Tha an làrach, na batharan agus na seirbheisean againn uile ag amas air an fheadhainn a tha co-dhiù 16 bliadhnaichean a dh’aois. Ma tha thu nas òige na 16 bliadhnaichean a dh’aois, tha e riatanach fon GDPR (<a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation">General Data Protection Regulation</a>) nach cleachd thu an làrach seo.</p> <p>Ma tha am frithealaiche seo sna Stàitean Aonaichte (SAA): Tha an làrach, na batharan agus na seirbheisean againn uile ag amas air an fheadhainn a tha co-dhiù 13 bliadhnaichean a dh’aois. Ma tha thu nas òige na 16 bliadhnaichean a dh’aois, tha e riatanach fon COPPA (<a href="https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act">Children''s Online Privacy Protection Act</a>)ha an làrach, na batharan agus na seirbheisean againn uile ag amas air an fheadhainn a tha co-dhiù 16 bliadhnaichean a dh’aois. Ma tha thu nas òige na 16 bliadhnaichean a dh’aois, tha e riatanach fon GDPR (<a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation">General Data Protection Regulation</a>) nach cleachd thu an làrach seo.</p> <p>Ma tha am frithealaiche seo sna Stàitean Aonaichte (SAA): Tha an làrach, na batharan agus na seirbheisean againn uile ag amas air an fheadhainn a tha co-dhiù 13 bliadhnaichean a dh’aois. Ma tha thu nas òige na 16 bliadhnaichean a dh’aois, tha e riatanach fon COPPA (<a href="https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act">Children''s Online Privacy Protection Act</a>) nach cleachd thu an làrach seo.</p> <p>Dh’fhaoidte gu bheil am frithealaiche seo fo riatanasan lagha eile ma tha e ann an uachdranas laghail eile.</p> <hr class="spacer" /> <h3 id="changes">Atharraichean air a’ phoileasaidh phrìobhaideachd againn</h3> <p>Ma chuireas sinn romhainn am poileasaidh prìobhaideachd againn atharrachadh, postaichidh sinn na h-atharraichean dhan duilleag seo.</p> <p>Tha an sgrìobhainn seo fo cheadachas CC-BY-SA. Chaidh ùrachadh an turas mu dheireadh an t-7mh dhen Mhart 2018.</p> <p>Chaidh a fhreagarrachadh o thùs o <a href="https://github.com/discourse/discourse">phoileasaidh prìobhaideachd Discourse</a>.</p> nach cleachd thu an làrach seo.</p> <p>Dh’fhaoidte gu bheil am frithealaiche seo fo riatanasan lagha eile ma tha e ann an uachdranas laghail eile.</p> <hr class="spacer" /> <h3 id="changes">Atharraichean air a’ phoileasaidh phrìobhaideachd againn</h3> <p>Ma chuireas sinn romhainn am poileasaidh prìobhaideachd againn atharrachadh, postaichidh sinn na h-atharraichean dhan duilleag seo.</p> <p>Tha an sgrìobhainn seo fo cheadachas CC-BY-SA. Chaidh ùrachadh an turas mu dheireadh an t-7mh dhen Mhart 2018.</p> <p>Chaidh a fhreagarrachadh o thùs o <a href="https://github.com/discourse/discourse">phoileasaidh prìobhaideachd Discourse</a>.</p> + body_html: '<h2>Poileasaidh prìobhaideachd</h2> <h3 id="collect">Dè am fiosrachadh a chruinnicheas sinn?</h3> <ul> <li><em>Fiosrachadh bunasach a’ cunntais</em>: Ma chlàraicheas tu leis an fhrithealaiche seo, dh’fhaoidte gun dèid iarraidh ort gun cuir thu a-steach ainm-cleachdaiche, seòladh puist-d agus facal-faire. Faodaidh tu barrachd fiosrachaidh a chur ris a’ phròifil agad ma thogras tu, can ainm-taisbeanaidh agus teacsa mu do dhèidhinn agus dealbhan pròifile ’s banna-chinn a luchdadh suas. Thèid an t-ainm-cleachdaiche, an t-ainm-taisbeanaidh, an teacsa mu do dhèidhinn agus dealbhan na pròifile ’s a bhanna-chinn a shealltainn gu poblach an-còmhnaidh.</li> <li><em>Postaichean, luchd-leantainn agus fiosrachadh poblach eile</em>: Tha liosta nan daoine air a leanas tu poblach mar a tha i dhan luchd-leantainn agad. Nuair a chuireas tu a-null teachdaireachd, thèid an t-àm ’s an ceann-latha a stòradh cho math ris an aplacaid leis an do chuir thu am foirm a-null. Faodaidh ceanglachain meadhain a bhith am broinn teachdaireachdan, can dealbhan no videothan. Tha postaichean poblach agus postaichean falaichte o liostaichean ri ’m faighinn gu poblach. Nuair a bhrosnaicheas tu post air a’ phròifil agad, ’s e fiosrachadh poblach a tha sin cuideachd. Thèid na postaichean agad a lìbhrigeadh dhan luchd-leantainn agad agus is ciall dha seo gun dèid an lìbhrigeadh gu frithealaichean eile aig amannan is gun dèid lethbhreacan dhiubh a stòradh thall. Nuair a sguabas tu às post, thèid sin a lìbhrigeadh dhan luchd-leantainn agad cuideachd. Tha ath-bhlogachadh no dèanamh annsachd de phost eile poblach an-còmhnaidh.</li> <li><em>Postaichean dìreach is dhan luchd-leantainn a-mhàin</em>: Thèid a h-uile post a stòradh ’s a phròiseasadh air an fhrithealaiche. Thèid na postaichean dhan luchd-leantainn a-mhàin a lìbhrigeadh dhan luchd-leantainn agad agus dhan luchd-chleachdaidh a chaidh iomradh a dhèanamh orra sa phost. Thèid postaichean dìreach a lìbhrigeadh dhan luchd-chleachdaidh a chaidh iomradh a dhèanamh orra sa phost a-mhàin. Is ciall dha seo gun dèid an lìbhrigeadh gu frithealaichean eile aig amannan is gun dèid lethbhreacan dhiubh a stòradh thall. Nì sinn ar dìcheall gun cuingich sinn an t-inntrigeadh dha na postaichean air na daoine a fhuair ùghdarrachadh dhaibh ach dh’fhaoidte nach dèan frithealaichean eile seo. Mar sin dheth, tha e cudromach gun doir thu sùil air na frithealaichean dhan a bhuineas an luchd-leantainn agad. Faodaidh tu roghainn a chur air no dheth a leigeas leat aontachadh ri luchd-leantainn ùra no an diùltadh a làimh. <em>Thoir an aire gum faic rianairean an fhrithealaiche agus frithealaiche sam bith a gheibh am fiosrachadh na teachdaireachdan dhen leithid</em> agus gur urrainn dha na faightearan glacaidhean-sgrìn no lethbhreacan dhiubh a dhèanamh no an cho-roinneadh air dòighean eile. <em>Na co-roinn fiosrachadh cunnartach air Mastodon idir.</em></li> <li><em>IPan is meata-dàta eile</em>: Nuair a nì thu clàradh a-steach, clàraidh sinn an seòladh IP on a rinn thu clàradh a-steach cuide ri ainm aplacaid a’ bhrabhsair agad. Bidh a h-uile seisean clàraidh a-steach ri làimh dhut airson an lèirmheas agus an cùl-ghairm sna roghainnean. Thèid an seòladh IP as ùire a chleachd thu a stòradh suas ri 12 mhìos. Faodaidh sinn cuideachd logaichean an fhrithealaiche a chumail a ghabhas a-steach seòladh IP aig a h-uile iarrtas dhan fhrithealaiche againn.</li> </ul> <hr class="spacer" /> <h3 id="use">Dè na h-adhbharan air an cleachd sinn am fiosrachadh agad?</h3> <p>Seo na dòighean air an cleachd sinn fiosrachadh sam bith a chruinnich sinn uat ma dh’fhaoidte:</p> <ul> <li>Airson bun-ghleusan Mhastodon a lìbhrigeadh. Chan urrainn dhut eadar-ghnìomh a ghabhail le susbaint càich no an t-susbaint agad fhèin a phostadh ach nuair a bhios tu air do chlàradh a-steach. Mar eisimpleir, faodaidh tu leantainn air càch ach am faic thu na postaichean aca còmhla air loidhne-ama pearsanaichte na dachaigh agad.</li> <li>Airson cuideachadh le maorsainneachd na coimhearsnachd, can airson coimeas a dhèanamh eadar an seòladh IP agad ri feadhainn eile feuch am mothaich sinn do sheachnadh toirmisg no briseadh eile nan riaghailtean.</li> <li>Faodaidh sinn an seòladh puist-d agad a chleachdadh airson fiosrachadh no brathan mu eadar-ghnìomhan a ghabh càch leis an t-susbaint agad no teachdaireachdan a chur thugad, airson freagairt ri ceasnachaidhean agus/no iarrtasan no ceistean eile.</li> </ul> <hr class="spacer" /> <h3 id="protect">Ciamar a dhìonas sinn am fiosrachadh agad?</h3> <p>Cuiridh sinn iomadh gleus tèarainteachd an sàs ach an glèidheadh sinn sàbhailteachd an fhiosrachaidh phearsanta agad nuair a chuireas tu gin a-steach, nuair a chuireas tu a-null e no nuair a nì thu inntrigeadh air. Am measg gleusan eile, thèid seisean a’ bhrabhsair agad cuide ris an trafaig eadar na h-aplacaidean agad ’s an API a dhìon le SSL agus thèid hais a dhèanamh dhen fhacal-fhaire agad le algairim aon-shligheach làidir. Faodaidh tu dearbhadh dà-cheumnach a chur an comas airson barrachd tèarainteachd a chur ris an inntrigeadh dhan chunntas agad.</p> <hr class="spacer" /> <h3 id="data-retention">Dè am poileasaidh cumail dàta againn?</h3> <p>Nì sinn ar dìcheall:</p> <ul> <li>Nach cùm sinn logaidhean an fhrithealaiche sa bheil seòlaidhean IP nan iarrtasan uile dhan fhrithealaiche seo nas fhaide na 90 latha ma chumas sinn logaichean dhen leithid idir.</li> <li>Nach cùm sinn na seòlaidhean IP a tha co-cheangailte ri cleachdaichean clàraichte nas fhaide na 12 mhìos.</li> </ul> <p>’S urrainn dhut tasg-lann iarraidh dhen t-susbaint agad ’s a luchdadh a-nuas is gabhaidh seo a-staigh na postaichean, na ceanglachain meadhain, dealbh na pròifil agus dealbh a’ bhanna-chinn agad.</p> <p>’S urrainn dhut an cunntas agad a sguabadh às gu buan uair sam bith.</p> <hr class="spacer"/> <h3 id="cookies">An cleachd sinn briosgaidhean?</h3> <p>Cleachdaidh. ’S e faidhlichean beaga a tha sna briosgaidean a thar-chuireas làrach no solaraiche seirbheise gu clàr-cruaidh a’ choimpiutair agad leis a’ bhrabhsair-lìn agad (ma cheadaicheas tu sin). Bheir na briosgaidean sin comas dhan làrach gun aithnich i am brabhsair agad agus ma tha cunntas clàraichte agad, gun co-cheangail i ris a’ chunntas chlàraichte agad e.</p> <p>Cleachdaidh sinn briosgaidean airson na roghainnean agad a thuigsinn ’s a ghlèidheadh gus an tadhail thu oirnn san àm ri teachd.</p> <hr class="spacer" /> <h3 id="disclose">Am foillsich sinn fiosrachadh sam bith gu pàrtaidhean air an taobh a-muigh?</h3> <p>Cha reic, malairt no tar-chuir sinn fiosrachadh air a dh’aithnichear thu fhèin gu pàrtaidh sam bith air an taobh a-muigh. Cha ghabh seo a-staigh treas-phàrtaidhean earbsach a chuidicheas leinn le ruith na làraich againn, le obrachadh a’ ghnìomhachais againn no gus an t-seirbheis a thoirt leat cho fada ’s a dh’aontaicheas na treas-phàrtaidhean sin gun cùm iad am fiosrachadh dìomhair. Faodaidh sinn am fiosrachadh agad fhoillseachadh cuideachd nuair a bhios sinn dhen bheachd gu bheil am foillseachadh sin iomchaidh airson gèilleadh dhan lagh, poileasaidhean na làraich againn èigneachadh no na còraichean, an sealbh no an t-sàbhailteachd againn fhèin no aig càch a dhìon.</p> <p>Dh’fhaoidte gun dèid an t-susbaint phoblach agad a luchdadh a-nuas le frithealaichean eile san lìonra. Thèid na postaichean poblach agad ’s an fheadhainn dhan luchd-leantainn a-mhàin a lìbhrigeadh dha na frithealaichean far a bheil an luchd-leantainn agad a’ còmhnaidh agus thèid na teachdaireachdan dìreach a lìbhrigeadh gu frithealaichean nam faightearan nuair a bhios iad a’ còmhnaidh air frithealaiche eile.</p> <p>Nuair a dh’ùghdarraicheas tu aplacaid gun cleachd i an cunntas agad, a-rèir sgòp nan ceadan a dh’aontaicheas tu riutha, faodaidh i fiosrachadh poblach na pròifil agad, liosta na feadhna air a bhios tu a’ leantainn, an luchd-leantainn agad, na liostaichean agad, na postaichean agad uile ’s na h-annsachdan agad inntrigeadh. Chan urrainn do dh’aplacaidean an seòladh puist-d no am facal-faire agad inntrigeadh idir.</p> <hr class="spacer" /> <h3 id="children">Cleachdadh na làraich leis a’ chloinn</h3> <p>Ma tha am frithealaiche seo san Aonadh Eòrpach (AE) no san Roinn Eaconomach na h-Eòrpa (EEA): Tha an làrach, na batharan agus na seirbheisean againn uile ag amas air an fheadhainn a tha co-dhiù 16 bliadhnaichean a dh’aois. Ma tha thu nas òige na 16 bliadhnaichean a dh’aois, tha e riatanach fon GDPR (<a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation">General Data Protection Regulation</a>) nach cleachd thu an làrach seo.</p> <p>Ma tha am frithealaiche seo sna Stàitean Aonaichte (SAA): Tha an làrach, na batharan agus na seirbheisean againn uile ag amas air an fheadhainn a tha co-dhiù 13 bliadhnaichean a dh’aois. Ma tha thu nas òige na 16 bliadhnaichean a dh’aois, tha e riatanach fon COPPA (<a href="https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act">Children''s Online Privacy Protection Act</a>)ha an làrach, na batharan agus na seirbheisean againn uile ag amas air an fheadhainn a tha co-dhiù 16 bliadhnaichean a dh’aois. Ma tha thu nas òige na 16 bliadhnaichean a dh’aois, tha e riatanach fon GDPR (<a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation">General Data Protection Regulation</a>) nach cleachd thu an làrach seo.</p> <p>Ma tha am frithealaiche seo sna Stàitean Aonaichte (SAA): Tha an làrach, na batharan agus na seirbheisean againn uile ag amas air an fheadhainn a tha co-dhiù 13 bliadhnaichean a dh’aois. Ma tha thu nas òige na 16 bliadhnaichean a dh’aois, tha e riatanach fon COPPA (<a href="https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act">Children''s Online Privacy Protection Act</a>) nach cleachd thu an làrach seo.</p> <p>Dh’fhaoidte gu bheil am frithealaiche seo fo riatanasan lagha eile ma tha e ann an uachdranas laghail eile.</p> <hr class="spacer" /> <h3 id="changes">Atharraichean air a’ phoileasaidh phrìobhaideachd againn</h3> <p>Ma chuireas sinn romhainn am poileasaidh prìobhaideachd againn atharrachadh, postaichidh sinn na h-atharraichean dhan duilleag seo.</p> <p>Tha an sgrìobhainn seo fo cheadachas CC-BY-SA. Chaidh ùrachadh an turas mu dheireadh an t-7mh dhen Mhart 2018.</p> <p>Chaidh a fhreagarrachadh o thùs o <a href="https://github.com/discourse/discourse">phoileasaidh prìobhaideachd Discourse</a>.</p> ' title: Teirmichean na seirbheise ⁊ poileasaidh prìobhaideachd %{instance} @@ -1513,6 +1576,15 @@ gd: recovery_instructions_html: Ma chailleas tu an t-inntrigeadh dhan fhòn agad, ’s urrainn dhut fear dhe na còdan aisig gu h-ìosal a chleachdadh airson faighinn a-steach dhan chunntas agad a-rithist. <strong>Cùm na còdan aisig sàbhailte</strong>. Mar eisimpleir, ’s urrainn dhut an clò-bhualadh ’s a chumail far a bheil thu a’ cumail na sgrìobhainnean cudromach eile agad. webauthn: Iuchraichean tèarainteachd user_mailer: + appeal_approved: + action: Tadhail air a’ chunntas agad + explanation: Chaidh aontachadh ris an ath-thagradh agad air an rabhadh o %{strike_date} a chuir thu a-null %{appeal_date}. Tha deagh chliù air a’ chunntas agad a-rithist. + subject: Chaidh aontachadh ris an ath-thagradh agad o %{date} + title: Chaidh aontachadh ri ath-thagradh + appeal_rejected: + explanation: Chaidh an t-ath-thagradh agad air an rabhadh o %{strike_date} a chuir thu a-null %{appeal_date} a dhiùltadh. + subject: Chaidh an t-ath-thagradh agad o %{date} a dhiùltadh + title: Chaidh ath-thagradh a dhiùltadh backup_ready: explanation: Dh’iarr thu lethbhreac-glèidhidh slàn dhen chunntas Mastodon agad. Tha e deis ri luchdadh a-nuas a-nis! subject: Tha an tasg-lann agad deis ri luchdadh a-nuas @@ -1524,25 +1596,34 @@ gd: subject: Dearbh an oidhirp air clàradh a-steach title: Oidhirp clàraidh a-steach warning: + appeal: Cuir ath-thagradh a-null + appeal_description: Ma tha thu dhen bheachd gur e mearachd a th’ ann, ’s urrainn dhut ath-thagradh a chur a-null gun sgioba aig %{instance}. categories: spam: Spama violation: Tha an t-susbaint a’ briseadh na riaghailtean giùlain a leanas explanation: + delete_statuses: Thathar dhen bheachd gu bheil cuid dhe na postaichean agad a’ briseadh riaghailt no riaghailtean giùlain agus chaidh an toirt air falbh le maoir %{instance} an uairsin. disable: Chan urrainn dhut an cunntas agad a chleachdadh tuilleadh ach mairidh a’ phròifil ’s an dàta eile agad. Faodaidh tu lethbhreac-glèidhidh dhen dàta agad iarraidh, roghainnean a’ chunntais atharrachadh no an cunntas agad a sguabadh às. + mark_statuses_as_sensitive: Chuir maoir %{instance} comharra na frionasachd ri cuid dhe na postaichean agad. Is ciall dha seo gum feumar gnogag a thoirt air na meadhanan sna postaichean mus faicear ro-shealladh. ’S urrainn dhut fhèin comharra a chur gu bheil meadhan frionasach nuair a sgrìobhas tu post san à ri teachd. sensitive: O seo a-mach, thèid comharra na frionasachd a chur ri faidhle meadhain sam bith a luchdaicheas tu suas agus thèid am falach air cùlaibh rabhaidh a ghabhas briogadh air. silence: "’S urrainn dhut an cunntas agad a chleachdadh fhathast ach chan fhaic ach na daoine a tha a’ leantainn ort mu thràth na postaichean agad air an fhrithealaiche seo agus dh’fhaoidte gun dèid d’ às-dhùnadh o iomadh gleus luirg. Gidheadh, faodaidh càch leantainn ort a làimh fhathast." suspend: Chan urrainn dhut an cunntas agad a chleachdadh tuilleadh agus chan fhaigh thu grèim air a’ phròifil no air an dàta eile agad. ’S urrainn dhut clàradh a-steach fhathast airson lethbhreac-glèidhidh dhen dàta agad iarraidh mur dèid an dàta a thoirt air falbh an ceann 30 latha gu slàn ach cumaidh sinn cuid dhen dàta bhunasach ach nach seachain thu an cur à rèim. reason: 'Adhbhar:' + statuses: 'Iomradh air postaichean:' subject: delete_statuses: Chaidh na postaichean agad air %{acct} a thoirt air falbh disable: Chaidh an cunntas %{acct} agad a reòthadh + mark_statuses_as_sensitive: Chaidh comharra na frionasachd a chur ris na postaichean agad air %{acct} none: Rabhadh dha %{acct} + sensitive: Thèid comharra na frionasachd a chur ris na postaichean agad air %{acct} o seo a-mach silence: Chaidh an cunntas %{acct} agad a chuingeachadh suspend: Chaidh an cunntas %{acct} agad a chur à rèim title: delete_statuses: Chaidh postaichean a thoirt air falbh disable: Cunntas reòite + mark_statuses_as_sensitive: Chaidh comharra na frionasachd a chur ri postaichean none: Rabhadh + sensitive: Chaidh comharra na frionasachd a chur ri cunntas silence: Cunntas cuingichte suspend: Cunntas à rèim welcome: diff --git a/config/locales/gl.yml b/config/locales/gl.yml index f3a4beb70..e28d9e018 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -165,10 +165,6 @@ gl: pending: Revisión pendente perform_full_suspension: Suspender previous_strikes: Accións previas - previous_strikes_description_html: - one: Esta conta ten <strong>un</strong> evento. - other: Esta conta ten <strong>%{count}</strong> eventos. - zero: Esta conta ten <strong>boa reputación</strong>. promote: Promocionar protocol: Protocolo public: Público @@ -490,6 +486,7 @@ gl: other: Intentos fallidos durante %{count} días distintos. no_failures_recorded: Non hai fallos rexistrados. title: Dispoñibilidade + warning: Fallou o último intento de conectar con este servidor back_to_all: Todo back_to_limited: Limitado back_to_warning: Aviso @@ -526,10 +523,6 @@ gl: delivery_error_hint: Se non é posible a entrega durante %{count} días, será automáticamente marcado como non entregable. destroyed_msg: Os datos desde %{domain} están na cola para o borrado inminente. empty: Non se atopan dominios. - known_accounts: - one: "%{count} conta coñecida" - other: "%{count} contas coñecidas" - zero: Sen contas coñecidas moderation: all: Todo limited: Limitado @@ -774,6 +767,11 @@ gl: system_checks: database_schema_check: message_html: Existen migracións pendentes na base de datos. Bota man desta tarefa para facer que a aplicación funcione como se agarda dela + elasticsearch_running_check: + message_html: Non se puido conectar con Elasticsearch. Comproba que está funcionando, ou desactiva a busca por texto completo + elasticsearch_version_check: + message_html: 'Versión incompatible de Elasticsearch: %{value}' + version_comparison: Está executándose Elasticsearch %{running_version} pero requírese a %{required_version} rules_check: action: Xestionar regras do servidor message_html: Non tes definidas regras para o servidor. @@ -793,10 +791,6 @@ gl: description_html: Estas son ligazóns que actualmente están sendo compartidas por moitas contas das que o teu servidor recibe publicación. Pode ser de utilidade para as túas usuarias para saber o que acontece polo mundo. Non se mostran ligazóns de xeito público a non ser que autorices a quen as publica. Tamén podes permitir ou rexeitar ligazóns de xeito individual. disallow: Denegar ligazón disallow_provider: Denegar orixe - shared_by_over_week: - one: Compartido por unha persoa na última semana - other: Compartido por %{count} persoas na última semana - zero: Non foi compartido na última semana title: Ligazóns en voga usage_comparison: Compartido %{today} veces hoxe, comparado con %{yesterday} onte pending_review: Revisión pendente @@ -836,10 +830,6 @@ gl: trending_rank: 'En voga #%{rank}' usable: Pode ser usado usage_comparison: Utilizado %{today} veces hoxe, comparado coas %{yesterday} de onte - used_by_over_week: - one: Utilizado por unha persoa na última semana - other: Utilizado por %{count} persoas na última semana - zero: Non foi utilizado na última semana title: Tendencias warning_presets: add_new: Engadir novo diff --git a/config/locales/he.yml b/config/locales/he.yml index 67f3df609..97138fffa 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -169,17 +169,6 @@ he: remove_from_report: הסרה מהדיווח report: דווח title: ניהול - trends: - links: - shared_by_over_week: - one: שותף ע"י משתמש\ת אחד\ת בשבוע האחרון - other: שותף ע"י %{count} משתמשים בשבוע האחרון - zero: לא שותף בכלל בשבוע האחרון - tags: - used_by_over_week: - one: היה בשימוש משתמש\ת אחד\ת בשבוע האחרון - other: היה בשימוש ע"י %{count} משתמשים בשבוע האחרון - zero: לא היה בשימוש בכלל בשבוע האחרון application_mailer: settings: 'שינוי הגדרות דוא"ל: %{link}' view: 'תצוגה:' diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 000184317..abe5baf48 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -170,7 +170,6 @@ hu: previous_strikes_description_html: one: Ezt a fiókot <strong>egyszer</strong> szankcionálták. other: Ezt a fiókot <strong>%{count}</strong> esetben szankcionálták. - zero: Ez a fiók <strong>makulátlan</strong>. promote: Előléptetés protocol: Protokoll public: Nyilvános @@ -492,6 +491,7 @@ hu: other: Sikertelen próbálkozás %{count} különböző napon. no_failures_recorded: Nem rögzítettünk hibát. title: Elérhetőség + warning: Sikertelen volt az utolsó csatlakozási próbálkozás ehhez a szerverhez back_to_all: Mind back_to_limited: Korlátozott back_to_warning: Figyelmeztetés @@ -531,7 +531,6 @@ hu: known_accounts: one: "%{count} ismert fiók" other: "%{count} ismert fiók" - zero: Nincs ismert fiók moderation: all: Mind limited: Korlátozott @@ -776,6 +775,11 @@ hu: system_checks: database_schema_check: message_html: Vannak esedékes adatbázis migrációink. Kérlek, futtasd őket, hogy biztosítsd, hogy az alkalmazás megfelelően működjön + elasticsearch_running_check: + message_html: Nem sikerült az Elasticsearchhöz kapcsolódni. Ellenőrizze, hogy fut-e, vagy kapcsolja ki a teljes szöveges keresést. + elasticsearch_version_check: + message_html: 'Nem kompatibilis Elasticsearch verzió: %{value}' + version_comparison: Az Elasticsearch %{running_version} fut, de %{required_version} szükséges rules_check: action: Szerver szabályok menedzselése message_html: Még nem definiáltál egy szerver szabályt sem. @@ -796,9 +800,8 @@ hu: disallow: Hivatkozás letiltása disallow_provider: Közzétevő letiltása shared_by_over_week: - one: Egy ember osztotta meg az elmúlt héten - other: "%{count} ember osztotta meg az elmúlt héten" - zero: Senki sem osztotta meg az elmúlt héten + one: Egy ember osztotta meg a múlt héten + other: "%{count} ember osztotta meg a múlt héten" title: Felkapott hivatkozások usage_comparison: "%{today} alkalommal lett ma megosztva, a tegnapi %{yesterday} alkalomhoz képest" pending_review: Áttekintésre vár @@ -841,7 +844,6 @@ hu: used_by_over_week: one: Egy ember használta a múlt héten other: "%{count} ember használta a múlt héten" - zero: Senki sem használta a múlt héten title: Trendek warning_presets: add_new: Új hozzáadása diff --git a/config/locales/id.yml b/config/locales/id.yml index 97443b4a5..ccb71ebdd 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -160,9 +160,7 @@ id: perform_full_suspension: Lakukan suspen penuh previous_strikes: Peringatan sebelumnya previous_strikes_description_html: - one: Akun ini mendapatkan <strong>satu</strong> peringatan. - other: Akun ini mendapatkan <strong>%{count}</strong> peringatan. - zero: Akun ini <strong>status bagus</strong>. + other: Akun ini mendapatkan <strong>%{count}</strong> hukuman. promote: Promosikan protocol: Protokol public: Publik @@ -477,6 +475,7 @@ id: other: Upaya gagal dalam %{count} hari berbeda. no_failures_recorded: Tidak ada kegagalan tercatat. title: Ketersediaan + warning: Upaya terakhir untuk menyambung ke server ini tidak berhasil back_to_all: Semua back_to_limited: Terbatas back_to_warning: Peringatan @@ -514,9 +513,7 @@ id: destroyed_msg: Data dari %{domain} masuk antrean dihapus dalam waktu dekat. empty: Domain tidak ditemukan. known_accounts: - one: "%{count} akun dikenal" - other: "%{count} akun dikenal" - zero: Tidak ada akun yang dikenal + other: "%{count} akun yang dikenal" moderation: all: Semua limited: Terbatas @@ -760,6 +757,11 @@ id: system_checks: database_schema_check: message_html: Ada proses migrasi basis data tertunda. Silakan jalankan untuk memastikan aplikasi bekerja seperti yang diharapkan + elasticsearch_running_check: + message_html: Tidak dapat tersambung ke Elasticsearch. Pastikan itu berjalan, atau nonaktifkan pencarian teks penuh + elasticsearch_version_check: + message_html: 'Versi Elasticsearch tidak kompatibel: %{value}' + version_comparison: Elasticsearch %{running_version} sedang berjalan, sementara yang diwajibkan adalah %{required_version} rules_check: action: Kelola aturan server message_html: Anda belum menentukan aturan server apapun. @@ -780,9 +782,7 @@ id: disallow: Batalkan izin tautan disallow_provider: Batalkan izin penerbit shared_by_over_week: - one: Dibagikan oleh satu orang lebih dari seminggu lalu - other: Dibagikan oleh %{count} orang lebih dari seminggu lalu - zero: Tidak dibagikan siapapun lebih dari seminggu lalu + other: Dibagikan oleh %{count} orang selama seminggu terakhir title: Tautan sedang tren usage_comparison: Dibagikan %{today} kali hari ini, dibandingkan %{yesterday} kemarin pending_review: Tinjauan tertunda @@ -822,9 +822,7 @@ id: usable: Dapat digunakan usage_comparison: Digunakan %{today} kali hari ini, dibandingkan %{yesterday} kemarin used_by_over_week: - one: Dipakai oleh satu orang lebih dari seminggu lalu - other: Dipakai oleh %{count} orang selama seminggu terakhir - zero: Tidak dipakai siapapun lebih dari seminggu lalu + other: Digunakan oleh %{count} orang selama seminggu terakhir title: Tren warning_presets: add_new: Tambah baru diff --git a/config/locales/is.yml b/config/locales/is.yml index 04d193975..910ae0b79 100644 --- a/config/locales/is.yml +++ b/config/locales/is.yml @@ -168,7 +168,6 @@ is: previous_strikes_description_html: one: Þessi notandaaðgangur er með <strong>eina</strong> refsingu. other: Þessi notandaaðgangur er með <strong>%{count}</strong> refsingar. - zero: Þessi notandaaðgangur er <strong>í góðu lagi</strong>. promote: Hækka í tign protocol: Samskiptamáti public: Opinber @@ -490,6 +489,7 @@ is: other: Misheppnaðar tilraunir á %{count} mismunandi dögum. no_failures_recorded: Engar misheppnaðar tilraunir á skrá. title: Tiltækileiki + warning: Síðasta tilraun til að tengjast þessum netþjóni mistókst back_to_all: Allt back_to_limited: Takmarkað back_to_warning: Aðvörun @@ -529,7 +529,6 @@ is: known_accounts: one: "%{count} þekktur notandaaðgangur" other: "%{count} þekktir notendaaðgangar" - zero: Enginn þekktur notandaaðgangur moderation: all: Allt limited: Takmarkað @@ -774,6 +773,11 @@ is: system_checks: database_schema_check: message_html: Það eru fyrirliggjandi yfirfærslur á gagnagrunnum. Keyrðu þær til að tryggja að forritið hegði sér eins og skyldi + elasticsearch_running_check: + message_html: Gat ekki tengst við Elasticsearch-leitina. Gakktu úr skugga um að hún sé í gangi, eða gerðu leit í öllum texta óvirka + elasticsearch_version_check: + message_html: 'Ósamhæfð útgáfa Elasticsearch-leitar: %{value}' + version_comparison: Elasticsearch %{running_version} er í gangi á meðan útgáfa %{required_version} er nauðsynleg rules_check: action: Sýsla með reglur netþjónsins message_html: Þú hefur ekki skilgreint neinar reglur fyrir netþjón. @@ -796,7 +800,6 @@ is: shared_by_over_week: one: Deilt af einum aðila síðustu vikuna other: Deilt af %{count} aðilum síðustu vikuna - zero: Ekki deilt af neinum aðila síðustu vikuna title: Vinsælir tenglar usage_comparison: Deilt %{today} sinnum í dag, samanborið við %{yesterday} í gær pending_review: Bíður eftir yfirlestri @@ -839,7 +842,6 @@ is: used_by_over_week: one: Notað af einum aðila síðustu vikuna other: Notað af %{count} aðilum síðustu vikuna - zero: Ekki notað af neinum aðila síðustu vikuna title: Tilhneiging warning_presets: add_new: Bæta við nýju diff --git a/config/locales/it.yml b/config/locales/it.yml index d96e58540..92cd18d1a 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -168,7 +168,6 @@ it: previous_strikes_description_html: one: Questo account ha <strong>una</strong> violazione. other: Questo account ha <strong>%{count}</strong> violazioni. - zero: Questo account ha <strong>una buona reputazione</strong>. promote: Promuovi protocol: Protocollo public: Pubblico @@ -490,6 +489,7 @@ it: other: Tentativo fallito %{count} giorni differenti. no_failures_recorded: Nessun fallimento registrato. title: Disponibilità + warning: L'ultimo tentativo di connessione a questo server non è riuscito back_to_all: Tutto back_to_limited: Limitato back_to_warning: Avviso @@ -529,7 +529,6 @@ it: known_accounts: one: "%{count} account noto" other: "%{count} account noti" - zero: Nessun account noto moderation: all: Tutto limited: Limitato @@ -774,6 +773,11 @@ it: system_checks: database_schema_check: message_html: Ci sono migrazioni del database in attesa. Sei pregato di eseguirle per assicurarti che l'applicazione si comporti come previsto + elasticsearch_running_check: + message_html: Impossibile connettersi a Elasticsearch. Verificare che sia in esecuzione o disabilitare la ricerca full-text + elasticsearch_version_check: + message_html: 'Versione Elasticsearch incompatibile: %{value}' + version_comparison: È in esecuzione la versione %{running_version} di Elasticsearch, ma è richiesta la versione %{required_version} rules_check: action: Gestisci regole del server message_html: Non hai definito alcuna regola del server. @@ -796,7 +800,6 @@ it: shared_by_over_week: one: Condiviso da una persona nell'ultima settimana other: Condiviso da %{count} persone nell'ultima settimana - zero: Condiviso da nessuno nell'ultima settimana title: Link in tendenza usage_comparison: Condiviso %{today} volte oggi, rispetto a %{yesterday} ieri pending_review: Revisione in sospeso @@ -839,7 +842,6 @@ it: used_by_over_week: one: Usato da una persona nell'ultima settimana other: Usato da %{count} persone nell'ultima settimana - zero: Usato da nessuno nell'ultima settimana title: Tendenze warning_presets: add_new: Aggiungi nuovo diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 32b101147..84559e499 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -474,10 +474,6 @@ ja: delivery_error_hint: "%{count} 日間配送ができない場合は、自動的に配送不可としてマークされます。" destroyed_msg: "%{domain} からのデータは、すぐに削除されるように、キューに追加されました。" empty: ドメインが見つかりませんでした。 - known_accounts: - one: 既知のアカウントが%{count}件あります - other: 既知のアカウントが%{count}件あります - zero: 既知のアカウントはありません moderation: all: すべて limited: 制限あり @@ -716,7 +712,7 @@ ja: trends: allow: 許可 approved: 承認 - disallow: 不許可 + disallow: 拒否 links: allow: リンクの許可 allow_provider: 発行者の承認 @@ -731,8 +727,11 @@ ja: title: 発行者 rejected: 拒否 statuses: - allow: 投稿を許可する - disallow: 投稿を許可しない + allow: 掲載を許可 + allow_account: 投稿者を許可 + disallow: 掲載を拒否 + disallow_account: 投稿者を拒否 + title: トレンド投稿 tags: current_score: 現在のスコア %{score} dashboard: @@ -1309,6 +1308,7 @@ ja: default_language: UIの表示言語 disallowed_hashtags: other: '許可されていないハッシュタグが含まれています: %{tags}' + edited_at_html: "%{date} 編集済み" errors: in_reply_not_found: あなたが返信しようとしている投稿は存在しないようです。 open_in_web: Webで開く diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 7dacd90d3..a8e8e3622 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -162,9 +162,7 @@ ko: perform_full_suspension: 정지시키기 previous_strikes: 이전의 처벌들 previous_strikes_description_html: - one: 이 계정은 <strong>한<strong> 번의 처벌이 있었습니다. other: 이 계정은 <strong>%{count}</strong> 번의 처벌이 있었습니다. - zero: 이 계정은 처벌 기록이 <strong>없습니다</strong>. promote: 승급 protocol: 프로토콜 public: 공개 @@ -481,6 +479,7 @@ ko: other: 실패한 전달 시도 총 %{count}일. no_failures_recorded: 실패 기록이 없습니다. title: 가용성 + warning: 이 서버에 대한 마지막 연결 시도가 성공적이지 않았습니다 back_to_all: 전체 back_to_limited: 제한됨 back_to_warning: 경고 @@ -518,9 +517,7 @@ ko: destroyed_msg: "%{domain}의 데이터는 곧바로 지워지도록 대기열에 들어갔습니다." empty: 도메인이 하나도 없습니다. known_accounts: - one: "%{count} 개의 알려진 계정" other: "%{count} 개의 알려진 계정" - zero: 알려진 계정이 없습니다 moderation: all: 모두 limited: 제한됨 @@ -764,6 +761,11 @@ ko: system_checks: database_schema_check: message_html: 데이터베이스 마이그레이션이 대기중입니다. 응용프로그램이 예상한대로 동작할 수 있도록 마이그레이션을 실행해 주세요 + elasticsearch_running_check: + message_html: Elasticsearch에 연결할 수 없습니다. 실행중인지 확인하거나, 전문검색을 비활성화하세요 + elasticsearch_version_check: + message_html: '호환되지 않는 Elasticsearch 버전: %{value}' + version_comparison: Elasticsearch %{required_version}버전이 필요하지만 %{running_version}버전이 실행 중입니다. rules_check: action: 서버 규칙 관리 message_html: 아직 서버규칙을 정하지 않았습니다. @@ -784,9 +786,7 @@ ko: disallow: 링크 거부하기 disallow_provider: 출처 거부하기 shared_by_over_week: - one: 지난 주 동안 한 명의 사람이 공유했습니다 other: 지난 주 동안 %{count} 명의 사람들이 공유했습니다 - zero: 지난 주 동안 공유한 사람이 없습니다 title: 유행하는 링크 usage_comparison: 오늘은 %{today}회 공유되었고, 어제는 %{yesterday}회 공유되었습니다 pending_review: 심사 대기 @@ -826,9 +826,7 @@ ko: usable: 사용 가능 usage_comparison: 오늘은 %{today}회 사용되었고, 어제는 %{yesterday}회 사용되었습니다 used_by_over_week: - one: 지난 주 동안 한 명의 사람이 사용했습니다 other: 지난 주 동안 %{count} 명의 사람들이 사용했습니다 - zero: 지난 주 동안 사용한 사람이 없습니다 title: 유행 warning_presets: add_new: 새로 추가 diff --git a/config/locales/ku.yml b/config/locales/ku.yml index a457b4b07..1f5554f4b 100644 --- a/config/locales/ku.yml +++ b/config/locales/ku.yml @@ -21,7 +21,7 @@ ku: documentation: Pelbend federation_hint_html: Bi ajimêrê xwe %{instance} re tu dikarî kesên rajekar û li derveyî mastodonê bişopînî. get_apps: Sepaneke mobîl bicerbîne - hosted_on: Mastodon li ser%{domain} tê hildanê + hosted_on: Mastodon li ser %{domain} tê pêşkêşkirin instance_actor_flash: 'Ev ajimêr aktorekî aşopî ye ji bo rajekar were temsîl kirin tê bikaranîn ne ajimêra kesî ye. Ji bo armanca federasyonê dixebite û divê ney asteng kirin heta ku te xwest hemû nimûneyan asteng bikî, di vir de ger tu blogek navper bikarbînî. ' @@ -133,7 +133,7 @@ ku: enabled: Çalakkirî enabled_msg: Ajimêra %{username} bi serkeftî hat çalak kirin followers: Şopîner - follows: Dişopînê + follows: Dişopîne header: Jormalper inbox_url: Peyamên hatî URl invite_request_text: Sedemên tevlêbûnê @@ -168,7 +168,6 @@ ku: previous_strikes_description_html: one: Ev ajimêr <strong>yek</strong> binpêkirin kiriye. other: Ev ajimêr <strong>%{count}</strong> binpêkirin kiriye. - zero: Ev ajimêr <strong>di rewşeke baş de ye</strong>. promote: Derbasê asteke bilind be protocol: Protokol public: Gelemperî @@ -186,7 +185,7 @@ ku: send: E-nameya pejirandinê dîsa bişîne success: E-nameya pejirandinê bi awayekî serkeftî hate şandin! reset: Ji nû ve saz bike - reset_password: Pêborînê ji nû ve saz bike + reset_password: Borînpeyvê ji nû ve saz bike resubscribe: Dîsa beşdar bibe role: Maf roles: @@ -198,9 +197,9 @@ ku: search_same_email_domain: Bikarhênerên din ên bi heman navpera e-nameyê search_same_ip: Bikarhênerên din ên xwedî heman IP security_measures: - only_password: Têne pêborîn - password_and_2fa: Pêborîn û 2FA - password_and_sign_in_token: Pêborîn û navnîşana e-nameyê + only_password: Têne borînpeyv + password_and_2fa: Borînpeyv û 2FA + password_and_sign_in_token: Borînpeyv û navnîşana e-nameyê sensitive: Hêz-hestiyar sensitized: Wek hestiyar hatiye nîşankirin shared_inbox_url: URLya wergirtiyên parvekirî @@ -269,7 +268,7 @@ ku: reject_user: Bikarhêner nepejirîne remove_avatar_user: Avatarê rake reopen_report: Ragihandina ji nû ve veke - reset_password_user: Pêborînê ji nû ve saz bike + reset_password_user: Borînpeyvê ji nû ve saz bike resolve_report: Ragihandinê çareser bike sensitive_account: Ajimêra hêz-hestiyar silence_account: Ajimêrê bi sînor bike @@ -320,7 +319,7 @@ ku: reject_user_html: "%{name} tomarkirina ji %{target} nepejirand" remove_avatar_user_html: "%{name} avatara bikarhêner %{target} rakir" reopen_report_html: "%{name} ragihandina %{target} ji nû ve vekir" - reset_password_user_html: "%{name} pêborîna bikarhênerê %{target} ji nû ve saz kir" + reset_password_user_html: "%{name} borînpeyva bikarhêner %{target} ji nû ve saz kir" resolve_report_html: "%{name} ragihandina %{target} çareser kir" sensitive_account_html: "%{name} medyayê %{target} wekî hestiyarî nîşan kir" silence_account_html: "%{name} ajimêra %{target} bi sînor kir" @@ -492,6 +491,7 @@ ku: other: Hewldanên têkçûyî di %{count} rojên cuda de. no_failures_recorded: Di tomarê de têkçûn tune. title: Berdestbûnî + warning: Hewldana dawî ji bo girêdana bi vê rajekarê re bi ser neket back_to_all: Hemû back_to_limited: Sînorkirî back_to_warning: Hişyarî @@ -531,7 +531,6 @@ ku: known_accounts: one: "%{count} ajimêra naskirî" other: "%{count} ajimêrên naskirî" - zero: Ajimêra naskirî tune ye moderation: all: Hemû limited: Sînorkirî @@ -543,7 +542,7 @@ ku: title: Giştî total_blocked_by_us: Ji aliyê me ve hatiye astengkirin total_followed_by_them: Ji aliyê wan ve hatiye şopandin - total_followed_by_us: Ji aliyê ve me hate şopandin + total_followed_by_us: Ji aliyê me ve hatiye şopandin total_reported: Giliyên derheqê wan de total_storage: Pêvekên medyayê totals_time_period_hint_html: Tevahiyên ku li jêr têne xuyakirin daneyên hemû deman dihewîne. @@ -776,6 +775,11 @@ ku: system_checks: database_schema_check: message_html: Koçberiyên databasê yên li bendê hene. Ji kerema xwe wan bişopîne da ku bicîh bikî ku sepan wekî ku tê hêvî kirin tevbigere + elasticsearch_running_check: + message_html: Bi Elasticsearch re nayê girêdan. Ji kerema xwe kontrol bike ku ew dixebite, an lêgerîna tev-nivîsî neçalak bike + elasticsearch_version_check: + message_html: 'Guhertoya Elasticsearch a nelihevhatî: %{value}' + version_comparison: Elasticsearch %{running_version} dixebite lê %{required_version} pêwîst e rules_check: action: Rêzikên rajekara bi rê ve bibe message_html: Te qet rêzikên rajekara diyar nekiriye. @@ -797,8 +801,7 @@ ku: disallow_provider: Mafê nede weşanger shared_by_over_week: one: Di nava hefteya dawî de ji aliyê keskekî ve hate parvekirin - other: Di nava hefteya dawî de ji aliyê %{count} kes ve hate parvekirin - zero: Di nava hefteya dawî de ji aliyê kesekî ve nehate parvekirin + other: Di nava hefteya dawî de ji aliyê %{count} ve hate parvekirin title: Girêdanên di rojevê de usage_comparison: Îro %{today} car hate parvekirin, li gorî %{yesterday} duh pending_review: Li benda nirxandinê ye @@ -841,7 +844,6 @@ ku: used_by_over_week: one: Di nava hefteya dawî de ji aliyê kesekî ve hatiye bikaranîn other: Di nava hefteya dawî de ji %{count} kes ve hatiye bikaranîn - zero: Di nava hefteya dawî de ji aliyê kesekî ve nehate bikaranîn title: Rojev warning_presets: add_new: Yeka nû tevlî bike @@ -904,9 +906,9 @@ ku: sensitive_content: Naveroka hestiyarî toot_layout: Xêzkirina şandîya application_mailer: - notification_preferences: Hevyazên e-name yê biguherîne + notification_preferences: Sazkariyên e-nameyê biguherîne salutation: "%{name}," - settings: 'Hevyazên e-name yê biguherîne: %{link}' + settings: 'Sazkariyên e-nameyê biguherîne: %{link}' view: 'Nîşan bide:' view_profile: Profîlê nîşan bide view_status: Şandiyê nîşan bide @@ -920,7 +922,7 @@ ku: your_token: Nîşana gihîştina te auth: apply_for_account: Daxwaza vexwendinekê bike - change_password: Pêborîn + change_password: Borînpeyv checkbox_agreement_html: Ez <a href="%{rules_path}" target="_blank">rêbazên rajeker</a> û <a href="%{terms_path}" target="_blank">hêmanên karûbaran</a> dipejirînim checkbox_agreement_without_rules_html: Ez <a href="%{terms_path}" target="_blank">hêmanên karûbaran</a> rêbazên rajeker dipejirînim delete_account: Ajimêr jê bibe @@ -931,8 +933,8 @@ ku: suffix: Bi ajimêrekê, tu yê karibî kesan bişopînî, rojanekirinan bişînî û bi bikarhênerên ji her rajekarê Mastodon re peyaman bişînî û bêhtir! didnt_get_confirmation: Te rêwerzên pejirandinê wernegirt? dont_have_your_security_key: Kilîda te ya ewlehiyê tune ye? - forgot_password: Te pêborîna xwe jibîrkir? - invalid_reset_password_token: Ji nû ve sazkirina pêborînê nederbasdar e an jî qediya ye. Jkx daxwaza yeka nû bike. + forgot_password: Te borînpeyva xwe ji bîr kir? + invalid_reset_password_token: Ji nû ve sazkirina borînpeyvê nederbasdar e an jî qediya ye. Jkx daxwaza yeka nû bike. link_to_otp: Ji têlefona xwe an jî ji kodeke rizgarkirinê kodeke du-gavî binivîsine link_to_webauth: Amûra kilîta ewlehiya xwe bi kar bîne log_in_with: Têkeve bi riya @@ -947,9 +949,9 @@ ku: register: Tomar bibe registration_closed: "%{instance} endamên nû napejirîne" resend_confirmation: Rêwerên pejirandinê ji nû ve bişîne - reset_password: Pêborînê ji nû ve saz bike + reset_password: Borînpeyvê ji nû ve saz bike security: Ewlehî - set_new_password: Pêborîneke nû ji nû ve saz bike + set_new_password: Borînpeyveke nû ji nû ve saz bike setup: email_below_hint_html: Heke navnîşana e-nameya jêrîn ne rast be, tu dikarî wê li vir biguherîne û e-nameyeke pejirandinê ya nû bistîne. email_settings_hint_html: E-nameya pejirandinê ji %{email} re hate şandin. Heke ew navnîşana e-nameyê ne rast be, tu dikarî wê di sazkariyên ajimêr de biguherîne. @@ -963,7 +965,7 @@ ku: view_strikes: Binpêkirinên berê yên dijî ajimêrê xwe bibîne too_fast: Form pir zû hat şandin, dîsa biceribîne. trouble_logging_in: Têketina te de pirsgirêk çêdibe? - use_security_key: Kilîteke ewlehiyê bikar bîne + use_security_key: Kilîteke ewlehiyê bi kar bîne authorize_follow: already_following: Jixwe tu vê ajimêrê dişopînî already_requested: Jixwe te ji vê ajimêrê re daxwazîya şopandinê şandi bû @@ -975,12 +977,12 @@ ku: close: An jî, tu dikarî tenê ev çarçoveyê bigirî. return: Profîla vê bikarhênerê nîşan bike web: Biçe tevneyê - title: Bişopîne %{acct} + title: "%{acct} bişopîne" challenge: confirm: Bidomîne - hint_html: "<strong>Nîşe:</strong>Ji bo demjimêreke din em ê pêborîna te careke din ji te nexwazin." - invalid_password: Pêborîna nederbasdar - prompt: Ji bo bidomî lêborînê bipejirîne + hint_html: "<strong>Nîşe:</strong>Ji bo demjimêreke din em ê borînpeyva te careke din ji te nexwazin." + invalid_password: Borînpeyva nederbasdar + prompt: Ji bo bidomî borînpeyvê bipejirîne crypto: errors: invalid_key: ed25519 ne derbasdare ne jî Curve25519 kilîta @@ -1005,7 +1007,7 @@ ku: x_seconds: "%{count}çirke" deletes: challenge_not_passed: Zanyariyên ku te nivîsandî ne rast in - confirm_password: Pêborîna xwe ya heyî binivîsine da ku nasnameya xwe piştrast bikî + confirm_password: Borînpeyva xwe ya heyî binivîsine da ku nasnameya xwe piştrast bikî confirm_username: Navê bikarhêneriyê xwe binivîse da ku prosedurê piştrast bike proceed: Ajimêr jê bibe success_msg: Ajimêra te bi serkeftî hate jêbirin @@ -1175,10 +1177,10 @@ ku: login_activities: authentication_methods: otp: sepandina rastandina du-gavî - password: pêborîn + password: borînpeyv sign_in_token: koda ewlehiyê bo e-nameyê webauthn: kilîtên ewlehiyê - description_html: Heke çalakiya ku nas nakî dibînî, çêtir dibe ku pêborîna xwe biguherînî û rastandina du-gavî çalak bikî. + description_html: Heke çalakiya ku nas nakî dibînî, çêtir dibe ku borînpeyva xwe biguherînî û rastandina du-gavî çalak bikî. empty: Dîroka piştrastkirinê tune ye failed_sign_in_html: Hewldana têketinê ser neket bi%{method} ji %{ip} (%{browser}) de successful_sign_in_html: Bi serkeftî têketin bi %{method} ji %{ip}(%{browser}) çêbû @@ -1247,7 +1249,7 @@ ku: follow: body: "%{name} niha te dişopîne!" subject: "%{name} niha te dişopîne" - title: Şopînereke nû + title: Şopînera nû follow_request: action: Daxwazên şopandinê bi rê ve bibe body: "%{name} daxwaza şopandina te kir" @@ -1416,7 +1418,7 @@ ku: notifications: Agahdarî preferences: Hilbijarte profile: Profîl - relationships: Yên tê şopandin û şopîner + relationships: Şopandin û şopîner statuses_cleanup: Bi xweberî ve jêbirina şandiya strikes: Binpêkirinên çavdêriyê two_factor_authentication: Piştrastkirinê du-faktorî @@ -1596,7 +1598,7 @@ ku: <p>Originally adapted from the <a href="https://github.com/discourse/discourse">Discourse privacy policy</a>.</p> title: "%{instance} mercên bikaranîn û politîkayên nehêniyê" themes: - contrast: Mastodon (dijberiya bilind) + contrast: Mastodon (Dijberiya bilind) default: Mastodon (Tarî) mastodon-light: Mastodon (Ronahî) time: @@ -1635,8 +1637,8 @@ ku: title: Pakêtkirina arşîvan sign_in_token: details: 'Li vir hûrgiliyên hewldanê hene:' - explanation: 'Me hewildanek têketina ajimêra te ji navnîşana IPya nenas nas kir. Ger ev tu bî, ji kerema xwe koda ewlehiyê ya jêr têkeve rûpela jêpirsînê:' - further_actions: 'Ger ev ne tu bî, ji kerema xwe re şîfreya xwe biguherîne û li ser hesaba xwe rastkirina du-gavî çalak bike. Tu dikarî wê ji vê derê çêkî:' + explanation: 'Me hewildanek têketina ajimêra te ji navnîşana IP ya nenas destnîşan kir. Ger ev tu bî, ji kerema xwe koda ewlehiyê ya jêr binivîsîne di rûpela jêpirsînê de:' + further_actions: 'Ku ev ne tu bî, ji kerema xwe re borînpeyva xwe biguherîne û li ser ajimêra xwe rastkirina du-gavî çalak bike. Tu dikarî wê ji vê derê çê bikî:' subject: Ji kerema xwe re hewldanên têketinê piştrast bike title: Hewldanên têketinê warning: @@ -1693,7 +1695,7 @@ ku: invalid_otp_token: Koda du-gavî ya nelê invalid_sign_in_token: Kilîda ewlehiyê a nelê otp_lost_help_html: Heke te gihîştina herduyan ji dest da, dibe ku tu bi %{email} re têkilî deyne - seamless_external_login: Te bi servîsekî biyanî re têketina xwe kir, ji ber vê yekê şîfre û e-name nayê bikaranîn. + seamless_external_login: Te bi rajekarke biyanî re têketina xwe kir, ji ber vê yekê borînpeyv û e-name nayê bikaranîn. signed_in_as: 'Têketin wekî:' suspicious_sign_in_confirmation: Xuya dike ku te berê têketin ji vê amûrê nekiriye, ji ber vê yekê em kodeke ewlehiyê ji navnîşana e-nameya te re dişînin da ku piştrast bikî ku tu ye an na. verification: diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 8f6df9961..d695c5191 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -169,10 +169,6 @@ lv: pending: Gaida pārskatīšanu perform_full_suspension: Apturēt previous_strikes: Iepriekšējie brīdinājumi - previous_strikes_description_html: - one: Šim kontam ir <strong>viens</strong> brīdinājums. - other: Šim kontam ir <strong>%{count}</strong> brīdinājumi. - zero: Š konta <strong>stāvoklis ir labs</strong>. promote: Veicināt protocol: Protokols public: Publisks @@ -501,6 +497,7 @@ lv: zero: Neizdevušies mēģinājumi %{count} dienās. no_failures_recorded: Nav reģistrētu kļūdu. title: Pieejamība + warning: Pēdējais mēģinājums izveidot savienojumu ar šo serveri ir bijis neveiksmīgs back_to_all: Visas back_to_limited: Ierobežotās back_to_warning: Brīdinājums @@ -537,10 +534,6 @@ lv: delivery_error_hint: Ja piegāde nav iespējama %{count} dienas, tā tiks automātiski atzīmēta kā nepiegādājama. destroyed_msg: Dati no %{domain} tagad ir gaidīšanas rindā, lai tos drīzumā dzēstu. empty: Domēni nav atrasti. - known_accounts: - one: "%{count} zināms konts" - other: "%{count} zināmi konti" - zero: Nav zināmu kontu moderation: all: Visas limited: Ierobežotās @@ -786,6 +779,11 @@ lv: system_checks: database_schema_check: message_html: Notiek datubāzu migrācijas. Lūdzu, palaid tās, lai nodrošinātu, ka lietojumprogramma darbojas, kā paredzēts + elasticsearch_running_check: + message_html: Nevarēja izveidot savienojumu ar Elasticsearch. Lūdzu, pārbaudi, vai tā darbojas, vai atspējo pilna teksta meklēšanu + elasticsearch_version_check: + message_html: 'Nesaderīga Elasticsearch versija: %{value}' + version_comparison: Darbojas Elasticsearch %{running_version}, tomēr ir nepieciešama %{required_version} rules_check: action: Pārvaldīt servera nosacījumus message_html: Tu neesi definējis nevienu servera nosacījumu. @@ -805,10 +803,6 @@ lv: description_html: Šīs ir saites, kuras pašlaik bieži koplieto konti, no kuriem tavs serveris redz ziņas. Tas var palīdzēt taviem lietotājiem uzzināt, kas notiek pasaulē. Kamēr tu neapstiprini izdevēju, neviena saite netiek rādīta publiski. Vari arī atļaut vai noraidīt atsevišķas saites. disallow: Neatļaut saiti disallow_provider: Neatļaut publicētāju - shared_by_over_week: - one: Pēdējās nedēļas laikā kopīgoja viena persona - other: Pēdējās nedēļas laikā kopīgoja %{count} personas - zero: Pēdējās nedēļas laikā neviens nav kopīgojis title: Populārākās saites usage_comparison: Šodien kopīgots %{today} reizes, salīdzinot ar %{yesterday} vakar pending_review: Gaida pārskatīšanu @@ -849,10 +843,6 @@ lv: trending_rank: 'Populārākie #%{rank}' usable: Var tikt lietots usage_comparison: Šodien lietots %{today} reizes, salīdzinot ar %{yesterday} vakar - used_by_over_week: - one: Pēdējās nedēļas laikā izmantoja viens cilvēks - other: Pēdējās nedēļas laikā izmantoja %{count} personas - zero: Pēdējās nedēļas laikā neviens nav izmantojis title: Tendences warning_presets: add_new: Pievienot jaunu diff --git a/config/locales/nl.yml b/config/locales/nl.yml index a51ef07af..276fdb9b2 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1,7 +1,7 @@ --- nl: about: - about_hashtag_html: Dit zijn openbare toots die getagged zijn met <strong>#%{hashtag}</strong>. Je kunt er op reageren of iets anders mee doen als je op Mastodon (of ergens anders in de fediverse) een account hebt. + about_hashtag_html: Dit zijn openbare berichten die getagged zijn met <strong>#%{hashtag}</strong>. Je kunt er op reageren of iets anders mee doen als je op Mastodon (of ergens anders in de fediverse) een account hebt. about_mastodon_html: Mastodon is een sociaal netwerk dat gebruikt maakt van open webprotocollen en vrije software. Het is net zoals e-mail gedecentraliseerd. about_this: Over deze server active_count_after: actief @@ -31,7 +31,7 @@ nl: source_code: Broncode status_count_after: one: toot - other: toots + other: berichten status_count_before: Zij schreven tagline: Vrienden volgen en nieuwe ontdekken terms: Gebruiksvoorwaarden @@ -41,7 +41,7 @@ nl: reason: 'Reden:' rejecting_media: 'Mediabestanden van deze server worden niet verwerkt en er worden geen thumbnails getoond. Je moet handmatig naar deze server doorklikken om de mediabestanden te kunnen bekijken:' rejecting_media_title: Mediabestanden geweigerd - silenced: Toots van deze server worden nergens weergegeven, behalve op jouw eigen starttijdlijn wanneer je het account volgt. + silenced: Berichten van deze server worden nergens weergegeven, behalve op jouw eigen starttijdlijn wanneer je het account volgt. silenced_title: Beperkte servers suspended: Je bent niet in staat om iemand van deze server te volgen, en er worden geen gegevens van deze server verwerkt of opgeslagen, en met deze server uitgewisseld. suspended_title: Opgeschorte servers @@ -74,9 +74,9 @@ nl: following: Je moet dit account wel al volgen, alvorens je het kan aanbevelen posts: one: Toot - other: Toots - posts_tab_heading: Toots - posts_with_replies: Toots en reacties + other: Berichten + posts_tab_heading: Berichten + posts_with_replies: Berichten en reacties roles: admin: Beheerder bot: Bot @@ -193,7 +193,7 @@ nl: targeted_reports: Door anderen gerapporteerd silence: Beperken silenced: Beperkt - statuses: Toots + statuses: Berichten subscribe: Abonneren suspended: Opgeschort suspension_irreversible: De gegevens van dit account zijn onomkeerbaar verwijderd. Je kunt het opschorten van dit account ongedaan maken zodat het weer valt te gebruiken, maar de verwijderde gegevens worden hiermee niet hersteld. @@ -229,7 +229,7 @@ nl: destroy_custom_emoji: Lokale emoji verwijderen destroy_domain_allow: Domeingoedkeuring verwijderen destroy_domain_block: Domeinblokkade verwijderen - destroy_email_domain_block: E-maildomeinblokkade verwijderen + destroy_email_domain_block: Blokkade van e-maildomein verwijderen destroy_ip_block: IP-regel verwijderen destroy_status: Toot verwijderen destroy_unavailable_domain: Niet beschikbaar domein verwijderen @@ -245,16 +245,16 @@ nl: reset_password_user: Wachtwoord opnieuw instellen resolve_report: Rapportage oplossen sensitive_account: De media in jouw account als gevoelig markeren - silence_account: Account negeren + silence_account: Account beperken suspend_account: Account opschorten unassigned_report: Rapportage niet langer toewijzen unsensitive_account: De media in jouw account niet langer als gevoelig markeren - unsilence_account: Account niet langer negeren + unsilence_account: Account niet langer beperken unsuspend_account: Account niet langer opschorten update_announcement: Mededeling bijwerken update_custom_emoji: Lokale emoji bijwerken update_domain_block: Domeinblokkade bijwerken - update_status: Toot bijwerken + update_status: Bericht bijwerken actions: assigned_to_self_report_html: "%{name} heeft rapportage %{target} aan zichzelf toegewezen" change_email_user_html: "%{name} veranderde het e-mailadres van gebruiker %{target}" @@ -274,7 +274,7 @@ nl: destroy_domain_block_html: Domein %{target} is door %{name} gedeblokkeerd destroy_email_domain_block_html: "%{name} heeft het e-maildomein %{target} gedeblokkeerd" destroy_ip_block_html: "%{name} verwijderde regel voor IP %{target}" - destroy_status_html: Toot van %{target} is door %{name} verwijderd + destroy_status_html: Bericht van %{target} is door %{name} verwijderd destroy_unavailable_domain_html: "%{name} heeft de bezorging voor domein %{target} hervat" disable_2fa_user_html: De vereiste tweestapsverificatie voor %{target} is door %{name} uitgeschakeld disable_custom_emoji_html: Emoji %{target} is door %{name} uitgeschakeld @@ -297,8 +297,8 @@ nl: update_announcement_html: "%{name} heeft de mededeling %{target} bijgewerkt" update_custom_emoji_html: Emoji %{target} is door %{name} bijgewerkt update_domain_block_html: "%{name} heeft de domeinblokkade bijgewerkt voor %{target}" - update_status_html: "%{name} heeft de toots van %{target} bijgewerkt" - deleted_status: "(verwijderde toot}" + update_status_html: "%{name} heeft de berichten van %{target} bijgewerkt" + deleted_status: "(verwijderd bericht}" empty: Geen logs gevonden. filter_by_action: Op actie filteren filter_by_user: Op gebruiker filteren @@ -461,11 +461,11 @@ nl: relays: add_new: Nieuwe relayserver toevoegen delete: Verwijderen - description_html: Een <strong>federatierelay</strong> is een tussenliggende server die grote hoeveelheden openbare toots uitwisselt tussen servers die zich hierop hebben geabonneerd. <strong>Het kan kleine en middelgrote servers helpen om content uit de fediverse te ontdekken</strong>, waarvoor anders lokale gebruikers handmatig mensen van externe servers moeten volgen. + description_html: Een <strong>federatierelay</strong> is een tussenliggende server die grote hoeveelheden openbare berichten uitwisselt tussen servers die zich hierop hebben geabonneerd. <strong>Het kan kleine en middelgrote servers helpen om content van de fediverse te ontdekken</strong>, waarvoor anders lokale gebruikers handmatig mensen van externe servers moeten volgen. disable: Uitschakelen disabled: Uitgeschakeld enable: Inschakelen - enable_hint: Eenmaal ingeschakeld gaat jouw server zich op alle openbare toots van deze relayserver abonneren en stuurt het de openbare toots van jouw server naar de relayserver. + enable_hint: Eenmaal ingeschakeld gaat jouw server zich op alle openbare berichten van deze relayserver abonneren en stuurt het de openbare berichten van jouw server naar de relayserver. enabled: Ingeschakeld inbox_url: Relay-URL pending: Aan het wachten op toestemming van de relayserver @@ -506,7 +506,7 @@ nl: reported_by: Gerapporteerd door resolved: Opgelost resolved_msg: Rapportage succesvol opgelost! - status: Toot + status: Bericht title: Rapportages unassign: Niet langer toewijzen unresolved: Onopgelost @@ -520,7 +520,7 @@ nl: title: Serverregels settings: activity_api_enabled: - desc_html: Wekelijks overzicht van de hoeveelheid lokale toots, actieve gebruikers en nieuwe registraties + desc_html: Wekelijks overzicht van de hoeveelheid lokale berichten, actieve gebruikers en nieuwe registraties title: Statistieken over gebruikersactiviteit via de API publiceren bootstrap_timeline_accounts: desc_html: Meerdere gebruikersnamen met komma's scheiden. Deze accounts worden in ieder geval aan nieuwe gebruikers aanbevolen @@ -533,7 +533,7 @@ nl: title: Aangepaste CSS default_noindex: desc_html: Heeft invloed op alle gebruikers die deze instelling niet zelf hebben veranderd - title: Toots van gebruikers standaard niet door zoekmachines laten indexeren + title: Berichten van gebruikers standaard niet door zoekmachines laten indexeren domain_blocks: all: Aan iedereen disabled: Aan niemand @@ -561,7 +561,7 @@ nl: desc_html: Wordt op de voorpagina weergegeven wanneer registratie van nieuwe accounts is uitgeschakeld<br>En ook hier kan je HTML gebruiken title: Bericht wanneer registratie is uitgeschakeld deletion: - desc_html: Toestaan dat iedereen hun eigen account kan verwijderen + desc_html: Toestaan dat iedereen diens eigen account kan verwijderen title: Verwijderen account toestaan min_invite_role: disabled: Niemand @@ -606,7 +606,7 @@ nl: title: Hashtags toestaan om trending te worden zonder voorafgaande beoordeling trends: desc_html: Eerder beoordeelde hashtags die op dit moment trending zijn openbaar tonen - title: Trending hashtags + title: Trends site_uploads: delete: Geüpload bestand verwijderen destroyed_msg: Verwijderen website-upload geslaagd! @@ -615,8 +615,8 @@ nl: deleted: Verwijderd media: title: Media - no_status_selected: Er werden geen toots gewijzigd, omdat er geen enkele werd geselecteerd - title: Toots van account + no_status_selected: Er werden geen berichten gewijzigd, omdat er geen enkele werd geselecteerd + title: Berichten van account with_media: Met media system_checks: database_schema_check: @@ -662,14 +662,14 @@ nl: guide_link: https://crowdin.com/project/mastodon/nl guide_link_text: Iedereen kan bijdragen. sensitive_content: Gevoelige inhoud - toot_layout: Lay-out van toots + toot_layout: Lay-out van berichten application_mailer: notification_preferences: E-mailvoorkeuren wijzigen salutation: "%{name}," settings: 'E-mailvoorkeuren wijzigen: %{link}' view: 'Bekijk:' view_profile: Profiel bekijken - view_status: Toot bekijken + view_status: Bericht bekijken applications: created: Aanmaken toepassing geslaagd destroyed: Verwijderen toepassing geslaagd @@ -768,8 +768,8 @@ nl: success_msg: Jouw account is succesvol verwijderd warning: before: 'Lees deze tekst zorgvuldig voordat je verder gaat:' - caches: Toots en media die op andere servers zijn opgeslagen kunnen daar achterblijven - data_removal: Jouw toots en andere gegevens worden permanent verwijderd + caches: Berichten en media die op andere servers zijn opgeslagen kunnen daar achterblijven + data_removal: Jouw berichten en andere gegevens worden permanent verwijderd email_change_html: Je kunt <a href="%{path}">je e-mailadres wijzigen</a> zonder dat je jouw account hoeft te verwijderen email_contact_html: Wanneer het nog steeds niet aankomt, kun je voor hulp e-mailen naar <a href="mailto:%{email}">%{email}</a> email_reconfirmation_html: Wanneer je de bevestigingsmail niet hebt ontvangen, kun je deze <a href="%{path}">opnieuw aanvragen</a> @@ -805,7 +805,7 @@ nl: archive_takeout: date: Datum download: Jouw archief downloaden - hint_html: Je kunt een archief opvragen van jouw <strong>toots en geüploade media</strong>. De geëxporteerde gegevens zijn in het ActivityPub-formaat, dat door hiervoor geschikte software valt uit te lezen. Je kunt elke 7 dagen een kopie van je archief aanvragen. + hint_html: Je kunt een archief opvragen van jouw <strong>berichten en geüploade media</strong>. De geëxporteerde gegevens zijn in het ActivityPub-formaat, dat door hiervoor geschikte software valt uit te lezen. Je kunt elke 7 dagen een kopie van je archief aanvragen. in_progress: Jouw archief wordt samengesteld... request: Jouw archief opvragen size: Omvang @@ -820,7 +820,7 @@ nl: add_new: Nieuwe toevoegen errors: limit: Je hebt al het maximaal aantal hashtags uitgelicht - hint_html: "<strong>Wat zijn uitgelichte hashtags?</strong> Deze worden prominent op jouw openbare profiel getoond en stelt mensen in staat om jouw openbare toots per hashtag te bekijken. Het zijn een goed hulpmiddel om creatieve werkzaamheden of langetermijnprojecten bij te houden." + hint_html: "<strong>Wat zijn uitgelichte hashtags?</strong> Deze worden prominent op jouw openbare profiel getoond en stelt mensen in staat om jouw openbare berichten per hashtag te bekijken. Het zijn een goed hulpmiddel om creatieve werkzaamheden of langetermijnprojecten bij te houden." filters: contexts: account: Profielen @@ -901,7 +901,7 @@ nl: limit: Je hebt het maximaal aantal lijsten bereikt media_attachments: validations: - images_and_video: Een video kan niet aan een toot met afbeeldingen worden gekoppeld + images_and_video: Een video kan niet aan een bericht met afbeeldingen worden gekoppeld not_ready: Kan geen bestanden toevoegen die nog niet zijn verwerkt. Probeer het later opnieuw! too_many: Er kunnen niet meer dan 4 afbeeldingen toegevoegd worden migrations: @@ -954,8 +954,8 @@ nl: other: "%{count} nieuwe meldingen sinds jouw laatste bezoek \U0001F418" title: Tijdens jouw afwezigheid... favourite: - body: 'Jouw toot werd door %{name} aan hun favorieten toegevoegd:' - subject: "%{name} voegde jouw toot als favoriet toe" + body: 'Jouw bericht werd door %{name} aan diens favorieten toegevoegd:' + subject: "%{name} voegde jouw bericht als favoriet toe" title: Nieuwe favoriet follow: body: "%{name} volgt jou nu!" @@ -974,11 +974,11 @@ nl: poll: subject: Een poll van %{name} is beëindigd reblog: - body: 'Jouw toot werd door %{name} geboost:' - subject: "%{name} boostte jouw toot" + body: 'Jouw bericht werd door %{name} geboost:' + subject: "%{name} boostte jouw bericht" title: Nieuwe boost status: - subject: "%{name} heeft zojuist een toot geplaatst" + subject: "%{name} heeft zojuist een bericht geplaatst" notifications: email_events: E-mailmeldingen voor gebeurtenissen email_events_hint: 'Selecteer gebeurtenissen waarvoor je meldingen wilt ontvangen:' @@ -997,7 +997,7 @@ nl: code_hint: Voer de code in die door de authenticatie-app werd gegenereerd description_html: Na het instellen van <strong>tweestapsverificatie</strong> met een authenticatie-app, kun je alleen inloggen als je jouw mobiele telefoon bij je hebt. Hiermee genereer je namelijk de in te voeren toegangscode. enable: Inschakelen - instructions_html: "<strong>Scan deze QR-code in Google Authenticator of een soortgelijke app op jouw mobiele telefoon</strong>. Van nu af aan genereert deze app toegangscodes die je bij het inloggen moet invoeren." + instructions_html: "<strong>Scan deze QR-code in Google Authenticator of een soortgelijke app op jouw mobiele telefoon</strong>. Vanaf nu genereert deze app toegangscodes die je bij het inloggen moet invoeren." manual_instructions: 'Voor het geval je de QR-code niet kunt scannen en het handmatig moet invoeren, vind je hieronder de geheime code in platte tekst:' setup: Instellen wrong_code: De ingevoerde code is ongeldig! Klopt de systeemtijd van de server en die van jouw apparaat? @@ -1053,17 +1053,17 @@ nl: remote_interaction: favourite: proceed: Doorgaan met toevoegen aan jouw favorieten - prompt: 'Je wilt de volgende toot aan jouw favorieten toevoegen:' + prompt: 'Je wilt het volgende bericht aan jouw favorieten toevoegen:' reblog: proceed: Doorgaan met boosten - prompt: 'Je wilt de volgende toot boosten:' + prompt: 'Je wilt het volgende bericht boosten:' reply: proceed: Doorgaan met reageren - prompt: 'Je wilt op de volgende toot reageren:' + prompt: 'Je wilt op het volgende bericht reageren:' scheduled_statuses: - over_daily_limit: Je hebt de limiet van %{limit} in te plannen toots voor die dag overschreden - over_total_limit: Je hebt de limiet van %{limit} in te plannen toots overschreden - too_soon: De datum voor de ingeplande toot moet in de toekomst liggen + over_daily_limit: Je hebt de limiet van %{limit} in te plannen berichten voor vandaag overschreden + over_total_limit: Je hebt de limiet van %{limit} in te plannen berichten overschreden + too_soon: De datum voor het ingeplande bericht moet in de toekomst liggen sessions: activity: Laatst actief browser: Webbrowser @@ -1093,7 +1093,7 @@ nl: adobe_air: Adobe Air android: Android blackberry: Blackberry - chrome_os: ChromeOS + chrome_os: Chrome OS firefox_os: Firefox OS ios: iOS linux: Linux @@ -1144,12 +1144,12 @@ nl: one: 'bevatte een niet toegestane hashtag: %{tags}' other: 'bevatte niet toegestane hashtags: %{tags}' errors: - in_reply_not_found: De toot waarop je probeert te reageren lijkt niet te bestaan. + in_reply_not_found: Het bericht waarop je probeert te reageren lijkt niet te bestaan. open_in_web: In de webapp openen over_character_limit: Limiet van %{max} tekens overschreden pin_errors: - limit: Je hebt het maximaal aantal toots al vastgezet - ownership: Een toot van iemand anders kan niet worden vastgezet + limit: Je hebt het maximaal aantal bericht al vastgemaakt + ownership: Een bericht van iemand anders kan niet worden vastgemaakt reblog: Een boost kan niet worden vastgezet poll: total_people: @@ -1174,7 +1174,7 @@ nl: unlisted: Minder openbaar unlisted_long: Aan iedereen tonen, maar niet op openbare tijdlijnen stream_entries: - pinned: Vastgemaakte toot + pinned: Vastgemaakt bericht reblogged: boostte sensitive_content: Gevoelige inhoud tags: @@ -1332,7 +1332,7 @@ nl: otp_lost_help_html: Als je toegang tot beiden kwijt bent geraakt, neem dan contact op via %{email} seamless_external_login: Je bent ingelogd via een externe dienst, daarom zijn wachtwoorden en e-mailinstellingen niet beschikbaar. signed_in_as: 'Ingelogd als:' - suspicious_sign_in_confirmation: Het lijkt er op dat je nog niet eerder op dit apparaat bent ingelogd, en je bent een tijdje niet ingelogd, dus sturen we een beveiligingscode naar je e-mailadres om te bevestigen dat jij het bent. + suspicious_sign_in_confirmation: Het lijkt er op dat je nog niet eerder op dit apparaat bent ingelogd, dus sturen we een beveiligingscode naar jouw e-mailadres om te bevestigen dat jij het bent. verification: explanation_html: 'Je kunt <strong>jezelf verifiëren als de eigenaar van de links in de metadata van jouw profiel</strong>. Hiervoor moet op de gelinkte website een link terug naar jouw Mastodonprofiel staan. Deze link <strong>moet</strong> het <code>rel="me"</code>-attribuut bevatten. De omschrijving van de link maakt niet uit. Hier is een voorbeeld:' verification: Verificatie diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 9a093f9d3..15755bde7 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -170,10 +170,6 @@ pl: pending: Oczekuje na przegląd perform_full_suspension: Zawieś previous_strikes: Poprzednie ostrzeżenia - previous_strikes_description_html: - one: To konto ma <strong>jedno</strong> ostrzeżenie. - other: To konto ma <strong>%{count}</strong> ostrzeżeń. - zero: To konto jest <strong>w dobrym stanie</strong>. promote: Podnieś uprawnienia protocol: Protokół public: Publiczne @@ -748,6 +744,11 @@ pl: system_checks: database_schema_check: message_html: Istnieją oczekujące migracje bazy danych. Uruchom je, aby upewnić się, że aplikacja działa tak, jak powinna + elasticsearch_running_check: + message_html: Nie można połączyć się z Elasticsearch. Sprawdź czy jest uruchomiony lub wyłącz wyszukiwanie pełnotekstowe + elasticsearch_version_check: + message_html: 'Niekompatybilna wersja Elasticsearch: %{value}' + version_comparison: Elasticsearch w wersji %{running_version} jest uruchomiony, ale wymagana wersja to %{required_version} rules_check: action: Zarządzaj regułami serwera message_html: Nie zdefiniowano żadnych reguł serwera. diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 912e42a7d..1d0de0d4a 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -1471,6 +1471,7 @@ pt-BR: title: delete_statuses: Publicações removidas disable: Conta bloqueada + mark_statuses_as_sensitive: Postagens marcadas como sensíveis none: Aviso silence: Conta silenciada suspend: Conta banida diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index 0fdfff517..05f6ebf07 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -165,10 +165,6 @@ pt-PT: pending: Pendente de revisão perform_full_suspension: Fazer suspensão completa previous_strikes: Punições anteriores - previous_strikes_description_html: - one: Esta conta tem <strong>1</strong> punição. - other: Esta conta tem <strong>%{count}</strong> punições. - zero: Esta conta está <strong>em situação regular</strong>. promote: Promover protocol: Protocolo public: Público @@ -490,6 +486,7 @@ pt-PT: other: Tentativas em %{count} dias diferentes. no_failures_recorded: Sem falhas registadas. title: Disponibilidade + warning: A última tentativa de conectar a este servidor não foi bem sucedida back_to_all: Todas back_to_limited: Limitadas back_to_warning: Aviso @@ -526,10 +523,6 @@ pt-PT: delivery_error_hint: Se a entrega não for possível durante %{count} dias, será automaticamente marcada como não realizável. destroyed_msg: Dados de %{domain} estão agora na fila para iminente eliminação. empty: Não foram encontrados domínios. - known_accounts: - one: "%{count} conta conhecida" - other: "%{count} contas conhecidas" - zero: Nenhuma conta conhecida moderation: all: Todas limited: Limitadas @@ -774,6 +767,11 @@ pt-PT: system_checks: database_schema_check: message_html: Existem migrações de base de dados pendentes. Por favor, execute-as para garantir que o aplicativo se comporte como esperado + elasticsearch_running_check: + message_html: Não foi possível conectar ao Elasticsearch. Por favor, verifique se está em execução, ou desabilite a pesquisa de texto completo + elasticsearch_version_check: + message_html: 'Versão de Elasticsearch incompatível: %{value}' + version_comparison: A versão de Elasticsearch %{running_version} está em execução. No entanto, é obrigatória a versão %{required_version} rules_check: action: Gerir regras da instância message_html: Não definiu nenhuma regra para a instância. @@ -793,10 +791,6 @@ pt-PT: description_html: Estes são links que atualmente estão a ser frequentemente partilhados por contas visiveis pelo seu servidor. Eles podem ajudar os seus utilizador a descobrir o que está a acontecer no mundo. Nenhum link é exibido publicamente até que aprove o editor. Também pode permitir ou rejeitar links individualmente. disallow: Não permitir link disallow_provider: Não permitir editor - shared_by_over_week: - one: Partilhado por uma pessoa na última semana - other: Partilhado por %{count} pessoas na última semana - zero: Partilhado por ninguém na última semana title: Links em destaque usage_comparison: Partilhado %{today} vezes hoje, em comparação com %{yesterday} ontem pending_review: Pendente de revisão @@ -836,10 +830,6 @@ pt-PT: trending_rank: 'Tendência #%{rank}' usable: Pode ser utilizada usage_comparison: Utilizada %{today} vezes hoje, em comparação com %{yesterday} ontem - used_by_over_week: - one: Utilizada por uma pessoa na última semana - other: Utilizada por %{count} pessoas na última semana - zero: Utilizada por ninguém na última semana title: Tendências warning_presets: add_new: Adicionar novo diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 579ea6462..d6eab2a99 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -174,9 +174,10 @@ ru: perform_full_suspension: Блокировка previous_strikes: Предыдущие замечания previous_strikes_description_html: - one: У этой учетной записи <strong>одно</strong> замечание. - other: У этой учетной записи <strong>%{count}</strong> замечания. - zero: У этой учетной записи <strong>хорошая репутация</strong>. + few: У этой учётной записи <strong>%{count}</strong> замечания. + many: У этой учётной записи <strong>%{count}</strong> замечаний. + one: У этой учётной записи <strong>одно</strong> замечание. + other: У этой учетной записи <strong>%{count}</strong> замечание. promote: Повысить protocol: Протокол public: Публичный @@ -480,6 +481,7 @@ ru: availability: no_failures_recorded: Сбоев в записи нет. title: Доступность + warning: Последняя попытка подключения к этому серверу не удалась back_to_all: Все узлы back_to_limited: Все ограниченные узлы back_to_warning: Все узлы требующие внимания @@ -504,9 +506,10 @@ ru: destroyed_msg: Данные для домена %{domain} поставлены в очередь на удаление. empty: Домены не найдены. known_accounts: + few: "%{count} известные учётные записи" + many: "%{count} известных учётных записей" one: "%{count} известная учётная запись" - other: "%{count} известных учётных записей" - zero: Нет известных учётных записей + other: "%{count} известная учётная запись" moderation: all: Все limited: Ограниченные @@ -742,10 +745,16 @@ ru: none: "%{name} отправил(а) предупреждение %{target}" sensitive: "%{name} отметил(а) учетную запись %{target} как деликатную" silence: "%{name} ограничил(а) учетную запись %{target}" + appeal_approved: Обжаловано appeal_pending: Обжалование в обработке system_checks: database_schema_check: message_html: Есть отложенные миграции базы данных. Запустите их, чтобы убедиться, что приложение работает должным образом + elasticsearch_running_check: + message_html: Не удалось подключиться к Elasticsearch. Пожалуйста, проверьте, что он запущен, или отключите полнотекстовый поиск + elasticsearch_version_check: + message_html: 'Несовместимая версия Elasticsearch: %{value}' + version_comparison: Запущен Elasticsearch %{running_version}, а необходим %{required_version} rules_check: action: Управление правилами сервера message_html: Вы не определили правила сервера. @@ -765,9 +774,10 @@ ru: disallow: Запретить ссылку disallow_provider: Отклонить издание shared_by_over_week: + few: Поделилось %{count} человека за последнюю неделю + many: Поделилось %{count} человек за последнюю неделю one: Поделился один человек за последнюю неделю - other: Поделилось %{count} людей за последнюю неделю - zero: Никто не поделился за последнюю неделю + other: Поделился %{count} человек за последнюю неделю title: Актуальные ссылки usage_comparison: Поделились %{today} раз сегодня, по сравнению с %{yesterday} вчера pending_review: Ожидает рассмотрения @@ -795,9 +805,10 @@ ru: usable: Может использоваться usage_comparison: Использовано %{today} сегодня, для сравнения вчера %{yesterday} used_by_over_week: - one: За последнюю неделю использовано одним человеком - other: За последнюю неделю использовано %{count} людьми - zero: За последнюю неделю никто не использовал + few: За последнюю неделю использовало %{count} человека + many: За последнюю неделю использовало %{count} человек + one: За последнюю неделю использовал один человек + other: За последнюю неделю использовал %{count} человек title: Популярное warning_presets: add_new: Добавить @@ -806,6 +817,8 @@ ru: empty: Вы еще не определили пресеты предупреждений. title: Управление шаблонами предупреждений admin_mailer: + new_appeal: + subject: "%{username} обжалует решение модерации на %{instance}" new_pending_account: body: Ниже указана информация учётной записи. Вы можете одобрить или отклонить заявку. subject: Новая учётная запись для рассмотрения на %{instance} (%{username}) diff --git a/config/locales/simple_form.cs.yml b/config/locales/simple_form.cs.yml index c8cc9985d..767558b6f 100644 --- a/config/locales/simple_form.cs.yml +++ b/config/locales/simple_form.cs.yml @@ -35,6 +35,7 @@ cs: current_password: Z bezpečnostních důvodů prosím zadejte heslo současného účtu current_username: Potvrďte prosím tuto akci zadáním uživatelského jména aktuálního účtu digest: Odesíláno pouze po dlouhé době nečinnosti a pouze, pokud jste při své nepřítomnosti obdrželi osobní zprávy + discoverable: Umožnit, aby mohli váš účet objevit neznámí lidé pomocí doporučení, trendů a dalších funkcí email: Bude vám poslán potvrzovací e-mail fields: Na profilu můžete mít až 4 položky zobrazené jako tabulka header: PNG, GIF či JPG. Maximálně %{size}. Bude zmenšen na %{dimensions} px diff --git a/config/locales/simple_form.fa.yml b/config/locales/simple_form.fa.yml index c44a789d9..e6af4cee7 100644 --- a/config/locales/simple_form.fa.yml +++ b/config/locales/simple_form.fa.yml @@ -7,12 +7,12 @@ fa: account_migration: acct: نشانی username@domain را برای حسابی که میخواهید به آن منتقل شوید بنویسید account_warning_preset: - text: میتوانید مانند بوقهای معمولی کاربران دیگر را نام ببرید یا پیوند و برچسب بگذارید + text: میتوانید مانند فرستههای معمولی کاربران دیگر را نام ببرید یا پیوند و برچسب بگذارید title: اختیاری. برای گیرنده قابل مشاهده نیست admin_account_action: - include_statuses: این کاربر خواهد دید که کدام بوق او موجب اقدام مدیریتی یا هشدار شده است + include_statuses: این کاربر خواهد دید که کدام فرسته او موجب اقدام مدیریتی یا هشدار شده است send_email_notification: توضیحی که کاربر میبینید که برای حسابش چه رخ داده است - text_html: اختیاری. میتوانید مثل بوقهای معمولی بنویسید. میتوانید برای صرفهجویی در زمان <a href="%{path}">هشدارهای ازپیشآماده بیفزایید</a> + text_html: اختیاری. میتوانید مثل فرستههای معمولی بنویسید. میتوانید برای صرفهجویی در زمان <a href="%{path}">هشدارهای ازپیشآماده بیفزایید</a> type_html: با حساب <strong>%{acct}</strong> میخواهید چه کار کنید؟ types: disable: از استفادهٔ کاربر از حسابش جلوگیری میکند، ولی محتوایش را حذف یا پنهان نمیکند. @@ -26,7 +26,9 @@ fa: ends_at: اختیاری. اعلامیه در این به صورت خودکار نامنتشر خواهد شد scheduled_at: برای انتشار فوری اعلامیه، خالی بگذارید starts_at: اختیاری. در صورتی که اعلامیهتان محدود به بازهٔ زمانی خاصی است - text: میتوانید مانند یک بوق معمولی بنویسید. یادتان باشد که اعلامیهٔ شما فضای صفحهٔ کاربران را اشغال خواهد کرد + text: میتوانید مانند یک فرسته معمولی بنویسید. یادتان باشد که اعلامیهٔ شما فضای صفحهٔ کاربران را اشغال خواهد کرد + appeal: + text: فقط یک بار میتوانید برای اخطار درخواست تجدیدنظر کنید defaults: autofollow: کسانی که از راه دعوتنامه عضو میشوند به طور خودکار پیگیر شما خواهند شد avatar: یکی از قالبهای PNG یا GIF یا JPG. بیشترین اندازه %{size}. تصویر به اندازهٔ %{dimensions} پیکسل تبدیل خواهد شد @@ -35,24 +37,25 @@ fa: current_password: به دلایل امنیتی لطفاً رمز این حساب را وارد کنید current_username: برای تأیید، لطفاً نام کاربری حساب فعلی را وارد کنید digest: تنها وقتی فرستاده میشود که مدتی طولانی فعالیتی نداشته باشید و در این مدت برای شما پیغام خصوصیای نوشته شده باشد + discoverable: اجازه دهید حسابتان از طریق پیشنهادها، پرطرفدارها و سایر قابلیتها، توسط افراد غریبه قابل کشف باشد email: به شما ایمیل تأییدی فرستاده خواهد شد fields: شما میتوانید تا چهار مورد را در یک جدول در نمایهٔ خود نمایش دهید header: یکی از قالبهای PNG یا GIF یا JPG. بیشترین اندازه %{size}. تصویر به اندازهٔ %{dimensions} پیکسل تبدیل خواهد شد inbox_url: نشانی صفحهٔ اصلی رلهای را که میخواهید به کار ببرید کپی کنید - irreversible: بوقهای پالوده به طور برگشتناپذیری ناپدید میشوند، حتا اگر بعدها پالایه برداشته شود + irreversible: فرستههای پالوده به طور برگشتناپذیری ناپدید میشوند، حتا اگر بعدها پالایه برداشته شود locale: زبان واسط کاربری، رایانامهها و آگاهیهای ارسالی locked: باید پیگیران تازه را خودتان تأیید کنید password: دستکم باید ۸ نویسه داشته باشد - phrase: مستقل از کوچکی و بزرگی حروف، با متن اصلی یا هشدار محتوای بوقها مقایسه میشود + phrase: مستقل از کوچکی و بزرگی حروف، با متن اصلی یا هشدار محتوای فرستهها مقایسه میشود scopes: واسطهای برنامهنویسی که این برنامه به آن دسترسی دارد. اگر بالاترین سطح دسترسی را انتخاب کنید، دیگر نیازی به انتخاب سطحهای پایینی ندارید. - setting_aggregate_reblogs: برای بازبوقهایی که به تازگی برایتان نمایش داده شدهاند، بازبوقهای بیشتر را نشان نده (فقط روی بازبوقهای اخیر تأثیر میگذارد) + setting_aggregate_reblogs: برای تقویتهایی که به تازگی برایتان نمایش داده شدهاند، تقویتهای بیشتر را نمایش نده (فقط روی تقویتهای اخیر تأثیر میگذارد) setting_default_sensitive: تصاویر حساس به طور پیشفرض پنهان هستند و میتوانند با یک کلیک آشکار شوند setting_display_media_default: تصویرهایی را که به عنوان حساس علامت زده شدهاند پنهان کن setting_display_media_hide_all: همیشه همهٔ عکسها و ویدیوها را پنهان کن setting_display_media_show_all: همیشه تصویرهایی را که به عنوان حساس علامت زده شدهاند را نشان بده setting_hide_network: فهرست پیگیران شما و فهرست کسانی که شما پی میگیرید روی نمایهٔ شما دیده نخواهد شد setting_noindex: روی نمایهٔ عمومی و صفحهٔ نوشتههای شما تأثیر میگذارد - setting_show_application: برنامهای که به کمک آن بوق میزنید، در جزئیات بوق شما نمایش خواهد یافت + setting_show_application: برنامهای که به کمک آن فرسته میزنید، در جزئیات فرسته شما نمایش خواهد یافت setting_use_blurhash: سایهها بر اساس رنگهای بهکاررفته در تصویر پنهانشده ساخته میشوند ولی جزئیات تصویر در آنها آشکار نیست setting_use_pending_items: به جای پیشرفتن خودکار در فهرست، بهروزرسانی فهرست نوشتهها را پشت یک کلیک پنهان کن username: نام کاربری شما روی %{domain} یکتا خواهد بود @@ -60,6 +63,7 @@ fa: domain_allow: domain: این دامین خواهد توانست دادهها از این سرور را دریافت کند و دادههای از این دامین در اینجا پردازش و ذخیره خواهند شد email_domain_block: + domain: این میتواند نام دامنهای باشد که در نشانی رایانامه یا رکورد MX استفاده میشود. پس از ثبت نام بررسی خواهند شد. with_dns_records: تلاشی برای resolve کردن رکوردهای ساناد دامنهٔ دادهشده انجام شده و نتیجه نیز مسدود خواهد شد featured_tag: name: 'شاید بخواهید چنین چیزهایی را به کار ببرید:' @@ -99,7 +103,7 @@ fa: text: متن از پیش آمادهشده title: عنوان admin_account_action: - include_statuses: بوقهای گزارششده را در ایمیل بگنجان + include_statuses: فرستههای گزارششده را در ایمیل بگنجان send_email_notification: اطلاعرسانی به کاربر از راه ایمیل text: هشدار موردی type: کنش @@ -116,6 +120,8 @@ fa: scheduled_at: زمانبندی انتشار starts_at: آغاز رویداد text: اعلامیه + appeal: + text: توضیح دهید که چرا این تصمیم باید معکوس شود defaults: autofollow: دعوت از دیگران برای عضو شدن و پیگیری حساب شما avatar: تصویر نمایه @@ -144,10 +150,10 @@ fa: password: رمز phrase: کلیدواژه یا عبارت setting_advanced_layout: فعالسازی رابط کاربری پیشرفته - setting_aggregate_reblogs: بازبوقها را متحد کن + setting_aggregate_reblogs: تقویتها را در خطزمانی گروهبندی کن setting_auto_play_gif: پخش خودکار تصویرهای متحرک - setting_boost_modal: نمایش پیغام تأیید پیش از بازبوقیدن - setting_crop_images: در بوقهای بازنشده، تصویرها را به ابعاد ۱۶×۹ کوچک کن + setting_boost_modal: نمایش پیغام تأیید پیش از تقویت کردن + setting_crop_images: در فرستههای ناگسترده، تصویرها را به ابعاد ۱۶×۹ کوچک کن setting_default_language: زبان نوشتههای شما setting_default_privacy: حریم خصوصی نوشتهها setting_default_sensitive: همیشه تصاویر را به عنوان حساس علامت بزن @@ -157,7 +163,7 @@ fa: setting_display_media_default: پیشفرض setting_display_media_hide_all: نهفتن همه setting_display_media_show_all: نمایش همه - setting_expand_spoilers: همیشه بوقهایی را که هشدار محتوا دارند کامل نشان بده + setting_expand_spoilers: همیشه فرستههایی را که هشدار محتوا دارند کامل نشان بده setting_hide_network: نهفتن شبکهٔ ارتباطی setting_noindex: درخواست از موتورهای جستجوگر برای ظاهر نشدن در نتایج جستجو setting_reduce_motion: کاستن از حرکت در پویانماییها @@ -194,20 +200,23 @@ fa: sign_up_requires_approval: محدود کردن ثبت نامها severity: قانون notification_emails: + appeal: شخصی به تصمیم مدیر اعتراض کرد digest: فرستادن رایانامههای خلاصه favourite: وقتی کسی نوشتهٔ شما را پسندید ایمیل بفرست follow: وقتی کسی پیگیر شما شد ایمیل بفرست follow_request: وقتی کسی درخواست پیگیری کرد ایمیل بفرست mention: وقتی کسی از شما نام برد ایمیل بفرست pending_account: وقتی حساب تازهای نیاز به بازبینی داشت ایمیل بفرست - reblog: وقتی کسی نوشتهٔ شما را بازبوقید ایمیل بفرست + reblog: وقتی کسی فرستهٔ شما را تقویت کرد ایمیل بفرست + report: گزارش جدیدی فرستاده شد + trending_tag: روند جدیدی نیازمند بازبینی است rule: text: قانون tag: listable: اجازه به این برچسب برای ظاهر شدن در جستوجوها و پیشنهادها name: برچسب trendable: بگذارید که این برچسب در موضوعات پرطرفدار دیده شود - usable: بگذارید که این برچسب در بوقها به کار بروند + usable: بگذارید که این برچسب در فرستهها به کار بروند 'no': خیر required: mark: "*" diff --git a/config/locales/simple_form.gd.yml b/config/locales/simple_form.gd.yml index ac71f8307..31b636344 100644 --- a/config/locales/simple_form.gd.yml +++ b/config/locales/simple_form.gd.yml @@ -27,6 +27,8 @@ gd: scheduled_at: Fàg seo bàn airson am brath-fios fhoillseachadh sa bhad starts_at: Roghainnean. Cleachd seo airson am brath-fios a chuingeachadh rè ama shònraichte text: "’S urrainn dhut co-chàradh puist a chleachdadh. Thoir an aire air am meud a chaitheas am brath-fios air sgrìn an luchd-chleachdaidh" + appeal: + text: Chan urrainn dhut ath-thagradh a dhèanamh air rabhadh ach aon turas defaults: autofollow: Leanaidh na daoine a chlàraicheas leis a cuireadh ort gu fèin-obrachail avatar: PNG, GIF or JPG. %{size} air a char as motha. Thèid a sgèileadh sìos gu %{dimensions}px @@ -35,6 +37,7 @@ gd: current_password: A chùm tèarainteachd, cuir a-steach facal-faire a’ chunntais làithrich current_username: Airson seo a dhearbhadh, cuir a-steach ainm-cleachdaiche a’ chunntais làithrich digest: Cha dèid seo a chur ach nuair a bhios tu air ùine mhòr gun ghnìomh a ghabhail agus ma fhuair thu teachdaireachd phearsanta fhad ’s a bha thu air falbh + discoverable: Ceadaich gun lorg coigrich an cunntas agad le taic o mholaidhean, treandaichean is gleusan eile email: Thèid post-d dearbhaidh a chur thugad fields: Faodaidh tu suas ri 4 nithean a shealltainn mar chlàr air a’ phròifil agad header: PNG, GIF or JPG. %{size} air a char as motha. Thèid a sgèileadh sìos gu %{dimensions}px @@ -60,6 +63,7 @@ gd: domain_allow: domain: "’S urrainn dhan àrainn seo dàta fhaighinn on fhrithealaiche seo agus thèid an dàta a thig a-steach uaithe a phròiseasadh ’s a stòradh" email_domain_block: + domain: Seo ainm na h-àrainne a nochdas san t-seòladh puist-d no sa chlàr MX a chleachdas e. Thèid an dearbhadh aig àm a’ chlàraidh. with_dns_records: Thèid oidhirp a dhèanamh air fuasgladh clàran DNS na h-àrainne a chaidh a thoirt seachad agus thèid na toraidhean a bhacadh cuideachd featured_tag: name: 'Mholamaid fear dhe na tagaichean seo:' @@ -116,6 +120,8 @@ gd: scheduled_at: Cuir foillseachadh air an sgeideal starts_at: Toiseach an tachartais text: Brath-fios + appeal: + text: Mìnich carson a bu chòir an caochladh a chur orra defaults: autofollow: Thoir cuireadh dhaibh airson leantainn air a’ chunntas agad avatar: Avatar @@ -194,6 +200,7 @@ gd: sign_up_requires_approval: Cuingich clàraidhean ùra severity: Riaghailt notification_emails: + appeal: Tha cuideigin ag ath-thagradh co-dhùnadh na maorsainneachd digest: Cuir puist-d le geàrr-chunntas favourite: Is annsa le cuideigin am post agad follow: Lean cuideigin ort @@ -201,6 +208,8 @@ gd: mention: Thug cuideigin iomradh ort pending_account: Tha cunntas ùr feumach air lèirmheas reblog: Bhrosnaich cuideigin am post agad + report: Chaidh gearan ùr a chur a-null + trending_tag: Tha treand ùr ri lèirmheasadh rule: text: Riaghailt tag: diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index 8eb39dd9e..852c3abeb 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -27,6 +27,8 @@ ja: scheduled_at: お知らせを今すぐ掲載する場合は空欄にしてください starts_at: オプションです。お知らせしたい事柄の期間が決まっている場合に使用します text: 投稿と同じ構文を使用できます。アナウンスが占める画面のスペースに注意してください + appeal: + text: 一度だけ異議を申し立てることができます defaults: autofollow: 招待から登録した人が自動的にあなたをフォローするようになります avatar: "%{size}までのPNG、GIF、JPGが利用可能です。%{dimensions}pxまで縮小されます" @@ -116,6 +118,8 @@ ja: scheduled_at: 掲載予約日時 starts_at: 予定開始日時 text: お知らせ + appeal: + text: この決定を覆すべき理由を説明してください defaults: autofollow: 招待から参加後、あなたをフォロー avatar: アイコン @@ -194,6 +198,7 @@ ja: sign_up_requires_approval: 登録を制限 severity: ルール notification_emails: + appeal: モデレーターの判断に異議申し立てが行われました digest: タイムラインからピックアップしてメールで通知する favourite: お気に入り登録された時 follow: フォローされた時 @@ -201,6 +206,8 @@ ja: mention: 返信が来た時 pending_account: 新しいアカウントの承認が必要な時 reblog: 投稿がブーストされた時 + report: 新しいレポートが送信されました + trending_tag: 新しいトレンドタグにはレビューが必要です rule: text: ルール tag: diff --git a/config/locales/simple_form.ku.yml b/config/locales/simple_form.ku.yml index 4f38ae030..09621771d 100644 --- a/config/locales/simple_form.ku.yml +++ b/config/locales/simple_form.ku.yml @@ -3,20 +3,20 @@ ku: simple_form: hints: account_alias: - acct: Ajimêrê ku tu dixwazî bar bikî navê bikarhêner@domain diyar bike + acct: Ajimêrê ku tu dixwazî jê bar bikî navê bikarhêner@navpar diyar bike account_migration: - acct: Ajimêrê ku tu dixwazî bar bikî navê bikarhêner@domain diyar bike + acct: Ajimêrê ku tu dixwazî bar bikî bo wê navê bikarhêner@navpar diyar bike account_warning_preset: - text: Tu dikarî wek URLyan, hashtagan û şîroveyan, tootê ristesazî jî bikarbînî + text: Tu dikarî hevoksaziya şandiyê wekî URL, hashtag û şîroveyan, bi kar bînî title: Bi dilê xwe ye. Ji wergir re nay xûyakirin admin_account_action: - include_statuses: Bikarhênerê bibîne kîjan toot dibin sedemê çalakî an jî agahdarî + include_statuses: Bikarhêner wê bibîne kîjan şandî dibin sedemê çalakî an jî agahdarikirina çavdêriyê send_email_notification: Bikarhêner dê ravekirinê tiştê ku bi ajimêra wan re qewimî bistîne - text_html: Bi dili xwe ye. Tu dikarî hevoksazî ye toot bikarbînî. Tu dikarî <a href="%{path}"> pêşsazîyên hişyariyê lê zêde bikî </a> ji bo ku demê derbas nekî + text_html: Bi dilê xwe ye. Tu dikarî hevoksaziye şandiyê bi kar bînî. Tu dikarî <a href="%{path}"> pêşsaziyên hişyariyê tevlî bikî </a> ji bo ku demê derbas nekî type_html: Hilbijêre ka tu yê çi bikî bi <strong>%{acct}</strong> re types: - disable: Nehêle bila bikarhêner ajimêrê xwe bikar bîne lê naverokan jê nebe an jî veneşêre. - none: Ji bo ku tu hişyariyekê ji bikarhêner re bişînî vê bi kar bîne, bêyî ku çalakiyeke din dest lê neda. + disable: Nehêle bikarhêner ajimêrê xwe bi kar bîne lê naverokan jê nabe an jî veneşêre. + none: Ji bo ku tu hişyariyekê ji bikarhêner re bişînî vê bi kar bîne, bêyî ku çalakiyeke din bikî. sensitive: Neçar bihêle ku ev bikarhêner hemû pêvekên medyayê hestiyar nîşan bike. silence: Pêşî li bikarhêneran bigire ku bikarhêner bi herkesî ra xûyabarî neşîne, post û agahdarîyên xwe ji mirovên ku wan naşopîne veşêre. suspend: Pêşîya hevbandorîya vî ajimêrê bigire û naveroka wê jê bibe. Di nava 30 rojan de tê vegerandin. @@ -26,7 +26,7 @@ ku: ends_at: Bi dilê xwe ye. Daxuyanî di vê demê de bi xweberî ji weşanê de rabe scheduled_at: Vala bihêle ku yekcar daxûyanî were weşandin starts_at: Bi dilê xwe ye. Heke daxûyanî ya te di demeke diyar ve girêdayî be - text: Tu dikarî hevoksazî yên toot bikarbînî. Ji kerema xwe cihê ku ev daxuyanî li ser dîmenderê bikarhêner bigire baldar be + text: Tu dikarî hevoksaziya şandiyê bi kar bînî. Ji kerema xwe bila haya te ji cihê ku ev daxuyanî li ser dîmenderê bikarhêner bigire hebe appeal: text: Tu dikarî tenê carekê îtîraza binpêkirinê bikî defaults: @@ -34,7 +34,7 @@ ku: avatar: PNG, GIF an jî JPG. Herî zêde %{size} dê ber bi %{dimensions}px ve were kêmkirin bot: Ji yên din re nîşan bike ku ajimêr bi piranî kiryarên xweberî dike û dibe ku neyê çavdêrî kirin context: Yek an jî zêdetir girêdan divê parzûn were sepandin - current_password: Ji bo ewlehiyê ji kerema xwe şîfreya ajimêrê xwe niha têkevin + current_password: Ji bo ewlehiyê ji kerema xwe borînpeyva ajimêrê xwe têxe current_username: Ji bo piştrastkirinê, ji kerema xwe navê bikarhêner ya ajimêrê niha binvîse digest: Tenê piştî demek dirêj neçalakiyê de û tenê di nebûna te da peyamên teybetî standî be tê şandin discoverable: Mafê biden ku ajimêra te bi pêşniyar û taybetmendiyên din ji aliyê biyaniyan ve bê vedîtin @@ -42,10 +42,10 @@ ku: fields: Tu dikarî heya 4 hêmanan wekî tabloyek li ser profîla xwe nîşan bidî header: PNG, GIF an jî JPG. Herî zêde %{size} ber bi %{dimensions}px ve were kêmkirin inbox_url: URLyê di rûpela pêşî de guhêrkerê ku tu dixwazî bi kar bînî jê bigire - irreversible: Tootên parzûnkirî êdî bê veger wenda bibe, heger parzûn paşê were rakirin jî nabe + irreversible: Şandiyên parzûnkirî êdî bê veger wenda bibe, heger parzûn paşê were rakirin jî nabe locale: Zimanê navrûyê bikarhêner, agahdarîyên e-name û pêl kirin locked: Bi destan daxwazên şopê hilbijêrîne da ku kî bikaribe te bişopîne - password: Herî kêm 8 karakter bikar bîne + password: Herî kêm 8 tîpan bi kar bîne phrase: Ji rewşa nivîsê tîpên girdek/hûrdek an jî ji hişyariya naveroka ya şandiyê wek serbixwe wê were hevbeş kirin scopes: |- Sepana ku dê kîjan maf bide bigihije APIyan. @@ -56,7 +56,7 @@ ku: setting_display_media_hide_all: Medyayê tim veşêre setting_display_media_show_all: Medyayê tim nîşan bike setting_hide_network: Kesên ku te dişopîne û kesên tu dişopînî ev ên profîla te de were veşartin - setting_noindex: Bandor li hemî profîla te û tootên rûpela te dike + setting_noindex: Bandor li hemî profîla te û şandiyên rûpela te dike setting_show_application: Navê sepana ku tu ji bo şandinê wê bi kar tîne dê di dîtinê berferh ên di şandiyên te de were xuyakirin setting_use_blurhash: Gradyen xwe bi rengên dîtbarîyên veşartî ve radigire, lê belê hûrgilîyan diveşêre setting_use_pending_items: Li şûna ku herkê wek bixweber bizivirînî nûvekirina demnameyê li paş tikandinekî veşêre @@ -129,10 +129,10 @@ ku: avatar: Wêne bot: Ev ajimêrekî bot e chosen_languages: Parzûnê zimanan - confirm_new_password: Peborîna nû bipejirîne - confirm_password: Peborîn bipejirîne + confirm_new_password: Borînpeyva nû bipejirîne + confirm_password: Borînpeyvê bipejirîne context: Parzûnê naverokan - current_password: Pêborîna heyî + current_password: Borînpeyva heyî data: Dane discoverable: Ji yên din re ajimêrê pêşniyar bike display_name: Navê nîşandanê @@ -144,12 +144,12 @@ ku: inbox_url: URLya guhêzkera wergirtî irreversible: Li şûna veşartinê jê bibe locale: Zimanê navrûyê - locked: Ajimêr qefl bike + locked: Ajimêr kilît bike max_uses: Hejmara bikaranîna herî zêde - new_password: Pêborîna nû + new_password: Borînpeyva nû note: Jiyanname otp_attempt: Koda du faktoran - password: Pêborîn + password: Borînpeyv phrase: Peyvkilîd an jî hevok setting_advanced_layout: Navrûya tevnê yê pêşketî çalak bike setting_aggregate_reblogs: Di demnameyê de şandiyên bilindkirî kom bike @@ -169,7 +169,7 @@ ku: setting_hide_network: Grafîka xwe ya civakî veşêre setting_noindex: Bes e nexe di nav rêzên lêgerîna gerokan setting_reduce_motion: Lîstikên livoka kêm bike - setting_show_application: Sepana ku ji bo şandina toot'a tê bikaranîn diyar bike + setting_show_application: Sepana ku ji bo şandina şandiyan tê bikaranîn diyar bike setting_system_font_ui: Curenivîsa berdest a pergalê bi kar bîne setting_theme: Rûkarê malperê setting_trends: Rojeva îro nîşan bide diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml index 56a3f2b76..4ecbe1c9d 100644 --- a/config/locales/simple_form.nl.yml +++ b/config/locales/simple_form.nl.yml @@ -7,18 +7,18 @@ nl: account_migration: acct: Vul de gebruikersnaam@domein van het account in, waarnaartoe je wilt verhuizen account_warning_preset: - text: Je kunt voor toots specifieke tekst gebruiken, zoals URL's, hashtags en vermeldingen + text: Je kunt specifieke tekst voor berichten gebruiken, zoals URL's, hashtags en vermeldingen title: Optioneel. Niet zichtbaar voor de ontvanger admin_account_action: - include_statuses: De gebruiker ziet welke toots verantwoordelijk zijn voor de moderatieactie of waarschuwing - send_email_notification: De gebruiker ontvangt een uitleg over wat er met hun account is gebeurd - text_html: Optioneel. Je kunt voor toots specifieke tekst gebruiken. Om tijd te besparen kun je <a href="%{path}">presets voor waarschuwingen toevoegen</a> + include_statuses: De gebruiker ziet welke berichten verantwoordelijk zijn voor de moderatieactie of waarschuwing + send_email_notification: De gebruiker ontvangt een uitleg over wat er met diens account is gebeurd + text_html: Optioneel. Je kunt specifieke tekst voor berichten gebruiken. Om tijd te besparen kun je <a href="%{path}">presets voor waarschuwingen toevoegen</a> type_html: Kies wat er met <strong>%{acct}</strong> moet gebeuren types: - disable: Voorkom dat de gebruiker hun account gebruikt, maar verwijder of verberg de inhoud niet. + disable: Voorkom dat de gebruiker diens account gebruikt, maar verwijder of verberg de inhoud niet. none: Gebruik dit om een waarschuwing naar de gebruiker te sturen, zonder dat nog een andere actie wordt uitgevoerd. sensitive: Forceer dat alle mediabijlagen van deze gebruiker als gevoelig worden gemarkeerd. - silence: Voorkom dat de gebruiker openbare toots kan versturen, verberg hun toots en meldingen voor mensen die hen niet volgen. + silence: Voorkom dat de gebruiker openbare berichten kan versturen, verberg diens berichten en meldingen voor mensen die diegene niet volgen. suspend: Alle interacties van en met dit account blokkeren en de inhoud verwijderen. Dit kan binnen dertig dagen worden teruggedraaid. warning_preset_id: Optioneel. Je kunt nog steeds handmatig tekst toevoegen aan het eind van de voorinstelling announcement: @@ -26,7 +26,7 @@ nl: ends_at: Optioneel. De publicatie van de mededeling wordt op dit tijdstip automatisch beëindigd scheduled_at: Laat leeg om de mededeling meteen te publiceren starts_at: Optioneel. In het geval dat jouw mededeling aan een bepaald tijdvak is gebonden - text: Je kunt voor toots specifieke tekst gebruiken. Let op de ruimte die de mededeling op het scherm van de gebruiker inneemt + text: Je kunt specifieke tekst voor berichten gebruiken. Let op de ruimte die de mededeling op het scherm van de gebruiker inneemt defaults: autofollow: Mensen die zich via de uitnodiging hebben geregistreerd, volgen jou automatisch avatar: PNG, GIF of JPG. Maximaal %{size}. Wordt teruggeschaald naar %{dimensions}px @@ -39,20 +39,20 @@ nl: fields: Je kan maximaal 4 items als een tabel op je profiel weergeven header: PNG, GIF of JPG. Maximaal %{size}. Wordt teruggeschaald naar %{dimensions}px inbox_url: Kopieer de URL van de voorpagina van de relayserver die je wil gebruiken - irreversible: Gefilterde toots verdwijnen onomkeerbaar, zelfs als de filter later wordt verwijderd + irreversible: Gefilterde berichten verdwijnen onomkeerbaar, zelfs als de filter later wordt verwijderd locale: De taal van de gebruikersomgeving, e-mails en pushmeldingen locked: Door het goedkeuren van volgers handmatig bepalen wie jou mag volgen password: Gebruik tenminste 8 tekens phrase: Komt overeen ongeacht hoofd-/kleine letters of een inhoudswaarschuwing scopes: Tot welke API's heeft de toepassing toegang. Wanneer je een toestemming van het bovenste niveau kiest, hoef je geen individuele toestemmingen meer te kiezen. - setting_aggregate_reblogs: Geen nieuwe boosts tonen voor toots die recentelijk nog zijn geboost (heeft alleen effect op nieuw ontvangen boosts) + setting_aggregate_reblogs: Geen nieuwe boosts tonen voor berichten die recentelijk nog zijn geboost (heeft alleen effect op nieuw ontvangen boosts) setting_default_sensitive: Gevoelige media wordt standaard verborgen en kan met één klik worden getoond setting_display_media_default: Als gevoelig gemarkeerde media verbergen setting_display_media_hide_all: Media altijd verbergen setting_display_media_show_all: Media altijd tonen setting_hide_network: Wie jij volgt en wie jou volgen wordt niet op jouw profiel getoond - setting_noindex: Heeft invloed op jouw openbare profiel en toots - setting_show_application: De toepassing de je gebruikt om te tooten wordt in de gedetailleerde weergave van de toot getoond + setting_noindex: Heeft invloed op jouw openbare profiel en pagina's met berichten + setting_show_application: De toepassing de je gebruikt om berichten te plaatsen wordt in de gedetailleerde weergave van het bericht getoond setting_use_blurhash: Wazige kleurovergangen zijn gebaseerd op de kleuren van de verborgen media, waarmee elk detail verdwijnt setting_use_pending_items: De tijdlijn wordt bijgewerkt door op het aantal nieuwe items te klikken, in plaats van dat deze automatisch wordt bijgewerkt username: Jouw gebruikersnaam is uniek op %{domain} @@ -85,7 +85,7 @@ nl: tag: name: Je kunt elk woord met een hoofdletter beginnen, om zo bijvoorbeeld de tekst leesbaarder te maken user: - chosen_languages: Alleen toots in de aangevinkte talen worden op de openbare tijdlijnen getoond + chosen_languages: Alleen berichten in de aangevinkte talen worden op de openbare tijdlijnen getoond labels: account: fields: @@ -99,7 +99,7 @@ nl: text: Tekst van preset title: Titel admin_account_action: - include_statuses: Gerapporteerde toots aan de e-mail toevoegen + include_statuses: Gerapporteerde berichten aan de e-mail toevoegen send_email_notification: Meld dit per e-mail aan de gebruiker text: Aangepaste waarschuwing type: Actie @@ -146,22 +146,22 @@ nl: setting_advanced_layout: Geavanceerde webomgeving inschakelen setting_aggregate_reblogs: Boosts in tijdlijnen groeperen setting_auto_play_gif: Speel geanimeerde GIF's automatisch af - setting_boost_modal: Vraag voor het boosten van een toot een bevestiging - setting_crop_images: Afbeeldingen bijsnijden tot 16x9 in toots op tijdlijnen - setting_default_language: Taal van jouw toots - setting_default_privacy: Standaardzichtbaarheid van jouw toots + setting_boost_modal: Vraag voor het boosten van een bericht een bevestiging + setting_crop_images: Afbeeldingen bijsnijden tot 16x9 in berichten op tijdlijnen + setting_default_language: Taal van jouw berichten + setting_default_privacy: Zichtbaarheid van nieuwe berichten setting_default_sensitive: Media altijd als gevoelig markeren - setting_delete_modal: Vraag voor het verwijderen van een toot een bevestiging + setting_delete_modal: Vraag voor het verwijderen van een bericht een bevestiging setting_disable_swiping: Swipebewegingen uitschakelen setting_display_media: Mediaweergave setting_display_media_default: Standaard setting_display_media_hide_all: Alles verbergen setting_display_media_show_all: Alles tonen - setting_expand_spoilers: Altijd toots met inhoudswaarschuwingen uitklappen + setting_expand_spoilers: Altijd berichten met inhoudswaarschuwingen uitklappen setting_hide_network: Jouw volgers en wie je volgt verbergen - setting_noindex: Jouw toots niet door zoekmachines laten indexeren + setting_noindex: Jouw berichten niet door zoekmachines laten indexeren setting_reduce_motion: Langzamere animaties - setting_show_application: Toepassing onthullen die je voor het verzenden van toots gebruikt + setting_show_application: Toepassing onthullen die je voor het verzenden van berichten gebruikt setting_system_font_ui: Standaardlettertype van jouw systeem gebruiken setting_theme: Thema website setting_trends: Trends van vandaag tonen @@ -195,19 +195,19 @@ nl: severity: Regel notification_emails: digest: Periodiek e-mails met een samenvatting versturen - favourite: Wanneer iemand jouw toot aan hun favorieten heeft toegevoegd + favourite: Wanneer iemand jouw bericht aan diens favorieten heeft toegevoegd follow: Wanneer iemand jou is gaan volgen follow_request: Wanneer iemand jou wil volgen mention: Wanneer iemand jou heeft vermeld pending_account: Wanneer een nieuw account moet worden beoordeeld - reblog: Wanneer iemand jouw toot heeft geboost + reblog: Wanneer iemand jouw bericht heeft geboost rule: text: Regel tag: listable: Toestaan dat deze hashtag in zoekopdrachten en aanbevelingen te zien valt name: Hashtag trendable: Toestaan dat deze hashtag onder trends te zien valt - usable: Toestaan dat deze hashtag in toots gebruikt mag worden + usable: Toestaan dat deze hashtag in berichten gebruikt mag worden 'no': Nee required: mark: "*" diff --git a/config/locales/simple_form.sk.yml b/config/locales/simple_form.sk.yml index 5d42684c8..0bdc72a5e 100644 --- a/config/locales/simple_form.sk.yml +++ b/config/locales/simple_form.sk.yml @@ -153,6 +153,9 @@ sk: comment: Okomentuj invite_request: text: Prečo sa k nám chceš pridať? + ip_block: + comment: Komentár + severity: Pravidlo notification_emails: digest: Zasielať súhrnné emaily favourite: Zaslať email, ak si niekto obľúbi tvoj príspevok diff --git a/config/locales/simple_form.th.yml b/config/locales/simple_form.th.yml index 6557ecc4a..9ca4790fd 100644 --- a/config/locales/simple_form.th.yml +++ b/config/locales/simple_form.th.yml @@ -20,7 +20,7 @@ th: sensitive: บังคับให้ทำเครื่องหมายไฟล์แนบสื่อของผู้ใช้นี้ทั้งหมดว่าละเอียดอ่อน silence: ป้องกันไม่ให้ผู้ใช้สามารถโพสต์โดยมีการมองเห็นเป็นสาธารณะ ซ่อนโพสต์และการแจ้งเตือนของเขาจากผู้คนที่ไม่ได้กำลังติดตามผู้ใช้ suspend: ป้องกันไม่ให้มีการโต้ตอบใด ๆ จากหรือไปยังบัญชีนี้และลบเนื้อหาของบัญชี แปลงกลับได้ภายใน 30 วัน - warning_preset_id: ไม่จำเป็น คุณยังสามารถเพิ่มข้อความที่กำหนดเองที่จุดสิ้นสุดของค่าที่ตั้งไว้ล่วงหน้า + warning_preset_id: ไม่จำเป็น คุณยังคงสามารถเพิ่มข้อความที่กำหนดเองที่จุดสิ้นสุดของค่าที่ตั้งไว้ล่วงหน้า announcement: all_day: เมื่อกาเครื่องหมาย จะแสดงเฉพาะวันที่ของช่วงเวลาเท่านั้น ends_at: ไม่จำเป็น จะเลิกเผยแพร่ประกาศที่เวลานี้โดยอัตโนมัติ @@ -74,7 +74,7 @@ th: text: นี่จะช่วยให้เราตรวจทานใบสมัครของคุณ ip_block: comment: ไม่จำเป็น จดจำเหตุผลที่คุณเพิ่มกฎนี้ - ip: ป้อนที่อยู่ IPv4 หรือ IPv6 คุณสามารถปิดกั้นทั้งช่วงได้โดยใช้ไวยากรณ์ CIDR ระวังอย่าล็อคตัวเองออก! + ip: ป้อนที่อยู่ IPv4 หรือ IPv6 คุณสามารถปิดกั้นทั้งช่วงได้โดยใช้ไวยากรณ์ CIDR ระวังอย่าล็อคตัวคุณเองออก! severities: no_access: ปิดกั้นการเข้าถึงทรัพยากรทั้งหมด sign_up_requires_approval: การลงทะเบียนใหม่จะต้องมีการอนุมัติของคุณ @@ -133,6 +133,7 @@ th: expires_in: หมดอายุหลังจาก fields: ข้อมูลเมตาโปรไฟล์ header: ส่วนหัว + honeypot: "%{label} (ไม่ต้องกรอก)" inbox_url: URL กล่องขาเข้าแบบรีเลย์ irreversible: ลบแทนที่จะซ่อน locale: ภาษาส่วนติดต่อ @@ -194,6 +195,7 @@ th: sign_up_requires_approval: จำกัดการลงทะเบียน severity: กฎ notification_emails: + appeal: ใครสักคนอุทธรณ์การตัดสินใจของผู้ควบคุม digest: ส่งอีเมลสรุป favourite: ใครสักคนได้ชื่นชอบโพสต์ของคุณ follow: ใครสักคนได้ติดตามคุณ diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 2405c5872..687f4d40d 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -15,6 +15,7 @@ sk: contact: Kontakt contact_missing: Nezadaný contact_unavailable: Neuvedený/á + continue_to_web: Pokračovať na webovú aplikáciu discover_users: Objavuj užívateľov documentation: Dokumentácia federation_hint_html: S účtom na %{instance} budeš môcť následovať ľúdí na hociakom Mastodon serveri, ale aj na iných serveroch. @@ -24,6 +25,7 @@ sk: Tento účet je virtuálnym aktérom, ktorý predstavuje samotný server a nie žiadného jedného užívateľa. Je využívaný pre potreby federovania a nemal by byť blokovaný, pokiaľ nechceš zablokovať celý server, čo ide lepšie dosiahnúť cez blokovanie domény. learn_more: Zisti viac + logged_in_as_html: Práve si prihlásený/á ako %{username}. logout_before_registering: Už si prihlásený/á. privacy_policy: Zásady súkromia rules: Serverové pravidlá diff --git a/config/locales/sq.yml b/config/locales/sq.yml index a497ef81a..560f4bff7 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -166,9 +166,8 @@ sq: perform_full_suspension: Pezulloje previous_strikes: Paralajmërime të mëparshme previous_strikes_description_html: - one: Kjo llogari ka <strong>one</strong> paralajmërim. + one: Kjo llogari ka <strong>një</strong> paralajmërim. other: Kjo llogari ka <strong>%{count}</strong> paralajmërime. - zero: Kjo llogari është <strong>në pozita të mira</strong>. promote: Promovojeni protocol: Protokoll public: Publike @@ -373,6 +372,7 @@ sq: enable: Aktivizoje enabled: I aktivizuar enabled_msg: Ai emoxhi u aktivizua me sukses + image_hint: PNG ose GIF deri në %{size} list: Vëre në listë listed: Në listë new: @@ -468,6 +468,7 @@ sq: title: Zë i ri email në listë bllokimesh no_email_domain_block_selected: S’u ndryshuan blloqe përkatësish email, ngaqë s’qe përzgjedhur ndonjë resolved_dns_records_hint_html: Emri i përkatësisë jep u përket përkatësive vijuese MX, që janë përgjegjëset për pranim email-esh. Bllokimi i një përkatësie MX do të bllokojë regjistrime nga çfarëdo adrese email që përdor të njëjtën përkatësi MX, edhe nëse emri i dukshëm i përkatësisë është i ndryshëm. <strong>Jini i kujdesshëm të mos bllokoni shërbime të njohur email-esh.</strong> + resolved_through_html: Zgjidhur përmes %{domain} title: Listë bllokimesh email-esh follow_recommendations: description_html: "<strong>Rekomandimet për ndjekje ndihmojnë përdoruesit e rinj të gjejnë shpejt lëndë me interes</strong>. Kur një përdorues nuk ka ndërvepruar mjaftueshëm me të tjerët, që të formohen rekomandime të personalizuara ndjekjeje, rekomandohen këto llogari. Ato përzgjidhen çdo ditë, prej një përzierje llogarish me shkallën më të lartë të angazhimit dhe numrin më të lartë të ndjekësve vendorë për një gjuhë të dhënë." @@ -487,6 +488,7 @@ sq: one: Përpjekje e dështuar në %{count} ditë. other: Përpjekje e dështuar në %{count} ditë të ndryshme. no_failures_recorded: S’ka dështime të regjistruara. + warning: Përpjekja e fundit për t’u lidhur me këtë shërbyes ka qenë e pasuksesshme back_to_all: Krejt back_to_limited: E kufizuar back_to_warning: Kujdes @@ -526,7 +528,6 @@ sq: known_accounts: one: "%{count} llogari e njohur" other: "%{count} llogari të njohura" - zero: Pa llogari të njohur moderation: all: Krejt limited: Të kufizuarat @@ -771,6 +772,11 @@ sq: system_checks: database_schema_check: message_html: Ka migrime bazash të dhënash pezull. Ju lutemi, kryejini, për të qenë të sigurt se aplikacioni sillet siç priteet + elasticsearch_running_check: + message_html: S’u lidh dot me Elasticsearch. Ju lutemi, kontrolloni nëse ky xhiron, ose çaktivizoni kërkimin në tërë tekstin + elasticsearch_version_check: + message_html: 'Version Elasticsearch i papërputhshëm: %{value}' + version_comparison: Xhiron Elasticsearch %{running_version}, ndërkohë që është i domosdoshëm %{required_version} rules_check: action: Administroni rregulla shërbyesi message_html: S’keni përcaktuar ndonjë rregull shërbyesi. @@ -791,9 +797,8 @@ sq: disallow: Hiq lejimin e lidhjes disallow_provider: Mos e lejo botuesin shared_by_over_week: - one: Ndarë nga një person javën e kaluar - other: Ndarë nga %{count} persona javën e kaluar - zero: E pandarë nga njeri gjatë javës së kaluar + one: Ndarë me të tjerë nga një person gjatë javës së kaluar + other: Ndarë me të tjerë nga %{count} vetë gjatë javës së kaluar title: Lidhje në modë usage_comparison: Ndarë %{today} herë sot, kundrejt %{yesterday} dje pending_review: Në pritje të shqyrtimit @@ -832,9 +837,8 @@ sq: usable: Mund të përdoret usage_comparison: Përdorur %{today} herë sot, krahasuar me %{yesterday} dje used_by_over_week: - one: Përdorur nga një persona gjatë javës së kaluar - other: Përdorur nga %{count} persona gjatë javës së kaluar - zero: E papërdorur nga njeri gjatë javës së kaluar + one: Përdorur nga një person gjatë javës së kaluar + other: Përdorur nga %{count} vetë gjatë javës së kaluar title: Në modë warning_presets: add_new: Shtoni të ri @@ -1408,6 +1412,7 @@ sq: profile: Profil relationships: Ndjekje dhe ndjekës statuses_cleanup: Fshirje e automatizuar postimesh + strikes: Paralajmërime nga moderimi two_factor_authentication: Mirëfilltësim Dyfaktorësh webauthn_authentication: Kyçe sigurie statuses: @@ -1428,6 +1433,7 @@ sq: disallowed_hashtags: one: 'përmbante një hashtag të palejuar: %{tags}' other: 'përmbante hashtag-ë të palejuar: %{tags}' + edited_at_html: Përpunuar më %{date} errors: in_reply_not_found: Gjendja të cilës po provoni t’i përgjigjeni s’duket se ekziston. open_in_web: Hape në internet diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 40337ce69..c8424e5f5 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -160,10 +160,6 @@ sv: pending: Inväntar granskning perform_full_suspension: Utför full avstängning previous_strikes: Tidigare varningar - previous_strikes_description_html: - one: Detta konto har <strong>en</strong> varning. - other: Detta konto har <strong>%{count}</strong> varningar. - zero: Detta konto är <strong>i gott skick</strong>. promote: Befordra protocol: Protokoll public: Offentlig @@ -404,6 +400,8 @@ sv: status: Status title: Följ rekommendationer instances: + availability: + warning: Det senaste försöket att ansluta till denna värddator har misslyckats back_to_all: Alla back_to_limited: Begränsat back_to_warning: Varning diff --git a/config/locales/th.yml b/config/locales/th.yml index c4294be7f..ce40b9517 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -52,6 +52,7 @@ th: what_is_mastodon: Mastodon คืออะไร? accounts: choices_html: 'ตัวเลือกของ %{name}:' + endorsements_hint: คุณสามารถแนะนำผู้คนที่คุณติดตามจากส่วนติดต่อเว็บ และเขาจะปรากฏที่นี่ featured_tags_hint: คุณสามารถแนะนำแฮชแท็กที่เฉพาะเจาะจงที่จะแสดงที่นี่ follow: ติดตาม followers: @@ -66,6 +67,8 @@ th: nothing_here: ไม่มีสิ่งใดที่นี่! people_followed_by: ผู้คนที่ %{name} ติดตาม people_who_follow: ผู้คนที่ติดตาม %{name} + pin_errors: + following: คุณต้องกำลังติดตามคนที่คุณต้องการแนะนำอยู่แล้ว posts: other: โพสต์ posts_tab_heading: โพสต์ @@ -153,10 +156,6 @@ th: pending: การตรวจทานที่รอดำเนินการ perform_full_suspension: ระงับ previous_strikes: การดำเนินการก่อนหน้านี้ - previous_strikes_description_html: - one: บัญชีนี้มี <strong>หนึ่ง</strong> การดำเนินการ - other: บัญชีนี้มี <strong>%{count}</strong> การดำเนินการ - zero: บัญชีนี้ <strong>อยู่ในสถานะที่ดี</strong> promote: เลื่อนขั้น protocol: โปรโตคอล public: สาธารณะ @@ -269,6 +268,7 @@ th: update_domain_block: อัปเดตการปิดกั้นโดเมน update_status: อัปเดตโพสต์ actions: + approve_appeal_html: "%{name} ได้อนุมัติการอุทธรณ์การตัดสินใจในการควบคุมจาก %{target}" approve_user_html: "%{name} ได้อนุมัติการลงทะเบียนจาก %{target}" assigned_to_self_report_html: "%{name} ได้มอบหมายรายงาน %{target} ให้กับตนเอง" change_email_user_html: "%{name} ได้เปลี่ยนที่อยู่อีเมลของผู้ใช้ %{target}" @@ -299,6 +299,7 @@ th: enable_user_html: "%{name} ได้เปิดใช้งานการเข้าสู่ระบบสำหรับผู้ใช้ %{target}" memorialize_account_html: "%{name} ได้เปลี่ยนบัญชีของ %{target} เป็นหน้าอนุสรณ์" promote_user_html: "%{name} ได้เลื่อนขั้นผู้ใช้ %{target}" + reject_appeal_html: "%{name} ได้ปฏิเสธการอุทธรณ์การตัดสินใจในการควบคุมจาก %{target}" reject_user_html: "%{name} ได้ปฏิเสธการลงทะเบียนจาก %{target}" remove_avatar_user_html: "%{name} ได้เอาภาพประจำตัวของ %{target} ออก" reopen_report_html: "%{name} ได้เปิดรายงาน %{target} ใหม่" @@ -485,10 +486,6 @@ th: delivery_available: มีการจัดส่ง delivery_error_days: วันที่มีข้อผิดพลาดการจัดส่ง empty: ไม่พบโดเมน - known_accounts: - one: "%{count} บัญชีที่รู้จัก" - other: "%{count} บัญชีที่รู้จัก" - zero: ไม่มีบัญชีที่รู้จัก moderation: all: ทั้งหมด limited: จำกัดอยู่ @@ -551,6 +548,9 @@ th: other: "%{count} หมายเหตุ" action_log: รายการบันทึกการตรวจสอบ action_taken_by: ใช้การกระทำโดย + actions: + resolve_description_html: จะไม่ใช้การกระทำกับบัญชีที่รายงาน ไม่มีการบันทึกการดำเนินการ และจะปิดรายงาน + actions_description_html: ตัดสินใจว่าการกระทำใดที่จะใช้เพื่อแก้ปัญหารายงานนี้ หากคุณใช้การกระทำที่เป็นการลงโทษกับบัญชีที่รายงาน จะส่งการแจ้งเตือนอีเมลถึงเขา ยกเว้นเมื่อมีการเลือกหมวดหมู่ <strong>สแปม</strong> are_you_sure: คุณแน่ใจหรือไม่? assign_to_self: มอบหมายให้ฉัน assigned: ผู้ควบคุมที่ได้รับมอบหมาย @@ -709,6 +709,8 @@ th: suspend: "%{name} ได้ระงับบัญชีของ %{target}" appeal_approved: อุทธรณ์แล้ว system_checks: + elasticsearch_version_check: + message_html: 'รุ่น Elasticsearch ที่เข้ากันไม่ได้: %{value}' rules_check: action: จัดการกฎของเซิร์ฟเวอร์ message_html: คุณไม่ได้กำหนดกฎของเซิร์ฟเวอร์ใด ๆ @@ -727,10 +729,6 @@ th: allow_provider: อนุญาตผู้เผยแพร่ disallow: ไม่อนุญาตลิงก์ disallow_provider: ไม่อนุญาตผู้เผยแพร่ - shared_by_over_week: - one: แบ่งปันโดยหนึ่งคนในช่วงสัปดาห์ที่ผ่านมา - other: แบ่งปันโดย %{count} คนในช่วงสัปดาห์ที่ผ่านมา - zero: ไม่มีใครแบ่งปันในช่วงสัปดาห์ที่ผ่านมา title: ลิงก์ที่กำลังนิยม usage_comparison: แบ่งปัน %{today} ครั้งวันนี้ เทียบกับ %{yesterday} เมื่อวานนี้ pending_review: การตรวจทานที่รอดำเนินการ @@ -765,10 +763,6 @@ th: trending_rank: 'กำลังนิยม #%{rank}' usable: สามารถใช้ usage_comparison: ใช้ %{today} ครั้งวันนี้ เทียบกับ %{yesterday} เมื่อวานนี้ - used_by_over_week: - one: ใช้โดยหนึ่งคนในช่วงสัปดาห์ที่ผ่านมา - other: ใช้โดย %{count} คนในช่วงสัปดาห์ที่ผ่านมา - zero: ไม่มีใครใช้ในช่วงสัปดาห์ที่ผ่านมา title: แนวโน้ม warning_presets: add_new: เพิ่มใหม่ @@ -786,6 +780,9 @@ th: sensitive: เพื่อทำเครื่องหมายบัญชีของเขาว่าละเอียดอ่อน silence: เพื่อจำกัดบัญชีของเขา suspend: เพื่อระงับบัญชีของเขา + body: "%{target} กำลังอุทธรณ์การตัดสินใจในการควบคุมโดย %{action_taken_by} จาก %{date} ซึ่งเป็น %{type} เขาเขียนว่า:" + next_steps: คุณสามารถอนุมัติการอุทธรณ์เพื่อเลิกทำการตัดสินใจในการควบคุม หรือเพิกเฉยการอุทธรณ์ + subject: "%{username} กำลังอุทธรณ์การตัดสินใจในการควบคุมใน %{instance}" new_pending_account: body: รายละเอียดของบัญชีใหม่อยู่ด้านล่าง คุณสามารถอนุมัติหรือปฏิเสธใบสมัครนี้ new_report: @@ -875,6 +872,7 @@ th: confirming: กำลังรอการยืนยันอีเมลให้เสร็จสมบูรณ์ functional: บัญชีของคุณทำงานได้อย่างเต็มที่ pending: ใบสมัครของคุณกำลังรอดำเนินการตรวจทานโดยพนักงานของเรา นี่อาจใช้เวลาสักครู่ คุณจะได้รับอีเมลหากใบสมัครของคุณได้รับการอนุมัติ + view_strikes: ดูการดำเนินการที่ผ่านมากับบัญชีของคุณ too_fast: ส่งแบบฟอร์มเร็วเกินไป ลองอีกครั้ง trouble_logging_in: มีปัญหาในการเข้าสู่ระบบ? use_security_key: ใช้กุญแจความปลอดภัย @@ -946,6 +944,7 @@ th: submit: ส่งการอุทธรณ์ associated_report: รายงานที่เกี่ยวข้อง created_at: ลงวันที่ + description_html: นี่คือการกระทำที่ใช้กับบัญชีของคุณและคำเตือนที่ส่งถึงคุณโดยพนักงานของ %{instance} recipient: ส่งถึง status: 'โพสต์ #%{id}' title: "%{action} จาก %{date}" @@ -1402,9 +1401,11 @@ th: user_mailer: appeal_approved: action: ไปยังบัญชีของคุณ + explanation: อนุมัติการอุทธรณ์การดำเนินการกับบัญชีของคุณเมื่อ %{strike_date} ที่คุณได้ส่งเมื่อ %{appeal_date} แล้ว บัญชีของคุณอยู่ในสถานะที่ดีอีกครั้งหนึ่ง subject: อนุมัติการอุทธรณ์ของคุณจาก %{date} แล้ว title: อนุมัติการอุทธรณ์แล้ว appeal_rejected: + explanation: ปฏิเสธการอุทธรณ์การดำเนินการกับบัญชีของคุณเมื่อ %{strike_date} ที่คุณได้ส่งเมื่อ %{appeal_date} แล้ว subject: ปฏิเสธการอุทธรณ์ของคุณจาก %{date} แล้ว title: ปฏิเสธการอุทธรณ์แล้ว backup_ready: @@ -1423,6 +1424,13 @@ th: categories: spam: สแปม violation: เนื้อหาละเมิดหลักเกณฑ์ชุมชนดังต่อไปนี้ + explanation: + delete_statuses: มีการพบว่าโพสต์บางส่วนของคุณละเมิดหนึ่งหลักเกณฑ์ชุมชนหรือมากกว่าและได้รับการเอาออกโดยผู้ควบคุมของ %{instance} ในเวลาต่อมา + disable: คุณไม่สามารถใช้บัญชีของคุณได้อีกต่อไป แต่โปรไฟล์และข้อมูลอื่น ๆ ของคุณยังคงอยู่ในสภาพเดิม คุณสามารถขอข้อมูลสำรองของข้อมูลของคุณ เปลี่ยนการตั้งค่าบัญชี หรือลบบัญชีของคุณ + mark_statuses_as_sensitive: ทำเครื่องหมายโพสต์บางส่วนของคุณว่าละเอียดอ่อนโดยผู้ควบคุมของ %{instance} แล้ว นี่หมายความว่าผู้คนจะต้องแตะสื่อในโพสต์ก่อนที่จะแสดงตัวอย่าง คุณสามารถทำเครื่องหมายสื่อว่าละเอียดอ่อนด้วยตัวคุณเองเมื่อโพสต์ในอนาคต + sensitive: จากนี้ไป จะทำเครื่องหมายไฟล์สื่อที่อัปโหลดทั้งหมดของคุณว่าละเอียดอ่อนและซ่อนอยู่หลังการคลิกไปยังคำเตือน + silence: คุณยังคงสามารถใช้บัญชีของคุณแต่เฉพาะผู้คนที่กำลังติดตามคุณอยู่แล้วเท่านั้นที่จะเห็นโพสต์ของคุณในเซิร์ฟเวอร์นี้ และอาจแยกคุณออกจากคุณลักษณะการค้นพบต่าง ๆ อย่างไรก็ตาม ผู้อื่นอาจยังติดตามคุณด้วยตนเอง + suspend: คุณไม่สามารถใช้บัญชีของคุณได้อีกต่อไป และจะไม่สามารถเข้าถึงโปรไฟล์และข้อมูลอื่น ๆ ของคุณได้อีกต่อไป คุณยังคงสามารถเข้าสู่ระบบเพื่อขอข้อมูลสำรองของข้อมูลของคุณจนกว่าจะเอาข้อมูลออกอย่างสมบูรณ์ในเวลาประมาณ 30 วัน แต่เราจะเก็บรักษาข้อมูลพื้นฐานบางอย่างไว้เพื่อป้องกันไม่ให้คุณหลบเลี่ยงการระงับ reason: 'เหตุผล:' statuses: 'โพสต์ที่อ้างถึง:' subject: diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 6e6477b92..2733f5eba 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -165,10 +165,6 @@ tr: pending: Bekleyen yorum perform_full_suspension: Askıya al previous_strikes: Önceki eylemler - previous_strikes_description_html: - one: Bu hesap için <strong>bir</strong> eylem yapılmış. - other: Bu hesap için <strong>%{count}</strong> eylem yapılmış. - zero: Bu hesap <strong>hali iyi durumda</strong>. promote: Yükselt protocol: Protokol public: Herkese açık @@ -490,6 +486,7 @@ tr: other: "%{count} farklı gün başarısız girişim." no_failures_recorded: Kayıtlı başarısızlık yok. title: Ulaşılabilirlik + warning: Bu sunucuya önceki bağlanma denemesi başarısız olmuştu back_to_all: Tümü back_to_limited: Sınırlı back_to_warning: Uyarı @@ -526,10 +523,6 @@ tr: delivery_error_hint: Eğer teslimat %{count} gün boyunca mümkün olmazsa, otomatik olarak teslim edilemiyor olarak işaretlenecek. destroyed_msg: "%{domain} alan adından veriler hemen silinmek üzere kuyruğa alındı." empty: Alan adı bulunamadı. - known_accounts: - one: "%{count} bilinen hesap" - other: "%{count} bilinen hesap" - zero: Bilinen hesap yok moderation: all: Tümü limited: Sınırlı @@ -793,10 +786,6 @@ tr: description_html: Bu bağlantılar şu anda sunucunuzun gönderilerini gördüğü hesaplarca bolca paylaşılıyor. Kullanıcılarınızın dünyada neler olduğunu görmesine yardımcı olabilir. Yayıncıyı onaylamadığınız sürece hiçbir bağlantı herkese açık yayınlanmaz. Tekil bağlantıları onaylayabilir veya reddedebilirsiniz. disallow: Bağlantıya izin verme disallow_provider: Yayıncıya izin verme - shared_by_over_week: - one: Geçen hafta bir kişi paylaştı - other: Geçen hafta %{count} kişi paylaştı - zero: Geçen hafta kimse paylaşmadı title: Öne çıkan bağlantılar usage_comparison: Bugün %{today} kere paylaşıldı, dün %{yesterday} kere paylaşılmıştı pending_review: İnceleme bekliyor @@ -836,10 +825,6 @@ tr: trending_rank: 'Öne çıkanlar #%{rank}' usable: Kullanılabilir usage_comparison: Bugün %{today} kere kullanıldı, dün %{yesterday} kere kullanılmıştı - used_by_over_week: - one: Geçen hafta bir kişi tarafından kullanıldı - other: Geçen hafta %{count} kişi tarafından kullanıldı - zero: Geçen hafta kimse tarafından kullanılmadı title: Öne çıkanlar warning_presets: add_new: Yeni ekle diff --git a/config/locales/uk.yml b/config/locales/uk.yml index a4d29d3e4..a42f048d6 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -440,10 +440,15 @@ uk: add_new: Додати created_msg: Успішно додано поштовий домен до чорного списку delete: Видалити + dns: + types: + mx: MX-запис domain: Домен new: create: Додати домен + resolve: Розв'язати домен title: Нове блокування поштового домену + resolved_through_html: Розв'язано через %{domain} title: Чорний список поштових доменів follow_recommendations: description_html: "<strong>Слідувати рекомендаціям та допомогти новим користувачам швидко знайти цікавий вміст</strong>. Коли користувачі не взаємодіяли з іншими людьми достатньо, щоб сформувати персоналізовані рекомендації, радимо замість цього вказувати ці облікові записи. Вони щоденно переобчислюються з масиву облікових записів з найбільшою кількістю недавніх взаємодій і найбільшою кількістю місцевих підписників розраховується для цієї мови." @@ -459,6 +464,17 @@ uk: back_to_warning: Попередження by_domain: Домен confirm_purge: Ви впевнені, що хочете видалити ці дані з цього домену? + content_policies: + policies: + reject_media: Відхилити медіа + reject_reports: Відхилити скарги + silence: Обмеження + suspend: Призупинити + policy: Правила + reason: Суспільна причина + title: Політика вмісту + dashboard: + instance_languages_dimension: Найуживаніші мови delivery: all: Усі clear: Очистити помилки доставляння @@ -470,10 +486,6 @@ uk: delivery_error_hint: Якщо доставляння неможливе впродовж %{count} днів, воно автоматично позначиться недоставленим. destroyed_msg: Дані з %{domain} тепер у черзі на видалення. empty: Доменів не знайдено. - known_accounts: - one: "%{count} відомий обліковий запис" - other: "%{count} відомих облікових записів" - zero: Немає відомих облікових записів moderation: all: Усі limited: Обмежені @@ -560,6 +572,7 @@ uk: forwarded: Переслано forwarded_to: Переслано до %{domain} mark_as_resolved: Відмітити як вирішену + mark_as_sensitive: Позначити делікатним mark_as_unresolved: Відмітити як невирішену no_one_assigned: Ніхто notes: @@ -731,6 +744,11 @@ uk: rejected: Посилання цього публікатора можуть не будуть популярними title: Публікатори rejected: Відхилено + statuses: + allow: Дозволити оприлюднення + allow_account: Дозволити автора + disallow: Заборонити допис + disallow_account: Заборонити автора tags: current_score: Поточний результат %{score} dashboard: @@ -847,6 +865,7 @@ uk: status: account_status: Статус облікового запису confirming: Очікуємо на завершення підтвердження за допомогою електронної пошти. + functional: Ваш обліковий запис повністю робочий. pending: Ваша заява очікує на розгляд нашим персоналом. Це може зайняти деякий час. Ви отримаєте електронний лист, якщо ваша заява буде схвалена. redirecting_to: Ваш обліковий запис наразі неактивний, тому що він перенаправлений до %{acct}. too_fast: Форму подано занадто швидко, спробуйте ще раз. @@ -923,13 +942,16 @@ uk: submit: Подати апеляцію associated_report: Пов'язана скарга created_at: Застарілі + recipient: Адресант status: 'Допис #%{id}' status_removed: Допис уже вилучено з системи title: "%{action} від %{date}" title_actions: delete_statuses: Вилучення допису disable: Заморожування облікового запису + mark_statuses_as_sensitive: Позначати дописи делікатними none: Попередження + sensitive: Позначення облікового запису делікатним silence: Обмеження облікового запису suspend: Призупинення облікового запису your_appeal_approved: Вашу апеляцію було схвалено @@ -1113,6 +1135,9 @@ uk: carry_mutes_over_text: Цей користувач переїхав з %{acct}, який ви заглушили. copy_account_note_text: 'Цей користувач був переміщений з %{acct}, ось ваші попередні нотатки:' notification_mailer: + admin: + sign_up: + subject: "%{name} приєднується" digest: action: Показати усі сповіщення body: Коротко про пропущене вами з Вашого останнього входу %{since} @@ -1334,6 +1359,7 @@ uk: many: 'заборонених хештеґів: %{tags}' one: 'заборонений хештеґ: %{tags}' other: 'заборонених хештеґів: %{tags}' + edited_at_html: Відредаговано %{date} errors: in_reply_not_found: Статуса, на який ви намагаєтеся відповісти, не існує. open_in_web: Відкрити у вебі @@ -1396,7 +1422,7 @@ uk: '2629746': 1 місяць '31556952': 1 рік '5259492': 2 місяці - '604800': 1 week + '604800': 1 тиждень '63113904': 2 роки '7889238': 3 місяці min_age_label: Поріг давності diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 459b950a6..14e6c1c3b 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -51,7 +51,7 @@ vi: user_count_after: other: người dùng user_count_before: Nhà của - what_is_mastodon: Tham gia Mastodon + what_is_mastodon: Mastodon accounts: choices_html: "%{name} tôn vinh:" endorsements_hint: Bạn có thể tôn vinh những người bạn theo dõi và họ sẽ hiển thị ở giao diện web. @@ -160,9 +160,7 @@ vi: perform_full_suspension: Vô hiệu hóa previous_strikes: Lịch sử kiểm duyệt previous_strikes_description_html: - one: Người dùng này có <strong>một</strong> lần cảnh cáo. - other: Người dùng này có <strong>%{count}</strong> lần cảnh cáo. - zero: Người dùng này <strong>chưa từng bị cảnh cáo</strong>. + other: Người này bị cảnh cáo <strong>%{count}</strong> lần. promote: Chỉ định vai trò protocol: Giao thức public: Công khai @@ -186,7 +184,7 @@ vi: roles: admin: Quản trị viên moderator: Kiểm duyệt viên - staff: Nhân viên + staff: Đội ngũ user: Người dùng search: Tìm kiếm search_same_email_domain: Tra cứu email @@ -227,25 +225,25 @@ vi: whitelisted: Danh sách trắng action_logs: action_types: - approve_appeal: Đồng ý kháng cáo + approve_appeal: Phê duyệt kháng cáo approve_user: Phê duyệt người dùng assigned_to_self_report: Tự xử lý báo cáo - change_email_user: Đổi email - confirm_user: Xác thực - create_account_warning: Cảnh cáo + change_email_user: Đổi email người dùng + confirm_user: Xác thực người dùng + create_account_warning: Cảnh cáo người dùng create_announcement: Tạo thông báo mới - create_custom_emoji: Tạo emoji mới - create_domain_allow: Tạo cho phép máy chủ mới - create_domain_block: Tạo chặn máy chủ mới - create_email_domain_block: Tạo chặn tên miền email mới + create_custom_emoji: Tạo emoji + create_domain_allow: Cho phép máy chủ + create_domain_block: Chặn máy chủ + create_email_domain_block: Chặn tên miền email create_ip_block: Tạo chặn IP mới - create_unavailable_domain: Tạo máy chủ không khả dụng + create_unavailable_domain: Máy chủ không khả dụng demote_user: Xóa vai trò destroy_announcement: Xóa thông báo destroy_custom_emoji: Xóa emoji - destroy_domain_allow: Xóa máy chủ cho phép - destroy_domain_block: Xóa máy chủ đã chặn - destroy_email_domain_block: Xóa tên miền email đã chặn + destroy_domain_allow: Bỏ cho phép máy chủ + destroy_domain_block: Bỏ chặn máy chủ + destroy_email_domain_block: Bỏ chặn tên miền email destroy_instance: Thanh trừng máy chủ destroy_ip_block: Xóa IP đã chặn destroy_status: Xóa tút @@ -253,10 +251,10 @@ vi: disable_2fa_user: Vô hiệu hóa 2FA disable_custom_emoji: Vô hiệu hóa emoji disable_sign_in_token_auth_user: Tắt xác thực bằng email cho người dùng - disable_user: Khóa người dùng - enable_custom_emoji: Kích hoạt Emoji + disable_user: Vô hiệu hóa đăng nhập + enable_custom_emoji: Cho phép Emoji enable_sign_in_token_auth_user: Bật xác thực bằng email cho người dùng - enable_user: Kích hoạt lại người dùng + enable_user: Bỏ vô hiệu hóa đăng nhập memorialize_account: Đánh dấu tưởng niệm promote_user: Chỉ định vai trò reject_appeal: Từ chối kháng cáo @@ -265,24 +263,24 @@ vi: reopen_report: Mở lại báo cáo reset_password_user: Đặt lại mật khẩu resolve_report: Xử lý báo cáo - sensitive_account: Đánh dấu nhạy cảm - silence_account: Đánh dấu hạn chế - suspend_account: Đánh dấu vô hiệu hóa + sensitive_account: Áp đặt nhạy cảm + silence_account: Áp đặt hạn chế + suspend_account: Áp đặt vô hiệu hóa unassigned_report: Báo cáo chưa xử lý unblock_email_account: Mở khóa địa chỉ email unsensitive_account: Bỏ nhạy cảm unsilence_account: Bỏ hạn chế unsuspend_account: Bỏ vô hiệu hóa update_announcement: Cập nhật thông báo - update_custom_emoji: Cập nhật Emoji mới + update_custom_emoji: Cập nhật Emoji update_domain_block: Cập nhật máy chủ chặn update_status: Cập nhật tút actions: approve_appeal_html: "%{name} đã phê duyệt quyết định kiểm duyệt từ %{target}" approve_user_html: "%{name} đã chấp nhận đăng ký từ %{target}" assigned_to_self_report_html: "%{name} tự xử lý báo cáo %{target}" - change_email_user_html: "%{name} đã thay đổi địa chỉ email cho %{target}" - confirm_user_html: "%{name} xác nhận địa chỉ email của người dùng %{target}" + change_email_user_html: "%{name} đã thay đổi địa chỉ email của %{target}" + confirm_user_html: "%{name} đã xác thực địa chỉ email của %{target}" create_account_warning_html: "%{name} đã gửi cảnh cáo %{target}" create_announcement_html: "%{name} tạo thông báo mới %{target}" create_custom_emoji_html: "%{name} đã tải lên biểu tượng cảm xúc mới %{target}" @@ -295,7 +293,7 @@ vi: destroy_announcement_html: "%{name} xóa thông báo %{target}" destroy_custom_emoji_html: "%{name} đã xóa emoji %{target}" destroy_domain_allow_html: "%{name} đã ngừng liên hợp với %{target}" - destroy_domain_block_html: "%{name} bỏ chặn tên miền email %{target}" + destroy_domain_block_html: "%{name} bỏ chặn máy chủ %{target}" destroy_email_domain_block_html: "%{name} bỏ chặn tên miền email %{target}" destroy_instance_html: "%{name} thanh trừng máy chủ %{target}" destroy_ip_block_html: "%{name} bỏ chặn IP %{target}" @@ -307,14 +305,14 @@ vi: disable_user_html: "%{name} vô hiệu hóa đăng nhập %{target}" enable_custom_emoji_html: "%{name} cho phép Emoji %{target}" enable_sign_in_token_auth_user_html: "%{name} bật xác thực email của %{target}" - enable_user_html: "%{name} mở khóa cho người dùng %{target}" + enable_user_html: "%{name} bỏ vô hiệu hóa đăng nhập %{target}" memorialize_account_html: "%{name} đã biến tài khoản %{target} thành một trang tưởng niệm" promote_user_html: "%{name} chỉ định vai trò cho %{target}" - reject_appeal_html: "%{name} đã phản đối quyết định kiểm duyệt từ %{target}" + reject_appeal_html: "%{name} đã từ chối kháng cáo của %{target}" reject_user_html: "%{name} đã từ chối đăng ký từ %{target}" remove_avatar_user_html: "%{name} đã xóa ảnh đại diện của %{target}" reopen_report_html: "%{name} mở lại báo cáo %{target}" - reset_password_user_html: "%{name} đặt lại mật khẩu của người dùng %{target}" + reset_password_user_html: "%{name} đã đặt lại mật khẩu của %{target}" resolve_report_html: "%{name} đã xử lý báo cáo %{target}" sensitive_account_html: "%{name} đánh dấu nội dung của %{target} là nhạy cảm" silence_account_html: "%{name} đã ẩn %{target}" @@ -323,15 +321,15 @@ vi: unblock_email_account_html: "%{name} mở khóa địa chỉ email của %{target}" unsensitive_account_html: "%{name} đánh dấu nội dung của %{target} là bình thường" unsilence_account_html: "%{name} đã bỏ ẩn %{target}" - unsuspend_account_html: "%{name} đã ngừng vô hiệu hóa %{target}" + unsuspend_account_html: "%{name} đã bỏ vô hiệu hóa %{target}" update_announcement_html: "%{name} cập nhật thông báo %{target}" update_custom_emoji_html: "%{name} đã cập nhật emoji %{target}" update_domain_block_html: "%{name} cập nhật chặn máy chủ %{target}" update_status_html: "%{name} cập nhật tút của %{target}" deleted_status: "(tút đã xóa)" empty: Không tìm thấy bản ghi. - filter_by_action: Lọc theo hành động - filter_by_user: Lọc theo người + filter_by_action: Theo hành động + filter_by_user: Theo người title: Nhật ký kiểm duyệt announcements: destroyed_msg: Xóa thông báo thành công! @@ -388,7 +386,7 @@ vi: interactions: tương tác media_storage: Dung lượng lưu trữ new_users: người dùng mới - opened_reports: báo cáo chưa xử lí + opened_reports: tổng báo cáo pending_appeals_html: other: "<strong>%{count}</strong> kháng cáo đang chờ" pending_reports_html: @@ -477,6 +475,7 @@ vi: other: Thất bại tạm thời vào %{count} ngày khác. no_failures_recorded: Chưa bao giờ thất bại. title: Khả dụng + warning: Lần thử cuối cùng để kết nối tới máy chủ này đã không thành công back_to_all: Toàn bộ back_to_limited: Hạn chế back_to_warning: Cảnh báo @@ -514,9 +513,7 @@ vi: destroyed_msg: Dữ liệu từ %{domain} đã lên lịch để xóa. empty: Không có máy chủ nào. known_accounts: - one: "%{count} người dùng đã biết" - other: "%{count} người dùng đã biết" - zero: Không có người dùng đã biết + other: "%{count} tài khoản đã biết" moderation: all: Tất cả limited: Hạn chế @@ -584,20 +581,20 @@ vi: action_log: Nhật ký kiểm duyệt action_taken_by: Hành động được thực hiện bởi actions: - delete_description_html: Những tút bị báo cáo sẽ được xóa và 1 thẹo sẽ được ghi lại để giúp bạn lưu ý về tài khoản này trong tương lai. - mark_as_sensitive_description_html: Media trong báo cáo sẽ bị đánh dấu nhạy cảm và bạn nhận 1 lần cảnh cáo. + delete_description_html: Những tút bị báo cáo sẽ được xóa và 1 lần cảnh cáo sẽ được ghi lại để giúp bạn lưu ý về tài khoản này trong tương lai. + mark_as_sensitive_description_html: Media trong báo cáo sẽ bị đánh dấu nhạy cảm và họ nhận 1 lần cảnh cáo. other_description_html: Những tùy chọn để kiểm soát tài khoản và giao tiếp với tài khoản bị báo cáo. - resolve_description_html: Không có hành động nào áp dụng đối với tài khoản bị báo cáo, không có thẹo, và báo cáo sẽ được đóng. + resolve_description_html: Không có hành động nào áp dụng đối với tài khoản bị báo cáo, không có cảnh cáo, và báo cáo sẽ được đóng. silence_description_html: Trang cá nhân sẽ chỉ hiển thị với những người đã theo dõi hoặc tìm kiếm thủ công, hạn chế tối đa tầm ảnh hưởng của nó. Có thể đổi lại bình thường sau. suspend_description_html: Trang cá nhân và tất cả các nội dung sẽ không thể truy cập cho đến khi nó bị xóa hoàn toàn. Không thể tương tác với tài khoản. Đảo ngược trong vòng 30 ngày. - actions_description_html: Quyết định hướng xử lý báo cáo này. Nếu áp đặt trừng phạt, một email thông báo sẽ được gửi cho họ, ngoại trừ nếu đó là <strong>Spam</strong>. + actions_description_html: Hướng xử lý báo cáo này. Nếu áp đặt trừng phạt, một email thông báo sẽ được gửi cho họ, ngoại trừ <strong>Spam</strong>. add_to_report: Bổ sung báo cáo are_you_sure: Bạn có chắc không? assign_to_self: Giao cho tôi assigned: Người xử lý by_target_domain: Tên tài khoản bị báo cáo category: Phân loại - category_description_html: Lý do tài khoản hoặc nội dung này bị báo cáo sẽ được trích dẫn trong giao tiếp với tài khoản báo cáo + category_description_html: Lý do tài khoản hoặc nội dung này bị báo cáo sẽ được trích dẫn khi giao tiếp với họ comment: none: Không có mô tả comment_description_html: 'Để cung cấp thêm thông tin, %{name} cho biết:' @@ -628,7 +625,7 @@ vi: skip_to_actions: Kiểm duyệt ngay status: Trạng thái statuses: Nội dung bị báo cáo - statuses_description_html: Lý do tài khoản hoặc nội dung này bị báo cáo sẽ được trích dẫn trong giao tiếp với tài khoản báo cáo + statuses_description_html: Lý do tài khoản hoặc nội dung này bị báo cáo sẽ được trích dẫn khi giao tiếp với họ target_origin: Nguồn báo cáo title: Báo cáo unassign: Bỏ qua @@ -703,8 +700,8 @@ vi: desc_html: Nếu tắt, bảng tin sẽ chỉ hiển thị nội dung do người dùng của máy chủ này tạo ra title: Bao gồm nội dung từ mạng liên hợp trên bảng tin không được xác thực show_staff_badge: - desc_html: Hiển thị huy hiệu nhân viên trên trang người dùng - title: Hiển thị huy hiệu nhân viên + desc_html: Hiện huy hiệu đội ngũ trên trang người dùng + title: Hiện huy hiệu đội ngũ site_description: desc_html: Nội dung giới thiệu về máy chủ. Mô tả những gì làm cho máy chủ Mastodon này đặc biệt và bất cứ điều gì quan trọng khác. Bạn có thể dùng các thẻ HTML, đặc biệt là <code><a></code> và <code><em></code>. title: Mô tả máy chủ @@ -760,6 +757,11 @@ vi: system_checks: database_schema_check: message_html: Có cơ sở dữ liệu đang chờ xử lý. Xin khởi động nó để ứng dụng có thể hoạt động một cách ổn định nhất + elasticsearch_running_check: + message_html: Không thể kết nối Elasticsearch. Hãy kiểm tra xem nó có đang chạy, hay tìm kiếm full-text bị tắt + elasticsearch_version_check: + message_html: 'Phiên bản Elasticsearch không tương thích: %{value}' + version_comparison: Đang dùng Elasticsearch %{running_version} trong khi bắt buộc phải có %{required_version} rules_check: action: Sửa quy tắc máy chủ message_html: Bạn chưa cập nhật quy tắc máy chủ. @@ -774,15 +776,13 @@ vi: approved: Đã cho phép disallow: Cấm links: - allow: Liên kết cho phép - allow_provider: Nguồn đăng cho phép - description_html: Đây là những liên kết được chia sẻ nhiều trên máy chủ của bạn. Nó có thể giúp người dùng tìm hiểu những gì đang xảy ra trên thế giới. Không có liên kết nào được hiển thị công khai cho đến khi bạn duyệt nguồn. Bạn cũng có thể cho phép hoặc từ chối từng liên kết riêng. - disallow: Liên kết cấm - disallow_provider: Nguồn đăng bị cấm + allow: Cho phép liên kết + allow_provider: Cho phép nguồn đăng + description_html: Đây là những liên kết được chia sẻ nhiều trên máy chủ của bạn. Nó có thể giúp người dùng tìm hiểu những gì đang xảy ra trên thế giới. Không có liên kết nào được hiển thị công khai cho đến khi bạn duyệt nguồn đăng. Bạn cũng có thể cho phép hoặc từ chối từng liên kết riêng. + disallow: Cấm liên kết + disallow_provider: Cấm nguồn đăng shared_by_over_week: - one: một người chia sẻ trong tuần qua - other: "%{count} người chia sẻ trong tuần qua" - zero: Không ai chia sẻ trong tuần qua + other: "%{count} người chia sẻ tuần rồi" title: Liên kết xu hướng usage_comparison: Chia sẻ %{today} lần hôm nay, so với %{yesterday} lần hôm qua pending_review: Đang chờ @@ -796,8 +796,8 @@ vi: allow: Cho phép tút allow_account: Cho phép người đăng description_html: Đây là những tút đang được đăng lại và yêu thích rất nhiều trên máy chủ của bạn. Nó có thể giúp người dùng mới và người dùng cũ tìm thấy nhiều người hơn để theo dõi. Không có tút nào được hiển thị công khai cho đến khi bạn cho phép người đăng và người cho phép đề xuất tài khoản của họ cho người khác. Bạn cũng có thể cho phép hoặc từ chối từng tút riêng. - disallow: Không cho phép tút - disallow_account: Không cho phép người đăng + disallow: Cấm tút + disallow_account: Cấm người đăng not_discoverable: Tác giả đã chọn không tham gia mục khám phá shared_by: other: Được thích và đăng lại %{friendly_count} lần @@ -817,14 +817,12 @@ vi: not_usable: Không được phép dùng peaked_on_and_decaying: Đỉnh điểm %{date}, giờ đang giảm title: Hashtag xu hướng - trendable: Có thể xuất hiện thành xu hướng + trendable: Có thể trở thành xu hướng trending_rank: 'Xu hướng #%{rank}' usable: Có thể dùng usage_comparison: Dùng %{today} lần hôm nay, so với %{yesterday} hôm qua used_by_over_week: - one: Dùng bởi một người trong tuần qua - other: Dùng bởi %{count} người trong tuần qua - zero: Không ai dùng trong tuần qua + other: "%{count} người dùng tuần rồi" title: Xu hướng warning_presets: add_new: Thêm mới @@ -1094,7 +1092,7 @@ vi: new: title: Thêm bộ lọc mới footer: - developers: Nhà phát triển + developers: Phát triển more: Nhiều hơn resources: Quy tắc trending_now: Xu hướng @@ -1433,7 +1431,7 @@ vi: show_more: Đọc thêm show_newer: Mới hơn show_older: Cũ hơn - show_thread: Toàn chủ đề + show_thread: Xem chuỗi tút này sign_in_to_participate: Đăng nhập để trả lời tút này title: '%{name}: "%{quote}"' visibilities: @@ -1609,7 +1607,7 @@ vi: none: Cảnh báo sensitive: Tài khoản đã bị đánh dấu nhạy cảm silence: Tài khoản bị hạn chế - suspend: Toài khoản bị vô hiệu hóa + suspend: Tài khoản bị vô hiệu hóa welcome: edit_profile_action: Cài đặt trang cá nhân edit_profile_step: Bạn có thể tùy chỉnh trang cá nhân của mình bằng cách tải lên ảnh đại diện, ảnh bìa, thay đổi tên hiển thị và hơn thế nữa. Nếu bạn muốn những người theo dõi mới phải được phê duyệt, hãy chuyển tài khoản sang trạng thái khóa. diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 6561a5716..48c2ec09a 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -161,10 +161,6 @@ zh-CN: pending: 待审核 perform_full_suspension: 封禁 previous_strikes: 既往处罚 - previous_strikes_description_html: - one: 此账号有<strong>1次</strong>处罚。 - other: 此账号有<strong>%{count}次</strong>处罚。 - zero: 此账号<strong>记录良好</strong>。 promote: 升任 protocol: 协议 public: 公开页面 @@ -479,6 +475,7 @@ zh-CN: other: 在 %{count} 天中尝试失败。 no_failures_recorded: 没有失败记录。 title: 可用性 + warning: 上一次连接到此服务器的尝试失败了 back_to_all: 全部 back_to_limited: 受限 back_to_warning: 警告 @@ -515,10 +512,6 @@ zh-CN: delivery_error_hint: 如果投递已不可用 %{count} 天,它将被自动标记为无法投递。 destroyed_msg: "%{domain} 中的数据现在正在排队等待被立刻删除。" empty: 暂无域名。 - known_accounts: - one: "%{count} 个已知帐户" - other: "%{count} 个已知帐户" - zero: 没有已知账户 moderation: all: 全部 limited: 受限的 @@ -781,10 +774,6 @@ zh-CN: description_html: 这些是当前此服务器可见账号的嘟文中被大量分享的链接。它可以帮助用户了解正在发生的事情。发布者获得批准前不会公开显示任何链接。你也可以批准或拒绝单个链接。 disallow: 不允许链接 disallow_provider: 不允许发布者 - shared_by_over_week: - one: 过去一周内被 1 个人分享过 - other: 过去一周内被 %{count} 个人分享过 - zero: 过去一周内未被分享过 title: 热门链接 usage_comparison: 今日被分享 %{today} 次,前一日为 %{yesterday} 次 pending_review: 待审核 @@ -823,10 +812,6 @@ zh-CN: trending_rank: '热门 #%{rank}' usable: 可以使用 usage_comparison: 今日被使用 %{today} 次,前一日为 %{yesterday} 次 - used_by_over_week: - one: 过去一周内被 1 个人使用过 - other: 过去一周内被 %{count} 个人使用过 - zero: 过去一周内未被使用过 title: 流行趋势 warning_presets: add_new: 添加新条目 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 43a71a5dd..90625c5fd 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -160,9 +160,7 @@ zh-TW: perform_full_suspension: 停權 previous_strikes: 先前的警示 previous_strikes_description_html: - one: 此帳號已有 <strong>1</strong> 次警示。 other: 此帳號已有 <strong>%{count}</strong> 次警示。 - zero: 此帳號<strong>信譽良好</strong>。 promote: 晉級 protocol: 協議 public: 公開 @@ -479,6 +477,7 @@ zh-TW: other: 錯誤嘗試於 %{count} 天。 no_failures_recorded: 報告中沒有錯誤。 title: 可用狀態 + warning: 上一次嘗試連線至本伺服器失敗 back_to_all: 所有 back_to_limited: 受限制的 back_to_warning: 警告 @@ -516,9 +515,7 @@ zh-TW: destroyed_msg: 來自 %{domain} 的資料現在正在佇列中等待刪除。 empty: 找不到網域 known_accounts: - one: "%{count} 個已知帳號" other: "%{count} 個已知帳號" - zero: 沒有已知帳號 moderation: all: 全部 limited: 限制 @@ -762,6 +759,11 @@ zh-TW: system_checks: database_schema_check: message_html: 有挂起的数据库迁移,请运行它们以确保应用程序按照预期运行。 + elasticsearch_running_check: + message_html: 無法連接 Elasticsearch。請檢查是否正在執行中,或者已關閉全文搜尋。 + elasticsearch_version_check: + message_html: 不相容的 Elasticsearch 版本:%{value} + version_comparison: Elasticsearch %{running_version} 版正在執行,需要 %{required_version} 版。 rules_check: action: 管理服务器规则 message_html: 你没有定义任何服务器规则。 @@ -782,9 +784,7 @@ zh-TW: disallow: 不允許連結 disallow_provider: 不允許發行者 shared_by_over_week: - one: 上週由 1 個人分享 - other: 上週由 %{count} 個人分享 - zero: 上週無人分享 + other: 上週被 %{count} 名使用者分享 title: 熱門連結 usage_comparison: 於今日被 %{today} 人分享,相較於昨日 %{yesterday} 人 pending_review: 等待審核中 @@ -824,9 +824,7 @@ zh-TW: usable: 可被使用 usage_comparison: 於今日被使用 %{today} 次,相較於昨日 %{yesterday} 次 used_by_over_week: - one: 上週被 1 個人使用 other: 上週被 %{count} 個人使用 - zero: 上週無人使用 title: 熱門榜 warning_presets: add_new: 新增 diff --git a/config/routes.rb b/config/routes.rb index 4ed2ee760..55e17ab14 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -581,6 +581,10 @@ Rails.application.routes.draw do resources :media, only: [:create] get '/search', to: 'search#index', as: :search resources :suggestions, only: [:index] + + namespace :admin do + resources :accounts, only: [:index] + end end namespace :web do diff --git a/config/sidekiq.yml b/config/sidekiq.yml index c8b1a20dd..f2ae9279b 100644 --- a/config/sidekiq.yml +++ b/config/sidekiq.yml @@ -22,7 +22,7 @@ class: Scheduler::EmailDomainBlockRefreshScheduler queue: scheduler trends_review_notifications_scheduler: - every: '2h' + every: '6h' class: Scheduler::Trends::ReviewNotificationsScheduler queue: scheduler media_cleanup_scheduler: diff --git a/docker-compose.yml b/docker-compose.yml index 01fe320a4..5c2c0c5df 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,5 @@ version: '3' services: - db: restart: always image: postgres:14-alpine @@ -8,11 +7,11 @@ services: networks: - internal_network healthcheck: - test: ["CMD", "pg_isready", "-U", "postgres"] + test: ['CMD', 'pg_isready', '-U', 'postgres'] volumes: - ./postgres14:/var/lib/postgresql/data environment: - - "POSTGRES_HOST_AUTH_METHOD=trust" + - 'POSTGRES_HOST_AUTH_METHOD=trust' redis: restart: always @@ -20,28 +19,28 @@ services: networks: - internal_network healthcheck: - test: ["CMD", "redis-cli", "ping"] + test: ['CMD', 'redis-cli', 'ping'] volumes: - ./redis:/data -# es: -# restart: always -# image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2 -# environment: -# - "ES_JAVA_OPTS=-Xms512m -Xmx512m" -# - "cluster.name=es-mastodon" -# - "discovery.type=single-node" -# - "bootstrap.memory_lock=true" -# networks: -# - internal_network -# healthcheck: -# test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"] -# volumes: -# - ./elasticsearch:/usr/share/elasticsearch/data -# ulimits: -# memlock: -# soft: -1 -# hard: -1 + # es: + # restart: always + # image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2 + # environment: + # - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + # - "cluster.name=es-mastodon" + # - "discovery.type=single-node" + # - "bootstrap.memory_lock=true" + # networks: + # - internal_network + # healthcheck: + # test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"] + # volumes: + # - ./elasticsearch:/usr/share/elasticsearch/data + # ulimits: + # memlock: + # soft: -1 + # hard: -1 web: build: . @@ -53,13 +52,14 @@ services: - external_network - internal_network healthcheck: - test: ["CMD-SHELL", "wget -q --spider --proxy=off localhost:3000/health || exit 1"] + # prettier-ignore + test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:3000/health || exit 1'] ports: - - "127.0.0.1:3000:3000" + - '127.0.0.1:3000:3000' depends_on: - db - redis -# - es + # - es volumes: - ./public/system:/mastodon/public/system @@ -73,9 +73,10 @@ services: - external_network - internal_network healthcheck: - test: ["CMD-SHELL", "wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1"] + # prettier-ignore + test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1'] ports: - - "127.0.0.1:4000:4000" + - '127.0.0.1:4000:4000' depends_on: - db - redis @@ -95,24 +96,24 @@ services: volumes: - ./public/system:/mastodon/public/system healthcheck: - test: ["CMD-SHELL", "ps aux | grep '[s]idekiq\ 6' || false"] + test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"] -## Uncomment to enable federation with tor instances along with adding the following ENV variables -## http_proxy=http://privoxy:8118 -## ALLOW_ACCESS_TO_HIDDEN_SERVICE=true -# tor: -# image: sirboops/tor -# networks: -# - external_network -# - internal_network -# -# privoxy: -# image: sirboops/privoxy -# volumes: -# - ./priv-config:/opt/config -# networks: -# - external_network -# - internal_network + ## Uncomment to enable federation with tor instances along with adding the following ENV variables + ## http_proxy=http://privoxy:8118 + ## ALLOW_ACCESS_TO_HIDDEN_SERVICE=true + # tor: + # image: sirboops/tor + # networks: + # - external_network + # - internal_network + # + # privoxy: + # image: sirboops/privoxy + # volumes: + # - ./priv-config:/opt/config + # networks: + # - external_network + # - internal_network networks: external_network: diff --git a/lib/mastodon/email_domain_blocks_cli.rb b/lib/mastodon/email_domain_blocks_cli.rb index f79df302a..f39f47069 100644 --- a/lib/mastodon/email_domain_blocks_cli.rb +++ b/lib/mastodon/email_domain_blocks_cli.rb @@ -32,9 +32,9 @@ module Mastodon multiple domains to the command. When the --with-dns-records option is given, an attempt to resolve the - given domains' DNS records will be made and the results (A, AAAA and MX) will - also be blocked. This can be helpful if you are blocking an e-mail server that - has many different domains pointing to it as it allows you to essentially block + given domains' MX records will be made and the results will also be blocked. + This can be helpful if you are blocking an e-mail server that has many + different domains pointing to it as it allows you to essentially block it at the root. LONG_DESC def add(*domains) @@ -53,26 +53,19 @@ module Mastodon next end - email_domain_block = EmailDomainBlock.new(domain: domain, with_dns_records: options[:with_dns_records] || false) - email_domain_block.save! - processed += 1 - - next unless email_domain_block.with_dns_records? - - hostnames = [] - ips = [] - - Resolv::DNS.open do |dns| - dns.timeouts = 5 - hostnames = dns.getresources(email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s } - - ([email_domain_block.domain] + hostnames).uniq.each do |hostname| - ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::A).to_a.map { |e| e.address.to_s }) - ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::AAAA).to_a.map { |e| e.address.to_s }) + other_domains = [] + if options[:with_dns_records] + Resolv::DNS.open do |dns| + dns.timeouts = 5 + other_domains = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a end end - (hostnames + ips).uniq.each do |hostname| + email_domain_block = EmailDomainBlock.new(domain: domain, other_domains: other_domains) + email_domain_block.save! + processed += 1 + + (email_domain_block.other_domains || []).uniq.each do |hostname| another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: email_domain_block) if EmailDomainBlock.where(domain: hostname).exists? diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index cdeeb6ea2..ba060a7da 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -17,7 +17,7 @@ module Mastodon end def flags - 'rc1' + '' end def suffix diff --git a/lib/sanitize_ext/sanitize_config.rb b/lib/sanitize_ext/sanitize_config.rb index fed504cf2..c02de967b 100644 --- a/lib/sanitize_ext/sanitize_config.rb +++ b/lib/sanitize_ext/sanitize_config.rb @@ -56,18 +56,6 @@ class Sanitize end end - LINK_REL_TRANSFORMER = lambda do |env| - return unless env[:node_name] == 'a' and env[:node]['href'] - - node = env[:node] - - rel = (node['rel'] || '').split(' ') & ['tag'] - unless env[:config][:outgoing] && TagManager.instance.local_url?(node['href']) - rel += ['nofollow', 'noopener', 'noreferrer'] - end - node['rel'] = rel.join(' ') - end - UNSUPPORTED_HREF_TRANSFORMER = lambda do |env| return unless env[:node_name] == 'a' @@ -98,6 +86,7 @@ class Sanitize add_attributes: { 'a' => { + 'rel' => 'nofollow noopener noreferrer', 'target' => '_blank', }, }, @@ -111,7 +100,6 @@ class Sanitize CLASS_WHITELIST_TRANSFORMER, IMG_TAG_TRANSFORMER, UNSUPPORTED_HREF_TRANSFORMER, - LINK_REL_TRANSFORMER, ] ) @@ -136,5 +124,48 @@ class Sanitize 'source' => { 'src' => HTTP_PROTOCOLS } ) ) + + LINK_REL_TRANSFORMER = lambda do |env| + return unless env[:node_name] == 'a' && env[:node]['href'] + + node = env[:node] + + rel = (node['rel'] || '').split(' ') & ['tag'] + rel += ['nofollow', 'noopener', 'noreferrer'] unless TagManager.instance.local_url?(node['href']) + + if rel.empty? + node['rel']&.delete + else + node['rel'] = rel.join(' ') + end + end + + LINK_TARGET_TRANSFORMER = lambda do |env| + return unless env[:node_name] == 'a' && env[:node]['href'] + + node = env[:node] + if node['target'] != '_blank' && TagManager.instance.local_url?(node['href']) + node['target']&.delete + else + node['target'] = '_blank' + end + end + + MASTODON_OUTGOING ||= freeze_config MASTODON_STRICT.merge( + attributes: merge( + MASTODON_STRICT[:attributes], + 'a' => %w(href rel class title target) + ), + + add_attributes: {}, + + transformers: [ + CLASS_WHITELIST_TRANSFORMER, + IMG_TAG_TRANSFORMER, + UNSUPPORTED_HREF_TRANSFORMER, + LINK_REL_TRANSFORMER, + LINK_TARGET_TRANSFORMER, + ] + ) end end diff --git a/package.json b/package.json index f35747bd9..99f0e3daa 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "test:lint": "${npm_execpath} run test:lint:js && ${npm_execpath} run test:lint:sass", "test:lint:js": "eslint --ext=js . --cache", "test:lint:sass": "sass-lint -v", - "test:jest": "cross-env NODE_ENV=test jest" + "test:jest": "cross-env NODE_ENV=test jest", + "format": "prettier --write '**/*.{json,yml}", + "format-check": "prettier --write '**/*.{json,yml}" }, "repository": { "type": "git", @@ -61,13 +63,13 @@ }, "private": true, "dependencies": { - "@babel/core": "^7.17.7", - "@babel/plugin-proposal-decorators": "^7.17.2", + "@babel/core": "^7.17.8", + "@babel/plugin-proposal-decorators": "^7.17.8", "@babel/plugin-transform-react-inline-elements": "^7.16.7", "@babel/plugin-transform-runtime": "^7.17.0", "@babel/preset-env": "^7.16.11", "@babel/preset-react": "^7.16.7", - "@babel/runtime": "^7.17.7", + "@babel/runtime": "^7.17.8", "@gamestdio/websocket": "^0.3.2", "@github/webauthn-json": "^0.5.7", "@rails/ujs": "^6.1.5", @@ -76,7 +78,7 @@ "atrament": "0.2.4", "autoprefixer": "^9.8.8", "axios": "^0.26.1", - "babel-loader": "^8.2.3", + "babel-loader": "^8.2.4", "babel-plugin-lodash": "^3.3.4", "babel-plugin-preval": "^5.1.0", "babel-plugin-react-intl": "^6.2.0", @@ -175,7 +177,7 @@ "ws": "^8.5.0" }, "devDependencies": { - "@testing-library/jest-dom": "^5.16.2", + "@testing-library/jest-dom": "^5.16.3", "@testing-library/react": "^12.1.4", "babel-eslint": "^10.1.0", "babel-jest": "^27.5.1", @@ -183,14 +185,15 @@ "eslint-plugin-import": "~2.25.4", "eslint-plugin-jsx-a11y": "~6.5.1", "eslint-plugin-promise": "~6.0.0", - "eslint-plugin-react": "~7.29.3", + "eslint-plugin-react": "~7.29.4", "jest": "^27.5.1", + "prettier": "^2.6.1", "raf": "^3.4.1", "react-intl-translations-manager": "^5.0.3", "react-test-renderer": "^16.14.0", "sass-lint": "^1.13.1", "webpack-dev-server": "^3.11.3", - "yargs": "^17.3.1" + "yargs": "^17.4.0" }, "resolutions": { "kind-of": "^6.0.3" diff --git a/scalingo.json b/scalingo.json index 51d9b5b9f..511c1802a 100644 --- a/scalingo.json +++ b/scalingo.json @@ -92,8 +92,5 @@ "scripts": { "postdeploy": "bundle exec rails db:migrate && bundle exec rails db:seed" }, - "addons": [ - "postgresql", - "redis" - ] + "addons": ["postgresql", "redis"] } diff --git a/spec/controllers/admin/accounts_controller_spec.rb b/spec/controllers/admin/accounts_controller_spec.rb index 0f71d697c..1779fb7c0 100644 --- a/spec/controllers/admin/accounts_controller_spec.rb +++ b/spec/controllers/admin/accounts_controller_spec.rb @@ -194,9 +194,7 @@ RSpec.describe Admin::AccountsController, type: :controller do end describe 'POST #unblock_email' do - subject do - -> { post :unblock_email, params: { id: account.id } } - end + subject { post :unblock_email, params: { id: account.id } } let(:current_user) { Fabricate(:user, admin: admin) } let(:account) { Fabricate(:account, suspended: true) } @@ -206,11 +204,11 @@ RSpec.describe Admin::AccountsController, type: :controller do let(:admin) { true } it 'succeeds in removing email blocks' do - is_expected.to change { CanonicalEmailBlock.where(reference_account: account).count }.from(1).to(0) + expect { subject }.to change { CanonicalEmailBlock.where(reference_account: account).count }.from(1).to(0) end it 'redirects to admin account path' do - subject.call + subject expect(response).to redirect_to admin_account_path(account.id) end end @@ -219,7 +217,7 @@ RSpec.describe Admin::AccountsController, type: :controller do let(:admin) { false } it 'fails to remove avatar' do - subject.call + subject expect(response).to have_http_status :forbidden end end diff --git a/spec/controllers/api/v1/admin/accounts_controller_spec.rb b/spec/controllers/api/v1/admin/accounts_controller_spec.rb index 3f61bbc0b..b69595f7e 100644 --- a/spec/controllers/api/v1/admin/accounts_controller_spec.rb +++ b/spec/controllers/api/v1/admin/accounts_controller_spec.rb @@ -30,15 +30,44 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do end describe 'GET #index' do + let!(:remote_account) { Fabricate(:account, domain: 'example.org') } + let!(:other_remote_account) { Fabricate(:account, domain: 'foo.bar') } + let!(:suspended_account) { Fabricate(:account, suspended: true) } + let!(:suspended_remote) { Fabricate(:account, domain: 'foo.bar', suspended: true) } + let!(:disabled_account) { Fabricate(:user, disabled: true).account } + let!(:pending_account) { Fabricate(:user, approved: false).account } + let!(:admin_account) { user.account } + + let(:params) { {} } + before do - get :index + pending_account.user.update(approved: false) + get :index, params: params end it_behaves_like 'forbidden for wrong scope', 'write:statuses' it_behaves_like 'forbidden for wrong role', 'user' - it 'returns http success' do - expect(response).to have_http_status(200) + [ + [{ active: 'true', local: 'true', staff: 'true' }, [:admin_account]], + [{ by_domain: 'example.org', remote: 'true' }, [:remote_account]], + [{ suspended: 'true' }, [:suspended_account]], + [{ disabled: 'true' }, [:disabled_account]], + [{ pending: 'true' }, [:pending_account]], + ].each do |params, expected_results| + context "when called with #{params.inspect}" do + let(:params) { params } + + it 'returns http success' do + expect(response).to have_http_status(200) + end + + it "returns the correct accounts (#{expected_results.inspect})" do + json = body_as_json + + expect(json.map { |a| a[:id].to_i }).to eq (expected_results.map { |symbol| send(symbol).id }) + end + end end end diff --git a/spec/controllers/api/v2/admin/accounts_controller_spec.rb b/spec/controllers/api/v2/admin/accounts_controller_spec.rb new file mode 100644 index 000000000..3212ddb84 --- /dev/null +++ b/spec/controllers/api/v2/admin/accounts_controller_spec.rb @@ -0,0 +1,73 @@ +require 'rails_helper' + +RSpec.describe Api::V2::Admin::AccountsController, type: :controller do + render_views + + let(:role) { 'moderator' } + let(:user) { Fabricate(:user, role: role) } + let(:scopes) { 'admin:read admin:write' } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:account) { Fabricate(:account) } + + before do + allow(controller).to receive(:doorkeeper_token) { token } + end + + shared_examples 'forbidden for wrong scope' do |wrong_scope| + let(:scopes) { wrong_scope } + + it 'returns http forbidden' do + expect(response).to have_http_status(403) + end + end + + shared_examples 'forbidden for wrong role' do |wrong_role| + let(:role) { wrong_role } + + it 'returns http forbidden' do + expect(response).to have_http_status(403) + end + end + + describe 'GET #index' do + let!(:remote_account) { Fabricate(:account, domain: 'example.org') } + let!(:other_remote_account) { Fabricate(:account, domain: 'foo.bar') } + let!(:suspended_account) { Fabricate(:account, suspended: true) } + let!(:suspended_remote) { Fabricate(:account, domain: 'foo.bar', suspended: true) } + let!(:disabled_account) { Fabricate(:user, disabled: true).account } + let!(:pending_account) { Fabricate(:user, approved: false).account } + let!(:admin_account) { user.account } + + let(:params) { {} } + + before do + pending_account.user.update(approved: false) + get :index, params: params + end + + it_behaves_like 'forbidden for wrong scope', 'write:statuses' + it_behaves_like 'forbidden for wrong role', 'user' + + [ + [{ status: 'active', origin: 'local', permissions: 'staff' }, [:admin_account]], + [{ by_domain: 'example.org', origin: 'remote' }, [:remote_account]], + [{ status: 'suspended' }, [:suspended_remote, :suspended_account]], + [{ status: 'disabled' }, [:disabled_account]], + [{ status: 'pending' }, [:pending_account]], + ].each do |params, expected_results| + context "when called with #{params.inspect}" do + let(:params) { params } + + it 'returns http success' do + expect(response).to have_http_status(200) + end + + it "returns the correct accounts (#{expected_results.inspect})" do + json = body_as_json + + expect(json.map { |a| a[:id].to_i }).to eq (expected_results.map { |symbol| send(symbol).id }) + end + end + end + end +end diff --git a/spec/controllers/settings/exports/bookmarks_controller_specs.rb b/spec/controllers/settings/exports/bookmarks_controller_spec.rb index 85761577b..a06c02e0c 100644 --- a/spec/controllers/settings/exports/bookmarks_controller_specs.rb +++ b/spec/controllers/settings/exports/bookmarks_controller_spec.rb @@ -3,11 +3,16 @@ require 'rails_helper' describe Settings::Exports::BookmarksController do render_views + let(:user) { Fabricate(:user) } + let(:account) { Fabricate(:account, domain: 'foo.bar') } + let(:status) { Fabricate(:status, account: account, uri: 'https://foo.bar/statuses/1312') } + describe 'GET #index' do - it 'returns a csv of the bookmarked toots' do - user = Fabricate(:user) - user.account.bookmarks.create!(status: Fabricate(:status, uri: 'https://foo.bar/statuses/1312')) + before do + user.account.bookmarks.create!(status: status) + end + it 'returns a csv of the bookmarked toots' do sign_in user, scope: :user get :index, format: :csv diff --git a/spec/lib/advanced_text_formatter_spec.rb b/spec/lib/advanced_text_formatter_spec.rb new file mode 100644 index 000000000..4e859c93c --- /dev/null +++ b/spec/lib/advanced_text_formatter_spec.rb @@ -0,0 +1,282 @@ +require 'rails_helper' + +RSpec.describe AdvancedTextFormatter do + describe '#to_s' do + let(:preloaded_accounts) { nil } + let(:content_type) { 'text/markdown' } + + subject { described_class.new(text, preloaded_accounts: preloaded_accounts, content_type: content_type).to_s } + + context 'given a markdown source' do + let(:content_type) { 'text/markdown' } + + context 'given text containing plain text' do + let(:text) { 'text' } + + it 'paragraphizes the text' do + is_expected.to eq '<p>text</p>' + end + end + + context 'given text containing line feeds' do + let(:text) { "line\nfeed" } + + it 'removes line feeds' do + is_expected.not_to include "\n" + end + end + + context 'given some inline code using backticks' do + let(:text) { 'test `foo` bar' } + + it 'formats code using <code>' do + is_expected.to include 'test <code>foo</code> bar' + end + end + + context 'given a block code' do + let(:text) { "test\n\n```\nint main(void) {\n return 0;\n}\n```\n" } + + it 'formats code using <pre> and <code>' do + is_expected.to include '<pre><code>int main' + end + end + + context 'given some quote' do + let(:text) { "> foo\n\nbar" } + + it 'formats code using <code>' do + is_expected.to include '<blockquote><p>foo</p></blockquote>' + end + end + + context 'given text containing linkable mentions' do + let(:preloaded_accounts) { [Fabricate(:account, username: 'alice')] } + let(:text) { '@alice' } + + it 'creates a mention link' do + is_expected.to include '<a href="https://cb6e6126.ngrok.io/@alice" class="u-url mention">@<span>alice</span></a></span>' + end + end + + context 'given text containing unlinkable mentions' do + let(:preloaded_accounts) { [] } + let(:text) { '@alice' } + + it 'does not create a mention link' do + is_expected.to include '@alice' + end + end + + context 'given a stand-alone medium URL' do + let(:text) { 'https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4' } + + it 'matches the full URL' do + is_expected.to include 'href="https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4"' + end + end + + context 'given a stand-alone google URL' do + let(:text) { 'http://google.com' } + + it 'matches the full URL' do + is_expected.to include 'href="http://google.com"' + end + end + + context 'given a stand-alone URL with a newer TLD' do + let(:text) { 'http://example.gay' } + + it 'matches the full URL' do + is_expected.to include 'href="http://example.gay"' + end + end + + context 'given a stand-alone IDN URL' do + let(:text) { 'https://nic.みんな/' } + + it 'matches the full URL' do + is_expected.to include 'href="https://nic.みんな/"' + end + + it 'has display URL' do + is_expected.to include '<span class="">nic.みんな/</span>' + end + end + + context 'given a URL with a trailing period' do + let(:text) { 'http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona. ' } + + it 'matches the full URL but not the period' do + is_expected.to include 'href="http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona"' + end + end + + context 'given a URL enclosed with parentheses' do + let(:text) { '(http://google.com/)' } + + it 'matches the full URL but not the parentheses' do + is_expected.to include 'href="http://google.com/"' + end + end + + context 'given a URL with a trailing exclamation point' do + let(:text) { 'http://www.google.com!' } + + it 'matches the full URL but not the exclamation point' do + is_expected.to include 'href="http://www.google.com"' + end + end + + context 'given a URL with a trailing single quote' do + let(:text) { "http://www.google.com'" } + + it 'matches the full URL but not the single quote' do + is_expected.to include 'href="http://www.google.com"' + end + end + end + + context 'given a URL with a trailing angle bracket' do + let(:text) { 'http://www.google.com>' } + + it 'matches the full URL but not the angle bracket' do + is_expected.to include 'href="http://www.google.com"' + end + end + + context 'given a URL with a query string' do + context 'with escaped unicode character' do + let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' } + + it 'matches the full URL' do + is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink"' + end + end + + context 'with unicode character' do + let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓&q=autolink' } + + it 'matches the full URL' do + is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=✓&q=autolink"' + end + end + + context 'with unicode character at the end' do + let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓' } + + it 'matches the full URL' do + is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=✓"' + end + end + + context 'with escaped and not escaped unicode characters' do + let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink' } + + it 'preserves escaped unicode characters' do + is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink"' + end + end + + context 'given a URL with parentheses in it' do + let(:text) { 'https://en.wikipedia.org/wiki/Diaspora_(software)' } + + it 'matches the full URL' do + is_expected.to include 'href="https://en.wikipedia.org/wiki/Diaspora_(software)"' + end + end + + context 'given a URL in quotation marks' do + let(:text) { '"https://example.com/"' } + + it 'does not match the quotation marks' do + is_expected.to include 'href="https://example.com/"' + end + end + + context 'given a URL in angle brackets' do + let(:text) { '<https://example.com/>' } + + it 'does not match the angle brackets' do + is_expected.to include 'href="https://example.com/"' + end + end + + context 'given a URL containing unsafe code (XSS attack, invisible part)' do + let(:text) { %q{http://example.com/blahblahblahblah/a<script>alert("Hello")</script>} } + + it 'does not include the HTML in the URL' do + is_expected.to include '"http://example.com/blahblahblahblah/a"' + end + + it 'does not include a script tag' do + is_expected.to_not include '<script>' + end + end + + context 'given text containing HTML code (script tag)' do + let(:text) { '<script>alert("Hello")</script>' } + + it 'does not include a script tag' do + is_expected.to_not include '<script>' + end + end + + context 'given text containing HTML (XSS attack)' do + let(:text) { %q{<img src="javascript:alert('XSS');">} } + + it 'does not include the javascript' do + is_expected.to_not include 'href="javascript:' + end + end + + context 'given an invalid URL' do + let(:text) { 'http://www\.google\.com' } + + it 'outputs the raw URL' do + is_expected.to eq '<p>http://www\.google\.com</p>' + end + end + + context 'given text containing a hashtag' do + let(:text) { '#hashtag' } + + it 'creates a hashtag link' do + is_expected.to include '/tags/hashtag" class="mention hashtag" rel="tag">#<span>hashtag</span></a>' + end + end + + context 'given text containing a hashtag with Unicode chars' do + let(:text) { '#hashtagタグ' } + + it 'creates a hashtag link' do + is_expected.to include '/tags/hashtag%E3%82%BF%E3%82%B0" class="mention hashtag" rel="tag">#<span>hashtagタグ</span></a>' + end + end + + context 'given text with a stand-alone xmpp: URI' do + let(:text) { 'xmpp:user@instance.com' } + + it 'matches the full URI' do + is_expected.to include 'href="xmpp:user@instance.com"' + end + end + + context 'given text with an xmpp: URI with a query-string' do + let(:text) { 'please join xmpp:muc@instance.com?join right now' } + + it 'matches the full URI' do + is_expected.to include 'href="xmpp:muc@instance.com?join"' + end + end + + context 'given text containing a magnet: URI' do + let(:text) { 'wikipedia gives this example of a magnet uri: magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a' } + + it 'matches the full URI' do + is_expected.to include 'href="magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a"' + end + end + end + end +end diff --git a/spec/lib/emoji_formatter_spec.rb b/spec/lib/emoji_formatter_spec.rb new file mode 100644 index 000000000..129445aa5 --- /dev/null +++ b/spec/lib/emoji_formatter_spec.rb @@ -0,0 +1,55 @@ +require 'rails_helper' + +RSpec.describe EmojiFormatter do + let!(:emoji) { Fabricate(:custom_emoji, shortcode: 'coolcat') } + + def preformat_text(str) + TextFormatter.new(str).to_s + end + + describe '#to_s' do + subject { described_class.new(text, emojis).to_s } + + let(:emojis) { [emoji] } + + context 'given text that is not marked as html-safe' do + let(:text) { 'Foo' } + + it 'raises an argument error' do + expect { subject }.to raise_error ArgumentError + end + end + + context 'given text with an emoji shortcode at the start' do + let(:text) { preformat_text(':coolcat: Beep boop') } + + it 'converts the shortcode to an image tag' do + is_expected.to match(/<img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) + end + end + + context 'given text with an emoji shortcode in the middle' do + let(:text) { preformat_text('Beep :coolcat: boop') } + + it 'converts the shortcode to an image tag' do + is_expected.to match(/Beep <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) + end + end + + context 'given text with concatenated emoji shortcodes' do + let(:text) { preformat_text(':coolcat::coolcat:') } + + it 'does not touch the shortcodes' do + is_expected.to match(/:coolcat::coolcat:/) + end + end + + context 'given text with an emoji shortcode at the end' do + let(:text) { preformat_text('Beep boop :coolcat:') } + + it 'converts the shortcode to an image tag' do + is_expected.to match(/boop <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) + end + end + end +end diff --git a/spec/lib/formatter_spec.rb b/spec/lib/formatter_spec.rb deleted file mode 100644 index 73cb39550..000000000 --- a/spec/lib/formatter_spec.rb +++ /dev/null @@ -1,638 +0,0 @@ -require 'rails_helper' - -RSpec.describe Formatter do - let(:local_account) { Fabricate(:account, domain: nil, username: 'alice') } - let(:remote_account) { Fabricate(:account, domain: 'remote.test', username: 'bob', url: 'https://remote.test/') } - - shared_examples 'encode and link URLs' do - context 'given a stand-alone medium URL' do - let(:text) { 'https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4' } - - it 'matches the full URL' do - is_expected.to include 'href="https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4"' - end - end - - context 'given a stand-alone google URL' do - let(:text) { 'http://google.com' } - - it 'matches the full URL' do - is_expected.to include 'href="http://google.com"' - end - end - - context 'given a stand-alone URL with a newer TLD' do - let(:text) { 'http://example.gay' } - - it 'matches the full URL' do - is_expected.to include 'href="http://example.gay"' - end - end - - context 'given a stand-alone IDN URL' do - let(:text) { 'https://nic.みんな/' } - - it 'matches the full URL' do - is_expected.to include 'href="https://nic.みんな/"' - end - - it 'has display URL' do - is_expected.to include '<span class="">nic.みんな/</span>' - end - end - - context 'given a URL with a trailing period' do - let(:text) { 'http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona. ' } - - it 'matches the full URL but not the period' do - is_expected.to include 'href="http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona"' - end - end - - context 'given a URL enclosed with parentheses' do - let(:text) { '(http://google.com/)' } - - it 'matches the full URL but not the parentheses' do - is_expected.to include 'href="http://google.com/"' - end - end - - context 'given a URL with a trailing exclamation point' do - let(:text) { 'http://www.google.com!' } - - it 'matches the full URL but not the exclamation point' do - is_expected.to include 'href="http://www.google.com"' - end - end - - context 'given a URL with a trailing single quote' do - let(:text) { "http://www.google.com'" } - - it 'matches the full URL but not the single quote' do - is_expected.to include 'href="http://www.google.com"' - end - end - - context 'given a URL with a trailing angle bracket' do - let(:text) { 'http://www.google.com>' } - - it 'matches the full URL but not the angle bracket' do - is_expected.to include 'href="http://www.google.com"' - end - end - - context 'given a URL with a query string' do - context 'with escaped unicode character' do - let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' } - - it 'matches the full URL' do - is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink"' - end - end - - context 'with unicode character' do - let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓&q=autolink' } - - it 'matches the full URL' do - is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=✓&q=autolink"' - end - end - - context 'with unicode character at the end' do - let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓' } - - it 'matches the full URL' do - is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=✓"' - end - end - - context 'with escaped and not escaped unicode characters' do - let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink' } - - it 'preserves escaped unicode characters' do - is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink"' - end - end - end - - context 'given a URL with parentheses in it' do - let(:text) { 'https://en.wikipedia.org/wiki/Diaspora_(software)' } - - it 'matches the full URL' do - is_expected.to include 'href="https://en.wikipedia.org/wiki/Diaspora_(software)"' - end - end - - context 'given a URL in quotation marks' do - let(:text) { '"https://example.com/"' } - - it 'does not match the quotation marks' do - is_expected.to include 'href="https://example.com/"' - end - end - - context 'given a URL in angle brackets' do - let(:text) { '<https://example.com/>' } - - it 'does not match the angle brackets' do - is_expected.to include 'href="https://example.com/"' - end - end - - context 'given a URL with Japanese path string' do - let(:text) { 'https://ja.wikipedia.org/wiki/日本' } - - it 'matches the full URL' do - is_expected.to include 'href="https://ja.wikipedia.org/wiki/日本"' - end - end - - context 'given a URL with Korean path string' do - let(:text) { 'https://ko.wikipedia.org/wiki/대한민국' } - - it 'matches the full URL' do - is_expected.to include 'href="https://ko.wikipedia.org/wiki/대한민국"' - end - end - - context 'given a URL with a full-width space' do - let(:text) { 'https://example.com/ abc123' } - - it 'does not match the full-width space' do - is_expected.to include 'href="https://example.com/"' - end - end - - context 'given a URL in Japanese quotation marks' do - let(:text) { '「[https://example.org/」' } - - it 'does not match the quotation marks' do - is_expected.to include 'href="https://example.org/"' - end - end - - context 'given a URL with Simplified Chinese path string' do - let(:text) { 'https://baike.baidu.com/item/中华人民共和国' } - - it 'matches the full URL' do - is_expected.to include 'href="https://baike.baidu.com/item/中华人民共和国"' - end - end - - context 'given a URL with Traditional Chinese path string' do - let(:text) { 'https://zh.wikipedia.org/wiki/臺灣' } - - it 'matches the full URL' do - is_expected.to include 'href="https://zh.wikipedia.org/wiki/臺灣"' - end - end - - context 'given a URL containing unsafe code (XSS attack, visible part)' do - let(:text) { %q{http://example.com/b<del>b</del>} } - - it 'does not include the HTML in the URL' do - is_expected.to include '"http://example.com/b"' - end - - it 'escapes the HTML' do - is_expected.to include '<del>b</del>' - end - end - - context 'given a URL containing unsafe code (XSS attack, invisible part)' do - let(:text) { %q{http://example.com/blahblahblahblah/a<script>alert("Hello")</script>} } - - it 'does not include the HTML in the URL' do - is_expected.to include '"http://example.com/blahblahblahblah/a"' - end - - it 'escapes the HTML' do - is_expected.to include '<script>alert("Hello")</script>' - end - end - - context 'given text containing HTML code (script tag)' do - let(:text) { '<script>alert("Hello")</script>' } - - it 'escapes the HTML' do - is_expected.to include '<p><script>alert("Hello")</script></p>' - end - end - - context 'given text containing HTML (XSS attack)' do - let(:text) { %q{<img src="javascript:alert('XSS');">} } - - it 'escapes the HTML' do - is_expected.to include '<p><img src="javascript:alert('XSS');"></p>' - end - end - - context 'given an invalid URL' do - let(:text) { 'http://www\.google\.com' } - - it 'outputs the raw URL' do - is_expected.to eq '<p>http://www\.google\.com</p>' - end - end - - context 'given text containing a hashtag' do - let(:text) { '#hashtag' } - - it 'creates a hashtag link' do - is_expected.to include '/tags/hashtag" class="mention hashtag" rel="tag">#<span>hashtag</span></a>' - end - end - - context 'given text containing a hashtag with Unicode chars' do - let(:text) { '#hashtagタグ' } - - it 'creates a hashtag link' do - is_expected.to include '/tags/hashtag%E3%82%BF%E3%82%B0" class="mention hashtag" rel="tag">#<span>hashtagタグ</span></a>' - end - end - - context 'given a stand-alone xmpp: URI' do - let(:text) { 'xmpp:user@instance.com' } - - it 'matches the full URI' do - is_expected.to include 'href="xmpp:user@instance.com"' - end - end - - context 'given a an xmpp: URI with a query-string' do - let(:text) { 'please join xmpp:muc@instance.com?join right now' } - - it 'matches the full URI' do - is_expected.to include 'href="xmpp:muc@instance.com?join"' - end - end - - context 'given text containing a magnet: URI' do - let(:text) { 'wikipedia gives this example of a magnet uri: magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a' } - - it 'matches the full URI' do - is_expected.to include 'href="magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a"' - end - end - end - - describe '#format_spoiler' do - subject { Formatter.instance.format_spoiler(status) } - - context 'given a post containing plain text' do - let(:status) { Fabricate(:status, text: 'text', spoiler_text: 'Secret!', uri: nil) } - - it 'Returns the spoiler text' do - is_expected.to eq 'Secret!' - end - end - - context 'given a post with an emoji shortcode at the start' do - let!(:emoji) { Fabricate(:custom_emoji) } - let(:status) { Fabricate(:status, text: 'text', spoiler_text: ':coolcat: Secret!', uri: nil) } - let(:text) { ':coolcat: Beep boop' } - - it 'converts the shortcode to an image tag' do - is_expected.to match(/<img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - end - - describe '#format' do - subject { Formatter.instance.format(status) } - - context 'given a post with local status' do - context 'given a reblogged post' do - let(:reblog) { Fabricate(:status, account: local_account, text: 'Hello world', uri: nil) } - let(:status) { Fabricate(:status, reblog: reblog) } - - it 'returns original status with credit to its author' do - is_expected.to include 'RT <span class="h-card"><a href="https://cb6e6126.ngrok.io/@alice" class="u-url mention">@<span>alice</span></a></span> Hello world' - end - end - - context 'given a post containing plain text' do - let(:status) { Fabricate(:status, text: 'text', uri: nil) } - - it 'paragraphizes the text' do - is_expected.to eq '<p>text</p>' - end - end - - context 'given a post containing line feeds' do - let(:status) { Fabricate(:status, text: "line\nfeed", uri: nil) } - - it 'removes line feeds' do - is_expected.not_to include "\n" - end - end - - context 'given a post containing linkable mentions' do - let(:status) { Fabricate(:status, mentions: [ Fabricate(:mention, account: local_account) ], text: '@alice') } - - it 'creates a mention link' do - is_expected.to include '<a href="https://cb6e6126.ngrok.io/@alice" class="u-url mention">@<span>alice</span></a></span>' - end - end - - context 'given a post containing unlinkable mentions' do - let(:status) { Fabricate(:status, text: '@alice', uri: nil) } - - it 'does not create a mention link' do - is_expected.to include '@alice' - end - end - - context do - let(:content_type) { 'text/plain' } - - subject do - status = Fabricate(:status, text: text, content_type: content_type, uri: nil) - Formatter.instance.format(status) - end - - context 'given an invalid URL (invalid port)' do - let(:text) { 'https://foo.bar:X/' } - let(:content_type) { 'text/markdown' } - - it 'outputs the raw URL' do - is_expected.to eq '<p>https://foo.bar:X/</p>' - end - end - - include_examples 'encode and link URLs' - end - - context 'given a post with custom_emojify option' do - let!(:emoji) { Fabricate(:custom_emoji) } - let(:status) { Fabricate(:status, account: local_account, text: text) } - - subject { Formatter.instance.format(status, custom_emojify: true) } - - context 'given a post with an emoji shortcode at the start' do - let(:text) { ':coolcat: Beep boop' } - - it 'converts the shortcode to an image tag' do - is_expected.to match(/<p><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - - context 'given a post with an emoji shortcode in the middle' do - let(:text) { 'Beep :coolcat: boop' } - - it 'converts the shortcode to an image tag' do - is_expected.to match(/Beep <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - - context 'given a post with concatenated emoji shortcodes' do - let(:text) { ':coolcat::coolcat:' } - - it 'does not touch the shortcodes' do - is_expected.to match(/:coolcat::coolcat:/) - end - end - - context 'given a post with an emoji shortcode at the end' do - let(:text) { 'Beep boop :coolcat:' } - - it 'converts the shortcode to an image tag' do - is_expected.to match(/boop <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - end - end - - context 'given a post with remote status' do - let(:status) { Fabricate(:status, account: remote_account, text: 'Beep boop') } - - it 'reformats the post' do - is_expected.to eq 'Beep boop' - end - - context 'given a post with custom_emojify option' do - let!(:emoji) { Fabricate(:custom_emoji, domain: remote_account.domain) } - let(:status) { Fabricate(:status, account: remote_account, text: text) } - - subject { Formatter.instance.format(status, custom_emojify: true) } - - context 'given a post with an emoji shortcode at the start' do - let(:text) { '<p>:coolcat: Beep boop<br />' } - - it 'converts the shortcode to an image tag' do - is_expected.to match(/<p><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - - context 'given a post with an emoji shortcode in the middle' do - let(:text) { '<p>Beep :coolcat: boop</p>' } - - it 'converts the shortcode to an image tag' do - is_expected.to match(/Beep <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - - context 'given a post with concatenated emoji' do - let(:text) { '<p>:coolcat::coolcat:</p>' } - - it 'does not touch the shortcodes' do - is_expected.to match(/<p>:coolcat::coolcat:<\/p>/) - end - end - - context 'given a post with an emoji shortcode at the end' do - let(:text) { '<p>Beep boop<br />:coolcat:</p>' } - - it 'converts the shortcode to an image tag' do - is_expected.to match(/<br><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - end - end - end - - describe '#reformat' do - subject { Formatter.instance.reformat(text) } - - context 'given a post containing plain text' do - let(:text) { 'Beep boop' } - - it 'keeps the plain text' do - is_expected.to include 'Beep boop' - end - end - - context 'given a post containing script tags' do - let(:text) { '<script>alert("Hello")</script>' } - - it 'strips the scripts' do - is_expected.to_not include '<script>alert("Hello")</script>' - end - end - - context 'given a post containing malicious classes' do - let(:text) { '<span class="mention status__content__spoiler-link">Show more</span>' } - - it 'strips the malicious classes' do - is_expected.to_not include 'status__content__spoiler-link' - end - end - end - - describe '#plaintext' do - subject { Formatter.instance.plaintext(status) } - - context 'given a post with local status' do - let(:status) { Fabricate(:status, text: '<p>a text by a nerd who uses an HTML tag in text</p>', content_type: content_type, uri: nil) } - let(:content_type) { 'text/plain' } - - it 'returns the raw text' do - is_expected.to eq '<p>a text by a nerd who uses an HTML tag in text</p>' - end - end - - context 'given a post with remote status' do - let(:status) { Fabricate(:status, account: remote_account, text: '<script>alert("Hello")</script>') } - - it 'returns tag-stripped text' do - is_expected.to eq '' - end - end - end - - describe '#simplified_format' do - subject { Formatter.instance.simplified_format(account) } - - context 'given a post with local status' do - let(:account) { Fabricate(:account, domain: nil, note: text) } - - context 'given a post containing linkable mentions for local accounts' do - let(:text) { '@alice' } - - before { local_account } - - it 'creates a mention link' do - is_expected.to eq '<p><span class="h-card"><a href="https://cb6e6126.ngrok.io/@alice" class="u-url mention">@<span>alice</span></a></span></p>' - end - end - - context 'given a post containing linkable mentions for remote accounts' do - let(:text) { '@bob@remote.test' } - - before { remote_account } - - it 'creates a mention link' do - is_expected.to eq '<p><span class="h-card"><a href="https://remote.test/" class="u-url mention">@<span>bob</span></a></span></p>' - end - end - - context 'given a post containing unlinkable mentions' do - let(:text) { '@alice' } - - it 'does not create a mention link' do - is_expected.to eq '<p>@alice</p>' - end - end - - context 'given a post with custom_emojify option' do - let!(:emoji) { Fabricate(:custom_emoji) } - - before { account.note = text } - subject { Formatter.instance.simplified_format(account, custom_emojify: true) } - - context 'given a post with an emoji shortcode at the start' do - let(:text) { ':coolcat: Beep boop' } - - it 'converts the shortcode to an image tag' do - is_expected.to match(/<p><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - - context 'given a post with an emoji shortcode in the middle' do - let(:text) { 'Beep :coolcat: boop' } - - it 'converts the shortcode to an image tag' do - is_expected.to match(/Beep <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - - context 'given a post with concatenated emoji shortcodes' do - let(:text) { ':coolcat::coolcat:' } - - it 'does not touch the shortcodes' do - is_expected.to match(/:coolcat::coolcat:/) - end - end - - context 'given a post with an emoji shortcode at the end' do - let(:text) { 'Beep boop :coolcat:' } - - it 'converts the shortcode to an image tag' do - is_expected.to match(/boop <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - end - - include_examples 'encode and link URLs' - end - - context 'given a post with remote status' do - let(:text) { '<script>alert("Hello")</script>' } - let(:account) { Fabricate(:account, domain: 'remote', note: text) } - - it 'reformats' do - is_expected.to_not include '<script>alert("Hello")</script>' - end - - context 'with custom_emojify option' do - let!(:emoji) { Fabricate(:custom_emoji, domain: remote_account.domain) } - - before { remote_account.note = text } - - subject { Formatter.instance.simplified_format(remote_account, custom_emojify: true) } - - context 'given a post with an emoji shortcode at the start' do - let(:text) { '<p>:coolcat: Beep boop<br />' } - - it 'converts shortcode to image tag' do - is_expected.to match(/<p><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - - context 'given a post with an emoji shortcode in the middle' do - let(:text) { '<p>Beep :coolcat: boop</p>' } - - it 'converts shortcode to image tag' do - is_expected.to match(/Beep <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - - context 'given a post with concatenated emoji shortcodes' do - let(:text) { '<p>:coolcat::coolcat:</p>' } - - it 'does not touch the shortcodes' do - is_expected.to match(/<p>:coolcat::coolcat:<\/p>/) - end - end - - context 'given a post with an emoji shortcode at the end' do - let(:text) { '<p>Beep boop<br />:coolcat:</p>' } - - it 'converts shortcode to image tag' do - is_expected.to match(/<br><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/) - end - end - end - end - end - - describe '#sanitize' do - let(:html) { '<script>alert("Hello")</script>' } - - subject { Formatter.instance.sanitize(html, Sanitize::Config::MASTODON_STRICT) } - - it 'sanitizes' do - is_expected.to eq '' - end - end -end diff --git a/spec/lib/html_aware_formatter_spec.rb b/spec/lib/html_aware_formatter_spec.rb new file mode 100644 index 000000000..18d23abf5 --- /dev/null +++ b/spec/lib/html_aware_formatter_spec.rb @@ -0,0 +1,44 @@ +require 'rails_helper' + +RSpec.describe HtmlAwareFormatter do + describe '#to_s' do + subject { described_class.new(text, local).to_s } + + context 'when local' do + let(:local) { true } + let(:text) { 'Foo bar' } + + it 'returns formatted text' do + is_expected.to eq '<p>Foo bar</p>' + end + end + + context 'when remote' do + let(:local) { false } + + context 'given plain text' do + let(:text) { 'Beep boop' } + + it 'keeps the plain text' do + is_expected.to include 'Beep boop' + end + end + + context 'given text containing script tags' do + let(:text) { '<script>alert("Hello")</script>' } + + it 'strips the scripts' do + is_expected.to_not include '<script>alert("Hello")</script>' + end + end + + context 'given text containing malicious classes' do + let(:text) { '<span class="mention status__content__spoiler-link">Show more</span>' } + + it 'strips the malicious classes' do + is_expected.to_not include 'status__content__spoiler-link' + end + end + end + end +end diff --git a/spec/lib/link_details_extractor_spec.rb b/spec/lib/link_details_extractor_spec.rb index 84bb4579c..7ea867c61 100644 --- a/spec/lib/link_details_extractor_spec.rb +++ b/spec/lib/link_details_extractor_spec.rb @@ -25,6 +25,14 @@ RSpec.describe LinkDetailsExtractor do expect(subject.canonical_url).to eq 'https://foo.com/article' end end + + context 'when canonical URL is set to "null"' do + let(:html) { '<!doctype html><link rel="canonical" href="null" />' } + + it 'ignores the canonical URLs' do + expect(subject.canonical_url).to eq original_url + end + end end context 'when structured data is present' do diff --git a/spec/lib/plain_text_formatter_spec.rb b/spec/lib/plain_text_formatter_spec.rb new file mode 100644 index 000000000..c3d0ee630 --- /dev/null +++ b/spec/lib/plain_text_formatter_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe PlainTextFormatter do + describe '#to_s' do + subject { described_class.new(status.text, status.local?).to_s } + + context 'given a post with local status' do + let(:status) { Fabricate(:status, text: '<p>a text by a nerd who uses an HTML tag in text</p>', uri: nil) } + + it 'returns the raw text' do + is_expected.to eq '<p>a text by a nerd who uses an HTML tag in text</p>' + end + end + + context 'given a post with remote status' do + let(:remote_account) { Fabricate(:account, domain: 'remote.test', username: 'bob', url: 'https://remote.test/') } + let(:status) { Fabricate(:status, account: remote_account, text: '<p>Hello</p><script>alert("Hello")</script>') } + + it 'returns tag-stripped text' do + is_expected.to eq 'Hello' + end + end + end +end diff --git a/spec/lib/rss/serializer_spec.rb b/spec/lib/rss/serializer_spec.rb index 0364d13de..1da45d302 100644 --- a/spec/lib/rss/serializer_spec.rb +++ b/spec/lib/rss/serializer_spec.rb @@ -13,13 +13,6 @@ describe RSS::Serializer do subject { RSS::Serializer.new.send(:status_title, status) } - context 'if destroyed?' do - it 'returns "#{account.acct} deleted status"' do - status.destroy! - expect(subject).to eq "#{account.acct} deleted status" - end - end - context 'on a toot with long text' do let(:text) { "This toot's text is longer than the allowed number of characters" } diff --git a/spec/lib/sanitize_config_spec.rb b/spec/lib/sanitize_config_spec.rb index 8bcffb2e5..dc6418e5b 100644 --- a/spec/lib/sanitize_config_spec.rb +++ b/spec/lib/sanitize_config_spec.rb @@ -41,18 +41,8 @@ describe Sanitize::Config do end end - describe '::MASTODON_STRICT' do - subject { Sanitize::Config::MASTODON_STRICT } - - it_behaves_like 'common HTML sanitization' - - it 'keeps a with href and rel tag' do - expect(Sanitize.fragment('<a href="http://example.com" rel="tag">Test</a>', subject)).to eq '<a href="http://example.com" rel="tag nofollow noopener noreferrer" target="_blank">Test</a>' - end - end - - describe '::MASTODON_STRICT with outgoing toots' do - subject { Sanitize::Config::MASTODON_STRICT.merge(outgoing: true) } + describe '::MASTODON_OUTGOING' do + subject { Sanitize::Config::MASTODON_OUTGOING } around do |example| original_web_domain = Rails.configuration.x.web_domain @@ -62,9 +52,9 @@ describe Sanitize::Config do it_behaves_like 'common HTML sanitization' - it 'keeps a with href and rel tag, not adding to rel if url is local' do + it 'keeps a with href and rel tag, not adding to rel or target if url is local' do Rails.configuration.x.web_domain = 'domain.test' - expect(Sanitize.fragment('<a href="http://domain.test/tags/foo" rel="tag">Test</a>', subject)).to eq '<a href="http://domain.test/tags/foo" rel="tag" target="_blank">Test</a>' + expect(Sanitize.fragment('<a href="http://domain.test/tags/foo" rel="tag">Test</a>', subject)).to eq '<a href="http://domain.test/tags/foo" rel="tag">Test</a>' end end end diff --git a/spec/lib/text_formatter_spec.rb b/spec/lib/text_formatter_spec.rb new file mode 100644 index 000000000..52a9d2498 --- /dev/null +++ b/spec/lib/text_formatter_spec.rb @@ -0,0 +1,313 @@ +require 'rails_helper' + +RSpec.describe TextFormatter do + describe '#to_s' do + let(:preloaded_accounts) { nil } + + subject { described_class.new(text, preloaded_accounts: preloaded_accounts).to_s } + + context 'given text containing plain text' do + let(:text) { 'text' } + + it 'paragraphizes the text' do + is_expected.to eq '<p>text</p>' + end + end + + context 'given text containing line feeds' do + let(:text) { "line\nfeed" } + + it 'removes line feeds' do + is_expected.not_to include "\n" + end + end + + context 'given text containing linkable mentions' do + let(:preloaded_accounts) { [Fabricate(:account, username: 'alice')] } + let(:text) { '@alice' } + + it 'creates a mention link' do + is_expected.to include '<a href="https://cb6e6126.ngrok.io/@alice" class="u-url mention">@<span>alice</span></a></span>' + end + end + + context 'given text containing unlinkable mentions' do + let(:preloaded_accounts) { [] } + let(:text) { '@alice' } + + it 'does not create a mention link' do + is_expected.to include '@alice' + end + end + + context 'given a stand-alone medium URL' do + let(:text) { 'https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4' } + + it 'matches the full URL' do + is_expected.to include 'href="https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4"' + end + end + + context 'given a stand-alone google URL' do + let(:text) { 'http://google.com' } + + it 'matches the full URL' do + is_expected.to include 'href="http://google.com"' + end + end + + context 'given a stand-alone URL with a newer TLD' do + let(:text) { 'http://example.gay' } + + it 'matches the full URL' do + is_expected.to include 'href="http://example.gay"' + end + end + + context 'given a stand-alone IDN URL' do + let(:text) { 'https://nic.みんな/' } + + it 'matches the full URL' do + is_expected.to include 'href="https://nic.みんな/"' + end + + it 'has display URL' do + is_expected.to include '<span class="">nic.みんな/</span>' + end + end + + context 'given a URL with a trailing period' do + let(:text) { 'http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona. ' } + + it 'matches the full URL but not the period' do + is_expected.to include 'href="http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona"' + end + end + + context 'given a URL enclosed with parentheses' do + let(:text) { '(http://google.com/)' } + + it 'matches the full URL but not the parentheses' do + is_expected.to include 'href="http://google.com/"' + end + end + + context 'given a URL with a trailing exclamation point' do + let(:text) { 'http://www.google.com!' } + + it 'matches the full URL but not the exclamation point' do + is_expected.to include 'href="http://www.google.com"' + end + end + + context 'given a URL with a trailing single quote' do + let(:text) { "http://www.google.com'" } + + it 'matches the full URL but not the single quote' do + is_expected.to include 'href="http://www.google.com"' + end + end + + context 'given a URL with a trailing angle bracket' do + let(:text) { 'http://www.google.com>' } + + it 'matches the full URL but not the angle bracket' do + is_expected.to include 'href="http://www.google.com"' + end + end + + context 'given a URL with a query string' do + context 'with escaped unicode character' do + let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' } + + it 'matches the full URL' do + is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink"' + end + end + + context 'with unicode character' do + let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓&q=autolink' } + + it 'matches the full URL' do + is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=✓&q=autolink"' + end + end + + context 'with unicode character at the end' do + let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓' } + + it 'matches the full URL' do + is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=✓"' + end + end + + context 'with escaped and not escaped unicode characters' do + let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink' } + + it 'preserves escaped unicode characters' do + is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink"' + end + end + end + + context 'given a URL with parentheses in it' do + let(:text) { 'https://en.wikipedia.org/wiki/Diaspora_(software)' } + + it 'matches the full URL' do + is_expected.to include 'href="https://en.wikipedia.org/wiki/Diaspora_(software)"' + end + end + + context 'given a URL in quotation marks' do + let(:text) { '"https://example.com/"' } + + it 'does not match the quotation marks' do + is_expected.to include 'href="https://example.com/"' + end + end + + context 'given a URL in angle brackets' do + let(:text) { '<https://example.com/>' } + + it 'does not match the angle brackets' do + is_expected.to include 'href="https://example.com/"' + end + end + + context 'given a URL with Japanese path string' do + let(:text) { 'https://ja.wikipedia.org/wiki/日本' } + + it 'matches the full URL' do + is_expected.to include 'href="https://ja.wikipedia.org/wiki/日本"' + end + end + + context 'given a URL with Korean path string' do + let(:text) { 'https://ko.wikipedia.org/wiki/대한민국' } + + it 'matches the full URL' do + is_expected.to include 'href="https://ko.wikipedia.org/wiki/대한민국"' + end + end + + context 'given a URL with a full-width space' do + let(:text) { 'https://example.com/ abc123' } + + it 'does not match the full-width space' do + is_expected.to include 'href="https://example.com/"' + end + end + + context 'given a URL in Japanese quotation marks' do + let(:text) { '「[https://example.org/」' } + + it 'does not match the quotation marks' do + is_expected.to include 'href="https://example.org/"' + end + end + + context 'given a URL with Simplified Chinese path string' do + let(:text) { 'https://baike.baidu.com/item/中华人民共和国' } + + it 'matches the full URL' do + is_expected.to include 'href="https://baike.baidu.com/item/中华人民共和国"' + end + end + + context 'given a URL with Traditional Chinese path string' do + let(:text) { 'https://zh.wikipedia.org/wiki/臺灣' } + + it 'matches the full URL' do + is_expected.to include 'href="https://zh.wikipedia.org/wiki/臺灣"' + end + end + + context 'given a URL containing unsafe code (XSS attack, visible part)' do + let(:text) { %q{http://example.com/b<del>b</del>} } + + it 'does not include the HTML in the URL' do + is_expected.to include '"http://example.com/b"' + end + + it 'escapes the HTML' do + is_expected.to include '<del>b</del>' + end + end + + context 'given a URL containing unsafe code (XSS attack, invisible part)' do + let(:text) { %q{http://example.com/blahblahblahblah/a<script>alert("Hello")</script>} } + + it 'does not include the HTML in the URL' do + is_expected.to include '"http://example.com/blahblahblahblah/a"' + end + + it 'escapes the HTML' do + is_expected.to include '<script>alert("Hello")</script>' + end + end + + context 'given text containing HTML code (script tag)' do + let(:text) { '<script>alert("Hello")</script>' } + + it 'escapes the HTML' do + is_expected.to include '<p><script>alert("Hello")</script></p>' + end + end + + context 'given text containing HTML (XSS attack)' do + let(:text) { %q{<img src="javascript:alert('XSS');">} } + + it 'escapes the HTML' do + is_expected.to include '<p><img src="javascript:alert('XSS');"></p>' + end + end + + context 'given an invalid URL' do + let(:text) { 'http://www\.google\.com' } + + it 'outputs the raw URL' do + is_expected.to eq '<p>http://www\.google\.com</p>' + end + end + + context 'given text containing a hashtag' do + let(:text) { '#hashtag' } + + it 'creates a hashtag link' do + is_expected.to include '/tags/hashtag" class="mention hashtag" rel="tag">#<span>hashtag</span></a>' + end + end + + context 'given text containing a hashtag with Unicode chars' do + let(:text) { '#hashtagタグ' } + + it 'creates a hashtag link' do + is_expected.to include '/tags/hashtag%E3%82%BF%E3%82%B0" class="mention hashtag" rel="tag">#<span>hashtagタグ</span></a>' + end + end + + context 'given text with a stand-alone xmpp: URI' do + let(:text) { 'xmpp:user@instance.com' } + + it 'matches the full URI' do + is_expected.to include 'href="xmpp:user@instance.com"' + end + end + + context 'given text with an xmpp: URI with a query-string' do + let(:text) { 'please join xmpp:muc@instance.com?join right now' } + + it 'matches the full URI' do + is_expected.to include 'href="xmpp:muc@instance.com?join"' + end + end + + context 'given text containing a magnet: URI' do + let(:text) { 'wikipedia gives this example of a magnet uri: magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a' } + + it 'matches the full URI' do + is_expected.to include 'href="magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a"' + end + end + end +end diff --git a/spec/models/media_attachment_spec.rb b/spec/models/media_attachment_spec.rb index 7360b23cf..cbd9a09c5 100644 --- a/spec/models/media_attachment_spec.rb +++ b/spec/models/media_attachment_spec.rb @@ -186,14 +186,6 @@ RSpec.describe MediaAttachment, type: :model do expect(media.valid?).to be false end - describe 'descriptions for remote attachments' do - it 'are cut off at 1500 characters' do - media = Fabricate(:media_attachment, description: 'foo' * 1000, remote_url: 'http://example.com/blah.jpg') - - expect(media.description.size).to be <= 1_500 - end - end - describe 'size limit validation' do it 'rejects video files that are too large' do stub_const 'MediaAttachment::IMAGE_LIMIT', 100.megabytes diff --git a/spec/services/activitypub/process_status_update_service_spec.rb b/spec/services/activitypub/process_status_update_service_spec.rb index 788c7c9d9..f87adcae1 100644 --- a/spec/services/activitypub/process_status_update_service_spec.rb +++ b/spec/services/activitypub/process_status_update_service_spec.rb @@ -46,6 +46,29 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do expect(status.reload.spoiler_text).to eq 'Show more' end + context 'with no changes at all' do + let(:payload) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Note', + content: 'Hello world', + } + end + + before do + subject.call(status, json) + end + + it 'does not create any edits' do + expect(status.reload.edits).to be_empty + end + + it 'does not mark status as edited' do + expect(status.edited?).to be false + end + end + context 'with no changes and originally with no ordered_media_attachment_ids' do let(:payload) do { @@ -61,8 +84,12 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do subject.call(status, json) end - it 'does not record an update' do - expect(status.reload.edited?).to be false + it 'does not create any edits' do + expect(status.reload.edits).to be_empty + end + + it 'does not mark status as edited' do + expect(status.edited?).to be false end end diff --git a/spec/services/after_block_service_spec.rb b/spec/services/after_block_service_spec.rb index fe5b26b2b..c09425d7c 100644 --- a/spec/services/after_block_service_spec.rb +++ b/spec/services/after_block_service_spec.rb @@ -1,9 +1,7 @@ require 'rails_helper' RSpec.describe AfterBlockService, type: :service do - subject do - -> { described_class.new.call(account, target_account) } - end + subject { described_class.new.call(account, target_account) } let(:account) { Fabricate(:account) } let(:target_account) { Fabricate(:account) } @@ -24,7 +22,7 @@ RSpec.describe AfterBlockService, type: :service do FeedManager.instance.push_to_home(account, other_account_status) FeedManager.instance.push_to_home(account, other_account_reblog) - is_expected.to change { + expect { subject }.to change { Redis.current.zrange(home_timeline_key, 0, -1) }.from([status.id.to_s, other_account_status.id.to_s, other_account_reblog.id.to_s]).to([other_account_status.id.to_s]) end @@ -43,7 +41,7 @@ RSpec.describe AfterBlockService, type: :service do FeedManager.instance.push_to_list(list, other_account_status) FeedManager.instance.push_to_list(list, other_account_reblog) - is_expected.to change { + expect { subject }.to change { Redis.current.zrange(list_timeline_key, 0, -1) }.from([status.id.to_s, other_account_status.id.to_s, other_account_reblog.id.to_s]).to([other_account_status.id.to_s]) end diff --git a/spec/services/delete_account_service_spec.rb b/spec/services/delete_account_service_spec.rb index 9c785fc17..1fbe4d07c 100644 --- a/spec/services/delete_account_service_spec.rb +++ b/spec/services/delete_account_service_spec.rb @@ -23,12 +23,10 @@ RSpec.describe DeleteAccountService, type: :service do let!(:account_note) { Fabricate(:account_note, account: account) } - subject do - -> { described_class.new.call(account) } - end + subject { described_class.new.call(account) } it 'deletes associated owned records' do - is_expected.to change { + expect { subject }.to change { [ account.statuses, account.media_attachments, @@ -43,7 +41,7 @@ RSpec.describe DeleteAccountService, type: :service do end it 'deletes associated target records' do - is_expected.to change { + expect { subject }.to change { [ AccountPin.where(target_account: account), ].map(&:count) @@ -51,7 +49,7 @@ RSpec.describe DeleteAccountService, type: :service do end it 'deletes associated target notifications' do - is_expected.to change { + expect { subject }.to change { [ 'poll', 'favourite', 'status', 'mention', 'follow' ].map { |type| Notification.where(type: type).count } @@ -73,7 +71,7 @@ RSpec.describe DeleteAccountService, type: :service do let!(:local_follower) { Fabricate(:account) } it 'sends a delete actor activity to all known inboxes' do - subject.call + subject expect(a_request(:post, "https://alice.com/inbox")).to have_been_made.once expect(a_request(:post, "https://bob.com/inbox")).to have_been_made.once end @@ -91,7 +89,7 @@ RSpec.describe DeleteAccountService, type: :service do let!(:local_follower) { Fabricate(:account) } it 'sends a reject follow to follower inboxes' do - subject.call + subject expect(a_request(:post, account.inbox_url)).to have_been_made.once end end diff --git a/spec/services/mute_service_spec.rb b/spec/services/mute_service_spec.rb index 4bb839b8d..bdec1c67b 100644 --- a/spec/services/mute_service_spec.rb +++ b/spec/services/mute_service_spec.rb @@ -1,9 +1,7 @@ require 'rails_helper' RSpec.describe MuteService, type: :service do - subject do - -> { described_class.new.call(account, target_account) } - end + subject { described_class.new.call(account, target_account) } let(:account) { Fabricate(:account) } let(:target_account) { Fabricate(:account) } @@ -21,45 +19,41 @@ RSpec.describe MuteService, type: :service do FeedManager.instance.push_to_home(account, status) FeedManager.instance.push_to_home(account, other_account_status) - is_expected.to change { + expect { subject }.to change { Redis.current.zrange(home_timeline_key, 0, -1) }.from([status.id.to_s, other_account_status.id.to_s]).to([other_account_status.id.to_s]) end end it 'mutes account' do - is_expected.to change { + expect { subject }.to change { account.muting?(target_account) }.from(false).to(true) end context 'without specifying a notifications parameter' do it 'mutes notifications from the account' do - is_expected.to change { + expect { subject }.to change { account.muting_notifications?(target_account) }.from(false).to(true) end end context 'with a true notifications parameter' do - subject do - -> { described_class.new.call(account, target_account, notifications: true) } - end + subject { described_class.new.call(account, target_account, notifications: true) } it 'mutes notifications from the account' do - is_expected.to change { + expect { subject }.to change { account.muting_notifications?(target_account) }.from(false).to(true) end end context 'with a false notifications parameter' do - subject do - -> { described_class.new.call(account, target_account, notifications: false) } - end + subject { described_class.new.call(account, target_account, notifications: false) } it 'does not mute notifications from the account' do - is_expected.to_not change { + expect { subject }.to_not change { account.muting_notifications?(target_account) }.from(false) end diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb index 83e62ff36..67dd0483b 100644 --- a/spec/services/notify_service_spec.rb +++ b/spec/services/notify_service_spec.rb @@ -1,9 +1,7 @@ require 'rails_helper' RSpec.describe NotifyService, type: :service do - subject do - -> { described_class.new.call(recipient, type, activity) } - end + subject { described_class.new.call(recipient, type, activity) } let(:user) { Fabricate(:user) } let(:recipient) { user.account } @@ -11,42 +9,42 @@ RSpec.describe NotifyService, type: :service do let(:activity) { Fabricate(:follow, account: sender, target_account: recipient) } let(:type) { :follow } - it { is_expected.to change(Notification, :count).by(1) } + it { expect { subject }.to change(Notification, :count).by(1) } it 'does not notify when sender is blocked' do recipient.block!(sender) - is_expected.to_not change(Notification, :count) + expect { subject }.to_not change(Notification, :count) end it 'does not notify when sender is muted with hide_notifications' do recipient.mute!(sender, notifications: true) - is_expected.to_not change(Notification, :count) + expect { subject }.to_not change(Notification, :count) end it 'does notify when sender is muted without hide_notifications' do recipient.mute!(sender, notifications: false) - is_expected.to change(Notification, :count) + expect { subject }.to change(Notification, :count) end it 'does not notify when sender\'s domain is blocked' do recipient.block_domain!(sender.domain) - is_expected.to_not change(Notification, :count) + expect { subject }.to_not change(Notification, :count) end it 'does still notify when sender\'s domain is blocked but sender is followed' do recipient.block_domain!(sender.domain) recipient.follow!(sender) - is_expected.to change(Notification, :count) + expect { subject }.to change(Notification, :count) end it 'does not notify when sender is silenced and not followed' do sender.silence! - is_expected.to_not change(Notification, :count) + expect { subject }.to_not change(Notification, :count) end it 'does not notify when recipient is suspended' do recipient.suspend! - is_expected.to_not change(Notification, :count) + expect { subject }.to_not change(Notification, :count) end context 'for direct messages' do @@ -61,7 +59,7 @@ RSpec.describe NotifyService, type: :service do let(:enabled) { true } it 'does not notify' do - is_expected.to_not change(Notification, :count) + expect { subject }.to_not change(Notification, :count) end context 'if the message chain is initiated by recipient, but is not direct message' do @@ -70,7 +68,7 @@ RSpec.describe NotifyService, type: :service do let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct, thread: reply_to)) } it 'does not notify' do - is_expected.to_not change(Notification, :count) + expect { subject }.to_not change(Notification, :count) end end @@ -81,7 +79,7 @@ RSpec.describe NotifyService, type: :service do let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct, thread: dummy_reply)) } it 'does not notify' do - is_expected.to_not change(Notification, :count) + expect { subject }.to_not change(Notification, :count) end end @@ -91,7 +89,7 @@ RSpec.describe NotifyService, type: :service do let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct, thread: reply_to)) } it 'does notify' do - is_expected.to change(Notification, :count) + expect { subject }.to change(Notification, :count) end end end @@ -100,7 +98,7 @@ RSpec.describe NotifyService, type: :service do let(:enabled) { false } it 'does notify' do - is_expected.to change(Notification, :count) + expect { subject }.to change(Notification, :count) end end end @@ -112,17 +110,17 @@ RSpec.describe NotifyService, type: :service do it 'shows reblogs by default' do recipient.follow!(sender) - is_expected.to change(Notification, :count) + expect { subject }.to change(Notification, :count) end it 'shows reblogs when explicitly enabled' do recipient.follow!(sender, reblogs: true) - is_expected.to change(Notification, :count) + expect { subject }.to change(Notification, :count) end it 'shows reblogs when disabled' do recipient.follow!(sender, reblogs: false) - is_expected.to change(Notification, :count) + expect { subject }.to change(Notification, :count) end end @@ -134,12 +132,12 @@ RSpec.describe NotifyService, type: :service do it 'does not notify when conversation is muted' do recipient.mute_conversation!(activity.status.conversation) - is_expected.to_not change(Notification, :count) + expect { subject }.to_not change(Notification, :count) end it 'does not notify when it is a reply to a blocked user' do recipient.block!(asshole) - is_expected.to_not change(Notification, :count) + expect { subject }.to_not change(Notification, :count) end end @@ -147,7 +145,7 @@ RSpec.describe NotifyService, type: :service do let(:sender) { recipient } it 'does not notify when recipient is the sender' do - is_expected.to_not change(Notification, :count) + expect { subject }.to_not change(Notification, :count) end end @@ -163,7 +161,7 @@ RSpec.describe NotifyService, type: :service do let(:enabled) { true } it 'sends email' do - is_expected.to change(ActionMailer::Base.deliveries, :count).by(1) + expect { subject }.to change(ActionMailer::Base.deliveries, :count).by(1) end end @@ -171,7 +169,7 @@ RSpec.describe NotifyService, type: :service do let(:enabled) { false } it "doesn't send email" do - is_expected.to_not change(ActionMailer::Base.deliveries, :count).from(0) + expect { subject }.to_not change(ActionMailer::Base.deliveries, :count).from(0) end end end diff --git a/spec/services/suspend_account_service_spec.rb b/spec/services/suspend_account_service_spec.rb index cf7eb257a..5d45e4ffd 100644 --- a/spec/services/suspend_account_service_spec.rb +++ b/spec/services/suspend_account_service_spec.rb @@ -5,9 +5,7 @@ RSpec.describe SuspendAccountService, type: :service do let!(:local_follower) { Fabricate(:user, current_sign_in_at: 1.hour.ago).account } let!(:list) { Fabricate(:list, account: local_follower) } - subject do - -> { described_class.new.call(account) } - end + subject { described_class.new.call(account) } before do allow(FeedManager.instance).to receive(:unmerge_from_home).and_return(nil) @@ -18,13 +16,13 @@ RSpec.describe SuspendAccountService, type: :service do end it "unmerges from local followers' feeds" do - subject.call + subject expect(FeedManager.instance).to have_received(:unmerge_from_home).with(account, local_follower) expect(FeedManager.instance).to have_received(:unmerge_from_list).with(account, list) end it 'marks account as suspended' do - is_expected.to change { account.suspended? }.from(false).to(true) + expect { subject }.to change { account.suspended? }.from(false).to(true) end end @@ -51,7 +49,7 @@ RSpec.describe SuspendAccountService, type: :service do end it 'sends an update actor to followers and reporters' do - subject.call + subject expect(a_request(:post, remote_follower.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once expect(a_request(:post, remote_reporter.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once end @@ -77,7 +75,7 @@ RSpec.describe SuspendAccountService, type: :service do end it 'sends a reject follow' do - subject.call + subject expect(a_request(:post, account.inbox_url).with { |req| match_reject_follow_request(req, account, local_followee) }).to have_been_made.once end end diff --git a/spec/services/unsuspend_account_service_spec.rb b/spec/services/unsuspend_account_service_spec.rb index 0593beb6f..3ac4cc085 100644 --- a/spec/services/unsuspend_account_service_spec.rb +++ b/spec/services/unsuspend_account_service_spec.rb @@ -5,9 +5,7 @@ RSpec.describe UnsuspendAccountService, type: :service do let!(:local_follower) { Fabricate(:user, current_sign_in_at: 1.hour.ago).account } let!(:list) { Fabricate(:list, account: local_follower) } - subject do - -> { described_class.new.call(account) } - end + subject { described_class.new.call(account) } before do allow(FeedManager.instance).to receive(:merge_into_home).and_return(nil) @@ -33,7 +31,7 @@ RSpec.describe UnsuspendAccountService, type: :service do end it 'marks account as unsuspended' do - is_expected.to change { account.suspended? }.from(true).to(false) + expect { subject }.to change { account.suspended? }.from(true).to(false) end include_examples 'common behavior' do @@ -47,13 +45,13 @@ RSpec.describe UnsuspendAccountService, type: :service do end it "merges back into local followers' feeds" do - subject.call + subject expect(FeedManager.instance).to have_received(:merge_into_home).with(account, local_follower) expect(FeedManager.instance).to have_received(:merge_into_list).with(account, list) end it 'sends an update actor to followers and reporters' do - subject.call + subject expect(a_request(:post, remote_follower.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once expect(a_request(:post, remote_reporter.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once end @@ -75,18 +73,18 @@ RSpec.describe UnsuspendAccountService, type: :service do end it 're-fetches the account' do - subject.call + subject expect(resolve_account_service).to have_received(:call).with(account) end it "merges back into local followers' feeds" do - subject.call + subject expect(FeedManager.instance).to have_received(:merge_into_home).with(account, local_follower) expect(FeedManager.instance).to have_received(:merge_into_list).with(account, list) end it 'marks account as unsuspended' do - is_expected.to change { account.suspended? }.from(true).to(false) + expect { subject }.to change { account.suspended? }.from(true).to(false) end end @@ -99,18 +97,18 @@ RSpec.describe UnsuspendAccountService, type: :service do end it 're-fetches the account' do - subject.call + subject expect(resolve_account_service).to have_received(:call).with(account) end it "does not merge back into local followers' feeds" do - subject.call + subject expect(FeedManager.instance).to_not have_received(:merge_into_home).with(account, local_follower) expect(FeedManager.instance).to_not have_received(:merge_into_list).with(account, list) end it 'does not mark the account as unsuspended' do - is_expected.not_to change { account.suspended? } + expect { subject }.not_to change { account.suspended? } end end @@ -120,12 +118,12 @@ RSpec.describe UnsuspendAccountService, type: :service do end it 're-fetches the account' do - subject.call + subject expect(resolve_account_service).to have_received(:call).with(account) end it "does not merge back into local followers' feeds" do - subject.call + subject expect(FeedManager.instance).to_not have_received(:merge_into_home).with(account, local_follower) expect(FeedManager.instance).to_not have_received(:merge_into_list).with(account, list) end diff --git a/spec/services/update_status_service_spec.rb b/spec/services/update_status_service_spec.rb index 78cc89cd4..71a73be5b 100644 --- a/spec/services/update_status_service_spec.rb +++ b/spec/services/update_status_service_spec.rb @@ -3,6 +3,23 @@ require 'rails_helper' RSpec.describe UpdateStatusService, type: :service do subject { described_class.new } + context 'when nothing changes' do + let!(:status) { Fabricate(:status, text: 'Foo', language: 'en') } + + before do + allow(ActivityPub::DistributionWorker).to receive(:perform_async) + subject.call(status, status.account_id, text: 'Foo') + end + + it 'does not create an edit' do + expect(status.reload.edits).to be_empty + end + + it 'does not notify anyone' do + expect(ActivityPub::DistributionWorker).to_not have_received(:perform_async) + end + end + context 'when text changes' do let!(:status) { Fabricate(:status, text: 'Foo') } let(:preview_card) { Fabricate(:preview_card) } diff --git a/spec/validators/status_length_validator_spec.rb b/spec/validators/status_length_validator_spec.rb index 643ea6d22..4c80a59e6 100644 --- a/spec/validators/status_length_validator_spec.rb +++ b/spec/validators/status_length_validator_spec.rb @@ -55,6 +55,13 @@ describe StatusLengthValidator do expect(status.errors).to have_received(:add) end + it 'does not count overly long URLs as 23 characters flat' do + text = "http://example.com/valid?#{'#foo?' * 1000}" + status = double(spoiler_text: '', text: text, errors: double(add: nil), local?: true, reblog?: false) + subject.validate(status) + expect(status.errors).to have_received(:add) + end + it 'counts only the front part of remote usernames' do username = '@alice' chars = StatusLengthValidator::MAX_CHARS - 1 - username.length @@ -64,5 +71,13 @@ describe StatusLengthValidator do subject.validate(status) expect(status.errors).to_not have_received(:add) end + + it 'does count both parts of remote usernames for overly long domains' do + text = "@alice@#{'b' * 500}.com" + status = double(spoiler_text: '', text: text, errors: double(add: nil), local?: true, reblog?: false) + + subject.validate(status) + expect(status.errors).to have_received(:add) + end end end diff --git a/streaming/index.js b/streaming/index.js index 3fdc9615e..780c4015d 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -167,6 +167,11 @@ const startWorker = async (workerId) => { const redisPrefix = redisNamespace ? `${redisNamespace}:` : ''; + /** + * @type {Object.<string, Array.<function(string): void>>} + */ + const subs = {}; + const redisSubscribeClient = await redisUrlToClient(redisParams, process.env.REDIS_URL); const redisClient = await redisUrlToClient(redisParams, process.env.REDIS_URL); @@ -191,23 +196,55 @@ const startWorker = async (workerId) => { }; /** + * @param {string} message + * @param {string} channel + */ + const onRedisMessage = (message, channel) => { + const callbacks = subs[channel]; + + log.silly(`New message on channel ${channel}`); + + if (!callbacks) { + return; + } + + callbacks.forEach(callback => callback(message)); + }; + + /** * @param {string} channel * @param {function(string): void} callback */ const subscribe = (channel, callback) => { log.silly(`Adding listener for ${channel}`); - redisSubscribeClient.subscribe(channel, callback); + subs[channel] = subs[channel] || []; + + if (subs[channel].length === 0) { + log.verbose(`Subscribe ${channel}`); + redisSubscribeClient.subscribe(channel, onRedisMessage); + } + + subs[channel].push(callback); }; /** * @param {string} channel - * @param {function(string): void} callback */ const unsubscribe = (channel, callback) => { log.silly(`Removing listener for ${channel}`); - redisSubscribeClient.unsubscribe(channel, callback); + if (!subs[channel]) { + return; + } + + subs[channel] = subs[channel].filter(item => item !== callback); + + if (subs[channel].length === 0) { + log.verbose(`Unsubscribe ${channel}`); + redisSubscribeClient.unsubscribe(channel); + delete subs[channel]; + } }; const FALSE_VALUES = [ diff --git a/yarn.lock b/yarn.lock index f96a75354..173fbaeb3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -33,18 +33,18 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.17.7", "@babel/core@^7.7.2", "@babel/core@^7.8.0": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.7.tgz#f7c28228c83cdf2dbd1b9baa06eaf9df07f0c2f9" - integrity sha512-djHlEfFHnSnTAcPb7dATbiM5HxGOP98+3JLBZtjRb5I7RXrw7kFRoG2dXM8cm3H+o11A8IFH/uprmJpwFynRNQ== +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.17.8", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" + integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.16.7" "@babel/generator" "^7.17.7" "@babel/helper-compilation-targets" "^7.17.7" "@babel/helper-module-transforms" "^7.17.7" - "@babel/helpers" "^7.17.7" - "@babel/parser" "^7.17.7" + "@babel/helpers" "^7.17.8" + "@babel/parser" "^7.17.8" "@babel/template" "^7.16.7" "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" @@ -96,10 +96,10 @@ browserslist "^4.17.5" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.1": - version "7.17.1" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz#9699f14a88833a7e055ce57dcd3ffdcd25186b21" - integrity sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ== +"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.6": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz#3778c1ed09a7f3e65e6d6e0f6fbfcc53809d92c9" + integrity sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg== dependencies: "@babel/helper-annotate-as-pure" "^7.16.7" "@babel/helper-environment-visitor" "^7.16.7" @@ -276,10 +276,10 @@ "@babel/traverse" "^7.16.8" "@babel/types" "^7.16.8" -"@babel/helpers@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.7.tgz#6fc0a24280fd00026e85424bbfed4650e76d7127" - integrity sha512-TKsj9NkjJfTBxM7Phfy7kv6yYc4ZcOo+AaWGqQOKTPDOmcGkIFb5xNA746eKisQkm4yavUYh4InYM9S+VnO01w== +"@babel/helpers@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" + integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== dependencies: "@babel/template" "^7.16.7" "@babel/traverse" "^7.17.3" @@ -294,10 +294,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.7", "@babel/parser@^7.7.0": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.7.tgz#fc19b645a5456c8d6fdb6cecd3c66c0173902800" - integrity sha512-bm3AQf45vR4gKggRfvJdYJ0gFLoCbsPxiFLSH6hTVYABptNHY6l9NrhnucVjQ/X+SPtLANT9lc0fFhikj+VBRA== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8", "@babel/parser@^7.7.0": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" + integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": version "7.16.7" @@ -341,12 +341,12 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-proposal-decorators@^7.17.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.2.tgz#c36372ddfe0360cac1ee331a238310bddca11493" - integrity sha512-WH8Z95CwTq/W8rFbMqb9p3hicpt4RX4f0K659ax2VHxgOyT6qQmUaEVEjIh4WR9Eh9NymkVn5vwsrE68fAQNUw== +"@babel/plugin-proposal-decorators@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.8.tgz#4f0444e896bee85d35cf714a006fc5418f87ff00" + integrity sha512-U69odN4Umyyx1xO1rTII0IDkAEC+RNlcKXtqOblfpzqy1C+aOplb76BQNq0+XdpVkOaPlpEDwd++joY8FNFJKA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.1" + "@babel/helper-create-class-features-plugin" "^7.17.6" "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-replace-supers" "^7.16.7" "@babel/plugin-syntax-decorators" "^7.17.0" @@ -1008,10 +1008,10 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.7", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825" - integrity sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== dependencies: regenerator-runtime "^0.13.4" @@ -1469,10 +1469,10 @@ lz-string "^1.4.4" pretty-format "^27.0.2" -"@testing-library/jest-dom@^5.16.2": - version "5.16.2" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.2.tgz#f329b36b44aa6149cd6ced9adf567f8b6aa1c959" - integrity sha512-6ewxs1MXWwsBFZXIk4nKKskWANelkdUehchEOokHsN8X7c2eKXGw+77aRV63UU8f/DTSVUPLaGxdrj4lN7D/ug== +"@testing-library/jest-dom@^5.16.3": + version "5.16.3" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.3.tgz#b76851a909586113c20486f1679ffb4d8ec27bfa" + integrity sha512-u5DfKj4wfSt6akfndfu1eG06jsdyA/IUrlX2n3pyq5UXgXMhXY+NJb8eNK/7pqPWAhCKsCGWDdDO0zKMKAYkEA== dependencies: "@babel/runtime" "^7.9.2" "@types/testing-library__jest-dom" "^5.9.1" @@ -2333,13 +2333,13 @@ babel-jest@^27.5.1: graceful-fs "^4.2.9" slash "^3.0.0" -babel-loader@^8.2.3: - version "8.2.3" - resolved "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz" - integrity sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw== +babel-loader@^8.2.4: + version "8.2.4" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.4.tgz#95f5023c791b2e9e2ca6f67b0984f39c82ff384b" + integrity sha512-8dytA3gcvPPPv4Grjhnt8b5IIiTcq/zeXOPk4iTYI0SVXcsmuGg7JtBRDp8S9X+gJfhQ8ektjXZlDu1Bb33U8A== dependencies: find-cache-dir "^3.3.1" - loader-utils "^1.4.0" + loader-utils "^2.0.0" make-dir "^3.1.0" schema-utils "^2.6.5" @@ -2898,7 +2898,7 @@ caniuse-api@^3.0.0: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001286: version "1.0.30001310" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001310.tgz" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001310.tgz#da02cd07432c9eece6992689d1b84ca18139eea8" integrity sha512-cb9xTV8k9HTIUA3GnPUJCk0meUnrHL5gy5QePfDjxHyNBcnzPzrHFv5GqfP7ue5b1ZyzZL0RJboD6hQlPXjhjg== chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: @@ -4320,10 +4320,10 @@ eslint-plugin-promise@~6.0.0: resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz" integrity sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw== -eslint-plugin-react@~7.29.3: - version "7.29.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.3.tgz#f4eab757f2756d25d6d4c2a58a9e20b004791f05" - integrity sha512-MzW6TuCnDOcta67CkpDyRfRsEVx9FNMDV8wZsDqe1luHPdGTrQIUaUXD27Ja3gHsdOIs/cXzNchWGlqm+qRVRg== +eslint-plugin-react@~7.29.4: + version "7.29.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz#4717de5227f55f3801a5fd51a16a4fa22b5914d2" + integrity sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ== dependencies: array-includes "^3.1.4" array.prototype.flatmap "^1.2.5" @@ -8505,6 +8505,11 @@ prelude-ls@~1.1.2: resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= +prettier@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17" + integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A== + pretty-format@^25.2.1, pretty-format@^25.5.0: version "25.5.0" resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz" @@ -11343,10 +11348,10 @@ yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.3.1: - version "17.3.1" - resolved "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz" - integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== +yargs@^17.4.0: + version "17.4.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.4.0.tgz#9fc9efc96bd3aa2c1240446af28499f0e7593d00" + integrity sha512-WJudfrk81yWFSOkZYpAZx4Nt7V4xp7S/uJkX0CnxovMCt1wCE8LNftPpNuF9X/u9gN5nsD7ycYtRcDf2pL3UiA== dependencies: cliui "^7.0.2" escalade "^3.1.1" |