diff options
Diffstat (limited to 'app')
218 files changed, 3559 insertions, 2656 deletions
diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb index 5850bd56d..a6e33a5d9 100644 --- a/app/controllers/about_controller.rb +++ b/app/controllers/about_controller.rb @@ -4,13 +4,17 @@ class AboutController < ApplicationController before_action :set_pack layout 'public' - before_action :set_instance_presenter, only: [:show, :more, :terms] + before_action :set_body_classes, only: :show + before_action :set_instance_presenter + before_action :set_expires_in - def show - @hide_navbar = true - end + skip_before_action :check_user_permissions, only: [:more, :terms] - def more; end + def show; end + + def more + flash.now[:notice] = I18n.t('about.instance_actor_flash') if params[:instance_actor] + end def terms; end @@ -32,4 +36,12 @@ class AboutController < ApplicationController def set_instance_presenter @instance_presenter = InstancePresenter.new end + + def set_body_classes + @hide_navbar = true + end + + def set_expires_in + expires_in 0, public: true + end end diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 245263607..3937e9e8a 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -4,8 +4,10 @@ class AccountsController < ApplicationController PAGE_SIZE = 20 include AccountControllerConcern + include SignatureAuthentication before_action :set_cache_headers + before_action :set_body_classes def show respond_to do |format| @@ -17,9 +19,8 @@ class AccountsController < ApplicationController not_found unless current_account && current_account.following?(@account) end end - mark_cacheable! unless user_signed_in? + expires_in 0, public: true unless user_signed_in? - @body_classes = 'with-modals' @pinned_statuses = [] @endorsed_accounts = @account.endorsed_accounts.to_a.sample(4) @@ -40,10 +41,8 @@ class AccountsController < ApplicationController end format.json do - # TODO: Remember to add authorized_fetch_mode, restrict_fields_to when ported -# expires_in 3.minutes, public: !(signed_request_account.present?) - expires_in 3.minutes, public: true - render_with_cache json: @account, content_type: 'application/activity+json', serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter + expires_in 3.minutes, public: !(authorized_fetch_mode? && signed_request_account.present?) + render json: @account, content_type: 'application/activity+json', serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter, fields: restrict_fields_to end end end @@ -58,6 +57,10 @@ class AccountsController < ApplicationController end end + def set_body_classes + @body_classes = 'with-modals' + end + def show_pinned_statuses? [reblogs_requested?, replies_requested?, media_requested?, tag_requested?, params[:max_id].present?, params[:min_id].present?].none? end @@ -148,4 +151,12 @@ class AccountsController < ApplicationController filtered_statuses.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id]).to_a end end + + def restrict_fields_to + if signed_request_account.present? || public_fetch_mode? + # Return all fields + else + %i(id type preferred_username inbox public_key endpoints) + end + end end diff --git a/app/controllers/activitypub/base_controller.rb b/app/controllers/activitypub/base_controller.rb new file mode 100644 index 000000000..a3b5c4dfa --- /dev/null +++ b/app/controllers/activitypub/base_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class ActivityPub::BaseController < Api::BaseController + private + + def set_cache_headers + response.headers['Vary'] = 'Signature' if authorized_fetch_mode? + end +end diff --git a/app/controllers/activitypub/collections_controller.rb b/app/controllers/activitypub/collections_controller.rb index cd23506f3..217700d15 100644 --- a/app/controllers/activitypub/collections_controller.rb +++ b/app/controllers/activitypub/collections_controller.rb @@ -1,24 +1,21 @@ # frozen_string_literal: true -class ActivityPub::CollectionsController < Api::BaseController +class ActivityPub::CollectionsController < ActivityPub::BaseController include SignatureVerification + include AccountOwnedConcern - before_action :set_account + before_action :require_signature!, if: :authorized_fetch_mode? before_action :set_size before_action :set_statuses before_action :set_cache_headers def show - expires_in 3.minutes - render_with_cache json: collection_presenter, content_type: 'application/activity+json', serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, skip_activities: true + expires_in 3.minutes, public: public_fetch_mode? + render json: collection_presenter, content_type: 'application/activity+json', serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, skip_activities: true end private - def set_account - @account = Account.find_local!(params[:account_username]) - end - def set_statuses @statuses = scope_for_collection @statuses = cache_collection(@statuses, Status) diff --git a/app/controllers/activitypub/inboxes_controller.rb b/app/controllers/activitypub/inboxes_controller.rb index 36f837841..7cfd9a25e 100644 --- a/app/controllers/activitypub/inboxes_controller.rb +++ b/app/controllers/activitypub/inboxes_controller.rb @@ -3,40 +3,54 @@ class ActivityPub::InboxesController < Api::BaseController include SignatureVerification include JsonLdHelper + include AccountOwnedConcern - before_action :set_account + before_action :skip_unknown_actor_delete + before_action :require_signature! def create - if unknown_deleted_account? - head 202 - elsif signed_request_account - process_payload - head 202 - else - render plain: signature_verification_failure_reason, status: 401 - end + upgrade_account + process_payload + head 202 end private + def skip_unknown_actor_delete + head 202 if unknown_deleted_account? + end + def unknown_deleted_account? json = Oj.load(body, mode: :strict) - json['type'] == 'Delete' && json['actor'].present? && json['actor'] == value_or_id(json['object']) && !Account.where(uri: json['actor']).exists? + json.is_a?(Hash) && json['type'] == 'Delete' && json['actor'].present? && json['actor'] == value_or_id(json['object']) && !Account.where(uri: json['actor']).exists? rescue Oj::ParseError false end - def set_account - @account = Account.find_local!(params[:account_username]) if params[:account_username] + def account_required? + params[:account_username].present? end def body return @body if defined?(@body) - @body = request.body.read.force_encoding('UTF-8') + + @body = request.body.read + @body.force_encoding('UTF-8') if @body.present? + request.body.rewind if request.body.respond_to?(:rewind) + @body end + def upgrade_account + if signed_request_account.ostatus? + signed_request_account.update(last_webfingered_at: nil) + ResolveAccountWorker.perform_async(signed_request_account.acct) + end + + DeliveryFailureTracker.track_inverse_success!(signed_request_account) + end + def process_payload ActivityPub::ProcessingWorker.perform_async(signed_request_account.id, body, @account&.id) end diff --git a/app/controllers/activitypub/outboxes_controller.rb b/app/controllers/activitypub/outboxes_controller.rb index 1fe043d5e..165827bb7 100644 --- a/app/controllers/activitypub/outboxes_controller.rb +++ b/app/controllers/activitypub/outboxes_controller.rb @@ -1,26 +1,22 @@ # frozen_string_literal: true -class ActivityPub::OutboxesController < Api::BaseController +class ActivityPub::OutboxesController < ActivityPub::BaseController LIMIT = 20 include SignatureVerification + include AccountOwnedConcern - before_action :set_account + before_action :require_signature!, if: :authorized_fetch_mode? before_action :set_statuses before_action :set_cache_headers def show - expires_in 1.minute, public: true unless page_requested? - + expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?) render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json' end private - def set_account - @account = Account.find_local!(params[:account_username]) - end - def outbox_presenter if page_requested? ActivityPub::CollectionPresenter.new( diff --git a/app/controllers/activitypub/replies_controller.rb b/app/controllers/activitypub/replies_controller.rb new file mode 100644 index 000000000..ab755ed4e --- /dev/null +++ b/app/controllers/activitypub/replies_controller.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +class ActivityPub::RepliesController < ActivityPub::BaseController + include SignatureAuthentication + include Authorization + include AccountOwnedConcern + + DESCENDANTS_LIMIT = 60 + + before_action :require_signature!, if: :authorized_fetch_mode? + before_action :set_status + before_action :set_cache_headers + before_action :set_replies + + def index + expires_in 0, public: public_fetch_mode? + render json: replies_collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json', skip_activities: true + end + + private + + def set_status + @status = @account.statuses.find(params[:status_id]) + authorize @status, :show? + rescue Mastodon::NotPermittedError + raise ActiveRecord::RecordNotFound + end + + def set_replies + @replies = page_params[:other_accounts] ? Status.where.not(account_id: @account.id) : @account.statuses + @replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted]) + @replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id]) + end + + def replies_collection_presenter + page = ActivityPub::CollectionPresenter.new( + id: account_status_replies_url(@account, @status, page_params), + type: :unordered, + part_of: account_status_replies_url(@account, @status), + next: next_page, + items: @replies.map { |status| status.local ? status : status.id } + ) + + return page if page_requested? + + ActivityPub::CollectionPresenter.new( + id: account_status_replies_url(@account, @status), + type: :unordered, + first: page + ) + end + + def page_requested? + params[:page] == 'true' + end + + def next_page + account_status_replies_url( + @account, + @status, + page: true, + min_id: @replies&.last&.id, + other_accounts: !(@replies&.last&.account_id == @account.id && @replies.size == DESCENDANTS_LIMIT) + ) + end + + def page_params + params_slice(:other_accounts, :min_id).merge(page: true) + end +end diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb index aedfeb70e..faa2df1b5 100644 --- a/app/controllers/admin/dashboard_controller.rb +++ b/app/controllers/admin/dashboard_controller.rb @@ -31,6 +31,7 @@ module Admin @profile_directory = Setting.profile_directory @timeline_preview = Setting.timeline_preview @keybase_integration = Setting.enable_keybase + @spam_check_enabled = Setting.spam_check_enabled end private diff --git a/app/controllers/api/proofs_controller.rb b/app/controllers/api/proofs_controller.rb index 3e7443641..1ec02c126 100644 --- a/app/controllers/api/proofs_controller.rb +++ b/app/controllers/api/proofs_controller.rb @@ -1,10 +1,9 @@ # frozen_string_literal: true class Api::ProofsController < Api::BaseController - before_action :set_account + include AccountOwnedConcern + before_action :set_provider - before_action :check_account_approval - before_action :check_account_suspension def index render json: @account, serializer: @provider.serializer_class, monsterfork_api: monsterfork_api @@ -16,15 +15,7 @@ class Api::ProofsController < Api::BaseController @provider = ProofProvider.find(params[:provider]) || raise(ActiveRecord::RecordNotFound) end - def set_account - @account = Account.find_local!(params[:username]) - end - - def check_account_approval - not_found if @account.user_pending? - end - - def check_account_suspension - gone if @account.suspended? + def username_param + params[:username] end end diff --git a/app/controllers/api/v1/follows_controller.rb b/app/controllers/api/v1/follows_controller.rb deleted file mode 100644 index 94e377622..000000000 --- a/app/controllers/api/v1/follows_controller.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::FollowsController < Api::BaseController - before_action -> { doorkeeper_authorize! :follow, :'write:follows' } - before_action :require_user! - - respond_to :json - - def create - raise ActiveRecord::RecordNotFound if follow_params[:uri].blank? - - @account = FollowService.new.call(current_user.account, target_uri).try(:target_account) - - if @account.nil? - username, domain = target_uri.split('@') - @account = Account.find_remote!(username, domain) - end - - render json: @account, serializer: REST::AccountSerializer, monsterfork_api: monsterfork_api - end - - private - - def target_uri - follow_params[:uri].strip.gsub(/\A@/, '') - end - - def follow_params - params.permit(:uri) - end -end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 364e8487f..23e7c1f97 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -43,6 +43,14 @@ class ApplicationController < ActionController::Base Rails.env.production? end + def authorized_fetch_mode? + ENV['AUTHORIZED_FETCH'] == 'true' + end + + def public_fetch_mode? + !authorized_fetch_mode? + end + def store_current_location store_location_for(:user, request.url) unless request.format == :json end @@ -254,11 +262,7 @@ class ApplicationController < ActionController::Base end def set_cache_headers - response.headers['Vary'] = 'Accept' - end - - def mark_cacheable! - expires_in 0, public: true + response.headers['Vary'] = public_fetch_mode? ? 'Accept' : 'Accept, Signature' end def monsterfork_api diff --git a/app/controllers/concerns/account_controller_concern.rb b/app/controllers/concerns/account_controller_concern.rb index 34204dc16..4fd9af688 100644 --- a/app/controllers/concerns/account_controller_concern.rb +++ b/app/controllers/concerns/account_controller_concern.rb @@ -3,25 +3,20 @@ module AccountControllerConcern extend ActiveSupport::Concern + include AccountOwnedConcern + FOLLOW_PER_PAGE = 12 included do layout 'public' - before_action :set_account - before_action :check_account_approval - before_action :check_account_suspension before_action :check_account_hidden before_action :set_instance_presenter - before_action :set_link_headers + before_action :set_link_headers, if: -> { request.format.nil? || request.format == :html } end private - def set_account - @account = Account.find_local!(username_param) - end - def set_instance_presenter @instance_presenter = InstancePresenter.new end @@ -35,14 +30,10 @@ module AccountControllerConcern ) end - def username_param - params[:account_username] - end - def webfinger_account_link [ webfinger_account_url, - [%w(rel lrdd), %w(type application/xrd+xml)], + [%w(rel lrdd), %w(type application/jrd+json)], ] end @@ -57,17 +48,6 @@ module AccountControllerConcern webfinger_url(resource: @account.to_webfinger_s) end - def check_account_approval - not_found if @account.user_pending? - end - - def check_account_suspension - if @account.suspended? - expires_in(3.minutes, public: true) - gone - end - end - def check_account_hidden not_found if @account.hidden? end diff --git a/app/controllers/concerns/account_owned_concern.rb b/app/controllers/concerns/account_owned_concern.rb new file mode 100644 index 000000000..99c240fe9 --- /dev/null +++ b/app/controllers/concerns/account_owned_concern.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module AccountOwnedConcern + extend ActiveSupport::Concern + + included do + before_action :set_account, if: :account_required? + before_action :check_account_approval, if: :account_required? + before_action :check_account_suspension, if: :account_required? + end + + private + + def account_required? + true + end + + def set_account + @account = Account.find_local!(username_param) + end + + def username_param + params[:account_username] + end + + def check_account_approval + not_found if @account.local? && @account.user_pending? + end + + def check_account_suspension + expires_in(3.minutes, public: true) && gone if @account.suspended? + end +end diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb index 00a5090fa..64eb20913 100644 --- a/app/controllers/concerns/signature_verification.rb +++ b/app/controllers/concerns/signature_verification.rb @@ -5,12 +5,22 @@ module SignatureVerification extend ActiveSupport::Concern + include DomainControlHelper + + def require_signature! + render plain: signature_verification_failure_reason, status: signature_verification_failure_code unless signed_request_account + end + def signed_request? request.headers['Signature'].present? end def signature_verification_failure_reason - return @signature_verification_failure_reason if defined?(@signature_verification_failure_reason) + @signature_verification_failure_reason + end + + def signature_verification_failure_code + @signature_verification_failure_code || 401 end def signed_request_account @@ -123,6 +133,13 @@ module SignatureVerification end def account_from_key_id(key_id) + domain = key_id.start_with?('acct:') ? key_id.split('@').last : key_id + + if domain_not_allowed?(domain) + @signature_verification_failure_code = 403 + return + end + if key_id.start_with?('acct:') stoplight_wrap_request { ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, '')) } elsif !ActivityPub::TagManager.instance.local_uri?(key_id) diff --git a/app/controllers/concerns/status_controller_concern.rb b/app/controllers/concerns/status_controller_concern.rb new file mode 100644 index 000000000..62a7cf508 --- /dev/null +++ b/app/controllers/concerns/status_controller_concern.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +module StatusControllerConcern + extend ActiveSupport::Concern + + ANCESTORS_LIMIT = 40 + DESCENDANTS_LIMIT = 60 + DESCENDANTS_DEPTH_LIMIT = 20 + + def create_descendant_thread(starting_depth, statuses) + depth = starting_depth + statuses.size + + if depth < DESCENDANTS_DEPTH_LIMIT + { + statuses: statuses, + starting_depth: starting_depth, + } + else + next_status = statuses.pop + + { + statuses: statuses, + starting_depth: starting_depth, + next_status: next_status, + } + end + end + + def set_ancestors + @ancestors = @status.reply? ? cache_collection(@status.ancestors(ANCESTORS_LIMIT, current_account), Status) : [] + @next_ancestor = @ancestors.size < ANCESTORS_LIMIT ? nil : @ancestors.shift + end + + def set_descendants + @max_descendant_thread_id = params[:max_descendant_thread_id]&.to_i + @since_descendant_thread_id = params[:since_descendant_thread_id]&.to_i + + descendants = cache_collection( + @status.descendants( + DESCENDANTS_LIMIT, + current_account, + @max_descendant_thread_id, + @since_descendant_thread_id, + DESCENDANTS_DEPTH_LIMIT + ), + Status + ) + + @descendant_threads = [] + + if descendants.present? + statuses = [descendants.first] + starting_depth = 0 + + descendants.drop(1).each_with_index do |descendant, index| + if descendants[index].id == descendant.in_reply_to_id + statuses << descendant + else + @descendant_threads << create_descendant_thread(starting_depth, statuses) + + # The thread is broken, assume it's a reply to the root status + starting_depth = 0 + + # ... unless we can find its ancestor in one of the already-processed threads + @descendant_threads.reverse_each do |descendant_thread| + statuses = descendant_thread[:statuses] + + index = statuses.find_index do |thread_status| + thread_status.id == descendant.in_reply_to_id + end + + if index.present? + starting_depth = descendant_thread[:starting_depth] + index + 1 + break + end + end + + statuses = [descendant] + end + end + + @descendant_threads << create_descendant_thread(starting_depth, statuses) + end + + @max_descendant_thread_id = @descendant_threads.pop[:statuses].first.id if descendants.size >= DESCENDANTS_LIMIT + end +end diff --git a/app/controllers/custom_css_controller.rb b/app/controllers/custom_css_controller.rb index 6e80feaf8..e3f67bd14 100644 --- a/app/controllers/custom_css_controller.rb +++ b/app/controllers/custom_css_controller.rb @@ -6,6 +6,7 @@ class CustomCssController < ApplicationController before_action :set_cache_headers def show + expires_in 3.minutes, public: true render plain: Setting.custom_css || '', content_type: 'text/css' end end diff --git a/app/controllers/emojis_controller.rb b/app/controllers/emojis_controller.rb index 41f1e1c5c..fe4c19cad 100644 --- a/app/controllers/emojis_controller.rb +++ b/app/controllers/emojis_controller.rb @@ -8,7 +8,7 @@ class EmojisController < ApplicationController respond_to do |format| format.json do expires_in 3.minutes, public: true - render_with_cache json: @emoji, content_type: 'application/activity+json', serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter + render json: @emoji, content_type: 'application/activity+json', serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter end end end diff --git a/app/controllers/follower_accounts_controller.rb b/app/controllers/follower_accounts_controller.rb index fab9c8462..e2ba9bf00 100644 --- a/app/controllers/follower_accounts_controller.rb +++ b/app/controllers/follower_accounts_controller.rb @@ -2,14 +2,16 @@ class FollowerAccountsController < ApplicationController include AccountControllerConcern + include SignatureVerification + before_action :require_signature!, if: -> { request.format == :json && authorized_fetch_mode? } before_action :set_cache_headers def index respond_to do |format| format.html do use_pack 'public' - mark_cacheable! unless user_signed_in? + expires_in 0, public: true unless user_signed_in? next if @account.user_hides_network? @@ -18,9 +20,9 @@ class FollowerAccountsController < ApplicationController end format.json do - raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network? + raise Mastodon::NotPermittedError if page_requested? && @account.user_hides_network? - expires_in 3.minutes, public: true if params[:page].blank? + expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?) render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, @@ -36,6 +38,10 @@ class FollowerAccountsController < ApplicationController @follows ||= Follow.where(target_account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account) end + def page_requested? + params[:page].present? + end + def page_url(page) account_followers_url(@account, page: page) unless page.nil? end @@ -43,7 +49,7 @@ class FollowerAccountsController < ApplicationController def collection_presenter options = { type: :ordered } options[:size] = @account.followers_count unless Setting.hide_followers_count || @account.user&.setting_hide_followers_count - if params[:page].present? + if page_requested? ActivityPub::CollectionPresenter.new( id: account_followers_url(@account, page: params.fetch(:page, 1)), items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) }, diff --git a/app/controllers/following_accounts_controller.rb b/app/controllers/following_accounts_controller.rb index 272116040..49f1f3218 100644 --- a/app/controllers/following_accounts_controller.rb +++ b/app/controllers/following_accounts_controller.rb @@ -2,14 +2,16 @@ class FollowingAccountsController < ApplicationController include AccountControllerConcern + include SignatureVerification + before_action :require_signature!, if: -> { request.format == :json && authorized_fetch_mode? } before_action :set_cache_headers def index respond_to do |format| format.html do use_pack 'public' - mark_cacheable! unless user_signed_in? + expires_in 0, public: true unless user_signed_in? next if @account.user_hides_network? @@ -18,9 +20,9 @@ class FollowingAccountsController < ApplicationController end format.json do - raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network? + raise Mastodon::NotPermittedError if page_requested? && @account.user_hides_network? - expires_in 3.minutes, public: true if params[:page].blank? + expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?) render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, @@ -36,12 +38,16 @@ class FollowingAccountsController < ApplicationController @follows ||= Follow.where(account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account) end + def page_requested? + params[:page].present? + end + def page_url(page) account_following_index_url(@account, page: page) unless page.nil? end def collection_presenter - if params[:page].present? + if page_requested? ActivityPub::CollectionPresenter.new( id: account_following_index_url(@account, page: params.fetch(:page, 1)), type: :ordered, diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 7e0de18a4..2b40b99df 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -23,7 +23,7 @@ class HomeController < ApplicationController when 'statuses' status = Status.find_by(id: matches[2]) - if status && status.distributable? + if status&.distributable? redirect_to(ActivityPub::TagManager.instance.url_for(status)) return end @@ -64,7 +64,7 @@ class HomeController < ApplicationController if request.path.start_with?('/web') new_user_session_path elsif single_user_mode? - short_account_path(Account.local.without_suspended.first) + short_account_path(Account.local.without_suspended.where('id > 0').first) else about_path end diff --git a/app/controllers/instance_actors_controller.rb b/app/controllers/instance_actors_controller.rb new file mode 100644 index 000000000..41f33602e --- /dev/null +++ b/app/controllers/instance_actors_controller.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class InstanceActorsController < ApplicationController + include AccountControllerConcern + + def show + expires_in 10.minutes, public: true + render json: @account, content_type: 'application/activity+json', serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter, fields: restrict_fields_to + end + + private + + def set_account + @account = Account.find(-99) + end + + def restrict_fields_to + %i(id type preferred_username inbox public_key endpoints url manually_approves_followers) + end +end diff --git a/app/controllers/intents_controller.rb b/app/controllers/intents_controller.rb index 9f41cf48a..ca89fc7fe 100644 --- a/app/controllers/intents_controller.rb +++ b/app/controllers/intents_controller.rb @@ -2,6 +2,7 @@ class IntentsController < ApplicationController before_action :check_uri + rescue_from Addressable::URI::InvalidURIError, with: :handle_invalid_uri def show diff --git a/app/controllers/manifests_controller.rb b/app/controllers/manifests_controller.rb index 332d845d8..1e5db4393 100644 --- a/app/controllers/manifests_controller.rb +++ b/app/controllers/manifests_controller.rb @@ -4,6 +4,7 @@ class ManifestsController < ApplicationController skip_before_action :store_current_location def show + expires_in 3.minutes, public: true render json: InstancePresenter.new, serializer: ManifestSerializer end end diff --git a/app/controllers/media_controller.rb b/app/controllers/media_controller.rb index a245db2d1..9dc27c103 100644 --- a/app/controllers/media_controller.rb +++ b/app/controllers/media_controller.rb @@ -31,7 +31,6 @@ class MediaController < ApplicationController def verify_permitted_status! authorize @media_attachment.status, :show? rescue Mastodon::NotPermittedError - # Reraise in order to get a 404 instead of a 403 error code raise ActiveRecord::RecordNotFound end end diff --git a/app/controllers/public_timelines_controller.rb b/app/controllers/public_timelines_controller.rb index ab774c20c..e0609ec12 100644 --- a/app/controllers/public_timelines_controller.rb +++ b/app/controllers/public_timelines_controller.rb @@ -9,20 +9,16 @@ class PublicTimelinesController < ApplicationController before_action :set_instance_presenter def show - respond_to do |format| - format.html do - @initial_state_json = ActiveModelSerializers::SerializableResource.new( - InitialStatePresenter.new(settings: { known_fediverse: Setting.show_known_fediverse_at_about_page }, token: current_session&.token), - serializer: InitialStateSerializer, monsterfork_api: monsterfork_api - ).to_json - end - end + @initial_state_json = ActiveModelSerializers::SerializableResource.new( + InitialStatePresenter.new(settings: { known_fediverse: Setting.show_known_fediverse_at_about_page }, token: current_session&.token), + serializer: InitialStateSerializer, monsterfork_api: monsterfork_api + ).to_json end private def check_enabled - raise ActiveRecord::RecordNotFound unless Setting.timeline_preview + not_found unless Setting.timeline_preview end def set_body_classes diff --git a/app/controllers/remote_follow_controller.rb b/app/controllers/remote_follow_controller.rb index 2caa9c24e..08b53a4d8 100644 --- a/app/controllers/remote_follow_controller.rb +++ b/app/controllers/remote_follow_controller.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true class RemoteFollowController < ApplicationController + include AccountOwnedConcern + layout 'modal' - before_action :set_account before_action :set_pack - before_action :gone, if: :suspended_account? before_action :set_body_classes def new @@ -29,14 +29,6 @@ class RemoteFollowController < ApplicationController use_pack 'modal' end - def set_account - @account = Account.find_local!(params[:account_username]) - end - - def suspended_account? - @account.suspended? - end - def set_body_classes @body_classes = 'modal-layout' @hide_header = true diff --git a/app/controllers/remote_unfollows_controller.rb b/app/controllers/remote_unfollows_controller.rb deleted file mode 100644 index af5943363..000000000 --- a/app/controllers/remote_unfollows_controller.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -class RemoteUnfollowsController < ApplicationController - layout 'modal' - - before_action :authenticate_user! - before_action :set_body_classes - - def create - @account = unfollow_attempt.try(:target_account) - - if @account.nil? - render :error - else - render :success - end - rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError - render :error - end - - private - - def unfollow_attempt - username, domain = acct_without_prefix.split('@') - UnfollowService.new.call(current_account, Account.find_remote!(username, domain)) - end - - def acct_without_prefix - acct_params.gsub(/\Aacct:/, '') - end - - def acct_params - params.fetch(:acct, '') - end - - def set_body_classes - @body_classes = 'modal-layout' - end -end diff --git a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb index 8518c61ee..363b32e17 100644 --- a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb +++ b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb @@ -11,7 +11,7 @@ module Settings def create if current_user.validate_and_consume_otp!(confirmation_params[:code]) - flash[:notice] = I18n.t('two_factor_authentication.enabled_success') + flash.now[:notice] = I18n.t('two_factor_authentication.enabled_success') current_user.otp_required_for_login = true @recovery_codes = current_user.generate_otp_backup_codes! diff --git a/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb b/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb index 94d1567f3..0555d61db 100644 --- a/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb +++ b/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb @@ -6,7 +6,7 @@ module Settings def create @recovery_codes = current_user.generate_otp_backup_codes! current_user.save! - flash[:notice] = I18n.t('two_factor_authentication.recovery_codes_regenerated') + flash.now[:notice] = I18n.t('two_factor_authentication.recovery_codes_regenerated') render :index end end diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb index a000f4dcf..1e7adb7da 100644 --- a/app/controllers/statuses_controller.rb +++ b/app/controllers/statuses_controller.rb @@ -1,26 +1,24 @@ # frozen_string_literal: true class StatusesController < ApplicationController + include StatusControllerConcern include SignatureAuthentication include Authorization - - ANCESTORS_LIMIT = 40 - DESCENDANTS_LIMIT = 60 - DESCENDANTS_DEPTH_LIMIT = 20 + include AccountOwnedConcern layout 'public' - before_action :set_account + before_action :require_signature!, only: :show, if: -> { request.format == :json && authorized_fetch_mode? } before_action :set_status before_action :handle_sharekey_change, only: [:show], if: :user_signed_in? before_action :handle_webapp_redirect, only: [:show], if: :user_signed_in? before_action :set_instance_presenter before_action :set_link_headers - before_action :check_account_suspension - before_action :redirect_to_original, only: [:show] - before_action :set_referrer_policy_header, only: [:show] + before_action :redirect_to_original, only: :show + before_action :set_referrer_policy_header, only: :show before_action :set_cache_headers - before_action :set_replies, only: [:replies] + before_action :set_body_classes + before_action :set_autoplay, only: :embed content_security_policy only: :embed do |p| p.frame_ancestors(false) @@ -32,25 +30,20 @@ class StatusesController < ApplicationController use_pack 'public' expires_in 10.seconds, public: true if current_account.nil? - - @body_classes = 'with-modals' - set_ancestors set_descendants - - render 'stream_entries/show' end format.json do - expires_in 3.minutes, public: @status.distributable? - render_with_cache json: @status, content_type: 'application/activity+json', serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter + expires_in 3.minutes, public: @status.distributable? && public_fetch_mode? + render json: @status, content_type: 'application/activity+json', serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter end end end def activity - expires_in 3.minutes, public: @status.distributable? - render_with_cache json: @status, content_type: 'application/activity+json', serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter + expires_in 3.minutes, public: @status.distributable? && public_fetch_mode? + render json: @status, content_type: 'application/activity+json', serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter end def embed @@ -58,137 +51,24 @@ class StatusesController < ApplicationController expires_in 180, public: true response.headers['X-Frame-Options'] = 'ALLOWALL' - @autoplay = ActiveModel::Type::Boolean.new.cast(params[:autoplay]) - render 'stream_entries/embed', layout: 'embedded' - end - - def replies - render json: replies_collection_presenter, - serializer: ActivityPub::CollectionSerializer, - adapter: ActivityPub::Adapter, - content_type: 'application/activity+json', - skip_activities: true + render layout: 'embedded' end private - def replies_collection_presenter - page = ActivityPub::CollectionPresenter.new( - id: replies_account_status_url(@account, @status, page_params), - type: :unordered, - part_of: replies_account_status_url(@account, @status), - next: next_page, - items: @replies.map { |status| status.local ? status : status.id } - ) - if page_requested? - page - else - ActivityPub::CollectionPresenter.new( - id: replies_account_status_url(@account, @status), - type: :unordered, - first: page - ) - end - end - - def create_descendant_thread(starting_depth, statuses) - depth = starting_depth + statuses.size - if depth < DESCENDANTS_DEPTH_LIMIT - { statuses: statuses, starting_depth: starting_depth } - else - next_status = statuses.pop - { statuses: statuses, starting_depth: starting_depth, next_status: next_status } - end - end - - def set_account - @account = Account.find_local!(params[:account_username]) - end - - def set_ancestors - @ancestors = @status.reply? ? cache_collection(@status.ancestors(ANCESTORS_LIMIT, current_account), Status) : [] - @next_ancestor = @ancestors.size < ANCESTORS_LIMIT ? nil : @ancestors.shift - end - - def set_descendants - @max_descendant_thread_id = params[:max_descendant_thread_id]&.to_i - @since_descendant_thread_id = params[:since_descendant_thread_id]&.to_i - - descendants = cache_collection( - @status.descendants( - DESCENDANTS_LIMIT, - current_account, - @max_descendant_thread_id, - @since_descendant_thread_id, - DESCENDANTS_DEPTH_LIMIT - ), - Status - ) - - @descendant_threads = [] - - if descendants.present? - statuses = [descendants.first] - starting_depth = 0 - - descendants.drop(1).each_with_index do |descendant, index| - if descendants[index].id == descendant.in_reply_to_id - statuses << descendant - else - @descendant_threads << create_descendant_thread(starting_depth, statuses) - - # The thread is broken, assume it's a reply to the root status - starting_depth = 0 - - # ... unless we can find its ancestor in one of the already-processed threads - @descendant_threads.reverse_each do |descendant_thread| - statuses = descendant_thread[:statuses] - - index = statuses.find_index do |thread_status| - thread_status.id == descendant.in_reply_to_id - end - - if index.present? - starting_depth = descendant_thread[:starting_depth] + index + 1 - break - end - end - - statuses = [descendant] - end - end - - @descendant_threads << create_descendant_thread(starting_depth, statuses) - end - - @max_descendant_thread_id = @descendant_threads.pop[:statuses].first.id if descendants.size >= DESCENDANTS_LIMIT + def set_body_classes + @body_classes = 'with-modals' end def set_link_headers - response.headers['Link'] = LinkHeader.new( - [ - [ActivityPub::TagManager.instance.uri_for(@status), [%w(rel alternate), %w(type application/activity+json)]], - ] - ) + response.headers['Link'] = LinkHeader.new([[ActivityPub::TagManager.instance.uri_for(@status), [%w(rel alternate), %w(type application/activity+json)]]]) end def set_status - @status = @account.statuses.find(params[:id]) - @stream_entry = @status.stream_entry - - raise ActiveRecord::RecordNotFound if @stream_entry.nil? - - @type = @stream_entry.activity_type.downcase - @sharekey = params[:key] - - if @status.sharekey.present? && @sharekey == @status.sharekey.key - skip_authorization - else - authorize @status, :show? - end + @status = @account.statuses.find(params[:id]) + authorize @status, :show? rescue Mastodon::NotPermittedError - # Reraise in order to get a 404 raise ActiveRecord::RecordNotFound end @@ -213,39 +93,15 @@ class StatusesController < ApplicationController @instance_presenter = InstancePresenter.new end - def check_account_suspension - gone if @account.suspended? - end - def redirect_to_original - redirect_to ::TagManager.instance.url_for(@status.reblog) if @status.reblog? + redirect_to ActivityPub::TagManager.instance.url_for(@status.reblog) if @status.reblog? end def set_referrer_policy_header - return if @status.public_visibility? || @status.unlisted_visibility? - response.headers['Referrer-Policy'] = 'origin' - end - - def page_requested? - params[:page] == 'true' - end - - def set_replies - @replies = page_params[:other_accounts] ? Status.where.not(account_id: @account.id) : @account.statuses - @replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted]) - @replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id]) - end - - def next_page - last_reply = @replies.last - return if last_reply.nil? - same_account = last_reply.account_id == @account.id - return unless same_account || @replies.size == DESCENDANTS_LIMIT - same_account = false unless @replies.size == DESCENDANTS_LIMIT - replies_account_status_url(@account, @status, page: true, min_id: last_reply.id, other_accounts: !same_account) + response.headers['Referrer-Policy'] = 'origin' unless @status.distributable? end - def page_params - { page: true, other_accounts: params[:other_accounts], min_id: params[:min_id] }.compact + def set_autoplay + @autoplay = truthy_param?(:autoplay) end end diff --git a/app/controllers/stream_entries_controller.rb b/app/controllers/stream_entries_controller.rb deleted file mode 100644 index da5a8da8f..000000000 --- a/app/controllers/stream_entries_controller.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -class StreamEntriesController < ApplicationController - include Authorization - include SignatureVerification - - layout 'public' - - before_action :set_account - before_action :set_stream_entry - before_action :set_link_headers - before_action :check_account_suspension - before_action :set_cache_headers - - def show - respond_to do |format| - format.html do - use_pack 'public' - - expires_in 5.minutes, public: true unless @stream_entry.hidden? - - redirect_to short_account_status_url(params[:account_username], @stream_entry.activity) - end - end - end - - def embed - redirect_to embed_short_account_status_url(@account, @stream_entry.activity), status: 301 - end - - private - - def set_account - @account = Account.find_local!(params[:account_username]) - end - - def set_link_headers - response.headers['Link'] = LinkHeader.new( - [ - [ActivityPub::TagManager.instance.uri_for(@stream_entry.activity), [%w(rel alternate), %w(type application/activity+json)]], - ] - ) - end - - def set_stream_entry - @stream_entry = @account.stream_entries.where(activity_type: 'Status').find(params[:id]) - @type = 'status' - - raise ActiveRecord::RecordNotFound if @stream_entry.activity.nil? - authorize @stream_entry.activity, :show? if @stream_entry.hidden? - rescue Mastodon::NotPermittedError - # Reraise in order to get a 404 - raise ActiveRecord::RecordNotFound - end - - def check_account_suspension - gone if @account.suspended? - end -end diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index f89e8afba..952e59119 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -1,19 +1,23 @@ # frozen_string_literal: true class TagsController < ApplicationController + include SignatureVerification + PAGE_SIZE = 20 layout 'public' + before_action :require_signature!, if: -> { request.format == :json && authorized_fetch_mode? } + before_action :set_tag before_action :set_body_classes before_action :set_instance_presenter def show - @tag = Tag.find_normalized!(params[:id]) - respond_to do |format| format.html do use_pack 'about' + expires_in 0, public: true + @initial_state_json = ActiveModelSerializers::SerializableResource.new( InitialStatePresenter.new(settings: {}, token: current_session&.token), serializer: InitialStateSerializer, monsterfork_api: monsterfork_api @@ -21,6 +25,8 @@ class TagsController < ApplicationController end format.rss do + expires_in 0, public: true + @statuses = HashtagQueryService.new.call(@tag, params.slice(:any, :all, :none)).limit(PAGE_SIZE) @statuses = cache_collection(@statuses, Status) @@ -28,19 +34,22 @@ class TagsController < ApplicationController end format.json do + expires_in 3.minutes, public: public_fetch_mode? + @statuses = HashtagQueryService.new.call(@tag, params.slice(:any, :all, :none), current_account, params[:local]).paginate_by_max_id(PAGE_SIZE, params[:max_id]) @statuses = cache_collection(@statuses, Status) - render json: collection_presenter, - serializer: ActivityPub::CollectionSerializer, - adapter: ActivityPub::Adapter, - content_type: 'application/activity+json' + render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json' end end end private + def set_tag + @tag = Tag.find_normalized!(params[:id]) + end + def set_body_classes @body_classes = 'with-modals' end diff --git a/app/controllers/well_known/host_meta_controller.rb b/app/controllers/well_known/host_meta_controller.rb index 5fb70288a..2e9298c4a 100644 --- a/app/controllers/well_known/host_meta_controller.rb +++ b/app/controllers/well_known/host_meta_controller.rb @@ -13,7 +13,7 @@ module WellKnown format.xml { render content_type: 'application/xrd+xml' } end - expires_in(3.days, public: true) + expires_in 3.days, public: true end end end diff --git a/app/controllers/well_known/webfinger_controller.rb b/app/controllers/well_known/webfinger_controller.rb index 28654b61d..53f7f1e27 100644 --- a/app/controllers/well_known/webfinger_controller.rb +++ b/app/controllers/well_known/webfinger_controller.rb @@ -19,7 +19,7 @@ module WellKnown end end - expires_in(3.days, public: true) + expires_in 3.days, public: true rescue ActiveRecord::RecordNotFound head 404 end @@ -27,12 +27,9 @@ module WellKnown private def username_from_resource - resource_user = resource_param - + resource_user = resource_param username, domain = resource_user.split('@') - if Rails.configuration.x.alternate_domains.include?(domain) - resource_user = "#{username}@#{Rails.configuration.x.local_domain}" - end + resource_user = "#{username}@#{Rails.configuration.x.local_domain}" if Rails.configuration.x.alternate_domains.include?(domain) WebfingerResource.new(resource_user).username end diff --git a/app/helpers/admin/action_logs_helper.rb b/app/helpers/admin/action_logs_helper.rb index 427ac0c4e..c90818318 100644 --- a/app/helpers/admin/action_logs_helper.rb +++ b/app/helpers/admin/action_logs_helper.rb @@ -89,7 +89,7 @@ module Admin::ActionLogsHelper when 'DomainBlock', 'EmailDomainBlock' link_to record.domain, admin_instance_path(id: record.domain) when 'Status' - link_to record.account.acct, TagManager.instance.url_for(record) + link_to record.account.acct, ActivityPub::TagManager.instance.url_for(record) when 'AccountWarning' link_to record.target_account.acct, admin_account_path(record.target_account_id) end diff --git a/app/helpers/domain_control_helper.rb b/app/helpers/domain_control_helper.rb new file mode 100644 index 000000000..efd328f81 --- /dev/null +++ b/app/helpers/domain_control_helper.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module DomainControlHelper + def domain_not_allowed?(uri_or_domain) + return if uri_or_domain.blank? + + domain = begin + if uri_or_domain.include?('://') + Addressable::URI.parse(uri_or_domain).domain + else + uri_or_domain + end + end + + DomainBlock.blocked?(domain) + end +end diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb index df60b7dd7..b66e827fe 100644 --- a/app/helpers/home_helper.rb +++ b/app/helpers/home_helper.rb @@ -21,7 +21,7 @@ module HomeHelper end end else - link_to(path || TagManager.instance.url_for(account), class: 'account__display-name') do + link_to(path || ActivityPub::TagManager.instance.url_for(account), class: 'account__display-name') do content_tag(:div, class: 'account__avatar-wrapper') do content_tag(:div, '', class: 'account__avatar', style: "width: #{size}px; height: #{size}px; background-size: #{size}px #{size}px; background-image: url(#{full_asset_url(current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url)})") end + diff --git a/app/helpers/jsonld_helper.rb b/app/helpers/jsonld_helper.rb index 1c473efa3..a07ef9e3e 100644 --- a/app/helpers/jsonld_helper.rb +++ b/app/helpers/jsonld_helper.rb @@ -131,6 +131,7 @@ module JsonLdHelper end doc = JSON::LD::API::RemoteDocument.new(json, documentUrl: url) +# doc = JSON::LD::API::RemoteDocument.new(url, json) block_given? ? yield(doc) : doc end diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/statuses_helper.rb index 31ab03a65..00951086f 100644 --- a/app/helpers/stream_entries_helper.rb +++ b/app/helpers/statuses_helper.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module StreamEntriesHelper +module StatusesHelper EMBEDDED_CONTROLLER = 'statuses' EMBEDDED_ACTION = 'embed' @@ -136,11 +136,13 @@ module StreamEntriesHelper def status_text_summary(status) return if status.spoiler_text.blank? + I18n.t('statuses.content_warning', warning: status.spoiler_text) end def poll_summary(status) return unless status.preloadable_poll + status.preloadable_poll.options.map { |o| "[ ] #{o}" }.join("\n") end diff --git a/app/javascript/core/public.js b/app/javascript/core/public.js index 4be75647a..e04cded2b 100644 --- a/app/javascript/core/public.js +++ b/app/javascript/core/public.js @@ -47,7 +47,7 @@ const getProfileAvatarAnimationHandler = (swapTo) => { return ({ target }) => { const swapSrc = target.getAttribute(swapTo); //only change the img source if autoplay is off and the image src is actually different - if(target.getAttribute('data-autoplay') === 'false' && target.src !== swapSrc) { + if(target.getAttribute('data-autoplay') !== 'true' && target.src !== swapSrc) { target.src = swapSrc; } }; diff --git a/app/javascript/flavours/glitch/styles/containers.scss b/app/javascript/flavours/glitch/styles/containers.scss index b0c187eab..a1e4f135c 100644 --- a/app/javascript/flavours/glitch/styles/containers.scss +++ b/app/javascript/flavours/glitch/styles/containers.scss @@ -146,6 +146,10 @@ min-height: 100%; } + .flash-message { + margin-bottom: 10px; + } + @media screen and (max-width: 738px) { grid-template-columns: minmax(0, 50%) minmax(0, 50%); diff --git a/app/javascript/flavours/glitch/styles/index.scss b/app/javascript/flavours/glitch/styles/index.scss index 3af10dfa1..05d6b20b1 100644 --- a/app/javascript/flavours/glitch/styles/index.scss +++ b/app/javascript/flavours/glitch/styles/index.scss @@ -14,7 +14,7 @@ @import 'widgets'; @import 'forms'; @import 'accounts'; -@import 'stream_entries'; +@import 'statuses'; @import 'components/index'; @import 'polls'; @import 'about'; diff --git a/app/javascript/flavours/glitch/styles/stream_entries.scss b/app/javascript/flavours/glitch/styles/statuses.scss index de9c2612c..de9c2612c 100644 --- a/app/javascript/flavours/glitch/styles/stream_entries.scss +++ b/app/javascript/flavours/glitch/styles/statuses.scss diff --git a/app/javascript/mastodon/components/dropdown_menu.js b/app/javascript/mastodon/components/dropdown_menu.js index 91b65a02f..e122515c4 100644 --- a/app/javascript/mastodon/components/dropdown_menu.js +++ b/app/javascript/mastodon/components/dropdown_menu.js @@ -122,11 +122,11 @@ class DropdownMenu extends React.PureComponent { return <li key={`sep-${i}`} className='dropdown-menu__separator' />; } - const { text, href = '#' } = option; + const { text, href = '#', target = '_blank', method } = option; return ( <li className='dropdown-menu__item' key={`${text}-${i}`}> - <a href={href} target='_blank' rel='noopener' role='button' tabIndex='0' ref={i === 0 ? this.setFocusRef : null} onClick={this.handleClick} onKeyDown={this.handleItemKeyDown} data-index={i}> + <a href={href} target={target} data-method={method} rel='noopener' role='button' tabIndex='0' ref={i === 0 ? this.setFocusRef : null} onClick={this.handleClick} onKeyDown={this.handleItemKeyDown} data-index={i}> {text} </a> </li> diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js index 0376cf85a..bb4e7bdd2 100644 --- a/app/javascript/mastodon/components/scrollable_list.js +++ b/app/javascript/mastodon/components/scrollable_list.js @@ -32,6 +32,7 @@ export default class ScrollableList extends PureComponent { alwaysPrepend: PropTypes.bool, emptyMessage: PropTypes.node, children: PropTypes.node, + bindToDocument: PropTypes.bool, }; static defaultProps = { @@ -47,7 +48,9 @@ export default class ScrollableList extends PureComponent { handleScroll = throttle(() => { if (this.node) { - const { scrollTop, scrollHeight, clientHeight } = this.node; + const scrollTop = this.getScrollTop(); + const scrollHeight = this.getScrollHeight(); + const clientHeight = this.getClientHeight(); const offset = scrollHeight - scrollTop - clientHeight; if (400 > offset && this.props.onLoadMore && this.props.hasMore && !this.props.isLoading) { @@ -77,9 +80,14 @@ export default class ScrollableList extends PureComponent { scrollToTopOnMouseIdle = false; setScrollTop = newScrollTop => { - if (this.node.scrollTop !== newScrollTop) { + if (this.getScrollTop() !== newScrollTop) { this.lastScrollWasSynthetic = true; - this.node.scrollTop = newScrollTop; + + if (this.props.bindToDocument) { + document.scrollingElement.scrollTop = newScrollTop; + } else { + this.node.scrollTop = newScrollTop; + } } }; @@ -97,7 +105,7 @@ export default class ScrollableList extends PureComponent { this.clearMouseIdleTimer(); this.mouseIdleTimer = setTimeout(this.handleMouseIdle, MOUSE_IDLE_DELAY); - if (!this.mouseMovedRecently && this.node.scrollTop === 0) { + if (!this.mouseMovedRecently && this.getScrollTop() === 0) { // Only set if we just started moving and are scrolled to the top. this.scrollToTopOnMouseIdle = true; } @@ -132,15 +140,27 @@ export default class ScrollableList extends PureComponent { } getScrollPosition = () => { - if (this.node && (this.node.scrollTop > 0 || this.mouseMovedRecently)) { - return { height: this.node.scrollHeight, top: this.node.scrollTop }; + if (this.node && (this.getScrollTop() > 0 || this.mouseMovedRecently)) { + return { height: this.getScrollHeight(), top: this.getScrollTop() }; } else { return null; } } + getScrollTop = () => { + return this.props.bindToDocument ? document.scrollingElement.scrollTop : this.node.scrollTop; + } + + getScrollHeight = () => { + return this.props.bindToDocument ? document.scrollingElement.scrollHeight : this.node.scrollHeight; + } + + getClientHeight = () => { + return this.props.bindToDocument ? document.scrollingElement.clientHeight : this.node.clientHeight; + } + updateScrollBottom = (snapshot) => { - const newScrollTop = this.node.scrollHeight - snapshot; + const newScrollTop = this.getScrollHeight() - snapshot; this.setScrollTop(newScrollTop); } @@ -150,8 +170,8 @@ export default class ScrollableList extends PureComponent { React.Children.count(prevProps.children) < React.Children.count(this.props.children) && this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props); - if (someItemInserted && (this.node.scrollTop > 0 || this.mouseMovedRecently)) { - return this.node.scrollHeight - this.node.scrollTop; + if (someItemInserted && (this.getScrollTop() > 0 || this.mouseMovedRecently)) { + return this.getScrollHeight() - this.getScrollTop(); } else { return null; } @@ -161,7 +181,7 @@ export default class ScrollableList extends PureComponent { // Reset the scroll position when a new child comes in in order not to // jerk the scrollbar around if you're already scrolled down the page. if (snapshot !== null) { - this.setScrollTop(this.node.scrollHeight - snapshot); + this.setScrollTop(this.getScrollHeight() - snapshot); } } @@ -194,13 +214,23 @@ export default class ScrollableList extends PureComponent { } attachScrollListener () { - this.node.addEventListener('scroll', this.handleScroll); - this.node.addEventListener('wheel', this.handleWheel); + if (this.props.bindToDocument) { + document.addEventListener('scroll', this.handleScroll); + document.addEventListener('wheel', this.handleWheel); + } else { + this.node.addEventListener('scroll', this.handleScroll); + this.node.addEventListener('wheel', this.handleWheel); + } } detachScrollListener () { - this.node.removeEventListener('scroll', this.handleScroll); - this.node.removeEventListener('wheel', this.handleWheel); + if (this.props.bindToDocument) { + document.removeEventListener('scroll', this.handleScroll); + document.removeEventListener('wheel', this.handleWheel); + } else { + this.node.removeEventListener('scroll', this.handleScroll); + this.node.removeEventListener('wheel', this.handleWheel); + } } getFirstChildKey (props) { diff --git a/app/javascript/mastodon/containers/media_container.js b/app/javascript/mastodon/containers/media_container.js index 51d4f0fed..48492f43d 100644 --- a/app/javascript/mastodon/containers/media_container.js +++ b/app/javascript/mastodon/containers/media_container.js @@ -8,6 +8,7 @@ import Video from '../features/video'; import Card from '../features/status/components/card'; import Poll from 'mastodon/components/poll'; import ModalRoot from '../components/modal_root'; +import { getScrollbarWidth } from '../features/ui/components/modal_root'; import MediaModal from '../features/ui/components/media_modal'; import { List as ImmutableList, fromJS } from 'immutable'; @@ -31,6 +32,8 @@ export default class MediaContainer extends PureComponent { handleOpenMedia = (media, index) => { document.body.classList.add('with-modals--active'); + document.documentElement.style.marginRight = `${getScrollbarWidth()}px`; + this.setState({ media, index }); } @@ -38,11 +41,15 @@ export default class MediaContainer extends PureComponent { const media = ImmutableList([video]); document.body.classList.add('with-modals--active'); + document.documentElement.style.marginRight = `${getScrollbarWidth()}px`; + this.setState({ media, time }); } handleCloseMedia = () => { document.body.classList.remove('with-modals--active'); + document.documentElement.style.marginRight = 0; + this.setState({ media: null, index: null, time: null }); } diff --git a/app/javascript/mastodon/features/account_timeline/index.js b/app/javascript/mastodon/features/account_timeline/index.js index 27581bfdc..9914b7e65 100644 --- a/app/javascript/mastodon/features/account_timeline/index.js +++ b/app/javascript/mastodon/features/account_timeline/index.js @@ -44,6 +44,7 @@ class AccountTimeline extends ImmutablePureComponent { withReplies: PropTypes.bool, blockedBy: PropTypes.bool, isAccount: PropTypes.bool, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -77,7 +78,7 @@ class AccountTimeline extends ImmutablePureComponent { } render () { - const { shouldUpdateScroll, statusIds, featuredStatusIds, isLoading, hasMore, blockedBy, isAccount } = this.props; + const { shouldUpdateScroll, statusIds, featuredStatusIds, isLoading, hasMore, blockedBy, isAccount, multiColumn } = this.props; if (!isAccount) { return ( @@ -112,6 +113,7 @@ class AccountTimeline extends ImmutablePureComponent { onLoadMore={this.handleLoadMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/blocks/index.js b/app/javascript/mastodon/features/blocks/index.js index 96a219c94..8fb0f051b 100644 --- a/app/javascript/mastodon/features/blocks/index.js +++ b/app/javascript/mastodon/features/blocks/index.js @@ -32,6 +32,7 @@ class Blocks extends ImmutablePureComponent { accountIds: ImmutablePropTypes.list, hasMore: PropTypes.bool, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -43,7 +44,7 @@ class Blocks extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, accountIds, shouldUpdateScroll, hasMore } = this.props; + const { intl, accountIds, shouldUpdateScroll, hasMore, multiColumn } = this.props; if (!accountIds) { return ( @@ -64,6 +65,7 @@ class Blocks extends ImmutablePureComponent { hasMore={hasMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} /> diff --git a/app/javascript/mastodon/features/community_timeline/index.js b/app/javascript/mastodon/features/community_timeline/index.js index 7d26c98b0..2f6999f61 100644 --- a/app/javascript/mastodon/features/community_timeline/index.js +++ b/app/javascript/mastodon/features/community_timeline/index.js @@ -126,6 +126,7 @@ class CommunityTimeline extends React.PureComponent { onLoadMore={this.handleLoadMore} emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/compose/components/action_bar.js b/app/javascript/mastodon/features/compose/components/action_bar.js index 077226d70..d0303dbfb 100644 --- a/app/javascript/mastodon/features/compose/components/action_bar.js +++ b/app/javascript/mastodon/features/compose/components/action_bar.js @@ -15,6 +15,7 @@ const messages = defineMessages({ domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' }, mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' }, filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' }, + logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' }, }); export default @injectIntl @@ -42,6 +43,8 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(messages.blocks), to: '/blocks' }); menu.push({ text: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' }); menu.push({ text: intl.formatMessage(messages.filters), href: '/filters' }); + menu.push(null); + menu.push({ text: intl.formatMessage(messages.logout), href: '/auth/sign_out', target: null, method: 'delete' }); return ( <div className='compose__action-bar'> diff --git a/app/javascript/mastodon/features/domain_blocks/index.js b/app/javascript/mastodon/features/domain_blocks/index.js index 7c075f5a5..16e200b31 100644 --- a/app/javascript/mastodon/features/domain_blocks/index.js +++ b/app/javascript/mastodon/features/domain_blocks/index.js @@ -33,6 +33,7 @@ class Blocks extends ImmutablePureComponent { hasMore: PropTypes.bool, domains: ImmutablePropTypes.orderedSet, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -44,7 +45,7 @@ class Blocks extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, domains, shouldUpdateScroll, hasMore } = this.props; + const { intl, domains, shouldUpdateScroll, hasMore, multiColumn } = this.props; if (!domains) { return ( @@ -65,6 +66,7 @@ class Blocks extends ImmutablePureComponent { hasMore={hasMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {domains.map(domain => <DomainContainer key={domain} domain={domain} /> diff --git a/app/javascript/mastodon/features/favourited_statuses/index.js b/app/javascript/mastodon/features/favourited_statuses/index.js index fa9401b90..8c7b23869 100644 --- a/app/javascript/mastodon/features/favourited_statuses/index.js +++ b/app/javascript/mastodon/features/favourited_statuses/index.js @@ -95,6 +95,7 @@ class Favourites extends ImmutablePureComponent { onLoadMore={this.handleLoadMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/favourites/index.js b/app/javascript/mastodon/features/favourites/index.js index d1ac229a2..464f7aeb0 100644 --- a/app/javascript/mastodon/features/favourites/index.js +++ b/app/javascript/mastodon/features/favourites/index.js @@ -23,6 +23,7 @@ class Favourites extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, shouldUpdateScroll: PropTypes.func, accountIds: ImmutablePropTypes.list, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -36,7 +37,7 @@ class Favourites extends ImmutablePureComponent { } render () { - const { shouldUpdateScroll, accountIds } = this.props; + const { shouldUpdateScroll, accountIds, multiColumn } = this.props; if (!accountIds) { return ( @@ -56,6 +57,7 @@ class Favourites extends ImmutablePureComponent { scrollKey='favourites' shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/mastodon/features/follow_requests/index.js b/app/javascript/mastodon/features/follow_requests/index.js index 44624cb40..570cf57c8 100644 --- a/app/javascript/mastodon/features/follow_requests/index.js +++ b/app/javascript/mastodon/features/follow_requests/index.js @@ -32,6 +32,7 @@ class FollowRequests extends ImmutablePureComponent { hasMore: PropTypes.bool, accountIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -43,7 +44,7 @@ class FollowRequests extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, shouldUpdateScroll, accountIds, hasMore } = this.props; + const { intl, shouldUpdateScroll, accountIds, hasMore, multiColumn } = this.props; if (!accountIds) { return ( @@ -64,6 +65,7 @@ class FollowRequests extends ImmutablePureComponent { hasMore={hasMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountAuthorizeContainer key={id} id={id} /> diff --git a/app/javascript/mastodon/features/followers/index.js b/app/javascript/mastodon/features/followers/index.js index e3387e1be..dce05bdc6 100644 --- a/app/javascript/mastodon/features/followers/index.js +++ b/app/javascript/mastodon/features/followers/index.js @@ -36,6 +36,7 @@ class Followers extends ImmutablePureComponent { hasMore: PropTypes.bool, blockedBy: PropTypes.bool, isAccount: PropTypes.bool, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -55,7 +56,7 @@ class Followers extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount } = this.props; + const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn } = this.props; if (!isAccount) { return ( @@ -87,6 +88,7 @@ class Followers extends ImmutablePureComponent { prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} alwaysPrepend emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {blockedBy ? [] : accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/mastodon/features/following/index.js b/app/javascript/mastodon/features/following/index.js index 3bf89fb2b..d9f2ef079 100644 --- a/app/javascript/mastodon/features/following/index.js +++ b/app/javascript/mastodon/features/following/index.js @@ -36,6 +36,7 @@ class Following extends ImmutablePureComponent { hasMore: PropTypes.bool, blockedBy: PropTypes.bool, isAccount: PropTypes.bool, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -55,7 +56,7 @@ class Following extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount } = this.props; + const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn } = this.props; if (!isAccount) { return ( @@ -87,6 +88,7 @@ class Following extends ImmutablePureComponent { prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} alwaysPrepend emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {blockedBy ? [] : accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/mastodon/features/hashtag_timeline/index.js b/app/javascript/mastodon/features/hashtag_timeline/index.js index 0d3c97a64..c50f6a79a 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/index.js +++ b/app/javascript/mastodon/features/hashtag_timeline/index.js @@ -157,6 +157,7 @@ class HashtagTimeline extends React.PureComponent { onLoadMore={this.handleLoadMore} emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/home_timeline/index.js b/app/javascript/mastodon/features/home_timeline/index.js index 097f91c16..bf8ff117b 100644 --- a/app/javascript/mastodon/features/home_timeline/index.js +++ b/app/javascript/mastodon/features/home_timeline/index.js @@ -119,6 +119,7 @@ class HomeTimeline extends React.PureComponent { timelineId='home' emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage='Your home timeline is empty! Visit {public} or use search to get started and meet other users.' values={{ public: <Link to='/timelines/public'><FormattedMessage id='empty_column.home.public_timeline' defaultMessage='the public timeline' /></Link> }} />} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/list_timeline/index.js b/app/javascript/mastodon/features/list_timeline/index.js index 0db6d2228..844c93db1 100644 --- a/app/javascript/mastodon/features/list_timeline/index.js +++ b/app/javascript/mastodon/features/list_timeline/index.js @@ -184,6 +184,7 @@ class ListTimeline extends React.PureComponent { onLoadMore={this.handleLoadMore} emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet. When members of this list post new statuses, they will appear here.' />} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/lists/index.js b/app/javascript/mastodon/features/lists/index.js index 015e21b68..a06e0b934 100644 --- a/app/javascript/mastodon/features/lists/index.js +++ b/app/javascript/mastodon/features/lists/index.js @@ -40,6 +40,7 @@ class Lists extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, lists: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -47,7 +48,7 @@ class Lists extends ImmutablePureComponent { } render () { - const { intl, shouldUpdateScroll, lists } = this.props; + const { intl, shouldUpdateScroll, lists, multiColumn } = this.props; if (!lists) { return ( @@ -70,6 +71,7 @@ class Lists extends ImmutablePureComponent { shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} prepend={<ColumnSubheading text={intl.formatMessage(messages.subheading)} />} + bindToDocument={!multiColumn} > {lists.map(list => <ColumnLink key={list.get('id')} to={`/timelines/list/${list.get('id')}`} icon='list-ul' text={list.get('title')} /> diff --git a/app/javascript/mastodon/features/mutes/index.js b/app/javascript/mastodon/features/mutes/index.js index 4ed29a1ce..57d8b9915 100644 --- a/app/javascript/mastodon/features/mutes/index.js +++ b/app/javascript/mastodon/features/mutes/index.js @@ -32,6 +32,7 @@ class Mutes extends ImmutablePureComponent { hasMore: PropTypes.bool, accountIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -43,7 +44,7 @@ class Mutes extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { intl, shouldUpdateScroll, hasMore, accountIds } = this.props; + const { intl, shouldUpdateScroll, hasMore, accountIds, multiColumn } = this.props; if (!accountIds) { return ( @@ -64,6 +65,7 @@ class Mutes extends ImmutablePureComponent { hasMore={hasMore} shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} /> diff --git a/app/javascript/mastodon/features/notifications/index.js b/app/javascript/mastodon/features/notifications/index.js index 006c45657..c53f9b699 100644 --- a/app/javascript/mastodon/features/notifications/index.js +++ b/app/javascript/mastodon/features/notifications/index.js @@ -183,6 +183,7 @@ class Notifications extends React.PureComponent { onScrollToTop={this.handleScrollToTop} onScroll={this.handleScroll} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} > {scrollableContent} </ScrollableList> diff --git a/app/javascript/mastodon/features/pinned_statuses/index.js b/app/javascript/mastodon/features/pinned_statuses/index.js index 98cdbda3c..64ebfc7ae 100644 --- a/app/javascript/mastodon/features/pinned_statuses/index.js +++ b/app/javascript/mastodon/features/pinned_statuses/index.js @@ -28,6 +28,7 @@ class PinnedStatuses extends ImmutablePureComponent { statusIds: ImmutablePropTypes.list.isRequired, intl: PropTypes.object.isRequired, hasMore: PropTypes.bool.isRequired, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -43,7 +44,7 @@ class PinnedStatuses extends ImmutablePureComponent { } render () { - const { intl, shouldUpdateScroll, statusIds, hasMore } = this.props; + const { intl, shouldUpdateScroll, statusIds, hasMore, multiColumn } = this.props; return ( <Column icon='thumb-tack' heading={intl.formatMessage(messages.heading)} ref={this.setRef}> @@ -53,6 +54,7 @@ class PinnedStatuses extends ImmutablePureComponent { scrollKey='pinned_statuses' hasMore={hasMore} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/public_timeline/index.js b/app/javascript/mastodon/features/public_timeline/index.js index 2b7d9c56f..1edb303b8 100644 --- a/app/javascript/mastodon/features/public_timeline/index.js +++ b/app/javascript/mastodon/features/public_timeline/index.js @@ -126,6 +126,7 @@ class PublicTimeline extends React.PureComponent { scrollKey={`public_timeline-${columnId}`} emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other servers to fill it up' />} shouldUpdateScroll={shouldUpdateScroll} + bindToDocument={!multiColumn} /> </Column> ); diff --git a/app/javascript/mastodon/features/reblogs/index.js b/app/javascript/mastodon/features/reblogs/index.js index c05d21c74..26f93ad1b 100644 --- a/app/javascript/mastodon/features/reblogs/index.js +++ b/app/javascript/mastodon/features/reblogs/index.js @@ -23,6 +23,7 @@ class Reblogs extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, shouldUpdateScroll: PropTypes.func, accountIds: ImmutablePropTypes.list, + multiColumn: PropTypes.bool, }; componentWillMount () { @@ -36,7 +37,7 @@ class Reblogs extends ImmutablePureComponent { } render () { - const { shouldUpdateScroll, accountIds } = this.props; + const { shouldUpdateScroll, accountIds, multiColumn } = this.props; if (!accountIds) { return ( @@ -56,6 +57,7 @@ class Reblogs extends ImmutablePureComponent { scrollKey='reblogs' shouldUpdateScroll={shouldUpdateScroll} emptyMessage={emptyMessage} + bindToDocument={!multiColumn} > {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} /> diff --git a/app/javascript/mastodon/features/ui/components/modal_root.js b/app/javascript/mastodon/features/ui/components/modal_root.js index cc2ab6c8c..06f9e1bc4 100644 --- a/app/javascript/mastodon/features/ui/components/modal_root.js +++ b/app/javascript/mastodon/features/ui/components/modal_root.js @@ -32,6 +32,28 @@ const MODAL_COMPONENTS = { 'LIST_ADDER':ListAdder, }; +let cachedScrollbarWidth = null; + +export const getScrollbarWidth = () => { + if (cachedScrollbarWidth !== null) { + return cachedScrollbarWidth; + } + + const outer = document.createElement('div'); + outer.style.visibility = 'hidden'; + outer.style.overflow = 'scroll'; + document.body.appendChild(outer); + + const inner = document.createElement('div'); + outer.appendChild(inner); + + const scrollbarWidth = outer.offsetWidth - inner.offsetWidth; + cachedScrollbarWidth = scrollbarWidth; + outer.parentNode.removeChild(outer); + + return scrollbarWidth; +}; + export default class ModalRoot extends React.PureComponent { static propTypes = { @@ -47,8 +69,10 @@ export default class ModalRoot extends React.PureComponent { componentDidUpdate (prevProps, prevState, { visible }) { if (visible) { document.body.classList.add('with-modals--active'); + document.documentElement.style.marginRight = `${getScrollbarWidth()}px`; } else { document.body.classList.remove('with-modals--active'); + document.documentElement.style.marginRight = 0; } } diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js index 791133afd..d1a3dc949 100644 --- a/app/javascript/mastodon/features/ui/index.js +++ b/app/javascript/mastodon/features/ui/index.js @@ -110,12 +110,25 @@ class SwitchingColumnsArea extends React.PureComponent { componentWillMount () { window.addEventListener('resize', this.handleResize, { passive: true }); + + if (this.state.mobile || forceSingleColumn) { + document.body.classList.toggle('layout-single-column', true); + document.body.classList.toggle('layout-multiple-columns', false); + } else { + document.body.classList.toggle('layout-single-column', false); + document.body.classList.toggle('layout-multiple-columns', true); + } } - componentDidUpdate (prevProps) { + componentDidUpdate (prevProps, prevState) { if (![this.props.location.pathname, '/'].includes(prevProps.location.pathname)) { this.node.handleChildrenContentChange(); } + + if (prevState.mobile !== this.state.mobile && !forceSingleColumn) { + document.body.classList.toggle('layout-single-column', this.state.mobile); + document.body.classList.toggle('layout-multiple-columns', !this.state.mobile); + } } componentWillUnmount () { diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index 68c8835d1..d62ee90c2 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -1,8 +1,8 @@ { - "account.add_or_remove_from_list": "أضيف/ي أو أحذف/ي من القائمة", + "account.add_or_remove_from_list": "أضفه أو أزله من القائمة", "account.badges.bot": "روبوت", "account.block": "حظر @{name}", - "account.block_domain": "إخفاء كل شيئ قادم من إسم النطاق {domain}", + "account.block_domain": "إخفاء كل شيئ قادم من اسم النطاق {domain}", "account.blocked": "محظور", "account.direct": "رسالة خاصة إلى @{name}", "account.domain_blocked": "النطاق مخفي", @@ -19,7 +19,7 @@ "account.locked_info": "تم تأمين خصوصية هذا الحساب عبر قفل. صاحب الحساب يُراجِع يدويا طلبات المتابَعة و الاشتراك بحسابه.", "account.media": "وسائط", "account.mention": "أُذكُر/ي @{name}", - "account.moved_to": "{name} إنتقل إلى :", + "account.moved_to": "{name} انتقل إلى:", "account.mute": "كتم @{name}", "account.mute_notifications": "كتم الإخطارات من @{name}", "account.muted": "مكتوم", @@ -36,7 +36,7 @@ "account.unmute": "إلغاء الكتم عن @{name}", "account.unmute_notifications": "إلغاء كتم إخطارات @{name}", "alert.unexpected.message": "لقد طرأ هناك خطأ غير متوقّع.", - "alert.unexpected.title": "المعذرة !", + "alert.unexpected.title": "المعذرة!", "boost_modal.combo": "يمكنك/ي ضغط {combo} لتخطّي هذه في المرّة القادمة", "bundle_column_error.body": "لقد وقع هناك خطأ أثناء عملية تحميل هذا العنصر.", "bundle_column_error.retry": "إعادة المحاولة", @@ -45,7 +45,7 @@ "bundle_modal_error.message": "لقد وقع هناك خطأ أثناء عملية تحميل هذا العنصر.", "bundle_modal_error.retry": "إعادة المحاولة", "column.blocks": "الحسابات المحجوبة", - "column.community": "التَسَلْسُل الزَمني المحلي", + "column.community": "الخيط العام المحلي", "column.direct": "الرسائل المباشرة", "column.domain_blocks": "النطاقات المخفية", "column.favourites": "المفضلة", @@ -66,7 +66,7 @@ "column_subheading.settings": "الإعدادات", "community.column_settings.media_only": "الوسائط فقط", "compose_form.direct_message_warning": "لن يَظهر هذا التبويق إلا للمستخدمين المذكورين.", - "compose_form.direct_message_warning_learn_more": "إقرأ المزيد", + "compose_form.direct_message_warning_learn_more": "اقرأ المزيد", "compose_form.hashtag_warning": "هذا التبويق لن يُدرَج تحت أي وسم كان بما أنه غير مُدرَج. لا يُسمح بالبحث إلّا عن التبويقات العمومية عن طريق الوسوم.", "compose_form.lock_disclaimer": "حسابك ليس {locked}. يمكن لأي شخص متابعتك و عرض المنشورات.", "compose_form.lock_disclaimer.lock": "مقفل", @@ -77,22 +77,22 @@ "compose_form.poll.remove_option": "إزالة هذا الخيار", "compose_form.publish": "بوّق", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "تحديد الوسائط كحساسة", "compose_form.sensitive.marked": "لقد تم تحديد هذه الصورة كحساسة", "compose_form.sensitive.unmarked": "لم يتم تحديد الصورة كحساسة", "compose_form.spoiler.marked": "إنّ النص مخفي وراء تحذير", "compose_form.spoiler.unmarked": "النص غير مخفي", "compose_form.spoiler_placeholder": "تنبيه عن المحتوى", "confirmation_modal.cancel": "إلغاء", - "confirmations.block.block_and_report": "Block & Report", + "confirmations.block.block_and_report": "احجبه وابلغ عنه", "confirmations.block.confirm": "حجب", "confirmations.block.message": "هل أنت متأكد أنك تريد حجب {name} ؟", "confirmations.delete.confirm": "حذف", "confirmations.delete.message": "هل أنت متأكد أنك تريد حذف هذا المنشور ؟", - "confirmations.delete_list.confirm": "Delete", + "confirmations.delete_list.confirm": "احذف", "confirmations.delete_list.message": "هل تود حقا حذف هذه القائمة ؟", - "confirmations.domain_block.confirm": "إخفاء إسم النطاق كاملا", - "confirmations.domain_block.message": "متأكد من أنك تود حظر إسم النطاق {domain} بالكامل ؟ في غالب الأحيان يُستَحسَن كتم أو حظر بعض الحسابات بدلا من حظر نطاق بالكامل.\nلن تتمكن مِن رؤية محتوى هذا النطاق لا على خيوطك العمومية و لا في إشعاراتك. سوف يتم كذلك إزالة كافة متابعيك المنتمين إلى هذا النطاق.", + "confirmations.domain_block.confirm": "إخفاء اسم النطاق كاملا", + "confirmations.domain_block.message": "متأكد من أنك تود حظر اسم النطاق {domain} بالكامل ؟ في غالب الأحيان يُستَحسَن كتم أو حظر بعض الحسابات بدلا من حظر نطاق بالكامل.\nلن تتمكن مِن رؤية محتوى هذا النطاق لا على خيوطك العمومية و لا في إشعاراتك. سوف يتم كذلك إزالة كافة متابعيك المنتمين إلى هذا النطاق.", "confirmations.mute.confirm": "أكتم", "confirmations.mute.message": "هل أنت متأكد أنك تريد كتم {name} ؟", "confirmations.redraft.confirm": "إزالة و إعادة الصياغة", @@ -102,17 +102,17 @@ "confirmations.unfollow.confirm": "إلغاء المتابعة", "confirmations.unfollow.message": "متأكد من أنك تريد إلغاء متابعة {name} ؟", "embed.instructions": "يمكنكم إدماج هذا المنشور على موقعكم الإلكتروني عن طريق نسخ الشفرة أدناه.", - "embed.preview": "هكذا ما سوف يبدو عليه :", + "embed.preview": "هكذا ما سوف يبدو عليه:", "emoji_button.activity": "الأنشطة", "emoji_button.custom": "مخصص", "emoji_button.flags": "الأعلام", "emoji_button.food": "الطعام والشراب", "emoji_button.label": "أدرج إيموجي", "emoji_button.nature": "الطبيعة", - "emoji_button.not_found": "لا إيموجو !! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "لا إيموجو!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "أشياء", "emoji_button.people": "الناس", - "emoji_button.recent": "الشائعة الإستخدام", + "emoji_button.recent": "الشائعة الاستخدام", "emoji_button.search": "ابحث...", "emoji_button.search_results": "نتائج البحث", "emoji_button.symbols": "رموز", @@ -120,7 +120,7 @@ "empty_column.account_timeline": "ليس هناك تبويقات!", "empty_column.account_unavailable": "الملف الشخصي غير متوفر", "empty_column.blocks": "لم تقم بحظر أي مستخدِم بعد.", - "empty_column.community": "الخط الزمني المحلي فارغ. أكتب شيئا ما للعامة كبداية !", + "empty_column.community": "الخط العام المحلي فارغ. أكتب شيئا ما للعامة كبداية!", "empty_column.direct": "لم تتلق أية رسالة خاصة مباشِرة بعد. سوف يتم عرض الرسائل المباشرة هنا إن قمت بإرسال واحدة أو تلقيت البعض منها.", "empty_column.domain_blocks": "ليس هناك نطاقات مخفية بعد.", "empty_column.favourited_statuses": "ليس لديك أية تبويقات مفضلة بعد. عندما ستقوم بالإعجاب بواحد، سيظهر هنا.", @@ -133,13 +133,13 @@ "empty_column.lists": "ليس عندك أية قائمة بعد. سوف تظهر قائمتك هنا إن قمت بإنشاء واحدة.", "empty_column.mutes": "لم تقم بكتم أي مستخدم بعد.", "empty_column.notifications": "لم تتلق أي إشعار بعدُ. تفاعل مع المستخدمين الآخرين لإنشاء محادثة.", - "empty_column.public": "لا يوجد أي شيء هنا ! قم بنشر شيء ما للعامة، أو إتبع المستخدمين الآخرين المتواجدين على الخوادم الأخرى لملء خيط المحادثات", + "empty_column.public": "لا يوجد أي شيء هنا! قم بنشر شيء ما للعامة، أو اتبع المستخدمين الآخرين المتواجدين على الخوادم الأخرى لملء خيط المحادثات", "follow_request.authorize": "ترخيص", "follow_request.reject": "رفض", "getting_started.developers": "المُطوِّرون", "getting_started.directory": "دليل المستخدِمين والمستخدِمات", "getting_started.documentation": "الدليل", - "getting_started.heading": "إستعدّ للبدء", + "getting_started.heading": "استعدّ للبدء", "getting_started.invite": "دعوة أشخاص", "getting_started.open_source_notice": "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء، على جيت هب {github}.", "getting_started.security": "الأمان", @@ -156,16 +156,17 @@ "home.column_settings.basic": "أساسية", "home.column_settings.show_reblogs": "عرض الترقيات", "home.column_settings.show_replies": "عرض الردود", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, one {# يوم} other {# أيام}}", + "intervals.full.hours": "{number, plural, one {# ساعة} other {# ساعات}}", + "intervals.full.minutes": "{number, plural, one {# دقيقة} other {# دقائق}}", "introduction.federation.action": "التالي", - "introduction.federation.federated.headline": "Federated", + "introduction.federation.federated.headline": "الفديرالي", "introduction.federation.federated.text": "كافة المنشورات التي نُشِرت إلى العامة على الخوادم الأخرى للفديفرس سوف يتم عرضها على الخيط المُوحَّد.", - "introduction.federation.home.headline": "Home", + "introduction.federation.home.headline": "الرئيسي", "introduction.federation.home.text": "سوف تُعرَض منشورات الأشخاص الذين تُتابِعهم على الخيط الرئيسي. بإمكانك متابعة أي حساب أيا كان الخادم الذي هو عليه!", - "introduction.federation.local.headline": "Local", - "introduction.federation.local.text": "المنشورات المُوجّهة للعامة على نفس الخادم الذي أنتم عليه ستظهر على الخيط الزمني المحلي.", + "introduction.federation.local.headline": "الخيط العام المحلي", + "introduction.federation.local.text": "المنشورات المُوجّهة للعامة على نفس الخادم الذي أنتم عليه ستظهر على الخيط العام المحلي.", "introduction.interactions.action": "إنهاء العرض التوضيحي!", "introduction.interactions.favourite.headline": "الإضافة إلى المفضلة", "introduction.interactions.favourite.text": "يمكِنك إضافة أي تبويق إلى المفضلة و إعلام صاحبه أنك أعجِبت بذاك التبويق.", @@ -175,24 +176,24 @@ "introduction.interactions.reply.text": "يمكنكم الرد على تبويقاتكم و تبويقات الآخرين على شكل سلسلة محادثة.", "introduction.welcome.action": "هيا بنا!", "introduction.welcome.headline": "الخطوات الأولى", - "introduction.welcome.text": "مرحبا بكم على الفيديفيرس! بعد لحظات قليلة ، سيكون بمقدوركم بث رسائل والتحدث إلى أصدقائكم عبر تشكيلة واسعة من الخوادم المختلفة. هذا الخادم ، {domain} ، يستضيف ملفكم الشخصي ، لذا يجب تذكر اسمه جيدا.", + "introduction.welcome.text": "مرحبا بكم على الفديفرس! بعد لحظات قليلة ، سيكون بمقدوركم بث رسائل والتحدث إلى أصدقائكم عبر تشكيلة واسعة من الخوادم المختلفة. هذا الخادم ، {domain} ، يستضيف ملفكم الشخصي ، لذا يجب تذكر اسمه جيدا.", "keyboard_shortcuts.back": "للعودة", "keyboard_shortcuts.blocked": "لفتح قائمة المستخدمين المحظورين", "keyboard_shortcuts.boost": "للترقية", "keyboard_shortcuts.column": "للتركيز على منشور على أحد الأعمدة", "keyboard_shortcuts.compose": "للتركيز على نافذة تحرير النصوص", - "keyboard_shortcuts.description": "Description", + "keyboard_shortcuts.description": "الوصف", "keyboard_shortcuts.direct": "لفتح عمود الرسائل المباشرة", - "keyboard_shortcuts.down": "للإنتقال إلى أسفل القائمة", - "keyboard_shortcuts.enter": "to open status", + "keyboard_shortcuts.down": "للانتقال إلى أسفل القائمة", + "keyboard_shortcuts.enter": "لفتح المنشور", "keyboard_shortcuts.favourite": "للإضافة إلى المفضلة", "keyboard_shortcuts.favourites": "لفتح قائمة المفضلات", "keyboard_shortcuts.federated": "لفتح الخيط الزمني الفديرالي", "keyboard_shortcuts.heading": "Keyboard Shortcuts", "keyboard_shortcuts.home": "لفتح الخيط الرئيسي", - "keyboard_shortcuts.hotkey": "مفتاح الإختصار", + "keyboard_shortcuts.hotkey": "مفتاح الاختصار", "keyboard_shortcuts.legend": "لعرض هذا المفتاح", - "keyboard_shortcuts.local": "لفتح الخيط الزمني المحلي", + "keyboard_shortcuts.local": "لفتح الخيط العام المحلي", "keyboard_shortcuts.mention": "لذِكر الناشر", "keyboard_shortcuts.muted": "لفتح قائمة المستخدِمين المكتومين", "keyboard_shortcuts.my_profile": "لفتح ملفك الشخصي", @@ -204,23 +205,25 @@ "keyboard_shortcuts.search": "للتركيز على البحث", "keyboard_shortcuts.start": "لفتح عمود \"هيا نبدأ\"", "keyboard_shortcuts.toggle_hidden": "لعرض أو إخفاء النص مِن وراء التحذير", + "keyboard_shortcuts.toggle_sensitivity": "لعرض/إخفاء الوسائط", "keyboard_shortcuts.toot": "لتحرير تبويق جديد", "keyboard_shortcuts.unfocus": "لإلغاء التركيز على حقل النص أو نافذة البحث", - "keyboard_shortcuts.up": "للإنتقال إلى أعلى القائمة", + "keyboard_shortcuts.up": "للانتقال إلى أعلى القائمة", "lightbox.close": "إغلاق", "lightbox.next": "التالي", "lightbox.previous": "العودة", - "lightbox.view_context": "View context", + "lightbox.view_context": "اعرض السياق", "lists.account.add": "أضف إلى القائمة", - "lists.account.remove": "إحذف من القائمة", - "lists.delete": "Delete list", + "lists.account.remove": "احذف من القائمة", + "lists.delete": "احذف القائمة", "lists.edit": "تعديل القائمة", "lists.edit.submit": "تعديل العنوان", "lists.new.create": "إنشاء قائمة", "lists.new.title_placeholder": "عنوان القائمة الجديدة", "lists.search": "إبحث في قائمة الحسابات التي تُتابِعها", "lists.subheading": "قوائمك", - "loading_indicator.label": "تحميل ...", + "load_pending": "{count, plural, one {# new item} other {# new items}}", + "loading_indicator.label": "تحميل...", "media_gallery.toggle_visible": "عرض / إخفاء", "missing_indicator.label": "تعذر العثور عليه", "missing_indicator.sublabel": "تعذر العثور على هذا المورد", @@ -230,20 +233,22 @@ "navigation_bar.community_timeline": "الخيط العام المحلي", "navigation_bar.compose": "تحرير تبويق جديد", "navigation_bar.direct": "الرسائل المباشِرة", - "navigation_bar.discover": "إكتشف", + "navigation_bar.discover": "اكتشف", "navigation_bar.domain_blocks": "النطاقات المخفية", "navigation_bar.edit_profile": "تعديل الملف الشخصي", "navigation_bar.favourites": "المفضلة", "navigation_bar.filters": "الكلمات المكتومة", "navigation_bar.follow_requests": "طلبات المتابعة", + "navigation_bar.follows_and_followers": "المتابِعين والمتابَعون", "navigation_bar.info": "عن هذا الخادم", - "navigation_bar.keyboard_shortcuts": "إختصارات لوحة المفاتيح", + "navigation_bar.keyboard_shortcuts": "اختصارات لوحة المفاتيح", "navigation_bar.lists": "القوائم", "navigation_bar.logout": "خروج", "navigation_bar.mutes": "الحسابات المكتومة", - "navigation_bar.personal": "Personal", + "navigation_bar.personal": "شخصي", "navigation_bar.pins": "التبويقات المثبتة", "navigation_bar.preferences": "التفضيلات", + "navigation_bar.profile_directory": "دليل المستخدِمين", "navigation_bar.public_timeline": "الخيط العام الموحد", "navigation_bar.security": "الأمان", "notification.favourite": "أُعجِب {name} بمنشورك", @@ -251,19 +256,19 @@ "notification.mention": "{name} ذكرك", "notification.poll": "A poll you have voted in has ended", "notification.reblog": "{name} قام بترقية تبويقك", - "notifications.clear": "إمسح الإخطارات", + "notifications.clear": "امسح الإخطارات", "notifications.clear_confirmation": "أمتأكد من أنك تود مسح جل الإخطارات الخاصة بك و المتلقاة إلى حد الآن ؟", "notifications.column_settings.alert": "إشعارات سطح المكتب", - "notifications.column_settings.favourite": "المُفَضَّلة :", + "notifications.column_settings.favourite": "المُفَضَّلة:", "notifications.column_settings.filter_bar.advanced": "عرض كافة الفئات", "notifications.column_settings.filter_bar.category": "شريط الفلترة السريعة", "notifications.column_settings.filter_bar.show": "عرض", - "notifications.column_settings.follow": "متابعُون جُدُد :", - "notifications.column_settings.mention": "الإشارات :", + "notifications.column_settings.follow": "متابعُون جُدُد:", + "notifications.column_settings.mention": "الإشارات:", "notifications.column_settings.poll": "نتائج استطلاع الرأي:", "notifications.column_settings.push": "الإخطارات المدفوعة", "notifications.column_settings.reblog": "الترقيّات:", - "notifications.column_settings.show": "إعرِضها في عمود", + "notifications.column_settings.show": "اعرِضها في عمود", "notifications.column_settings.sound": "أصدر صوتا", "notifications.filter.all": "الكل", "notifications.filter.boosts": "الترقيات", @@ -274,11 +279,11 @@ "notifications.group": "{count} إشعارات", "poll.closed": "انتهى", "poll.refresh": "تحديث", - "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", + "poll.total_votes": "{count, plural, one {# صوت} other {# أصوات}}", "poll.vote": "صَوّت", "poll_button.add_poll": "إضافة استطلاع للرأي", "poll_button.remove_poll": "إزالة استطلاع الرأي", - "privacy.change": "إضبط خصوصية المنشور", + "privacy.change": "اضبط خصوصية المنشور", "privacy.direct.long": "أنشر إلى المستخدمين المشار إليهم فقط", "privacy.direct.short": "مباشر", "privacy.private.long": "أنشر لمتابعيك فقط", @@ -287,20 +292,20 @@ "privacy.public.short": "للعامة", "privacy.unlisted.long": "لا تقم بإدراجه على الخيوط العامة", "privacy.unlisted.short": "غير مدرج", - "regeneration_indicator.label": "جارٍ التحميل …", - "regeneration_indicator.sublabel": "جارٍ تجهيز تغذية صفحتك الرئيسية !", - "relative_time.days": "{number}d", - "relative_time.hours": "{number}h", + "regeneration_indicator.label": "جارٍ التحميل…", + "regeneration_indicator.sublabel": "جارٍ تجهيز تغذية صفحتك الرئيسية!", + "relative_time.days": "{number}ي", + "relative_time.hours": "{number}سا", "relative_time.just_now": "الآن", - "relative_time.minutes": "{number}m", - "relative_time.seconds": "{number}s", + "relative_time.minutes": "{number}د", + "relative_time.seconds": "{number}ثا", "reply_indicator.cancel": "إلغاء", "report.forward": "التحويل إلى {target}", - "report.forward_hint": "هذا الحساب ينتمي إلى خادوم آخَر. هل تودّ إرسال نسخة مجهولة مِن التقرير إلى هنالك أيضًا ؟", + "report.forward_hint": "هذا الحساب ينتمي إلى خادوم آخَر. هل تودّ إرسال نسخة مجهولة مِن التقرير إلى هنالك أيضًا؟", "report.hint": "سوف يتم إرسال التقرير إلى المُشرِفين على خادومكم. بإمكانكم الإدلاء بشرح عن سبب الإبلاغ عن الحساب أسفله:", "report.placeholder": "تعليقات إضافية", "report.submit": "إرسال", - "report.target": "إبلاغ", + "report.target": "ابلغ عن {target}", "search.placeholder": "ابحث", "search_popout.search_format": "نمط البحث المتقدم", "search_popout.tips.full_text": "النص البسيط يقوم بعرض المنشورات التي كتبتها أو قمت بإرسالها أو ترقيتها أو تمت الإشارة إليك فيها من طرف آخرين ، بالإضافة إلى مطابقة أسماء المستخدمين وأسماء العرض وعلامات التصنيف.", @@ -311,14 +316,15 @@ "search_results.accounts": "أشخاص", "search_results.hashtags": "الوُسوم", "search_results.statuses": "التبويقات", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} و {results}}", "status.admin_account": "افتح الواجهة الإدارية لـ @{name}", "status.admin_status": "افتح هذا المنشور على واجهة الإشراف", - "status.block": "Block @{name}", + "status.block": "احجب @{name}", "status.cancel_reblog_private": "إلغاء الترقية", "status.cannot_reblog": "تعذرت ترقية هذا المنشور", "status.copy": "نسخ رابط المنشور", - "status.delete": "إحذف", + "status.delete": "احذف", "status.detailed_status": "تفاصيل المحادثة", "status.direct": "رسالة خاصة إلى @{name}", "status.embed": "إدماج", @@ -341,32 +347,32 @@ "status.redraft": "إزالة و إعادة الصياغة", "status.reply": "ردّ", "status.replyAll": "رُد على الخيط", - "status.report": "إبلِغ عن @{name}", + "status.report": "ابلِغ عن @{name}", "status.sensitive_warning": "محتوى حساس", "status.share": "مشاركة", - "status.show_less": "إعرض أقلّ", + "status.show_less": "اعرض أقلّ", "status.show_less_all": "طي الكل", "status.show_more": "أظهر المزيد", "status.show_more_all": "توسيع الكل", "status.show_thread": "الكشف عن المحادثة", "status.unmute_conversation": "فك الكتم عن المحادثة", "status.unpin": "فك التدبيس من الملف الشخصي", - "suggestions.dismiss": "إلغاء الإقتراح", + "suggestions.dismiss": "إلغاء الاقتراح", "suggestions.header": "يمكن أن يهمك…", "tabs_bar.federated_timeline": "الموحَّد", "tabs_bar.home": "الرئيسية", - "tabs_bar.local_timeline": "المحلي", + "tabs_bar.local_timeline": "الخيط العام المحلي", "tabs_bar.notifications": "الإخطارات", "tabs_bar.search": "البحث", - "time_remaining.days": "{number, plural, one {# day} other {# days}} left", + "time_remaining.days": "{number, plural, one {# يوم} other {# أيام}} متبقية", "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", - "time_remaining.moments": "Moments remaining", + "time_remaining.moments": "لحظات متبقية", "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left", "trends.count_by_accounts": "{count} {rawCount, plural, one {person} آخرون {people}} يتحدثون", "ui.beforeunload": "سوف تفقد مسودتك إن تركت ماستدون.", - "upload_area.title": "إسحب ثم أفلت للرفع", - "upload_button.label": "إضافة وسائط (JPEG، PNG، GIF، WebM، MP4، MOV)", + "upload_area.title": "اسحب ثم أفلت للرفع", + "upload_button.label": "إضافة وسائط ({formats})", "upload_error.limit": "لقد تم بلوغ الحد الأقصى المسموح به لإرسال الملفات.", "upload_error.poll": "لا يمكن إدراج ملفات في استطلاعات الرأي.", "upload_form.description": "وصف للمعاقين بصريا", diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json index 57849c393..95defc52b 100644 --- a/app/javascript/mastodon/locales/ast.json +++ b/app/javascript/mastodon/locales/ast.json @@ -64,7 +64,7 @@ "column_header.show_settings": "Show settings", "column_header.unpin": "Desfixar", "column_subheading.settings": "Axustes", - "community.column_settings.media_only": "Media Only", + "community.column_settings.media_only": "Media only", "compose_form.direct_message_warning": "Esti toot namái va unviase a los usuarios mentaos.", "compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", @@ -156,6 +156,7 @@ "home.column_settings.basic": "Basic", "home.column_settings.show_reblogs": "Amosar toots compartíos", "home.column_settings.show_replies": "Amosar rempuestes", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Títulu nuevu de la llista", "lists.search": "Guetar ente la xente que sigues", "lists.subheading": "Les tos llistes", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Cargando...", "media_gallery.toggle_visible": "Toggle visibility", "missing_indicator.label": "Nun s'alcontró", @@ -311,6 +313,7 @@ "search_results.accounts": "Xente", "search_results.hashtags": "Etiquetes", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 7836146cd..2b78f5627 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -64,7 +64,7 @@ "column_header.show_settings": "Show settings", "column_header.unpin": "Unpin", "column_subheading.settings": "Settings", - "community.column_settings.media_only": "Media Only", + "community.column_settings.media_only": "Media only", "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", "compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", @@ -156,6 +156,7 @@ "home.column_settings.basic": "Basic", "home.column_settings.show_reblogs": "Show boosts", "home.column_settings.show_replies": "Show replies", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "New list title", "lists.search": "Search among people you follow", "lists.subheading": "Your lists", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Зареждане...", "media_gallery.toggle_visible": "Toggle visibility", "missing_indicator.label": "Not found", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json index bdf952d3a..358f994f3 100644 --- a/app/javascript/mastodon/locales/bn.json +++ b/app/javascript/mastodon/locales/bn.json @@ -1,13 +1,13 @@ { "account.add_or_remove_from_list": "তালিকাতে আরো যুক্ত বা মুছে ফেলুন", "account.badges.bot": "রোবট", - "account.block": "@{name} বন্ধ করুন", + "account.block": "@{name} কে বন্ধ করুন", "account.block_domain": "{domain} থেকে সব সরিয়ে ফেলুন", "account.blocked": "বন্ধ করা হয়েছে", - "account.direct": "@{name}কে সরকারি লিখুন", + "account.direct": "@{name} এর কাছে সরকারি লেখা পাঠাতে", "account.domain_blocked": "ওয়েবসাইট সরিয়ে ফেলা হয়েছে", - "account.edit_profile": "নিজের পাতা সম্পাদনা করুন", - "account.endorse": "নিজের পাতায় দেখান", + "account.edit_profile": "নিজের পাতা সম্পাদনা করতে", + "account.endorse": "আপনার নিজের পাতায় দেখাতে", "account.follow": "অনুসরণ করুন", "account.followers": "অনুসরণকারক", "account.followers.empty": "এই ব্যবহারকারীকে কেও এখনো অনুসরণ করে না।", @@ -18,21 +18,21 @@ "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": "@{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.unblock": "@{name}র কার্যকলাপ আবার দেখুন", "account.unblock_domain": "{domain}থেকে আবার দেখুন", - "account.unendorse": "নিজের পাতায় এটা দেখতে চান না", - "account.unfollow": "অনুসরণ বন্ধ করুন", + "account.unendorse": "আপনার নিজের পাতায় এটা না দেখাতে", + "account.unfollow": "অনুসরণ না করতে", "account.unmute": "@{name}র কার্যকলাপ আবার দেখুন", "account.unmute_notifications": "@{name}র প্রজ্ঞাপন দেওয়ার অনুমতি দিন", "alert.unexpected.message": "অপ্রত্যাশিত একটি সমস্যা হয়েছে।", @@ -42,7 +42,7 @@ "bundle_column_error.retry": "আবার চেষ্টা করুন", "bundle_column_error.title": "নেটওয়ার্কের সমস্যা হচ্ছে", "bundle_modal_error.close": "বন্ধ করুন", - "bundle_modal_error.message": "এই অংশটি দেখতে যেয়ে কোনো সমস্যা হয়েছে।", + "bundle_modal_error.message": "এই অংশটি দেখাতে যেয়ে কোনো সমস্যা হয়েছে।", "bundle_modal_error.retry": "আবার চেষ্টা করুন", "column.blocks": "যাদের বন্ধ করে রাখা হয়েছে", "column.community": "স্থানীয় সময়সারি", @@ -77,12 +77,12 @@ "compose_form.poll.remove_option": "এই বিকল্পটি মুছে ফেলুন", "compose_form.publish": "টুট", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "এই ছবি বা ভিডিওটি সংবেদনশীল হিসেবে চিহ্নিত করতে", "compose_form.sensitive.marked": "এই ছবি বা ভিডিওটি সংবেদনশীল হিসেবে চিহ্নিত করা হয়েছে", "compose_form.sensitive.unmarked": "এই ছবি বা ভিডিওটি সংবেদনশীল হিসেবে চিহ্নিত করা হয়নি", "compose_form.spoiler.marked": "লেখাটি সাবধানতার পেছনে লুকানো আছে", "compose_form.spoiler.unmarked": "লেখাটি লুকানো নেই", - "compose_form.spoiler_placeholder": "আপনার সাবধানতা এখানে লিখুন", + "compose_form.spoiler_placeholder": "আপনার লেখা দেখার সাবধানবাণী লিখুন", "confirmation_modal.cancel": "বাতিল করুন", "confirmations.block.block_and_report": "বন্ধ করুন এবং রিপোর্ট করুন", "confirmations.block.confirm": "বন্ধ করুন", @@ -99,7 +99,7 @@ "confirmations.redraft.message": "আপনি কি নিশ্চিত এটি মুছে ফেলে এবং আবার সম্পাদন করতে চান ? এটাতে যা পছন্দিত, সমর্থন বা মতামত আছে সেগুলো নতুন লেখার সাথে যুক্ত থাকবে না।", "confirmations.reply.confirm": "মতামত", "confirmations.reply.message": "এখন মতামত লিখতে গেলে আপনার এখন যেটা লিখছেন সেটা মুছে যাবে। আপনি নি নিশ্চিত এটা করতে চান ?", - "confirmations.unfollow.confirm": "অনুসরণ বন্ধ করুন", + "confirmations.unfollow.confirm": "অনুসরণ করা বাতিল করতে", "confirmations.unfollow.message": "আপনি কি নিশ্চিত {name} কে আর অনুসরণ করতে চান না ?", "embed.instructions": "এই লেখাটি আপনার ওয়েবসাইটে যুক্ত করতে নিচের কোডটি বেবহার করুন।", "embed.preview": "সেটা দেখতে এরকম হবে:", @@ -137,11 +137,11 @@ "follow_request.authorize": "অনুমতি দিন", "follow_request.reject": "প্রত্যাখ্যান করুন", "getting_started.developers": "তৈরিকারকদের জন্য", - "getting_started.directory": "নিজস্ব পাতার তালিকা", + "getting_started.directory": "নিজস্ব-পাতাগুলির তালিকা", "getting_started.documentation": "নথিপত্র", "getting_started.heading": "শুরু করা", "getting_started.invite": "অন্যদের আমন্ত্রণ করুন", - "getting_started.open_source_notice": "মাস্টাডন একটি মুক্ত সফটওয়্যার। আপনি তৈরিতে সাহায্য করতে পারেন অথবা সমস্যা রিপোর্ট করতে পারেন গিটহাবে {github}।", + "getting_started.open_source_notice": "মাস্টাডন একটি মুক্ত সফটওয়্যার। তৈরিতে সাহায্য করতে বা কোনো সমস্যা সম্পর্কে জানাতে আমাদের গিটহাবে যেতে পারেন {github}।", "getting_started.security": "নিরাপত্তা", "getting_started.terms": "ব্যবহারের নিয়মাবলী", "hashtag.column_header.tag_mode.all": "এবং {additional}", @@ -152,10 +152,11 @@ "hashtag.column_settings.tag_mode.all": "এগুলো সব", "hashtag.column_settings.tag_mode.any": "এর ভেতরে যেকোনোটা", "hashtag.column_settings.tag_mode.none": "এগুলোর একটাও না", - "hashtag.column_settings.tag_toggle": "আরো ট্যাগ এই কলামে যুক্ত করুন", + "hashtag.column_settings.tag_toggle": "আরো ট্যাগ এই কলামে যুক্ত করতে", "home.column_settings.basic": "সাধারণ", "home.column_settings.show_reblogs": "সমর্থনগুলো দেখান", "home.column_settings.show_replies": "মতামত দেখান", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# ঘটা} other {# ঘটা}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -195,7 +196,7 @@ "keyboard_shortcuts.local": "স্থানীয় সময়রেখাতে যেতে", "keyboard_shortcuts.mention": "লেখককে উল্লেখ করতে", "keyboard_shortcuts.muted": "বন্ধ করা ব্যবহারকারীদের তালিকা খুলতে", - "keyboard_shortcuts.my_profile": "নিজের পাতা দেখতে", + "keyboard_shortcuts.my_profile": "আপনার নিজের পাতা দেখতে", "keyboard_shortcuts.notifications": "প্রজ্ঞাপনের কলাম খুলতে", "keyboard_shortcuts.pinned": "পিন দেওয়া টুটের তালিকা খুলতে", "keyboard_shortcuts.profile": "লেখকের পাতা দেখতে", @@ -204,13 +205,14 @@ "keyboard_shortcuts.search": "খোঁজার অংশে ফোকাস করতে", "keyboard_shortcuts.start": "\"প্রথম শুরুর\" কলাম বের করতে", "keyboard_shortcuts.toggle_hidden": "CW লেখা দেখতে বা লুকাতে", + "keyboard_shortcuts.toggle_sensitivity": "ভিডিও/ছবি দেখতে বা বন্ধ করতে", "keyboard_shortcuts.toot": "নতুন একটা টুট লেখা শুরু করতে", "keyboard_shortcuts.unfocus": "লেখা বা খোঁজার জায়গায় ফোকাস না করতে", "keyboard_shortcuts.up": "তালিকার উপরের দিকে যেতে", "lightbox.close": "বন্ধ", "lightbox.next": "পরবর্তী", "lightbox.previous": "পূর্ববর্তী", - "lightbox.view_context": "View context", + "lightbox.view_context": "প্রসঙ্গটি দেখতে", "lists.account.add": "তালিকাতে যুক্ত করতে", "lists.account.remove": "তালিকা থেকে বাদ দিতে", "lists.delete": "তালিকা মুছে ফেলতে", @@ -220,6 +222,7 @@ "lists.new.title_placeholder": "তালিকার নতুন শিরোনাম দিতে", "lists.search": "যাদের অনুসরণ করেন তাদের ভেতরে খুঁজুন", "lists.subheading": "আপনার তালিকা", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "আসছে...", "media_gallery.toggle_visible": "দৃশ্যতার অবস্থা বদলান", "missing_indicator.label": "খুঁজে পাওয়া যায়নি", @@ -229,21 +232,23 @@ "navigation_bar.blocks": "বন্ধ করা ব্যবহারকারী", "navigation_bar.community_timeline": "স্থানীয় সময়রেখা", "navigation_bar.compose": "নতুন টুট লিখুন", - "navigation_bar.direct": "সরাসরি লেখা", + "navigation_bar.direct": "সরাসরি লেখাগুলি", "navigation_bar.discover": "ঘুরে দেখুন", "navigation_bar.domain_blocks": "বন্ধ করা ওয়েবসাইট", - "navigation_bar.edit_profile": "নিজের পাতা সম্পাদনা করুন", + "navigation_bar.edit_profile": "নিজের পাতা সম্পাদনা করতে", "navigation_bar.favourites": "পছন্দের", "navigation_bar.filters": "বন্ধ করা শব্দ", "navigation_bar.follow_requests": "অনুসরণের অনুরোধগুলি", + "navigation_bar.follows_and_followers": "যাদেরকে অনুসরণ করেন এবং যারা তাকে অনুসরণ করে", "navigation_bar.info": "এই সার্ভার সম্পর্কে", - "navigation_bar.keyboard_shortcuts": "চাবি ব্যবহার", + "navigation_bar.keyboard_shortcuts": "হটকীগুলি", "navigation_bar.lists": "তালিকাগুলো", "navigation_bar.logout": "বাইরে যান", "navigation_bar.mutes": "যেসব বেভহারকারীদের কার্যক্রম বন্ধ করা আছে", "navigation_bar.personal": "নিজস্ব", "navigation_bar.pins": "পিন দেওয়া টুট", "navigation_bar.preferences": "পছন্দসমূহ", + "navigation_bar.profile_directory": "নিজস্ব পাতার তালিকা", "navigation_bar.public_timeline": "যুক্তবিশ্বের সময়রেখা", "navigation_bar.security": "নিরাপত্তা", "notification.favourite": "{name} আপনার কার্যক্রম পছন্দ করেছেন", @@ -253,18 +258,18 @@ "notification.reblog": "{name} আপনার কার্যক্রমে সমর্থন দেখিয়েছেন", "notifications.clear": "প্রজ্ঞাপনগুলো মুছে ফেলতে", "notifications.clear_confirmation": "আপনি কি নির্চিত প্রজ্ঞাপনগুলো মুছে ফেলতে চান ?", - "notifications.column_settings.alert": "কম্পিউটারে প্রজ্ঞাপন", + "notifications.column_settings.alert": "কম্পিউটারে প্রজ্ঞাপনগুলি", "notifications.column_settings.favourite": "পছন্দের:", - "notifications.column_settings.filter_bar.advanced": "সব শ্রেণীগুলো দেখতে", - "notifications.column_settings.filter_bar.category": "দ্রুত ছাঁকনি বার", - "notifications.column_settings.filter_bar.show": "দেখতে", + "notifications.column_settings.filter_bar.advanced": "সব শ্রেণীগুলো দেখানো", + "notifications.column_settings.filter_bar.category": "সংক্ষিপ্ত ছাঁকনি অংশ", + "notifications.column_settings.filter_bar.show": "দেখানো", "notifications.column_settings.follow": "নতুন অনুসরণকারীরা:", "notifications.column_settings.mention": "প্রজ্ঞাপনগুলো:", "notifications.column_settings.poll": "নির্বাচনের ফলাফল:", - "notifications.column_settings.push": "পুশ প্রজ্ঞাপন", + "notifications.column_settings.push": "পুশ প্রজ্ঞাপনগুলি", "notifications.column_settings.reblog": "সমর্থনগুলো:", - "notifications.column_settings.show": "কলামে দেখান", - "notifications.column_settings.sound": "শব্দ বাজাতে", + "notifications.column_settings.show": "কলামে দেখানো", + "notifications.column_settings.sound": "শব্দ বাজানো", "notifications.filter.all": "সব", "notifications.filter.boosts": "সমর্থনগুলো", "notifications.filter.favourites": "পছন্দের গুলো", @@ -273,7 +278,7 @@ "notifications.filter.polls": "নির্বাচনের ফলাফল", "notifications.group": "{count} প্রজ্ঞাপন", "poll.closed": "বন্ধ", - "poll.refresh": "আবার সতেজ করতে", + "poll.refresh": "বদলেছে কিনা দেখতে", "poll.total_votes": "{count, plural, one {# ভোট} other {# ভোট}}", "poll.vote": "ভোট", "poll_button.add_poll": "একটা নির্বাচন যোগ করতে", @@ -292,7 +297,7 @@ "relative_time.days": "{number} দিন", "relative_time.hours": "{number} ঘন্টা", "relative_time.just_now": "এখন", - "relative_time.minutes": "{number} মাস", + "relative_time.minutes": "{number}ম", "relative_time.seconds": "{number} সেকেন্ড", "reply_indicator.cancel": "বাতিল করতে", "report.forward": "এটা আরো পাঠান {target} তে", @@ -311,6 +316,7 @@ "search_results.accounts": "মানুষ", "search_results.hashtags": "হ্যাশট্যাগগুলি", "search_results.statuses": "টুট", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {ফলাফল} other {ফলাফল}}", "status.admin_account": "@{name} র জন্য পরিচালনার ইন্টারফেসে ঢুকুন", "status.admin_status": "যায় লেখাটি পরিচালনার ইন্টারফেসে খুলুন", @@ -320,7 +326,7 @@ "status.copy": "লেখাটির লিংক কপি করতে", "status.delete": "মুছে ফেলতে", "status.detailed_status": "বিস্তারিত কথোপকথনের হিসেবে দেখতে", - "status.direct": "@{name} কে সরাসরি পাঠান", + "status.direct": "@{name} কে সরাসরি লেখা পাঠাতে", "status.embed": "এমবেড করতে", "status.favourite": "পছন্দের করতে", "status.filtered": "ছাঁকনিদিত", @@ -341,7 +347,7 @@ "status.redraft": "মুছে আবার নতুন করে লিখতে", "status.reply": "মতামত জানাতে", "status.replyAll": "লেখাযুক্ত সবার কাছে মতামত জানাতে", - "status.report": "@{name}কে রিপোর্ট করতে", + "status.report": "@{name} কে রিপোর্ট করতে", "status.sensitive_warning": "সংবেদনশীল কিছু", "status.share": "অন্যদের জানান", "status.show_less": "কম দেখতে", @@ -351,7 +357,7 @@ "status.show_thread": "আলোচনা দেখতে", "status.unmute_conversation": "আলোচনার প্রজ্ঞাপন চালু করতে", "status.unpin": "নিজের পাতা থেকে পিন করে রাখাটির পিন খুলতে", - "suggestions.dismiss": "সাহায্যের জন্য পরামর্শগুলো সরাতে", + "suggestions.dismiss": "সাহায্যের পরামর্শগুলো সরাতে", "suggestions.header": "আপনি হয়তোবা এগুলোতে আগ্রহী হতে পারেন…", "tabs_bar.federated_timeline": "যুক্তবিশ্ব", "tabs_bar.home": "বাড়ি", @@ -366,7 +372,7 @@ "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} কথা বলছে", "ui.beforeunload": "যে পর্যন্ত এটা লেখা হয়েছে, মাস্টাডন থেকে চলে গেলে এটা মুছে যাবে।", "upload_area.title": "টেনে এখানে ছেড়ে দিলে এখানে যুক্ত করা যাবে", - "upload_button.label": "ছবি বা ভিডিও যুক্ত করতে (এসব ধরণের JPEG, PNG, GIF, WebM, MP4, MOV)", + "upload_button.label": "ছবি বা ভিডিও যুক্ত করতে (এসব ধরণের: JPEG, PNG, GIF, WebM, MP4, MOV)", "upload_error.limit": "যা যুক্ত করতে চাচ্ছেন সেটি বেশি বড়, এখানকার সর্বাধিকের মেমোরির উপরে চলে গেছে।", "upload_error.poll": "নির্বাচনক্ষেত্রে কোনো ফাইল যুক্ত করা যাবেনা।", "upload_form.description": "যারা দেখতে পায়না তাদের জন্য এটা বর্ণনা করতে", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 0cafb1120..09f8838e9 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -1,7 +1,7 @@ { "account.add_or_remove_from_list": "Afegir o Treure de les llistes", "account.badges.bot": "Bot", - "account.block": "Bloca @{name}", + "account.block": "Bloqueja @{name}", "account.block_domain": "Amaga-ho tot de {domain}", "account.blocked": "Bloquejat", "account.direct": "Missatge directe @{name}", @@ -11,7 +11,7 @@ "account.follow": "Segueix", "account.followers": "Seguidors", "account.followers.empty": "Encara ningú no segueix aquest usuari.", - "account.follows": "Seguint", + "account.follows": "Seguiments", "account.follows.empty": "Aquest usuari encara no segueix a ningú.", "account.follows_you": "Et segueix", "account.hide_reblogs": "Amaga els impulsos de @{name}", @@ -44,7 +44,7 @@ "bundle_modal_error.close": "Tanca", "bundle_modal_error.message": "S'ha produït un error en carregar aquest component.", "bundle_modal_error.retry": "Torna-ho a provar", - "column.blocks": "Usuaris blocats", + "column.blocks": "Usuaris bloquejats", "column.community": "Línia de temps local", "column.direct": "Missatges directes", "column.domain_blocks": "Dominis ocults", @@ -54,7 +54,7 @@ "column.lists": "Llistes", "column.mutes": "Usuaris silenciats", "column.notifications": "Notificacions", - "column.pins": "Toot fixat", + "column.pins": "Toots fixats", "column.public": "Línia de temps federada", "column_back_button.label": "Enrere", "column_header.hide_settings": "Amaga la configuració", @@ -65,12 +65,12 @@ "column_header.unpin": "No fixis", "column_subheading.settings": "Configuració", "community.column_settings.media_only": "Només multimèdia", - "compose_form.direct_message_warning": "Aquest toot només serà enviat als usuaris esmentats. De totes maneres, els operadors de la teva o de qualsevol de les instàncies receptores poden inspeccionar aquest missatge.", + "compose_form.direct_message_warning": "Aquest toot només serà enviat als usuaris esmentats.", "compose_form.direct_message_warning_learn_more": "Aprèn més", "compose_form.hashtag_warning": "Aquest toot no es mostrarà en cap etiqueta ja que no està llistat. Només els toots públics poden ser cercats per etiqueta.", "compose_form.lock_disclaimer": "El teu compte no està bloquejat {locked}. Tothom pot seguir-te i veure els teus missatges a seguidors.", - "compose_form.lock_disclaimer.lock": "blocat", - "compose_form.placeholder": "En què estàs pensant?", + "compose_form.lock_disclaimer.lock": "bloquejat", + "compose_form.placeholder": "En què penses?", "compose_form.poll.add_option": "Afegeix una opció", "compose_form.poll.duration": "Durada de l'enquesta", "compose_form.poll.option_placeholder": "Opció {number}", @@ -84,11 +84,11 @@ "compose_form.spoiler.unmarked": "Text no ocult", "compose_form.spoiler_placeholder": "Escriu l'avís aquí", "confirmation_modal.cancel": "Cancel·la", - "confirmations.block.block_and_report": "Block & Report", - "confirmations.block.confirm": "Bloca", + "confirmations.block.block_and_report": "Bloquejar i informar", + "confirmations.block.confirm": "Bloqueja", "confirmations.block.message": "Estàs segur que vols bloquejar a {name}?", "confirmations.delete.confirm": "Suprimeix", - "confirmations.delete.message": "Estàs segur que vols suprimir aquest estat?", + "confirmations.delete.message": "Estàs segur que vols suprimir aquest toot?", "confirmations.delete_list.confirm": "Suprimeix", "confirmations.delete_list.message": "Estàs segur que vols suprimir permanentment aquesta llista?", "confirmations.domain_block.confirm": "Amaga tot el domini", @@ -96,12 +96,12 @@ "confirmations.mute.confirm": "Silencia", "confirmations.mute.message": "Estàs segur que vols silenciar {name}?", "confirmations.redraft.confirm": "Esborrar i refer", - "confirmations.redraft.message": "Estàs segur que vols esborrar aquesta publicació i tornar a redactar-la? Perderàs totes els impulsos i favorits, i les respostes a la publicació original es quedaran orfes.", + "confirmations.redraft.message": "Estàs segur que vols esborrar aquest toot i tornar a redactar-lo? Perderàs totes els impulsos i favorits, i les respostes al toot original es quedaran orfes.", "confirmations.reply.confirm": "Respon", "confirmations.reply.message": "Responen ara es sobreescriurà el missatge que estàs editant. Estàs segur que vols continuar?", "confirmations.unfollow.confirm": "Deixa de seguir", "confirmations.unfollow.message": "Estàs segur que vols deixar de seguir {name}?", - "embed.instructions": "Incrusta aquest estat al lloc web copiant el codi a continuació.", + "embed.instructions": "Incrusta aquest toot al lloc web copiant el codi a continuació.", "embed.preview": "Aquí tenim quin aspecte tindrá:", "emoji_button.activity": "Activitat", "emoji_button.custom": "Personalitzat", @@ -118,18 +118,18 @@ "emoji_button.symbols": "Símbols", "emoji_button.travel": "Viatges i Llocs", "empty_column.account_timeline": "No hi ha toots aquí!", - "empty_column.account_unavailable": "Profile unavailable", + "empty_column.account_unavailable": "Perfil no disponible", "empty_column.blocks": "Encara no has bloquejat cap usuari.", - "empty_column.community": "La línia de temps local és buida. Escriu alguna cosa públicament per fer rodar la pilota!", + "empty_column.community": "La línia de temps local és buida. Escriu alguna cosa públicament per a fer rodar la pilota!", "empty_column.direct": "Encara no tens missatges directes. Quan enviïs o rebis un, es mostrarà aquí.", "empty_column.domain_blocks": "Encara no hi ha dominis ocults.", "empty_column.favourited_statuses": "Encara no tens cap toot favorit. Quan en tinguis, apareixerà aquí.", "empty_column.favourites": "Encara ningú ha marcat aquest toot com a favorit. Quan algú ho faci, apareixera aquí.", - "empty_column.follow_requests": "Encara no teniu cap petició de seguiment. Quan rebeu una, apareixerà aquí.", + "empty_column.follow_requests": "Encara no teniu cap petició de seguiment. Quan rebis una, apareixerà aquí.", "empty_column.hashtag": "Encara no hi ha res en aquesta etiqueta.", "empty_column.home": "Encara no segueixes ningú. Visita {public} o fes cerca per començar i conèixer altres usuaris.", "empty_column.home.public_timeline": "la línia de temps pública", - "empty_column.list": "Encara no hi ha res en aquesta llista. Quan els membres d'aquesta llista publiquin nous estats, apareixeran aquí.", + "empty_column.list": "Encara no hi ha res en aquesta llista. Quan els membres d'aquesta llista publiquin nous toots, apareixeran aquí.", "empty_column.lists": "Encara no tens cap llista. Quan en facis una, apareixerà aquí.", "empty_column.mutes": "Encara no has silenciat cap usuari.", "empty_column.notifications": "Encara no tens notificacions. Interactua amb altres per iniciar la conversa.", @@ -156,6 +156,7 @@ "home.column_settings.basic": "Bàsic", "home.column_settings.show_reblogs": "Mostrar impulsos", "home.column_settings.show_replies": "Mostrar respostes", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# dia} other {# dies}}", "intervals.full.hours": "{number, plural, one {# hora} other {# hores}}", "intervals.full.minutes": "{number, plural, one {# minut} other {# minuts}}", @@ -179,31 +180,32 @@ "keyboard_shortcuts.back": "navegar enrera", "keyboard_shortcuts.blocked": "per obrir la llista d'usuaris bloquejats", "keyboard_shortcuts.boost": "impulsar", - "keyboard_shortcuts.column": "per centrar un estat en una de les columnes", + "keyboard_shortcuts.column": "per a centrar un toot en una de les columnes", "keyboard_shortcuts.compose": "per centrar l'area de composició de text", "keyboard_shortcuts.description": "Descripció", "keyboard_shortcuts.direct": "per obrir la columna de missatges directes", "keyboard_shortcuts.down": "per baixar en la llista", - "keyboard_shortcuts.enter": "ampliar estat", + "keyboard_shortcuts.enter": "ampliar el toot", "keyboard_shortcuts.favourite": "afavorir", "keyboard_shortcuts.favourites": "per obrir la llista de favorits", "keyboard_shortcuts.federated": "per obrir la línia de temps federada", "keyboard_shortcuts.heading": "Dreçeres de teclat", - "keyboard_shortcuts.home": "per obrir la línia de temps Inici", + "keyboard_shortcuts.home": "per a obrir la línia de temps Inici", "keyboard_shortcuts.hotkey": "Tecla d'accés directe", "keyboard_shortcuts.legend": "per a mostrar aquesta llegenda", - "keyboard_shortcuts.local": "per obrir la línia de temps local", - "keyboard_shortcuts.mention": "per esmentar l'autor", - "keyboard_shortcuts.muted": "per obrir la llista d'usuaris silenciats", - "keyboard_shortcuts.my_profile": "per obrir el teu perfil", - "keyboard_shortcuts.notifications": "per obrir la columna de notificacions", - "keyboard_shortcuts.pinned": "per obrir la llista de toots fixats", - "keyboard_shortcuts.profile": "per obrir el perfil de l'autor", + "keyboard_shortcuts.local": "per a obrir la línia de temps local", + "keyboard_shortcuts.mention": "per a esmentar l'autor", + "keyboard_shortcuts.muted": "per a obrir la llista d'usuaris silenciats", + "keyboard_shortcuts.my_profile": "per a obrir el teu perfil", + "keyboard_shortcuts.notifications": "per a obrir la columna de notificacions", + "keyboard_shortcuts.pinned": "per a obrir la llista de toots fixats", + "keyboard_shortcuts.profile": "per a obrir el perfil de l'autor", "keyboard_shortcuts.reply": "respondre", - "keyboard_shortcuts.requests": "per obrir la llista de sol·licituds de seguiment", - "keyboard_shortcuts.search": "per centrar la cerca", - "keyboard_shortcuts.start": "per obrir la columna \"Començar\"", + "keyboard_shortcuts.requests": "per a obrir la llista de sol·licituds de seguiment", + "keyboard_shortcuts.search": "per a centrar la cerca", + "keyboard_shortcuts.start": "per a obrir la columna \"Començar\"", "keyboard_shortcuts.toggle_hidden": "per a mostrar/amagar text sota CW", + "keyboard_shortcuts.toggle_sensitivity": "per a mostrar/amagar mèdia", "keyboard_shortcuts.toot": "per a començar un toot nou de trinca", "keyboard_shortcuts.unfocus": "descentrar l'area de composició de text/cerca", "keyboard_shortcuts.up": "moure amunt en la llista", @@ -213,19 +215,20 @@ "lightbox.view_context": "Veure el context", "lists.account.add": "Afegir a la llista", "lists.account.remove": "Treure de la llista", - "lists.delete": "Delete list", + "lists.delete": "Esborrar llista", "lists.edit": "Editar llista", "lists.edit.submit": "Canvi de títol", "lists.new.create": "Afegir llista", "lists.new.title_placeholder": "Nova llista", "lists.search": "Cercar entre les persones que segueixes", "lists.subheading": "Les teves llistes", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Carregant...", "media_gallery.toggle_visible": "Alternar visibilitat", "missing_indicator.label": "No trobat", "missing_indicator.sublabel": "Aquest recurs no pot ser trobat", "mute_modal.hide_notifications": "Amagar notificacions d'aquest usuari?", - "navigation_bar.apps": "Apps Mòbils", + "navigation_bar.apps": "Apps mòbils", "navigation_bar.blocks": "Usuaris bloquejats", "navigation_bar.community_timeline": "Línia de temps Local", "navigation_bar.compose": "Redacta nou toot", @@ -236,6 +239,7 @@ "navigation_bar.favourites": "Favorits", "navigation_bar.filters": "Paraules silenciades", "navigation_bar.follow_requests": "Sol·licituds de seguiment", + "navigation_bar.follows_and_followers": "Seguits i seguidors", "navigation_bar.info": "Sobre aquest servidor", "navigation_bar.keyboard_shortcuts": "Dreceres de teclat", "navigation_bar.lists": "Llistes", @@ -244,6 +248,7 @@ "navigation_bar.personal": "Personal", "navigation_bar.pins": "Toots fixats", "navigation_bar.preferences": "Preferències", + "navigation_bar.profile_directory": "Directori de perfils", "navigation_bar.public_timeline": "Línia de temps federada", "navigation_bar.security": "Seguretat", "notification.favourite": "{name} ha afavorit el teu estat", @@ -300,24 +305,25 @@ "report.hint": "El informe s'enviarà als moderadors del teu servidor. Pots explicar perquè vols informar d'aquest compte aquí:", "report.placeholder": "Comentaris addicionals", "report.submit": "Enviar", - "report.target": "Informes", + "report.target": "Informes {target}", "search.placeholder": "Cercar", "search_popout.search_format": "Format de cerca avançada", "search_popout.tips.full_text": "Text simple recupera publicacions que has escrit, les marcades com a favorites, les impulsades o en les que has estat esmentat, així com usuaris, noms d'usuari i etiquetes.", "search_popout.tips.hashtag": "etiqueta", - "search_popout.tips.status": "status", + "search_popout.tips.status": "estat", "search_popout.tips.text": "El text simple retorna coincidències amb els noms de visualització, els noms d'usuari i les etiquetes", "search_popout.tips.user": "usuari", "search_results.accounts": "Gent", "search_results.hashtags": "Etiquetes", "search_results.statuses": "Toots", - "search_results.total": "{count, number} {count, plural, un {result} altres {results}}", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", + "search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}", "status.admin_account": "Obre l'interfície de moderació per a @{name}", - "status.admin_status": "Obre aquest estat a la interfície de moderació", + "status.admin_status": "Obre aquest toot a la interfície de moderació", "status.block": "Bloqueja @{name}", "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.copy": "Copia l'enllaç al toot", "status.delete": "Esborrar", "status.detailed_status": "Visualització detallada de la conversa", "status.direct": "Missatge directe @{name}", @@ -363,12 +369,12 @@ "time_remaining.minutes": "{number, plural, one {# minut} other {# minuts}} restants", "time_remaining.moments": "Moments restants", "time_remaining.seconds": "{number, plural, one {# segon} other {# segons}} restants", - "trends.count_by_accounts": "{count} {rawCount, plural, una {person} altres {people}} parlant", - "ui.beforeunload": "El vostre esborrany es perdrà si sortiu de Mastodon.", - "upload_area.title": "Arrossega i deixa anar per carregar", + "trends.count_by_accounts": "{count} {rawCount, plural, one {persona} other {gent}} talking", + "ui.beforeunload": "El teu esborrany es perdrà si surts de Mastodon.", + "upload_area.title": "Arrossega i deixa anar per a carregar", "upload_button.label": "Afegir multimèdia (JPEG, PNG, GIF, WebM, MP4, MOV)", "upload_error.limit": "S'ha superat el límit de càrrega d'arxius.", - "upload_error.poll": "No es permet l'enviament de fitxers amb les enquestes.", + "upload_error.poll": "No es permet l'enviament de fitxers en les enquestes.", "upload_form.description": "Descriure els problemes visuals", "upload_form.focus": "Modificar la previsualització", "upload_form.undo": "Esborra", diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json index 8321d7e7e..948319ead 100644 --- a/app/javascript/mastodon/locales/co.json +++ b/app/javascript/mastodon/locales/co.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Bàsichi", "home.column_settings.show_reblogs": "Vede e spartere", "home.column_settings.show_replies": "Vede e risposte", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# ghjornu} other {# ghjorni}}", "intervals.full.hours": "{number, plural, one {# ora} other {# ore}}", "intervals.full.minutes": "{number, plural, one {# minuta} other {# minute}}", @@ -221,6 +222,7 @@ "lists.new.title_placeholder": "Titulu di a lista", "lists.search": "Circà indè i vostr'abbunamenti", "lists.subheading": "E vo liste", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Caricamentu...", "media_gallery.toggle_visible": "Cambià a visibilità", "missing_indicator.label": "Micca trovu", @@ -313,6 +315,7 @@ "search_results.accounts": "Ghjente", "search_results.hashtags": "Hashtag", "search_results.statuses": "Statuti", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {risultatu} other {risultati}}", "status.admin_account": "Apre l'interfaccia di muderazione per @{name}", "status.admin_status": "Apre stu statutu in l'interfaccia di muderazione", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index 5dd977374..a9d97f491 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Základní", "home.column_settings.show_reblogs": "Zobrazit boosty", "home.column_settings.show_replies": "Zobrazit odpovědi", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# den} few {# dny} many {# dne} other {# dní}}", "intervals.full.hours": "{number, plural, one {# hodina} few {# hodiny} many {# hodiny} other {# hodin}}", "intervals.full.minutes": "{number, plural, one {# minuta} few {# minuty} many {# minuty} other {# minut}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Název nového seznamu", "lists.search": "Hledejte mezi lidmi, které sledujete", "lists.subheading": "Vaše seznamy", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Načítám…", "media_gallery.toggle_visible": "Přepínat viditelnost", "missing_indicator.label": "Nenalezeno", @@ -312,6 +314,7 @@ "search_results.accounts": "Lidé", "search_results.hashtags": "Hashtagy", "search_results.statuses": "Tooty", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {výsledek} few {výsledky} many {výsledku} other {výsledků}}", "status.admin_account": "Otevřít moderátorské rozhraní pro uživatele @{name}", "status.admin_status": "Otevřít tento toot v moderátorském rozhraní", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 92dde4607..9de3efda8 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -45,7 +45,7 @@ "bundle_modal_error.message": "Aeth rhywbeth o'i le tra'n llwytho'r elfen hon.", "bundle_modal_error.retry": "Ceiswich eto", "column.blocks": "Defnyddwyr a flociwyd", - "column.community": "Llinell amser lleol", + "column.community": "Ffrwd lleol", "column.direct": "Negeseuon preifat", "column.domain_blocks": "Parthau cuddiedig", "column.favourites": "Ffefrynnau", @@ -71,20 +71,20 @@ "compose_form.lock_disclaimer": "Nid yw eich cyfri wedi'i {locked}. Gall unrhyw un eich dilyn i weld eich tŵtiau dilynwyr-yn-unig.", "compose_form.lock_disclaimer.lock": "wedi ei gloi", "compose_form.placeholder": "Beth sydd ar eich meddwl?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.poll.add_option": "Ychwanegu Dewisiad", + "compose_form.poll.duration": "Cyfnod pleidlais", + "compose_form.poll.option_placeholder": "Dewisiad {number}", + "compose_form.poll.remove_option": "Tynnu'r dewisiad", "compose_form.publish": "Tŵt", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "Marcio cyfryngau fel eu bod yn sensitif", "compose_form.sensitive.marked": "Cyfryngau wedi'u marcio'n sensitif", "compose_form.sensitive.unmarked": "Nid yw'r cyfryngau wedi'u marcio'n sensitif", "compose_form.spoiler.marked": "Testun wedi ei guddio gan rybudd", "compose_form.spoiler.unmarked": "Nid yw'r testun wedi ei guddio", "compose_form.spoiler_placeholder": "Ysgrifenwch eich rhybudd yma", "confirmation_modal.cancel": "Canslo", - "confirmations.block.block_and_report": "Block & Report", + "confirmations.block.block_and_report": "Rhwystro ac Adrodd", "confirmations.block.confirm": "Blocio", "confirmations.block.message": "Ydych chi'n sicr eich bod eisiau blocio {name}?", "confirmations.delete.confirm": "Dileu", @@ -109,7 +109,7 @@ "emoji_button.food": "Bwyd a Diod", "emoji_button.label": "Mewnosodwch emoji", "emoji_button.nature": "Natur", - "emoji_button.not_found": "Dim emojo!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "Dim emojau!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "Gwrthrychau", "emoji_button.people": "Pobl", "emoji_button.recent": "Defnyddir yn aml", @@ -117,8 +117,8 @@ "emoji_button.search_results": "Canlyniadau chwilio", "emoji_button.symbols": "Symbolau", "emoji_button.travel": "Teithio & Llefydd", - "empty_column.account_timeline": "No toots here!", - "empty_column.account_unavailable": "Profile unavailable", + "empty_column.account_timeline": "Dim tŵtiau fama!", + "empty_column.account_unavailable": "Proffil ddim ar gael", "empty_column.blocks": "Nid ydych wedi blocio unrhyw ddefnyddwyr eto.", "empty_column.community": "Mae'r ffrwd lleol yn wag. Ysgrifenwch rhywbeth yn gyhoeddus i gael dechrau arni!", "empty_column.direct": "Nid oes gennych unrhyw negeseuon preifat eto. Pan y byddwch yn anfon neu derbyn un, mi fydd yn ymddangos yma.", @@ -147,8 +147,8 @@ "hashtag.column_header.tag_mode.all": "a {additional}", "hashtag.column_header.tag_mode.any": "neu {additional}", "hashtag.column_header.tag_mode.none": "heb {additional}", - "hashtag.column_settings.select.no_options_message": "No suggestions found", - "hashtag.column_settings.select.placeholder": "Enter hashtags…", + "hashtag.column_settings.select.no_options_message": "Dim awgrymiadau i'w weld", + "hashtag.column_settings.select.placeholder": "Mewnbynnu hashnodau…", "hashtag.column_settings.tag_mode.all": "Pob un o'r rhain", "hashtag.column_settings.tag_mode.any": "Unrhyw un o'r rhain", "hashtag.column_settings.tag_mode.none": "Dim o'r rhain", @@ -156,26 +156,27 @@ "home.column_settings.basic": "Syml", "home.column_settings.show_reblogs": "Dangos bŵstiau", "home.column_settings.show_replies": "Dangos ymatebion", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, one {# ddydd} other {# o ddyddiau}}", + "intervals.full.hours": "{number, plural, one {# awr} other {# o oriau}}", + "intervals.full.minutes": "{number, plural, one {# funud} other {# o funudau}}", "introduction.federation.action": "Nesaf", "introduction.federation.federated.headline": "Ffederasiwn", - "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.", - "introduction.federation.home.headline": "Home", - "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!", - "introduction.federation.local.headline": "Local", - "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.", + "introduction.federation.federated.text": "Bydd pyst cyhoeddus o gweinyddion arall yn y Ffedysawd yn cael ai arddangos yn ffrwd y ffederasiwn.", + "introduction.federation.home.headline": "Hafan", + "introduction.federation.home.text": "Bydd pyst o bobl rydych yn ei ddilyn yn dangos yn eich ffrwd gatref. Gallwch dilyn unrhyw un ar unrhyw gweinydd!", + "introduction.federation.local.headline": "Lleol", + "introduction.federation.local.text": "Bydd pyst gyhoeddus o bobl ar yr un gweinydd a chi yn cael ei arddangos yn y ffrwd lleol.", "introduction.interactions.action": "Gorffen tiwtorial!", "introduction.interactions.favourite.headline": "Ffefryn", - "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", + "introduction.interactions.favourite.text": "Gallwch cadw tŵt am hwyrach, a gadael i'r awdur gwybod roeddech yn ei hoffi, trwy ei hoffi.", "introduction.interactions.reblog.headline": "Hwb", - "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", + "introduction.interactions.reblog.text": "Gallwch rhannu tŵtiau pobl eraill gyda'ch dilynwyr trwy eu bŵstio.", "introduction.interactions.reply.headline": "Ateb", - "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", + "introduction.interactions.reply.text": "Gallwch ateb i dŵtiau pobl eraill a thŵtiau eich hun, a fydd yn eu cadwyno at ei gilydd mewn sgwrs.", "introduction.welcome.action": "Awn ni!", "introduction.welcome.headline": "Camau cyntaf", - "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.", + "introduction.welcome.text": "Croeso i'r ffedysawd! Mewn ychydig o funudau, byddwch yn gallu darlledu negeseuon a siarad i'ch ffrindiau ar draws amrywiaeth eang o weinyddion. Ond mae'r gweinydd hyn, {domain}, yn arbennig - mae o'n gweinyddu eich proffil, fellu cofiwch ei enw.", "keyboard_shortcuts.back": "i lywio nôl", "keyboard_shortcuts.blocked": "i agor rhestr defnyddwyr a flociwyd", "keyboard_shortcuts.boost": "i fŵstio", @@ -190,7 +191,7 @@ "keyboard_shortcuts.federated": "i agor ffrwd y ffederasiwn", "keyboard_shortcuts.heading": "Llwybrau byr allweddell", "keyboard_shortcuts.home": "i agor ffrwd cartref", - "keyboard_shortcuts.hotkey": "Hotkey", + "keyboard_shortcuts.hotkey": "Bysell brys", "keyboard_shortcuts.legend": "i ddangos yr arwr yma", "keyboard_shortcuts.local": "i agor ffrwd lleol", "keyboard_shortcuts.mention": "i grybwyll yr awdur", @@ -204,22 +205,24 @@ "keyboard_shortcuts.search": "i ffocysu chwilio", "keyboard_shortcuts.start": "i agor colofn \"dechrau arni\"", "keyboard_shortcuts.toggle_hidden": "i ddangos/cuddio testun tu ôl i CW", + "keyboard_shortcuts.toggle_sensitivity": "i ddangos/gyddio cyfryngau", "keyboard_shortcuts.toot": "i ddechrau tŵt newydd sbon", "keyboard_shortcuts.unfocus": "i ddad-ffocysu ardal cyfansoddi testun/chwilio", "keyboard_shortcuts.up": "i symud yn uwch yn y rhestr", "lightbox.close": "Cau", "lightbox.next": "Nesaf", "lightbox.previous": "Blaenorol", - "lightbox.view_context": "View context", + "lightbox.view_context": "Gweld cyd-destyn", "lists.account.add": "Ychwanegwch at restr", "lists.account.remove": "Dileu o'r rhestr", "lists.delete": "Dileu rhestr", "lists.edit": "Golygwch rhestr", - "lists.edit.submit": "Change title", + "lists.edit.submit": "Newid teitl", "lists.new.create": "Ychwanegu rhestr", "lists.new.title_placeholder": "Teitl rhestr newydd", "lists.search": "Chwilio ymysg pobl yr ydych yn ei ddilyn", "lists.subheading": "Eich rhestrau", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Llwytho...", "media_gallery.toggle_visible": "Toglo gwelededd", "missing_indicator.label": "Heb ei ganfod", @@ -236,6 +239,7 @@ "navigation_bar.favourites": "Ffefrynnau", "navigation_bar.filters": "Geiriau a dawelwyd", "navigation_bar.follow_requests": "Ceisiadau dilyn", + "navigation_bar.follows_and_followers": "Dilynion a ddilynwyr", "navigation_bar.info": "Ynghylch yr achos hwn", "navigation_bar.keyboard_shortcuts": "Bysellau brys", "navigation_bar.lists": "Rhestrau", @@ -244,12 +248,13 @@ "navigation_bar.personal": "Personol", "navigation_bar.pins": "Tŵtiau wedi eu pinio", "navigation_bar.preferences": "Dewisiadau", + "navigation_bar.profile_directory": "Cyfeiriadur Proffil", "navigation_bar.public_timeline": "Ffrwd y ffederasiwn", "navigation_bar.security": "Diogelwch", "notification.favourite": "hoffodd {name} eich tŵt", "notification.follow": "dilynodd {name} chi", "notification.mention": "Soniodd {name} amdanoch chi", - "notification.poll": "A poll you have voted in has ended", + "notification.poll": "Mae pleidlais rydych wedi pleidleisio ynddi wedi dod i ben", "notification.reblog": "Hysbysebodd {name} eich tŵt", "notifications.clear": "Clirio hysbysiadau", "notifications.clear_confirmation": "Ydych chi'n sicr eich bod am glirio'ch holl hysbysiadau am byth?", @@ -260,8 +265,8 @@ "notifications.column_settings.filter_bar.show": "Dangos", "notifications.column_settings.follow": "Dilynwyr newydd:", "notifications.column_settings.mention": "Crybwylliadau:", - "notifications.column_settings.poll": "Poll results:", - "notifications.column_settings.push": "Hysbysiadau push", + "notifications.column_settings.poll": "Canlyniadau pleidlais:", + "notifications.column_settings.push": "Hysbysiadau gwthiadwy", "notifications.column_settings.reblog": "Hybiadau:", "notifications.column_settings.show": "Dangos yn y golofn", "notifications.column_settings.sound": "Chwarae sain", @@ -270,14 +275,14 @@ "notifications.filter.favourites": "Ffefrynnau", "notifications.filter.follows": "Yn dilyn", "notifications.filter.mentions": "Crybwylliadau", - "notifications.filter.polls": "Poll results", + "notifications.filter.polls": "Canlyniadau pleidlais", "notifications.group": "{count} o hysbysiadau", - "poll.closed": "Closed", - "poll.refresh": "Refresh", - "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", - "poll.vote": "Vote", - "poll_button.add_poll": "Add a poll", - "poll_button.remove_poll": "Remove poll", + "poll.closed": "Ar gau", + "poll.refresh": "Adnewyddu", + "poll.total_votes": "{count, plural, one {# bleidlais} other {# o bleidleisiau}}", + "poll.vote": "Pleidleisio", + "poll_button.add_poll": "Ychwanegu pleidlais", + "poll_button.remove_poll": "Tynnu pleidlais", "privacy.change": "Addasu preifatrwdd y tŵt", "privacy.direct.long": "Cyhoeddi i'r defnyddwyr sy'n cael eu crybwyll yn unig", "privacy.direct.short": "Uniongyrchol", @@ -289,11 +294,11 @@ "privacy.unlisted.short": "Heb ei restru", "regeneration_indicator.label": "Llwytho…", "regeneration_indicator.sublabel": "Mae eich ffrwd cartref yn cael ei baratoi!", - "relative_time.days": "{number}d", - "relative_time.hours": "{number}h", + "relative_time.days": "{number}dydd", + "relative_time.hours": "{number}awr", "relative_time.just_now": "nawr", - "relative_time.minutes": "{number}m", - "relative_time.seconds": "{number}s", + "relative_time.minutes": "{number}munud", + "relative_time.seconds": "{number}eiliad", "reply_indicator.cancel": "Canslo", "report.forward": "Ymlaen i {target}", "report.forward_hint": "Mae'r cyfrif o weinydd arall. Anfon copi anhysbys o'r adroddiad yno hefyd?", @@ -311,13 +316,14 @@ "search_results.accounts": "Pobl", "search_results.hashtags": "Hanshnodau", "search_results.statuses": "Tŵtiau", - "search_results.total": "{count, number} {count, plural, one {result} arall {results}}", - "status.admin_account": "Open moderation interface for @{name}", - "status.admin_status": "Open this tŵt in the moderation interface", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", + "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "status.admin_account": "Agor rhyngwyneb goruwchwylio ar gyfer @{name}", + "status.admin_status": "Agor y tŵt yn y rhyngwyneb goruwchwylio", "status.block": "Blocio @{name}", "status.cancel_reblog_private": "Dadfŵstio", "status.cannot_reblog": "Ni ellir sbarduno'r tŵt hwn", - "status.copy": "Copy link to status", + "status.copy": "Copïo cysylltiad i'r tŵt", "status.delete": "Dileu", "status.detailed_status": "Golwg manwl o'r sgwrs", "status.direct": "Neges breifat @{name}", @@ -358,17 +364,17 @@ "tabs_bar.local_timeline": "Lleol", "tabs_bar.notifications": "Hysbysiadau", "tabs_bar.search": "Chwilio", - "time_remaining.days": "{number, plural, one {# day} other {# days}} left", - "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", - "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", - "time_remaining.moments": "Moments remaining", - "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left", + "time_remaining.days": "{number, plural, one {# ddydd} other {# o ddyddiau}} ar ôl", + "time_remaining.hours": "{number, plural, one {# awr} other {# o oriau}} ar ôl", + "time_remaining.minutes": "{number, plural, one {# funud} other {# o funudau}} ar ôl", + "time_remaining.moments": "Munudau ar ôl", + "time_remaining.seconds": "{number, plural, one {# eiliad} other {# o eiliadau}} ar ôl", "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} yn siarad", "ui.beforeunload": "Mi fyddwch yn colli eich drafft os gadewch Mastodon.", "upload_area.title": "Llusgwch & gollwing i uwchlwytho", "upload_button.label": "Ychwanegwch gyfryngau (JPEG, PNG, GIF, WebM, MP4, MOV)", - "upload_error.limit": "File upload limit exceeded.", - "upload_error.poll": "File upload not allowed with polls.", + "upload_error.limit": "Wedi mynd heibio'r uchafswm terfyn uwchlwytho.", + "upload_error.poll": "Nid oes modd uwchlwytho ffeiliau â phleidleisiau.", "upload_form.description": "Disgrifio i'r rheini a nam ar ei golwg", "upload_form.focus": "Newid rhagolwg", "upload_form.undo": "Dileu", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index 0afacada1..c96110496 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Grundlæggende", "home.column_settings.show_reblogs": "Vis fremhævelser", "home.column_settings.show_replies": "Vis svar", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Ny liste titel", "lists.search": "Søg iblandt folk du følger", "lists.subheading": "Dine lister", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Indlæser...", "media_gallery.toggle_visible": "Ændre synlighed", "missing_indicator.label": "Ikke fundet", @@ -311,6 +313,7 @@ "search_results.accounts": "Folk", "search_results.hashtags": "Emnetags", "search_results.statuses": "Trut", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, et {result} andre {results}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 8b7d256eb..2b28384ab 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Einfach", "home.column_settings.show_reblogs": "Geteilte Beiträge anzeigen", "home.column_settings.show_replies": "Antworten anzeigen", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# Tag} other {# Tage}}", "intervals.full.hours": "{number, plural, one {# Stunde} other {# Stunden}}", "intervals.full.minutes": "{number, plural, one {# Minute} other {# Minuten}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Neuer Titel der Liste", "lists.search": "Suche nach Leuten denen du folgst", "lists.subheading": "Deine Listen", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Wird geladen …", "media_gallery.toggle_visible": "Sichtbarkeit umschalten", "missing_indicator.label": "Nicht gefunden", @@ -311,6 +313,7 @@ "search_results.accounts": "Personen", "search_results.hashtags": "Hashtags", "search_results.statuses": "Beiträge", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {Ergebnis} other {Ergebnisse}}", "status.admin_account": "Öffne Moderationsoberfläche für @{name}", "status.admin_status": "Öffne diesen Status in der Moderationsoberfläche", diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index ce51f6548..5c1ef6f08 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -161,6 +161,15 @@ { "descriptors": [ { + "defaultMessage": "{count, plural, one {# new item} other {# new items}}", + "id": "load_pending" + } + ], + "path": "app/javascript/mastodon/components/load_pending.json" + }, + { + "descriptors": [ + { "defaultMessage": "Loading...", "id": "loading_indicator.label" } @@ -735,7 +744,7 @@ { "descriptors": [ { - "defaultMessage": "Media Only", + "defaultMessage": "Media only", "id": "community.column_settings.media_only" } ], @@ -1005,6 +1014,10 @@ "id": "search_results.statuses" }, { + "defaultMessage": "Searching toots by their content is not enabled on this Mastodon server.", + "id": "search_results.statuses_fts_disabled" + }, + { "defaultMessage": "Hashtags", "id": "search_results.hashtags" }, @@ -1798,6 +1811,14 @@ "id": "notifications.column_settings.push" }, { + "defaultMessage": "Basic", + "id": "home.column_settings.basic" + }, + { + "defaultMessage": "Update in real-time", + "id": "home.column_settings.update_live" + }, + { "defaultMessage": "Quick filter bar", "id": "notifications.column_settings.filter_bar.category" }, diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index 8dd9e9eb9..703a0968a 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Βασικά", "home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων", "home.column_settings.show_replies": "Εμφάνιση απαντήσεων", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# μέρα} other {# μέρες}}", "intervals.full.hours": "{number, plural, one {# ώρα} other {# ώρες}}", "intervals.full.minutes": "{number, plural, one {# λεπτό} other {# λεπτά}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Τίτλος νέας λίστα", "lists.search": "Αναζήτησε μεταξύ των ανθρώπων που ακουλουθείς", "lists.subheading": "Οι λίστες σου", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Φορτώνει...", "media_gallery.toggle_visible": "Εναλλαγή ορατότητας", "missing_indicator.label": "Δε βρέθηκε", @@ -311,6 +313,7 @@ "search_results.accounts": "Άνθρωποι", "search_results.hashtags": "Ταμπέλες", "search_results.statuses": "Τουτ", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, zero {αποτελέσματα} one {αποτέλεσμα} other {αποτελέσματα}}", "status.admin_account": "Άνοιγμα λειτουργίας διαμεσολάβησης για τον/την @{name}", "status.admin_status": "Άνοιγμα αυτής της δημοσίευσης στη λειτουργία διαμεσολάβησης", diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 17dbef3e9..8a20cf206 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -164,6 +164,7 @@ "home.column_settings.basic": "Basic", "home.column_settings.show_reblogs": "Show repeats", "home.column_settings.show_replies": "Show replies", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -230,6 +231,7 @@ "lists.search": "Search among monsters in your pack", "lists.subheading": "Your lists", "lists.show_self": "Include your own roars", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Loading...", "media_gallery.toggle_visible": "Toggle visibility", "missing_indicator.label": "Not found", @@ -324,7 +326,12 @@ "search_popout.tips.user": "creature", "search_results.accounts": "Monsters", "search_results.hashtags": "Hashtags", +<<<<<<< HEAD "search_results.statuses": "Roars", +======= + "search_results.statuses": "TF spells", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", +>>>>>>> af0c4b345... Make a shoddy attempt to merge pull request #1158 from ThibG/glitch-soc/merge-upstream "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "Moderate @{name}", "status.admin_status": "Moderate roar", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index a89da4ad5..47ecd09b3 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Bazaj agordoj", "home.column_settings.show_reblogs": "Montri diskonigojn", "home.column_settings.show_replies": "Montri respondojn", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# tago} other {# tagoj}}", "intervals.full.hours": "{number, plural, one {# horo} other {# horoj}}", "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutoj}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Titolo de la nova listo", "lists.search": "Serĉi inter la homoj, kiujn vi sekvas", "lists.subheading": "Viaj listoj", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Ŝargado…", "media_gallery.toggle_visible": "Baskuligi videblecon", "missing_indicator.label": "Ne trovita", @@ -311,6 +313,7 @@ "search_results.accounts": "Homoj", "search_results.hashtags": "Kradvortoj", "search_results.statuses": "Mesaĝoj", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {rezulto} other {rezultoj}}", "status.admin_account": "Malfermi la kontrolan interfacon por @{name}", "status.admin_status": "Malfermi ĉi tiun mesaĝon en la kontrola interfaco", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 00d756d34..dc42bc7ef 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -1,5 +1,5 @@ { - "account.add_or_remove_from_list": "Add or Remove from lists", + "account.add_or_remove_from_list": "Agregar o eliminar de las listas", "account.badges.bot": "Bot", "account.block": "Bloquear", "account.block_domain": "Ocultar todo de {domain}", @@ -15,9 +15,9 @@ "account.follows.empty": "Este usuario todavía no sigue a nadie.", "account.follows_you": "Te sigue", "account.hide_reblogs": "Ocultar retoots de @{name}", - "account.link_verified_on": "Ownership of this link was checked on {date}", - "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.", - "account.media": "Media", + "account.link_verified_on": "El proprietario de este link fue verificado el {date}", + "account.locked_info": "El estado de privacidad de esta cuenta està configurado como bloqueado. El proprietario debe revisar manualmente quien puede seguirle.", + "account.media": "Multimedia", "account.mention": "Mencionar a @{name}", "account.moved_to": "{name} se ha mudado a:", "account.mute": "Silenciar a @{name}", @@ -36,7 +36,7 @@ "account.unmute": "Dejar de silenciar a @{name}", "account.unmute_notifications": "Dejar de silenciar las notificaciones de @{name}", "alert.unexpected.message": "Hubo un error inesperado.", - "alert.unexpected.title": "Oops!", + "alert.unexpected.title": "¡Ups!", "boost_modal.combo": "Puedes presionar {combo} para saltear este aviso la próxima vez", "bundle_column_error.body": "Algo salió mal al cargar este componente.", "bundle_column_error.retry": "Inténtalo de nuevo", @@ -71,25 +71,25 @@ "compose_form.lock_disclaimer": "Tu cuenta no está bloqueada. Todos pueden seguirte para ver tus toots solo para seguidores.", "compose_form.lock_disclaimer.lock": "bloqueado", "compose_form.placeholder": "¿En qué estás pensando?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.poll.add_option": "Añadir una opción", + "compose_form.poll.duration": "Duración de la encuesta", + "compose_form.poll.option_placeholder": "Elección {number}", + "compose_form.poll.remove_option": "Eliminar esta opción", "compose_form.publish": "Tootear", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "Marcar multimedia como sensible", "compose_form.sensitive.marked": "Material marcado como sensible", "compose_form.sensitive.unmarked": "Material no marcado como sensible", "compose_form.spoiler.marked": "Texto oculto tras la advertencia", "compose_form.spoiler.unmarked": "Texto no oculto", "compose_form.spoiler_placeholder": "Advertencia de contenido", "confirmation_modal.cancel": "Cancelar", - "confirmations.block.block_and_report": "Block & Report", + "confirmations.block.block_and_report": "Bloquear y Reportar", "confirmations.block.confirm": "Bloquear", "confirmations.block.message": "¿Estás seguro de que quieres bloquear a {name}?", "confirmations.delete.confirm": "Eliminar", "confirmations.delete.message": "¿Estás seguro de que quieres borrar este toot?", - "confirmations.delete_list.confirm": "Delete", + "confirmations.delete_list.confirm": "Eliminar", "confirmations.delete_list.message": "¿Seguro que quieres borrar esta lista permanentemente?", "confirmations.domain_block.confirm": "Ocultar dominio entero", "confirmations.domain_block.message": "¿Seguro de que quieres bloquear al dominio {domain} entero? En general unos cuantos bloqueos y silenciados concretos es suficiente y preferible.", @@ -97,8 +97,8 @@ "confirmations.mute.message": "¿Estás seguro de que quieres silenciar a {name}?", "confirmations.redraft.confirm": "Borrar y volver a borrador", "confirmations.redraft.message": "Estás seguro de que quieres borrar este estado y volverlo a borrador? Perderás todas las respuestas, impulsos y favoritos asociados a él, y las respuestas a la publicación original quedarán huérfanos.", - "confirmations.reply.confirm": "Reply", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.reply.confirm": "Responder", + "confirmations.reply.message": "Responder sobrescribirá el mensaje que estás escribiendo. ¿Estás seguro de que deseas continuar?", "confirmations.unfollow.confirm": "Dejar de seguir", "confirmations.unfollow.message": "¿Estás seguro de que quieres dejar de seguir a {name}?", "embed.instructions": "Añade este toot a tu sitio web con el siguiente código.", @@ -117,8 +117,8 @@ "emoji_button.search_results": "Resultados de búsqueda", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viajes y lugares", - "empty_column.account_timeline": "No toots here!", - "empty_column.account_unavailable": "Profile unavailable", + "empty_column.account_timeline": "¡No hay toots aquí!", + "empty_column.account_unavailable": "Perfil no disponible", "empty_column.blocks": "Aún no has bloqueado a ningún usuario.", "empty_column.community": "La línea de tiempo local está vacía. ¡Escribe algo para empezar la fiesta!", "empty_column.direct": "Aún no tienes ningún mensaje directo. Cuando envíes o recibas uno, se mostrará aquí.", @@ -137,54 +137,55 @@ "follow_request.authorize": "Autorizar", "follow_request.reject": "Rechazar", "getting_started.developers": "Desarrolladores", - "getting_started.directory": "Profile directory", - "getting_started.documentation": "Documentation", + "getting_started.directory": "Directorio de perfil", + "getting_started.documentation": "Documentación", "getting_started.heading": "Primeros pasos", "getting_started.invite": "Invitar usuarios", "getting_started.open_source_notice": "Mastodon es software libre. Puedes contribuir o reportar errores en {github}.", "getting_started.security": "Seguridad", "getting_started.terms": "Términos de servicio", - "hashtag.column_header.tag_mode.all": "and {additional}", - "hashtag.column_header.tag_mode.any": "or {additional}", - "hashtag.column_header.tag_mode.none": "without {additional}", - "hashtag.column_settings.select.no_options_message": "No suggestions found", - "hashtag.column_settings.select.placeholder": "Enter hashtags…", - "hashtag.column_settings.tag_mode.all": "All of these", - "hashtag.column_settings.tag_mode.any": "Any of these", - "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_header.tag_mode.all": "y {additional}", + "hashtag.column_header.tag_mode.any": "o {additional}", + "hashtag.column_header.tag_mode.none": "sin {additional}", + "hashtag.column_settings.select.no_options_message": "No se encontraron sugerencias", + "hashtag.column_settings.select.placeholder": "Introduzca hashtags…", + "hashtag.column_settings.tag_mode.all": "Cualquiera de estos", + "hashtag.column_settings.tag_mode.any": "Cualquiera de estos", + "hashtag.column_settings.tag_mode.none": "Ninguno de estos", "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Básico", "home.column_settings.show_reblogs": "Mostrar retoots", "home.column_settings.show_replies": "Mostrar respuestas", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", - "introduction.federation.action": "Next", - "introduction.federation.federated.headline": "Federated", - "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.", - "introduction.federation.home.headline": "Home", - "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, one {# día} other {# días}}", + "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}", + "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}", + "introduction.federation.action": "Siguiente", + "introduction.federation.federated.headline": "Federado", + "introduction.federation.federated.text": "Los mensajes públicos de otros servidores del fediverso aparecerán en la cronología federada.", + "introduction.federation.home.headline": "Inicio", + "introduction.federation.home.text": "Los posts de personas que sigues aparecerán en tu cronología. ¡Puedes seguir a cualquiera en cualquier servidor!", "introduction.federation.local.headline": "Local", - "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.", - "introduction.interactions.action": "Finish tutorial!", - "introduction.interactions.favourite.headline": "Favourite", - "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", - "introduction.interactions.reblog.headline": "Boost", - "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", - "introduction.interactions.reply.headline": "Reply", - "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", - "introduction.welcome.action": "Let's go!", - "introduction.welcome.headline": "First steps", - "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.", + "introduction.federation.local.text": "Los posts públicos de personas en el mismo servidor que aparecerán en la cronología local.", + "introduction.interactions.action": "¡Terminar tutorial!", + "introduction.interactions.favourite.headline": "Favorito", + "introduction.interactions.favourite.text": "Puedes guardar un toot para más tarde, y hacer saber al autor que te gustó, dándole a favorito.", + "introduction.interactions.reblog.headline": "Retootear", + "introduction.interactions.reblog.text": "Puedes compartir los toots de otras personas con tus seguidores retooteando los mismos.", + "introduction.interactions.reply.headline": "Responder", + "introduction.interactions.reply.text": "Puedes responder a tus propios toots y los de otras personas, que se encadenarán juntos en una conversación.", + "introduction.welcome.action": "¡Vamos!", + "introduction.welcome.headline": "Primeros pasos", + "introduction.welcome.text": "¡Bienvenido al fediverso! En unos momentos, podrás transmitir mensajes y hablar con tus amigos a través de una amplia variedad de servidores. Pero este servidor, {domain}, es especial, alberga tu perfil, así que recuerda su nombre.", "keyboard_shortcuts.back": "volver atrás", "keyboard_shortcuts.blocked": "abrir una lista de usuarios bloqueados", "keyboard_shortcuts.boost": "retootear", "keyboard_shortcuts.column": "enfocar un estado en una de las columnas", "keyboard_shortcuts.compose": "enfocar el área de texto de redacción", - "keyboard_shortcuts.description": "Description", + "keyboard_shortcuts.description": "Descripción", "keyboard_shortcuts.direct": "abrir la columna de mensajes directos", "keyboard_shortcuts.down": "mover hacia abajo en la lista", - "keyboard_shortcuts.enter": "to open status", + "keyboard_shortcuts.enter": "abrir estado", "keyboard_shortcuts.favourite": "añadir a favoritos", "keyboard_shortcuts.favourites": "abrir la lista de favoritos", "keyboard_shortcuts.federated": "abrir el timeline federado", @@ -204,22 +205,24 @@ "keyboard_shortcuts.search": "para poner el foco en la búsqueda", "keyboard_shortcuts.start": "abrir la columna \"comenzar\"", "keyboard_shortcuts.toggle_hidden": "mostrar/ocultar texto tras aviso de contenido (CW)", + "keyboard_shortcuts.toggle_sensitivity": "mostrar/ocultar medios", "keyboard_shortcuts.toot": "para comenzar un nuevo toot", "keyboard_shortcuts.unfocus": "para retirar el foco de la caja de redacción/búsqueda", "keyboard_shortcuts.up": "para ir hacia arriba en la lista", "lightbox.close": "Cerrar", "lightbox.next": "Siguiente", "lightbox.previous": "Anterior", - "lightbox.view_context": "View context", + "lightbox.view_context": "Ver contexto", "lists.account.add": "Añadir a lista", "lists.account.remove": "Quitar de lista", - "lists.delete": "Delete list", + "lists.delete": "Borrar lista", "lists.edit": "Editar lista", - "lists.edit.submit": "Change title", + "lists.edit.submit": "Cambiar título", "lists.new.create": "Añadir lista", "lists.new.title_placeholder": "Título de la nueva lista", "lists.search": "Buscar entre la gente a la que sigues", "lists.subheading": "Tus listas", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Cargando…", "media_gallery.toggle_visible": "Cambiar visibilidad", "missing_indicator.label": "No encontrado", @@ -236,6 +239,7 @@ "navigation_bar.favourites": "Favoritos", "navigation_bar.filters": "Palabras silenciadas", "navigation_bar.follow_requests": "Solicitudes para seguirte", + "navigation_bar.follows_and_followers": "Siguiendo y seguidores", "navigation_bar.info": "Información adicional", "navigation_bar.keyboard_shortcuts": "Atajos", "navigation_bar.lists": "Listas", @@ -244,40 +248,41 @@ "navigation_bar.personal": "Personal", "navigation_bar.pins": "Toots fijados", "navigation_bar.preferences": "Preferencias", + "navigation_bar.profile_directory": "Directorio de perfiles", "navigation_bar.public_timeline": "Historia federada", "navigation_bar.security": "Seguridad", "notification.favourite": "{name} marcó tu estado como favorito", "notification.follow": "{name} te empezó a seguir", "notification.mention": "{name} te ha mencionado", - "notification.poll": "A poll you have voted in has ended", + "notification.poll": "Una encuesta en la que has votado ha terminado", "notification.reblog": "{name} ha retooteado tu estado", "notifications.clear": "Limpiar notificaciones", "notifications.clear_confirmation": "¿Seguro que quieres limpiar permanentemente todas tus notificaciones?", "notifications.column_settings.alert": "Notificaciones de escritorio", "notifications.column_settings.favourite": "Favoritos:", - "notifications.column_settings.filter_bar.advanced": "Display all categories", - "notifications.column_settings.filter_bar.category": "Quick filter bar", - "notifications.column_settings.filter_bar.show": "Show", + "notifications.column_settings.filter_bar.advanced": "Mostrar todas las categorías", + "notifications.column_settings.filter_bar.category": "Barra de filtrado rápido", + "notifications.column_settings.filter_bar.show": "Mostrar", "notifications.column_settings.follow": "Nuevos seguidores:", "notifications.column_settings.mention": "Menciones:", - "notifications.column_settings.poll": "Poll results:", + "notifications.column_settings.poll": "Resultados de la votación:", "notifications.column_settings.push": "Notificaciones push", "notifications.column_settings.reblog": "Retoots:", "notifications.column_settings.show": "Mostrar en columna", "notifications.column_settings.sound": "Reproducir sonido", - "notifications.filter.all": "All", - "notifications.filter.boosts": "Boosts", - "notifications.filter.favourites": "Favourites", - "notifications.filter.follows": "Follows", - "notifications.filter.mentions": "Mentions", - "notifications.filter.polls": "Poll results", + "notifications.filter.all": "Todos", + "notifications.filter.boosts": "Retoots", + "notifications.filter.favourites": "Favoritos", + "notifications.filter.follows": "Seguidores", + "notifications.filter.mentions": "Menciones", + "notifications.filter.polls": "Resultados de la votación", "notifications.group": "{count} notificaciones", - "poll.closed": "Closed", - "poll.refresh": "Refresh", - "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", - "poll.vote": "Vote", - "poll_button.add_poll": "Add a poll", - "poll_button.remove_poll": "Remove poll", + "poll.closed": "Cerrada", + "poll.refresh": "Actualizar", + "poll.total_votes": "{count, plural, one {# voto} other {# votos}}", + "poll.vote": "Votar", + "poll_button.add_poll": "Añadir una encuesta", + "poll_button.remove_poll": "Eliminar encuesta", "privacy.change": "Ajustar privacidad", "privacy.direct.long": "Sólo mostrar a los usuarios mencionados", "privacy.direct.short": "Directo", @@ -286,7 +291,7 @@ "privacy.public.long": "Mostrar en la historia federada", "privacy.public.short": "Público", "privacy.unlisted.long": "No mostrar en la historia federada", - "privacy.unlisted.short": "Sin federar", + "privacy.unlisted.short": "No listado", "regeneration_indicator.label": "Cargando…", "regeneration_indicator.sublabel": "¡Tu historia de inicio se está preparando!", "relative_time.days": "{number}d", @@ -305,19 +310,20 @@ "search_popout.search_format": "Formato de búsqueda avanzada", "search_popout.tips.full_text": "Búsquedas de texto recuperan posts que has escrito, marcado como favoritos, retooteado o en los que has sido mencionado, así como usuarios, nombres y hashtags.", "search_popout.tips.hashtag": "etiqueta", - "search_popout.tips.status": "status", + "search_popout.tips.status": "estado", "search_popout.tips.text": "El texto simple devuelve correspondencias de nombre, usuario y hashtag", "search_popout.tips.user": "usuario", "search_results.accounts": "Gente", "search_results.hashtags": "Etiquetas", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", - "status.admin_account": "Open moderation interface for @{name}", - "status.admin_status": "Open this status in the moderation interface", - "status.block": "Block @{name}", + "status.admin_account": "Abrir interfaz de moderación para @{name}", + "status.admin_status": "Abrir este estado en la interfaz de moderación", + "status.block": "Bloquear a @{name}", "status.cancel_reblog_private": "Des-impulsar", "status.cannot_reblog": "Este toot no puede retootearse", - "status.copy": "Copy link to status", + "status.copy": "Copiar enlace al estado", "status.delete": "Borrar", "status.detailed_status": "Vista de conversación detallada", "status.direct": "Mensaje directo a @{name}", @@ -333,7 +339,7 @@ "status.open": "Expandir estado", "status.pin": "Fijar", "status.pinned": "Toot fijado", - "status.read_more": "Read more", + "status.read_more": "Leer más", "status.reblog": "Retootear", "status.reblog_private": "Implusar a la audiencia original", "status.reblogged_by": "Retooteado por {name}", @@ -348,27 +354,27 @@ "status.show_less_all": "Mostrar menos para todo", "status.show_more": "Mostrar más", "status.show_more_all": "Mostrar más para todo", - "status.show_thread": "Show thread", + "status.show_thread": "Ver hilo", "status.unmute_conversation": "Dejar de silenciar conversación", "status.unpin": "Dejar de fijar", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "Descartar sugerencia", + "suggestions.header": "Es posible que te interese…", "tabs_bar.federated_timeline": "Federado", "tabs_bar.home": "Inicio", "tabs_bar.local_timeline": "Local", "tabs_bar.notifications": "Notificaciones", "tabs_bar.search": "Buscar", - "time_remaining.days": "{number, plural, one {# day} other {# days}} left", - "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", - "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", - "time_remaining.moments": "Moments remaining", - "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left", - "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking", + "time_remaining.days": "{number, plural, one {# día restante} other {# días restantes}}", + "time_remaining.hours": "{number, plural, one {# hora restante} other {# horas restantes}}", + "time_remaining.minutes": "{number, plural, one {# minuto restante} other {# minutos restantes}}", + "time_remaining.moments": "Momentos restantes", + "time_remaining.seconds": "{number, plural, one {# segundo restante} other {# segundos restantes}}", + "trends.count_by_accounts": "{count} {rawCount, plural, one {persona} other {personas}} hablando", "ui.beforeunload": "Tu borrador se perderá si sales de Mastodon.", "upload_area.title": "Arrastra y suelta para subir", "upload_button.label": "Subir multimedia (JPEG, PNG, GIF, WebM, MP4, MOV)", - "upload_error.limit": "File upload limit exceeded.", - "upload_error.poll": "File upload not allowed with polls.", + "upload_error.limit": "Límite de subida de archivos excedido.", + "upload_error.poll": "Subida de archivos no permitida con encuestas.", "upload_form.description": "Describir para los usuarios con dificultad visual", "upload_form.focus": "Recortar", "upload_form.undo": "Borrar", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index d4cef3d5d..0c078840a 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -1,6 +1,6 @@ { "account.add_or_remove_from_list": "Gehitu edo kendu zerrendetatik", - "account.badges.bot": "Bot", + "account.badges.bot": "Bot-a", "account.block": "Blokeatu @{name}", "account.block_domain": "Ezkutatu {domain} domeinuko guztia", "account.blocked": "Blokeatuta", @@ -17,13 +17,13 @@ "account.hide_reblogs": "Ezkutatu @{name}(r)en bultzadak", "account.link_verified_on": "Esteka honen jabetzaren egiaztaketa data: {date}", "account.locked_info": "Kontu honen pribatutasun egoera blokeatuta gisa ezarri da. Jabeak eskuz erabakitzen du nork jarraitu diezaioken.", - "account.media": "Media", + "account.media": "Multimedia", "account.mention": "Aipatu @{name}", "account.moved_to": "{name} hona lekualdatu da:", "account.mute": "Mututu @{name}", "account.mute_notifications": "Mututu @{name}(r)en jakinarazpenak", "account.muted": "Mutututa", - "account.posts": "Tootak", + "account.posts": "Toot", "account.posts_with_replies": "Toot eta erantzunak", "account.report": "Salatu @{name}", "account.requested": "Onarpenaren zain. Klikatu jarraitzeko eskaera ezeztatzeko", @@ -32,7 +32,7 @@ "account.unblock": "Desblokeatu @{name}", "account.unblock_domain": "Berriz erakutsi {domain}", "account.unendorse": "Ez nabarmendu profilean", - "account.unfollow": "Jarraitzeari utzi", + "account.unfollow": "Utzi jarraitzeari", "account.unmute": "Desmututu @{name}", "account.unmute_notifications": "Desmututu @{name}(r)en jakinarazpenak", "alert.unexpected.message": "Ustekabeko errore bat gertatu da.", @@ -40,7 +40,7 @@ "boost_modal.combo": "{combo} sakatu dezakezu hurrengoan hau saltatzeko", "bundle_column_error.body": "Zerbait okerra gertatu da osagai hau kargatzean.", "bundle_column_error.retry": "Saiatu berriro", - "bundle_column_error.title": "Network error", + "bundle_column_error.title": "Sareko errorea", "bundle_modal_error.close": "Itxi", "bundle_modal_error.message": "Zerbait okerra gertatu da osagai hau kargatzean.", "bundle_modal_error.retry": "Saiatu berriro", @@ -71,21 +71,21 @@ "compose_form.lock_disclaimer": "Zure kontua ez dago {locked}. Edonork jarraitu zaitzake zure jarraitzaileentzako soilik diren mezuak ikusteko.", "compose_form.lock_disclaimer.lock": "giltzapetuta", "compose_form.placeholder": "Zer duzu buruan?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.poll.add_option": "Gehitu aukera bat", + "compose_form.poll.duration": "Inkestaren iraupena", + "compose_form.poll.option_placeholder": "{number}. aukera", + "compose_form.poll.remove_option": "Kendu aukera hau", "compose_form.publish": "Toot", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "Markatu multimedia hunkigarri gisa", "compose_form.sensitive.marked": "Multimedia edukia hunkigarri gisa markatu da", "compose_form.sensitive.unmarked": "Multimedia edukia ez da hunkigarri gisa markatu", "compose_form.spoiler.marked": "Testua abisu batek ezkutatzen du", "compose_form.spoiler.unmarked": "Testua ez dago ezkutatuta", "compose_form.spoiler_placeholder": "Idatzi zure abisua hemen", "confirmation_modal.cancel": "Utzi", - "confirmations.block.block_and_report": "Block & Report", - "confirmations.block.confirm": "Block", + "confirmations.block.block_and_report": "Blokeatu eta salatu", + "confirmations.block.confirm": "Blokeatu", "confirmations.block.message": "Ziur {name} blokeatu nahi duzula?", "confirmations.delete.confirm": "Ezabatu", "confirmations.delete.message": "Ziur mezu hau ezabatu nahi duzula?", @@ -118,7 +118,7 @@ "emoji_button.symbols": "Sinboloak", "emoji_button.travel": "Bidaiak eta tokiak", "empty_column.account_timeline": "Ez dago toot-ik hemen!", - "empty_column.account_unavailable": "Profile unavailable", + "empty_column.account_unavailable": "Profila ez dago eskuragarri", "empty_column.blocks": "Ez duzu erabiltzailerik blokeatu oraindik.", "empty_column.community": "Denbora-lerro lokala hutsik dago. Idatzi zerbait publikoki pilota biraka jartzeko!", "empty_column.direct": "Ez duzu mezu zuzenik oraindik. Baten bat bidali edo jasotzen duzunean, hemen agertuko da.", @@ -147,8 +147,8 @@ "hashtag.column_header.tag_mode.all": "eta {osagarria}", "hashtag.column_header.tag_mode.any": "edo {osagarria}", "hashtag.column_header.tag_mode.none": "gabe {osagarria}", - "hashtag.column_settings.select.no_options_message": "No suggestions found", - "hashtag.column_settings.select.placeholder": "Enter hashtags…", + "hashtag.column_settings.select.no_options_message": "Ez da proposamenik aurkitu", + "hashtag.column_settings.select.placeholder": "Sartu traolak…", "hashtag.column_settings.tag_mode.all": "Hauetako guztiak", "hashtag.column_settings.tag_mode.any": "Hautako edozein", "hashtag.column_settings.tag_mode.none": "Hauetako bat ere ez", @@ -156,15 +156,16 @@ "home.column_settings.basic": "Oinarrizkoa", "home.column_settings.show_reblogs": "Erakutsi bultzadak", "home.column_settings.show_replies": "Erakutsi erantzunak", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, one {egun #} other {# egun}}", + "intervals.full.hours": "{number, plural, one {ordu #} other {# ordu}}", + "intervals.full.minutes": "{number, plural, one {minutu #} other {# minutu}}", "introduction.federation.action": "Hurrengoa", - "introduction.federation.federated.headline": "Federated", + "introduction.federation.federated.headline": "Federatua", "introduction.federation.federated.text": "Fedibertsoko beste zerbitzarietako bidalketa publikoak federatutako denbora-lerroan agertuko dira.", - "introduction.federation.home.headline": "Home", + "introduction.federation.home.headline": "Hasiera", "introduction.federation.home.text": "Jarraitzen dituzun horien mezuak zure hasierako jarioan agertuko dira. Edozein zerbitzariko edonor jarraitu dezakezu!", - "introduction.federation.local.headline": "Local", + "introduction.federation.local.headline": "Lokala", "introduction.federation.local.text": "Zure zerbitzari berean dauden horien mezu publikoak denbora-lerro lokalean agertuko dira.", "introduction.interactions.action": "Amaitu tutoriala!", "introduction.interactions.favourite.headline": "Gogokoa", @@ -181,10 +182,10 @@ "keyboard_shortcuts.boost": "bultzada ematea", "keyboard_shortcuts.column": "mezu bat zutabe batean fokatzea", "keyboard_shortcuts.compose": "testua konposatzeko arean fokatzea", - "keyboard_shortcuts.description": "Description", + "keyboard_shortcuts.description": "Deskripzioa", "keyboard_shortcuts.direct": "mezu zuzenen zutabea irekitzeko", "keyboard_shortcuts.down": "zerrendan behera mugitzea", - "keyboard_shortcuts.enter": "to open status", + "keyboard_shortcuts.enter": "mezua irekitzeko", "keyboard_shortcuts.favourite": "gogoko egitea", "keyboard_shortcuts.favourites": "gogokoen zerrenda irekitzeko", "keyboard_shortcuts.federated": "federatutako denbora-lerroa irekitzeko", @@ -204,22 +205,24 @@ "keyboard_shortcuts.search": "bilaketan fokua jartzea", "keyboard_shortcuts.start": "\"Menua\" zutabea irekitzeko", "keyboard_shortcuts.toggle_hidden": "testua erakustea/ezkutatzea abisu baten atzean", + "keyboard_shortcuts.toggle_sensitivity": "multimedia erakutsi/ezkutatzeko", "keyboard_shortcuts.toot": "toot berria hastea", "keyboard_shortcuts.unfocus": "testua konposatzeko area / bilaketatik fokua kentzea", "keyboard_shortcuts.up": "zerrendan gora mugitzea", "lightbox.close": "Itxi", "lightbox.next": "Hurrengoa", "lightbox.previous": "Aurrekoa", - "lightbox.view_context": "View context", + "lightbox.view_context": "Ikusi testuingurua", "lists.account.add": "Gehitu zerrendara", "lists.account.remove": "Kendu zerrendatik", "lists.delete": "Ezabatu zerrenda", "lists.edit": "Editatu zerrenda", - "lists.edit.submit": "Change title", + "lists.edit.submit": "Aldatu izenburua", "lists.new.create": "Gehitu zerrenda", "lists.new.title_placeholder": "Zerrenda berriaren izena", "lists.search": "Bilatu jarraitzen dituzun pertsonen artean", "lists.subheading": "Zure zerrendak", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Kargatzen...", "media_gallery.toggle_visible": "Txandakatu ikusgaitasuna", "missing_indicator.label": "Ez aurkitua", @@ -236,20 +239,22 @@ "navigation_bar.favourites": "Gogokoak", "navigation_bar.filters": "Mutututako hitzak", "navigation_bar.follow_requests": "Jarraitzeko eskariak", + "navigation_bar.follows_and_followers": "Jarraitutakoak eta jarraitzaileak", "navigation_bar.info": "Zerbitzari honi buruz", "navigation_bar.keyboard_shortcuts": "Laster-teklak", "navigation_bar.lists": "Zerrendak", "navigation_bar.logout": "Amaitu saioa", "navigation_bar.mutes": "Mutututako erabiltzaileak", - "navigation_bar.personal": "Personal", + "navigation_bar.personal": "Pertsonala", "navigation_bar.pins": "Finkatutako toot-ak", "navigation_bar.preferences": "Hobespenak", + "navigation_bar.profile_directory": "Profilen direktorioa", "navigation_bar.public_timeline": "Federatutako denbora-lerroa", "navigation_bar.security": "Segurtasuna", "notification.favourite": "{name}(e)k zure mezua gogoko du", "notification.follow": "{name}(e)k jarraitzen zaitu", "notification.mention": "{name}(e)k aipatu zaitu", - "notification.poll": "A poll you have voted in has ended", + "notification.poll": "Zuk erantzun duzun inkesta bat bukatu da", "notification.reblog": "{name}(e)k bultzada eman dio zure mezuari", "notifications.clear": "Garbitu jakinarazpenak", "notifications.clear_confirmation": "Ziur zure jakinarazpen guztiak behin betirako garbitu nahi dituzula?", @@ -260,7 +265,7 @@ "notifications.column_settings.filter_bar.show": "Erakutsi", "notifications.column_settings.follow": "Jarraitzaile berriak:", "notifications.column_settings.mention": "Aipamenak:", - "notifications.column_settings.poll": "Poll results:", + "notifications.column_settings.poll": "Inkestaren emaitzak:", "notifications.column_settings.push": "Push jakinarazpenak", "notifications.column_settings.reblog": "Bultzadak:", "notifications.column_settings.show": "Erakutsi zutabean", @@ -270,14 +275,14 @@ "notifications.filter.favourites": "Gogokoak", "notifications.filter.follows": "Jarraipenak", "notifications.filter.mentions": "Aipamenak", - "notifications.filter.polls": "Poll results", + "notifications.filter.polls": "Inkestaren emaitza", "notifications.group": "{count} jakinarazpen", - "poll.closed": "Closed", - "poll.refresh": "Refresh", - "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", - "poll.vote": "Vote", - "poll_button.add_poll": "Add a poll", - "poll_button.remove_poll": "Remove poll", + "poll.closed": "Itxita", + "poll.refresh": "Berritu", + "poll.total_votes": "{count, plural, one {boto #} other {# boto}}", + "poll.vote": "Bozkatu", + "poll_button.add_poll": "Gehitu inkesta bat", + "poll_button.remove_poll": "Kendu inkesta", "privacy.change": "Doitu mezuaren pribatutasuna", "privacy.direct.long": "Bidali aipatutako erabiltzaileei besterik ez", "privacy.direct.short": "Zuzena", @@ -299,22 +304,23 @@ "report.forward_hint": "Kontu hau beste zerbitzari batekoa da. Bidali txostenaren kopia anonimo hara ere?", "report.hint": "Txostena zure zerbitzariaren moderatzaileei bidaliko zaie. Kontu hau zergatik salatzen duzun behean azaldu dezakezu:", "report.placeholder": "Iruzkin gehigarriak", - "report.submit": "Submit", + "report.submit": "Bidali", "report.target": "{target} salatzen", "search.placeholder": "Bilatu", "search_popout.search_format": "Bilaketa aurreratuaren formatua", "search_popout.tips.full_text": "Testu hutsarekin zuk idatzitako mezuak, gogokoak, bultzadak edo aipamenak aurkitu ditzakezu, bat datozen erabiltzaile-izenak, pantaila-izenak, eta traolak.", "search_popout.tips.hashtag": "traola", - "search_popout.tips.status": "status", + "search_popout.tips.status": "mezua", "search_popout.tips.text": "Testu hutsak pantaila-izenak, erabiltzaile-izenak eta traolak bilatzen ditu", "search_popout.tips.user": "erabiltzailea", "search_results.accounts": "Jendea", "search_results.hashtags": "Traolak", "search_results.statuses": "Toot-ak", - "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", + "search_results.total": "{count, number} {count, plural, one {emaitza} other {emaitzak}}", "status.admin_account": "Ireki @{name} erabiltzailearen moderazio interfazea", "status.admin_status": "Ireki mezu hau moderazio interfazean", - "status.block": "Block @{name}", + "status.block": "Blokeatu @{name}", "status.cancel_reblog_private": "Kendu bultzada", "status.cannot_reblog": "Mezu honi ezin zaio bultzada eman", "status.copy": "Kopiatu mezuaren esteka", @@ -358,17 +364,17 @@ "tabs_bar.local_timeline": "Lokala", "tabs_bar.notifications": "Jakinarazpenak", "tabs_bar.search": "Bilatu", - "time_remaining.days": "{number, plural, one {# day} other {# days}} left", - "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", - "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", - "time_remaining.moments": "Moments remaining", - "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left", + "time_remaining.days": "{number, plural, one {egun #} other {# egun}} amaitzeko", + "time_remaining.hours": "{number, plural, one {ordu #} other {# ordu}} amaitzeko", + "time_remaining.minutes": "{number, plural, one {minutu #} other {# minutu}} amaitzeko", + "time_remaining.moments": "Amaitzekotan", + "time_remaining.seconds": "{number, plural, one {segundo #} other {# segundo}} amaitzeko", "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} hitz egiten", "ui.beforeunload": "Zure zirriborroa galduko da Mastodon uzten baduzu.", "upload_area.title": "Arrastatu eta jaregin igotzeko", "upload_button.label": "Gehitu multimedia (JPEG, PNG, GIF, WebM, MP4, MOV)", "upload_error.limit": "Fitxategi igoera muga gaindituta.", - "upload_error.poll": "File upload not allowed with polls.", + "upload_error.poll": "Ez da inkestetan fitxategiak igotzea onartzen.", "upload_form.description": "Deskribatu ikusmen arazoak dituztenentzat", "upload_form.focus": "Aldatu aurrebista", "upload_form.undo": "Ezabatu", @@ -376,10 +382,10 @@ "video.close": "Itxi bideoa", "video.exit_fullscreen": "Irten pantaila osotik", "video.expand": "Hedatu bideoa", - "video.fullscreen": "Full screen", + "video.fullscreen": "Pantaila osoa", "video.hide": "Ezkutatu bideoa", "video.mute": "Mututu soinua", - "video.pause": "Pause", + "video.pause": "Pausatu", "video.play": "Jo", "video.unmute": "Desmututu soinua" } diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 3dcfbc7ac..fabf15cd3 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "اصلی", "home.column_settings.show_reblogs": "نمایش بازبوقها", "home.column_settings.show_replies": "نمایش پاسخها", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# روز} other {# روز}}", "intervals.full.hours": "{number, plural, one {# ساعت} other {# ساعت}}", "intervals.full.minutes": "{number, plural, one {# دقیقه} other {# دقیقه}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "نام فهرست تازه", "lists.search": "بین کسانی که پی میگیرید بگردید", "lists.subheading": "فهرستهای شما", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "بارگیری...", "media_gallery.toggle_visible": "تغییر پیدایی", "missing_indicator.label": "پیدا نشد", @@ -311,6 +313,7 @@ "search_results.accounts": "افراد", "search_results.hashtags": "هشتگها", "search_results.statuses": "بوقها", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {نتیجه} other {نتیجه}}", "status.admin_account": "محیط مدیریت مربوط به @{name} را باز کن", "status.admin_status": "این نوشته را در محیط مدیریت باز کن", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 9e098638f..05495d5d7 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -71,20 +71,20 @@ "compose_form.lock_disclaimer": "Tilisi ei ole {locked}. Kuka tahansa voi seurata tiliäsi ja nähdä vain seuraajille rajaamasi julkaisut.", "compose_form.lock_disclaimer.lock": "lukittu", "compose_form.placeholder": "Mitä mietit?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.poll.add_option": "Lisää valinta", + "compose_form.poll.duration": "Äänestyksen kesto", + "compose_form.poll.option_placeholder": "Valinta numero", + "compose_form.poll.remove_option": "Poista tämä valinta", "compose_form.publish": "Tuuttaa", - "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.publish_loud": "Julkista!", + "compose_form.sensitive.hide": "Valitse tämä arkaluontoisena", "compose_form.sensitive.marked": "Media on merkitty arkaluontoiseksi", "compose_form.sensitive.unmarked": "Mediaa ei ole merkitty arkaluontoiseksi", "compose_form.spoiler.marked": "Teksti on piilotettu varoituksen taakse", "compose_form.spoiler.unmarked": "Teksti ei ole piilotettu", "compose_form.spoiler_placeholder": "Sisältövaroitus", "confirmation_modal.cancel": "Peruuta", - "confirmations.block.block_and_report": "Block & Report", + "confirmations.block.block_and_report": "Estä ja raportoi", "confirmations.block.confirm": "Estä", "confirmations.block.message": "Haluatko varmasti estää käyttäjän {name}?", "confirmations.delete.confirm": "Poista", @@ -118,7 +118,7 @@ "emoji_button.symbols": "Symbolit", "emoji_button.travel": "Matkailu", "empty_column.account_timeline": "Ei ole 'toots' täällä!", - "empty_column.account_unavailable": "Profile unavailable", + "empty_column.account_unavailable": "Profiilia ei löydy", "empty_column.blocks": "Et ole vielä estänyt yhtään käyttäjää.", "empty_column.community": "Paikallinen aikajana on tyhjä. Homma lähtee käyntiin, kun kirjoitat jotain julkista!", "empty_column.direct": "Sinulla ei ole vielä yhtään viestiä yksittäiselle käyttäjälle. Kun lähetät tai vastaanotat sellaisen, se näkyy täällä.", @@ -138,7 +138,7 @@ "follow_request.reject": "Hylkää", "getting_started.developers": "Kehittäjille", "getting_started.directory": "Profiili hakemisto", - "getting_started.documentation": "Documentation", + "getting_started.documentation": "Documentaatio", "getting_started.heading": "Aloitus", "getting_started.invite": "Kutsu ihmisiä", "getting_started.open_source_notice": "Mastodon on avoimen lähdekoodin ohjelma. Voit avustaa tai raportoida ongelmia GitHubissa: {github}.", @@ -147,8 +147,8 @@ "hashtag.column_header.tag_mode.all": "ja {additional}", "hashtag.column_header.tag_mode.any": "tai {additional}", "hashtag.column_header.tag_mode.none": "ilman {additional}", - "hashtag.column_settings.select.no_options_message": "No suggestions found", - "hashtag.column_settings.select.placeholder": "Enter hashtags…", + "hashtag.column_settings.select.no_options_message": "Ehdostuta ei löydetty", + "hashtag.column_settings.select.placeholder": "Laita häshtägejä…", "hashtag.column_settings.tag_mode.all": "Kaikki", "hashtag.column_settings.tag_mode.any": "Kaikki", "hashtag.column_settings.tag_mode.none": "Ei mikään", @@ -156,25 +156,26 @@ "home.column_settings.basic": "Perusasetukset", "home.column_settings.show_reblogs": "Näytä buustaukset", "home.column_settings.show_replies": "Näytä vastaukset", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "Päivä päiviä", + "intervals.full.hours": "Tunti tunteja", + "intervals.full.minutes": "Minuuti minuuteja", "introduction.federation.action": "Seuraava", - "introduction.federation.federated.headline": "Federated", - "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.", - "introduction.federation.home.headline": "Home", - "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!", - "introduction.federation.local.headline": "Local", - "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.", - "introduction.interactions.action": "Finish tutorial!", - "introduction.interactions.favourite.headline": "Favourite", - "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", - "introduction.interactions.reblog.headline": "Boost", - "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", - "introduction.interactions.reply.headline": "Reply", - "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", - "introduction.welcome.action": "Let's go!", - "introduction.welcome.headline": "First steps", + "introduction.federation.federated.headline": "Federaatioitettu", + "introduction.federation.federated.text": "Julkisia viestejä muiden serverien that is not a word aikoo tulla federoituun aikajanaan.", + "introduction.federation.home.headline": "Koti", + "introduction.federation.home.text": "Viestit muilta pelaajilta jota seuraat aikovat tulla koti sivuusi. Voit seurata ketä vain missä vain serverillä!", + "introduction.federation.local.headline": "Paikallinen", + "introduction.federation.local.text": "Julkiset viestit muilta pelaajilta samalla serverillä tulevat sinun paikalliseen aikajanaan.", + "introduction.interactions.action": "Suorita harjoitus!", + "introduction.interactions.favourite.headline": "Lempi", + "introduction.interactions.favourite.text": "Toot is not a word.", + "introduction.interactions.reblog.headline": "Nopeutus", + "introduction.interactions.reblog.text": "Toot is not a word", + "introduction.interactions.reply.headline": "Vastaa", + "introduction.interactions.reply.text": "TOOT IS NOT A WORD", + "introduction.welcome.action": "Mennään!", + "introduction.welcome.headline": "Ensimmäiset askeleet", "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.", "keyboard_shortcuts.back": "liiku taaksepäin", "keyboard_shortcuts.blocked": "avaa lista estetyistä käyttäjistä", @@ -204,6 +205,7 @@ "keyboard_shortcuts.search": "siirry hakukenttään", "keyboard_shortcuts.start": "avaa \"Aloitus\" -sarake", "keyboard_shortcuts.toggle_hidden": "näytä/piilota sisältövaroituksella merkitty teksti", + "keyboard_shortcuts.toggle_sensitivity": "to show/hide media", "keyboard_shortcuts.toot": "ala kirjoittaa uutta tuuttausta", "keyboard_shortcuts.unfocus": "siirry pois tekstikentästä tai hakukentästä", "keyboard_shortcuts.up": "siirry listassa ylöspäin", @@ -220,6 +222,7 @@ "lists.new.title_placeholder": "Uuden listan nimi", "lists.search": "Etsi seuraamistasi henkilöistä", "lists.subheading": "Omat listat", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Ladataan...", "media_gallery.toggle_visible": "Säädä näkyvyyttä", "missing_indicator.label": "Ei löytynyt", @@ -236,6 +239,7 @@ "navigation_bar.favourites": "Suosikit", "navigation_bar.filters": "Mykistetyt sanat", "navigation_bar.follow_requests": "Seuraamispyynnöt", + "navigation_bar.follows_and_followers": "Follows and followers", "navigation_bar.info": "Tietoa tästä instanssista", "navigation_bar.keyboard_shortcuts": "Näppäinkomennot", "navigation_bar.lists": "Listat", @@ -244,6 +248,7 @@ "navigation_bar.personal": "Personal", "navigation_bar.pins": "Kiinnitetyt tuuttaukset", "navigation_bar.preferences": "Asetukset", + "navigation_bar.profile_directory": "Profile directory", "navigation_bar.public_timeline": "Yleinen aikajana", "navigation_bar.security": "Tunnukset", "notification.favourite": "{name} tykkäsi tilastasi", @@ -311,6 +316,7 @@ "search_results.accounts": "Ihmiset", "search_results.hashtags": "Hashtagit", "search_results.statuses": "Tuuttaukset", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 090f15bea..e3733f559 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Basique", "home.column_settings.show_reblogs": "Afficher les partages", "home.column_settings.show_replies": "Afficher les réponses", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# jour} other {# jours}}", "intervals.full.hours": "{number, plural, one {# heure} other {# heures}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Titre de la nouvelle liste", "lists.search": "Rechercher parmi les gens que vous suivez", "lists.subheading": "Vos listes", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Chargement…", "media_gallery.toggle_visible": "Modifier la visibilité", "missing_indicator.label": "Non trouvé", @@ -311,6 +313,7 @@ "search_results.accounts": "Comptes", "search_results.hashtags": "Hashtags", "search_results.statuses": "Pouets", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {résultat} other {résultats}}", "status.admin_account": "Ouvrir l'interface de modération pour @{name}", "status.admin_status": "Ouvrir ce statut dans l'interface de modération", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 61afd4cbf..2605f61f8 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -13,7 +13,7 @@ "account.followers.empty": "Ninguén está a seguir esta usuaria por agora.", "account.follows": "Seguindo", "account.follows.empty": "Esta usuaria aínda non segue a ninguén.", - "account.follows_you": "Séguena", + "account.follows_you": "Séguete", "account.hide_reblogs": "Ocultar repeticións de @{name}", "account.link_verified_on": "A propiedade de esta ligazón foi comprobada en {date}", "account.locked_info": "O estado da intimidade de esta conta estableceuse en pechado. A persoa dona da conta revisa quen pode seguila.", @@ -71,25 +71,25 @@ "compose_form.lock_disclaimer": "A súa conta non está {locked}. Calquera pode seguila para ver as súas mensaxes só-para-seguidoras.", "compose_form.lock_disclaimer.lock": "bloqueado", "compose_form.placeholder": "Qué contas?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.poll.add_option": "Engadir unha opción", + "compose_form.poll.duration": "Duración da sondaxe", + "compose_form.poll.option_placeholder": "Opción {number}", + "compose_form.poll.remove_option": "Eliminar esta opción", "compose_form.publish": "Toot", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "Marcar medios como sensibles", "compose_form.sensitive.marked": "Medios marcados como sensibles", "compose_form.sensitive.unmarked": "Os medios non están marcados como sensibles", "compose_form.spoiler.marked": "O texto está agochado tras un aviso", "compose_form.spoiler.unmarked": "O texto non está agochado", "compose_form.spoiler_placeholder": "Escriba o aviso aquí", "confirmation_modal.cancel": "Cancelar", - "confirmations.block.block_and_report": "Block & Report", + "confirmations.block.block_and_report": "Bloquear e Informar", "confirmations.block.confirm": "Bloquear", "confirmations.block.message": "Está segura de querer bloquear a {name}?", "confirmations.delete.confirm": "Borrar", "confirmations.delete.message": "Está segura de que quere eliminar este estado?", - "confirmations.delete_list.confirm": "Delete", + "confirmations.delete_list.confirm": "Eliminar", "confirmations.delete_list.message": "Estás seguro de que queres eliminar permanentemente esta lista?", "confirmations.domain_block.confirm": "Agochar un dominio completo", "confirmations.domain_block.message": "Realmente está segura de que quere bloquear por completo o dominio {domain}? Normalmente é suficiente, e preferible, bloquear de xeito selectivo varios elementos. Non verá contidos de ese dominio en ningunha liña temporal ou nas notificacións. As súas seguidoras en ese dominio serán eliminadas.", @@ -138,7 +138,7 @@ "follow_request.reject": "Rexeitar", "getting_started.developers": "Desenvolvedoras", "getting_started.directory": "Directorio do perfil", - "getting_started.documentation": "Documentation", + "getting_started.documentation": "Documentación", "getting_started.heading": "Comezando", "getting_started.invite": "Convide a xente", "getting_started.open_source_notice": "Mastodon é software de código aberto. Pode contribuír ou informar de fallos en GitHub en {github}.", @@ -147,8 +147,8 @@ "hashtag.column_header.tag_mode.all": "e {additional}", "hashtag.column_header.tag_mode.any": "ou {additional}", "hashtag.column_header.tag_mode.none": "sen {additional}", - "hashtag.column_settings.select.no_options_message": "No suggestions found", - "hashtag.column_settings.select.placeholder": "Enter hashtags…", + "hashtag.column_settings.select.no_options_message": "Non se atopan suxestións", + "hashtag.column_settings.select.placeholder": "Introducir etiquetas…", "hashtag.column_settings.tag_mode.all": "Todos estos", "hashtag.column_settings.tag_mode.any": "Calquera de estos", "hashtag.column_settings.tag_mode.none": "Ningún de estos", @@ -156,13 +156,14 @@ "home.column_settings.basic": "Básico", "home.column_settings.show_reblogs": "Mostrar repeticións", "home.column_settings.show_replies": "Mostrar respostas", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural,one {# día} other {# días}}", + "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}", "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}", "introduction.federation.action": "Seguinte", - "introduction.federation.federated.headline": "Federated", + "introduction.federation.federated.headline": "Federado", "introduction.federation.federated.text": "Publicacións públicas desde outros servidores do fediverso aparecerán na liña temporal federada.", - "introduction.federation.home.headline": "Home", + "introduction.federation.home.headline": "Inicio", "introduction.federation.home.text": "Publicacións de xente que vostede segue aparecerán no TL de Inicio. Pode seguir a calquera en calquer servidor!", "introduction.federation.local.headline": "Local", "introduction.federation.local.text": "Publicacións públicas de xente no seu mesmo servidor aparecerán na liña temporal local.", @@ -204,22 +205,24 @@ "keyboard_shortcuts.search": "para centrar a busca", "keyboard_shortcuts.start": "abrir columna \"comezando\"", "keyboard_shortcuts.toggle_hidden": "mostrar/agochar un texto detrás do AC", + "keyboard_shortcuts.toggle_sensitivity": "mostrar/ocultar medios", "keyboard_shortcuts.toot": "escribir un toot novo", "keyboard_shortcuts.unfocus": "quitar o foco do área de escritura/busca", "keyboard_shortcuts.up": "ir hacia arriba na lista", "lightbox.close": "Fechar", "lightbox.next": "Seguinte", "lightbox.previous": "Anterior", - "lightbox.view_context": "View context", + "lightbox.view_context": "Ver contexto", "lists.account.add": "Engadir á lista", "lists.account.remove": "Eliminar da lista", - "lists.delete": "Delete list", + "lists.delete": "Eliminar lista", "lists.edit": "Editar lista", - "lists.edit.submit": "Change title", + "lists.edit.submit": "Cambiar título", "lists.new.create": "Engadir lista", "lists.new.title_placeholder": "Novo título da lista", "lists.search": "Procurar entre a xente que segues", "lists.subheading": "As túas listas", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Cargando...", "media_gallery.toggle_visible": "Ocultar", "missing_indicator.label": "Non atopado", @@ -236,6 +239,7 @@ "navigation_bar.favourites": "Favoritas", "navigation_bar.filters": "Palabras acaladas", "navigation_bar.follow_requests": "Peticións de seguimento", + "navigation_bar.follows_and_followers": "Seguindo e seguidoras", "navigation_bar.info": "Sobre este servidor", "navigation_bar.keyboard_shortcuts": "Atallos", "navigation_bar.lists": "Listas", @@ -244,6 +248,7 @@ "navigation_bar.personal": "Persoal", "navigation_bar.pins": "Mensaxes fixadas", "navigation_bar.preferences": "Preferencias", + "navigation_bar.profile_directory": "Directorio de perfil", "navigation_bar.public_timeline": "Liña temporal federada", "navigation_bar.security": "Seguridade", "notification.favourite": "{name} marcou como favorito o seu estado", @@ -272,12 +277,12 @@ "notifications.filter.mentions": "Mencións", "notifications.filter.polls": "Resultados da sondaxe", "notifications.group": "{count} notificacións", - "poll.closed": "Closed", - "poll.refresh": "Refresh", - "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", + "poll.closed": "Pechado", + "poll.refresh": "Actualizar", + "poll.total_votes": "{count, plural, one {# voto} outros {# votos}}", "poll.vote": "Votar", - "poll_button.add_poll": "Add a poll", - "poll_button.remove_poll": "Remove poll", + "poll_button.add_poll": "Engadir sondaxe", + "poll_button.remove_poll": "Eliminar sondaxe", "privacy.change": "Axustar a intimidade do estado", "privacy.direct.long": "Enviar exclusivamente as usuarias mencionadas", "privacy.direct.short": "Directa", @@ -311,13 +316,14 @@ "search_results.accounts": "Xente", "search_results.hashtags": "Etiquetas", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count,plural,one {result} outros {results}}", "status.admin_account": "Abrir interface de moderación para @{name}", "status.admin_status": "Abrir este estado na interface de moderación", - "status.block": "Block @{name}", + "status.block": "Bloquear @{name}", "status.cancel_reblog_private": "Non promover", "status.cannot_reblog": "Esta mensaxe non pode ser promovida", - "status.copy": "Copy link to status", + "status.copy": "Copiar ligazón ao estado", "status.delete": "Eliminar", "status.detailed_status": "Vista detallada da conversa", "status.direct": "Mensaxe directa @{name}", @@ -358,17 +364,17 @@ "tabs_bar.local_timeline": "Local", "tabs_bar.notifications": "Notificacións", "tabs_bar.search": "Buscar", - "time_remaining.days": "{number, plural, one {# day} other {# days}} left", - "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", - "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", - "time_remaining.moments": "Moments remaining", - "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left", + "time_remaining.days": "{number, plural, one {# dia} other {# días}} restantes", + "time_remaining.hours": "{number, plural, one {# hora} other {# horas}} restantes", + "time_remaining.minutes": "{number, plural, one {# minuto} other {# minutos}} restantes", + "time_remaining.moments": "Está rematando", + "time_remaining.seconds": "{number, plural, one {# segundo} other {# segundos}} restantes", "trends.count_by_accounts": "{count} {rawCount, plural, one {person} outras {people}} conversando", "ui.beforeunload": "O borrador perderase se sae de Mastodon.", "upload_area.title": "Arrastre e solte para subir", - "upload_button.label": "Engadir medios (JPEG, PNG, GIF, WebM, MP4, MOV)", - "upload_error.limit": "File upload limit exceeded.", - "upload_error.poll": "File upload not allowed with polls.", + "upload_button.label": "Engadir medios ({formats})", + "upload_error.limit": "Excedeu o límite de subida de ficheiros.", + "upload_error.poll": "Non se poden subir ficheiros nas sondaxes.", "upload_form.description": "Describa para deficientes visuais", "upload_form.focus": "Cambiar vista previa", "upload_form.undo": "Eliminar", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index bf09ead22..b89417a0a 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -64,7 +64,7 @@ "column_header.show_settings": "הצגת העדפות", "column_header.unpin": "שחרור קיבוע", "column_subheading.settings": "אפשרויות", - "community.column_settings.media_only": "Media Only", + "community.column_settings.media_only": "Media only", "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", "compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", @@ -156,6 +156,7 @@ "home.column_settings.basic": "למתחילים", "home.column_settings.show_reblogs": "הצגת הדהודים", "home.column_settings.show_replies": "הצגת תגובות", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "New list title", "lists.search": "Search among people you follow", "lists.subheading": "Your lists", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "טוען...", "media_gallery.toggle_visible": "נראה\\בלתי נראה", "missing_indicator.label": "לא נמצא", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {תוצאה} other {תוצאות}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json index 5d8f4ab7f..90ddff57c 100644 --- a/app/javascript/mastodon/locales/hi.json +++ b/app/javascript/mastodon/locales/hi.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Basic", "home.column_settings.show_reblogs": "Show boosts", "home.column_settings.show_replies": "Show replies", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "New list title", "lists.search": "Search among people you follow", "lists.subheading": "Your lists", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Loading...", "media_gallery.toggle_visible": "Toggle visibility", "missing_indicator.label": "Not found", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index 5353cb572..23cea6960 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -64,7 +64,7 @@ "column_header.show_settings": "Show settings", "column_header.unpin": "Unpin", "column_subheading.settings": "Postavke", - "community.column_settings.media_only": "Media Only", + "community.column_settings.media_only": "Media only", "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", "compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", @@ -156,6 +156,7 @@ "home.column_settings.basic": "Osnovno", "home.column_settings.show_reblogs": "Pokaži boostove", "home.column_settings.show_replies": "Pokaži odgovore", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "New list title", "lists.search": "Search among people you follow", "lists.subheading": "Your lists", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Učitavam...", "media_gallery.toggle_visible": "Preklopi vidljivost", "missing_indicator.label": "Nije nađen", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index b906dd619..38d30efe4 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -1,107 +1,107 @@ { - "account.add_or_remove_from_list": "Add or Remove from lists", + "account.add_or_remove_from_list": "Hozzáadás és elvétel listáról", "account.badges.bot": "Bot", "account.block": "@{name} letiltása", "account.block_domain": "Minden elrejtése innen: {domain}", - "account.blocked": "Blocked", - "account.direct": "Direct Message @{name}", - "account.domain_blocked": "Domain hidden", + "account.blocked": "Letiltva", + "account.direct": "Közvetlen üzenet @{name} számára", + "account.domain_blocked": "Rejtett domain", "account.edit_profile": "Profil szerkesztése", - "account.endorse": "Feature on profile", + "account.endorse": "Kiemelés a profilodon", "account.follow": "Követés", - "account.followers": "Követők", - "account.followers.empty": "No one follows this user yet.", - "account.follows": "Követve", - "account.follows.empty": "This user doesn't follow anyone yet.", - "account.follows_you": "Követnek téged", - "account.hide_reblogs": "Rejtsd el a tülkölést @{name}-tól/től", - "account.link_verified_on": "Ownership of this link was checked on {date}", - "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.", + "account.followers": "Követő", + "account.followers.empty": "Ezt a felhasználót még senki sem követi.", + "account.follows": "Követett", + "account.follows.empty": "Ez a felhasználó még senkit sem követ.", + "account.follows_you": "Követ téged", + "account.hide_reblogs": "@{name} megtolásainak némítása", + "account.link_verified_on": "A linket ellenőriztük: {date}", + "account.locked_info": "Ez a fiók zárt. A tulaj engedélyezi, ki követheti őt.", "account.media": "Média", "account.mention": "@{name} említése", "account.moved_to": "{name} átköltözött:", "account.mute": "@{name} némítása", - "account.mute_notifications": "@{name} értesítések némítása", - "account.muted": "Muted", - "account.posts": "Státuszok", - "account.posts_with_replies": "Toots with replies", + "account.mute_notifications": "@{name} értesítéseinek némítása", + "account.muted": "Némítva", + "account.posts": "Tülkölés", + "account.posts_with_replies": "Tülkölés válaszokkal", "account.report": "@{name} jelentése", - "account.requested": "Engedélyre vár. Kattintson a követési kérés visszavonására", + "account.requested": "Engedélyre vár. Kattints a követési kérés visszavonásához", "account.share": "@{name} profiljának megosztása", - "account.show_reblogs": "@{name} kedvenceinek mutatása", - "account.unblock": "@{name} kiblokkolása", - "account.unblock_domain": "{domain} mutatása", - "account.unendorse": "Don't feature on profile", - "account.unfollow": "Követés abbahagyása", - "account.unmute": "@{name} kinémítása", - "account.unmute_notifications": "@{name} értesítéseinek kinémítása", - "alert.unexpected.message": "An unexpected error occurred.", - "alert.unexpected.title": "Oops!", - "boost_modal.combo": "Megnyomhatod {combo}, hogy átugord következő alkalommal", + "account.show_reblogs": "@{name} megtolásainak mutatása", + "account.unblock": "@{name} letiltásának feloldása", + "account.unblock_domain": "{domain} elrejtésének feloldása", + "account.unendorse": "Kiemelés törlése a profilodról", + "account.unfollow": "Követés vége", + "account.unmute": "@{name} némítás feloldása", + "account.unmute_notifications": "@{name} némított értesítéseinek feloldása", + "alert.unexpected.message": "Váratlan hiba történt.", + "alert.unexpected.title": "Hoppá!", + "boost_modal.combo": "Hogy átugord ezt következő alkalommal, használd {combo}", "bundle_column_error.body": "Hiba történt a komponens betöltése közben.", - "bundle_column_error.retry": "Próbálja újra", + "bundle_column_error.retry": "Próbáld újra", "bundle_column_error.title": "Hálózati hiba", - "bundle_modal_error.close": "Bezár", + "bundle_modal_error.close": "Bezárás", "bundle_modal_error.message": "Hiba történt a komponens betöltésekor.", - "bundle_modal_error.retry": "Próbálja újra", + "bundle_modal_error.retry": "Próbáld újra", "column.blocks": "Letiltott felhasználók", "column.community": "Helyi idővonal", - "column.direct": "Direct messages", - "column.domain_blocks": "Hidden domains", + "column.direct": "Közvetlen üzenetek", + "column.domain_blocks": "Rejtett domainek", "column.favourites": "Kedvencek", - "column.follow_requests": "Követési kérések", + "column.follow_requests": "Követési kérelmek", "column.home": "Kezdőlap", "column.lists": "Listák", "column.mutes": "Némított felhasználók", "column.notifications": "Értesítések", - "column.pins": "Kitűzött tülkölések", + "column.pins": "Kitűzött tülkök", "column.public": "Nyilvános idővonal", "column_back_button.label": "Vissza", "column_header.hide_settings": "Beállítások elrejtése", "column_header.moveLeft_settings": "Oszlop elmozdítása balra", - "column_header.moveRight_settings": "oszlop elmozdítása jobbra", - "column_header.pin": "Kitűz", + "column_header.moveRight_settings": "Oszlop elmozdítása jobbra", + "column_header.pin": "Kitűzés", "column_header.show_settings": "Beállítások mutatása", "column_header.unpin": "Kitűzés eltávolítása", "column_subheading.settings": "Beállítások", - "community.column_settings.media_only": "Media Only", - "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", - "compose_form.direct_message_warning_learn_more": "Learn more", - "compose_form.hashtag_warning": "Ezen tülkölés nem fog megjelenni semmilyen hashtag alatt mivel listázatlan. Csak a publikus tülkölések kereshetőek hashtag-el.", - "compose_form.lock_disclaimer": "Az ön fiókja nincs {locked}. Bárki követni tud, hogy megtekintse a kizárt követőknek szánt üzeneteid.", + "community.column_settings.media_only": "Csak média", + "compose_form.direct_message_warning": "Ezt a tülköt csak a benne megemlített felhasználók láthatják majd.", + "compose_form.direct_message_warning_learn_more": "Több infó", + "compose_form.hashtag_warning": "Ez a tülköd nem fog megjelenni semmilyen hashtag alatt mivel listázatlan. Csak nyilvános tülkök kereshetőek hashtaggel.", + "compose_form.lock_disclaimer": "A fiókod nincs {locked}. Bárki követni tud, hogy megtekintse a kizárólag követőknek szánt üzeneteidet.", "compose_form.lock_disclaimer.lock": "lezárva", - "compose_form.placeholder": "Mire gondolsz?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.placeholder": "Mi jár a fejedben?", + "compose_form.poll.add_option": "Lehetőség hozzáadása", + "compose_form.poll.duration": "Szavazás időtartama", + "compose_form.poll.option_placeholder": "Lehetőség {number}", + "compose_form.poll.remove_option": "Lehetőség törlése", "compose_form.publish": "Tülk", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", - "compose_form.sensitive.marked": "Media is marked as sensitive", - "compose_form.sensitive.unmarked": "Media is not marked as sensitive", - "compose_form.spoiler.marked": "Text is hidden behind warning", - "compose_form.spoiler.unmarked": "Text is not hidden", - "compose_form.spoiler_placeholder": "Figyelmeztetését írja ide", - "confirmation_modal.cancel": "Bezár", - "confirmations.block.block_and_report": "Block & Report", - "confirmations.block.confirm": "Letilt", - "confirmations.block.message": "Biztos benne, hogy le szeretné tiltani {name}?", - "confirmations.delete.confirm": "Töröl", - "confirmations.delete.message": "Biztos benne, hogy törölni szeretné ezt a státuszt?", - "confirmations.delete_list.confirm": "Töröl", - "confirmations.delete_list.message": "Biztos benne, hogy véglegesen törölni szeretné ezt a listát?", - "confirmations.domain_block.confirm": "Egész domain elrejtése", - "confirmations.domain_block.message": "Nagyon biztos abban, hogy le szeretné tiltani az egész {domain}-t? A legtöbb esetben néhány célszerű tiltás vagy némítás elegendő és kívánatosabb megoldás.", - "confirmations.mute.confirm": "Némít", - "confirmations.mute.message": "Biztos benne, hogy némítani szeretné {name}?", - "confirmations.redraft.confirm": "Delete & redraft", - "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.", - "confirmations.reply.confirm": "Reply", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "compose_form.sensitive.hide": "Média megjelölése szenzitívként", + "compose_form.sensitive.marked": "A médiát szenzitívnek jelölték", + "compose_form.sensitive.unmarked": "A médiát nem jelölték szenzitívnek", + "compose_form.spoiler.marked": "A szöveg figyelmeztetés mögé van rejtve", + "compose_form.spoiler.unmarked": "A szöveg nem rejtett", + "compose_form.spoiler_placeholder": "Írd ide a figyelmeztetést", + "confirmation_modal.cancel": "Mégse", + "confirmations.block.block_and_report": "Letiltás és Bejelentés", + "confirmations.block.confirm": "Letiltás", + "confirmations.block.message": "Biztos, hogy le szeretnéd tiltani {name}?", + "confirmations.delete.confirm": "Törlés", + "confirmations.delete.message": "Biztos, hogy törölni szeretnéd ezt a tülkölést?", + "confirmations.delete_list.confirm": "Törlés", + "confirmations.delete_list.message": "Biztos, hogy véglegesen törölni szeretnéd ezt a listát?", + "confirmations.domain_block.confirm": "Teljes domain elrejtése", + "confirmations.domain_block.message": "Egészen biztos, hogy le szeretnéd tiltani a teljes {domain}-t? A legtöbb esetben néhány célzott tiltás vagy némítás elegendő és kívánatosabb megoldás. Semmilyen tartalmat nem fogsz látni ebből a domainből se idővonalakon, se értesítésekben. Az ebben a domainben lévő követőidet is eltávolítjuk.", + "confirmations.mute.confirm": "Némítás", + "confirmations.mute.message": "Biztos, hogy némítani szeretnéd {name}?", + "confirmations.redraft.confirm": "Törlés és újraírás", + "confirmations.redraft.message": "Biztos, hogy ezt a tülköt szeretnéd törölni és újraírni? Minden megtolást és kedvencnek jelölést elvesztesz, az eredetire adott válaszok pedig elárvulnak.", + "confirmations.reply.confirm": "Válasz", + "confirmations.reply.message": "Ha most válaszolsz, ez felülírja a most szerkesztés alatt álló üzenetet. Mégis ezt szeretnéd?", "confirmations.unfollow.confirm": "Követés visszavonása", - "confirmations.unfollow.message": "Biztos benne, hogy vissza szeretné vonni {name} követését?", - "embed.instructions": "Ágyazza be ezen státuszt weboldalába az alábbi kód másolásával.", + "confirmations.unfollow.message": "Biztos, hogy vissza szeretnéd vonni {name} követését?", + "embed.instructions": "Ágyazd be ezt a tülköt a weboldaladba az alábbi kód kimásolásával.", "embed.preview": "Így fog kinézni:", "emoji_button.activity": "Aktivitás", "emoji_button.custom": "Egyéni", @@ -109,7 +109,7 @@ "emoji_button.food": "Étel és Ital", "emoji_button.label": "Emoji beszúrása", "emoji_button.nature": "Természet", - "emoji_button.not_found": "Nincsenek emojok!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "Nincsenek emojik!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "Tárgyak", "emoji_button.people": "Emberek", "emoji_button.recent": "Gyakran használt", @@ -117,269 +117,275 @@ "emoji_button.search_results": "Keresési találatok", "emoji_button.symbols": "Szimbólumok", "emoji_button.travel": "Utazás és Helyek", - "empty_column.account_timeline": "No toots here!", - "empty_column.account_unavailable": "Profile unavailable", - "empty_column.blocks": "You haven't blocked any users yet.", - "empty_column.community": "A helyi idővonal üres. Írj egy publikus stástuszt, hogy elindítsd a labdát!", - "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", - "empty_column.domain_blocks": "There are no hidden domains yet.", - "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", - "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", - "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", - "empty_column.hashtag": "Jelenleg nem található semmi ezen hashtaggel.", - "empty_column.home": "A hazai idővonala üres! Látogasd meg a {public} vagy használd a keresőt, hogy ismerj meg más felhasználókat.", - "empty_column.home.public_timeline": "publikus idővonal", - "empty_column.list": "A lista jelenleg üres. Mikor a listatagok új státuszt posztolnak itt meg fognak jelenni.", - "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.", - "empty_column.mutes": "You haven't muted any users yet.", - "empty_column.notifications": "Jelenleg nincsenek értesítései. Lépj kapcsolatba másokkal, hogy indítsd el a beszélgetést.", - "empty_column.public": "Jelenleg semmi nincs itt! Írj valamit publikusan vagy kövess más szervereken levő felhasználókat, hogy megtöltsd", - "follow_request.authorize": "Engedélyez", - "follow_request.reject": "Visszautasít", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", - "getting_started.documentation": "Documentation", + "empty_column.account_timeline": "Itt nincs tülkölés!", + "empty_column.account_unavailable": "A profil nem elérhető", + "empty_column.blocks": "Még senkit sem tiltottál le.", + "empty_column.community": "A helyi idővonal üres. Tülkölj egyet nyilvánosan, hogy elindítsd az eseményeket!", + "empty_column.direct": "Még nincs egy közvetlen üzeneted sem. Ha küldesz vagy kapsz egyet, itt fog megjelenni.", + "empty_column.domain_blocks": "Még nem rejtettél el egyetlen domaint sem.", + "empty_column.favourited_statuses": "Még nincs egy kedvenc tülköd sem. Ha kedvencnek jelölsz egyet, itt fog megjelenni.", + "empty_column.favourites": "Még senki sem jelölte ezt a tülköt kedvencként. Ha valaki mégis megteszi, itt fogjuk mutatni.", + "empty_column.follow_requests": "Még nincs egy követési kérésed sem. Ha kapsz egyet, itt fogjuk feltüntetni.", + "empty_column.hashtag": "Jelenleg nem található semmi ezzel a hashtaggel.", + "empty_column.home": "A saját idővonalad üres! Látogasd meg a {public} -at vagy használd a keresőt, hogy megismerj másokat.", + "empty_column.home.public_timeline": "nyilvános idővonal", + "empty_column.list": "A lista jelenleg üres. Ha a listatagok tülkölnek, itt fognak megjelenni.", + "empty_column.lists": "Még nem hoztál létre listát. Ha csinálsz egyet, itt látszik majd.", + "empty_column.mutes": "Még egy felhasználót sem némítottál le.", + "empty_column.notifications": "Jelenleg nincsenek értesítéseid. Lépj kapcsolatba másokkal, hogy elindítsd a beszélgetést.", + "empty_column.public": "Jelenleg itt nincs semmi! Írj valamit nyilvánosan vagy kövess más szervereken levő felhasználókat, hogy megtöltsd", + "follow_request.authorize": "Engedélyezés", + "follow_request.reject": "Visszautasítás", + "getting_started.developers": "Fejlesztőknek", + "getting_started.directory": "Profilok", + "getting_started.documentation": "Dokumentáció", "getting_started.heading": "Első lépések", - "getting_started.invite": "Invite people", - "getting_started.open_source_notice": "Mastodon egy nyílt forráskódú szoftver. Hozzájárulás vagy problémák jelentése a GitHub-on {github}.", - "getting_started.security": "Security", - "getting_started.terms": "Terms of service", - "hashtag.column_header.tag_mode.all": "and {additional}", - "hashtag.column_header.tag_mode.any": "or {additional}", - "hashtag.column_header.tag_mode.none": "without {additional}", - "hashtag.column_settings.select.no_options_message": "No suggestions found", - "hashtag.column_settings.select.placeholder": "Enter hashtags…", - "hashtag.column_settings.tag_mode.all": "All of these", - "hashtag.column_settings.tag_mode.any": "Any of these", - "hashtag.column_settings.tag_mode.none": "None of these", - "hashtag.column_settings.tag_toggle": "Include additional tags in this column", - "home.column_settings.basic": "Alap", - "home.column_settings.show_reblogs": "Ismétlések mutatása", + "getting_started.invite": "Mások meghívása", + "getting_started.open_source_notice": "A Mastodon nyílt forráskódú szoftver. Csatlakozhatsz a fejlesztéshez vagy jelenthetsz problémákat GitHub-on {github}.", + "getting_started.security": "Biztonság", + "getting_started.terms": "Felhasználási feltételek", + "hashtag.column_header.tag_mode.all": "és {additional}", + "hashtag.column_header.tag_mode.any": "vagy {additional}", + "hashtag.column_header.tag_mode.none": "nélküle {additional}", + "hashtag.column_settings.select.no_options_message": "Nincs javaslat", + "hashtag.column_settings.select.placeholder": "Addj meg hashtageket…", + "hashtag.column_settings.tag_mode.all": "Mindegyik", + "hashtag.column_settings.tag_mode.any": "Bármelyik", + "hashtag.column_settings.tag_mode.none": "Egyik sem", + "hashtag.column_settings.tag_toggle": "Új tagek felvétele ehhez az oszlophoz", + "home.column_settings.basic": "Alapértelmezések", + "home.column_settings.show_reblogs": "Megtolások mutatása", "home.column_settings.show_replies": "Válaszok mutatása", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", - "introduction.federation.action": "Next", - "introduction.federation.federated.headline": "Federated", - "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.", - "introduction.federation.home.headline": "Home", - "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!", - "introduction.federation.local.headline": "Local", - "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.", - "introduction.interactions.action": "Finish tutorial!", - "introduction.interactions.favourite.headline": "Favourite", - "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", - "introduction.interactions.reblog.headline": "Boost", - "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", - "introduction.interactions.reply.headline": "Reply", - "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", - "introduction.welcome.action": "Let's go!", - "introduction.welcome.headline": "First steps", - "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.", - "keyboard_shortcuts.back": "vissza navigálás", - "keyboard_shortcuts.blocked": "to open blocked users list", - "keyboard_shortcuts.boost": "ismétlés", - "keyboard_shortcuts.column": "összpontosítson egy státuszra az egyik oszlopban", - "keyboard_shortcuts.compose": "fókuszálja a szerkesztési szövegdobozt", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, one {# nap} other {# nap}}", + "intervals.full.hours": "{number, plural, one {# óra} other {# óra}}", + "intervals.full.minutes": "{number, plural, one {# perc} other {# perc}}", + "introduction.federation.action": "Következő", + "introduction.federation.federated.headline": "Föderációs", + "introduction.federation.federated.text": "A fediverzum más szervereiről származó nyilvános tülkök a föderációs idővonalon jelennek meg.", + "introduction.federation.home.headline": "Saját", + "introduction.federation.home.text": "A saját idővonaladon az általad követettek tülkjei jelennek meg. Bárkit követhetsz bármely szerveren.", + "introduction.federation.local.headline": "Helyi", + "introduction.federation.local.text": "A helyi idővonalon a veled közös szerveren lévő emberek nyilvános tülkjei jelennek meg.", + "introduction.interactions.action": "Oktatóanyag befejezése!", + "introduction.interactions.favourite.headline": "Kedvenc", + "introduction.interactions.favourite.text": "A kedvenc funkcióval elrakhatsz későbbre egy tülköt, illetve közölheted a szerzővel, hogy tetszett a megosztása.", + "introduction.interactions.reblog.headline": "Megtolás", + "introduction.interactions.reblog.text": "A saját követőiddel mások tülkjeit is megoszthatod úgy, hogy megtolod őket.", + "introduction.interactions.reply.headline": "Válasz", + "introduction.interactions.reply.text": "Saját vagy mások tülkjeire válaszolva egy beszélgetési láncot alakíthatsz ki.", + "introduction.welcome.action": "Csapjunk bele!", + "introduction.welcome.headline": "Első lépések", + "introduction.welcome.text": "Üdv a fediverzumban! Pár pillanat múlva már küldheted is üzeneteidet barátaidnak bármely szerveren. Ez a szerver {domain} viszont különleges. Ez tartja nyilván a profilod, szóval jegyezd meg a nevét.", + "keyboard_shortcuts.back": "visszafelé navigálás", + "keyboard_shortcuts.blocked": "letiltott felhasználók listájának megnyitása", + "keyboard_shortcuts.boost": "megtolás", + "keyboard_shortcuts.column": "fókuszálás egy tülkre az egyik oszlopban", + "keyboard_shortcuts.compose": "fókuszálás a szerkesztési szövegdobozra", "keyboard_shortcuts.description": "Leírás", - "keyboard_shortcuts.direct": "to open direct messages column", + "keyboard_shortcuts.direct": "közvetlen üzenetek megnyitása", "keyboard_shortcuts.down": "lefele navigálás a listában", - "keyboard_shortcuts.enter": "státusz megnyitása", - "keyboard_shortcuts.favourite": "kedvenccé tétel", - "keyboard_shortcuts.favourites": "to open favourites list", - "keyboard_shortcuts.federated": "to open federated timeline", - "keyboard_shortcuts.heading": "Billentyű rövidítések", - "keyboard_shortcuts.home": "to open home timeline", + "keyboard_shortcuts.enter": "tülk megnyitása", + "keyboard_shortcuts.favourite": "kedvencnek jelölés", + "keyboard_shortcuts.favourites": "kedvenc lista megnyitása", + "keyboard_shortcuts.federated": "föderációs idővonal megnyitása", + "keyboard_shortcuts.heading": "Billentyűparancsok", + "keyboard_shortcuts.home": "saját idővonal megnyitása", "keyboard_shortcuts.hotkey": "Gyorsbillentyű", "keyboard_shortcuts.legend": "jelmagyarázat megjelenítése", - "keyboard_shortcuts.local": "to open local timeline", - "keyboard_shortcuts.mention": "szerző megjelenítése", - "keyboard_shortcuts.muted": "to open muted users list", - "keyboard_shortcuts.my_profile": "to open your profile", - "keyboard_shortcuts.notifications": "to open notifications column", - "keyboard_shortcuts.pinned": "to open pinned toots list", - "keyboard_shortcuts.profile": "to open author's profile", - "keyboard_shortcuts.reply": "válaszolás", - "keyboard_shortcuts.requests": "to open follow requests list", - "keyboard_shortcuts.search": "kereső kiemelése", - "keyboard_shortcuts.start": "to open \"get started\" column", - "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW", - "keyboard_shortcuts.toot": "új tülk megkezdése", + "keyboard_shortcuts.local": "helyi idővonal megnyitása", + "keyboard_shortcuts.mention": "szerző megemlítése", + "keyboard_shortcuts.muted": "némított felhasználók listájának megnyitása", + "keyboard_shortcuts.my_profile": "profilod megnyitása", + "keyboard_shortcuts.notifications": "értesítések megnyitása", + "keyboard_shortcuts.pinned": "kitűzött tülkök listájának megnyitása", + "keyboard_shortcuts.profile": "szerző profiljának megnyitása", + "keyboard_shortcuts.reply": "válasz", + "keyboard_shortcuts.requests": "követési kérések listájának megnyitása", + "keyboard_shortcuts.search": "fókuszálás a keresőre", + "keyboard_shortcuts.start": "\"Első lépések\" megnyitása", + "keyboard_shortcuts.toggle_hidden": "tartalmi figyelmeztetéssel ellátott szöveg mutatása/elrejtése", + "keyboard_shortcuts.toggle_sensitivity": "média mutatása/elrejtése", + "keyboard_shortcuts.toot": "új tülk írása", "keyboard_shortcuts.unfocus": "tülk szerkesztés/keresés fókuszpontból való kivétele", - "keyboard_shortcuts.up": "fennebb helyezés a listában", + "keyboard_shortcuts.up": "felfelé mozdítás a listában", "lightbox.close": "Bezárás", "lightbox.next": "Következő", "lightbox.previous": "Előző", - "lightbox.view_context": "View context", + "lightbox.view_context": "Kontextus megtekintése", "lists.account.add": "Hozzáadás a listához", - "lists.account.remove": "Eltávolít a listából", + "lists.account.remove": "Eltávolítás a listából", "lists.delete": "Lista törlése", "lists.edit": "Lista szerkesztése", - "lists.edit.submit": "Change title", + "lists.edit.submit": "Cím megváltoztatása", "lists.new.create": "Lista hozzáadása", - "lists.new.title_placeholder": "Új lista cím", - "lists.search": "Keresés a követtett személyek között", + "lists.new.title_placeholder": "Új lista címe", + "lists.search": "Keresés a követett személyek között", "lists.subheading": "Listáid", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Betöltés...", - "media_gallery.toggle_visible": "Láthatóság váltása", + "media_gallery.toggle_visible": "Láthatóság állítása", "missing_indicator.label": "Nincs találat", - "missing_indicator.sublabel": "Ezen forrás nem található", - "mute_modal.hide_notifications": "Értesítések elrejtése ezen felhasználótól?", - "navigation_bar.apps": "Mobile apps", - "navigation_bar.blocks": "Tiltott felhasználók", + "missing_indicator.sublabel": "Ez az erőforrás nem található", + "mute_modal.hide_notifications": "Rejtsük el a felhasználótól származó értesítéseket?", + "navigation_bar.apps": "Mobil appok", + "navigation_bar.blocks": "Letiltott felhasználók", "navigation_bar.community_timeline": "Helyi idővonal", - "navigation_bar.compose": "Compose new toot", - "navigation_bar.direct": "Direct messages", - "navigation_bar.discover": "Discover", - "navigation_bar.domain_blocks": "Hidden domains", + "navigation_bar.compose": "Új tülk írása", + "navigation_bar.direct": "Közvetlen üzenetek", + "navigation_bar.discover": "Felfedezés", + "navigation_bar.domain_blocks": "Rejtett domainek", "navigation_bar.edit_profile": "Profil szerkesztése", "navigation_bar.favourites": "Kedvencek", - "navigation_bar.filters": "Muted words", - "navigation_bar.follow_requests": "Követési kérések", - "navigation_bar.info": "Ezen szerverről", + "navigation_bar.filters": "Némított szavak", + "navigation_bar.follow_requests": "Követési kérelmek", + "navigation_bar.follows_and_followers": "Követettek és követők", + "navigation_bar.info": "Erről a szerverről", "navigation_bar.keyboard_shortcuts": "Gyorsbillentyűk", "navigation_bar.lists": "Listák", "navigation_bar.logout": "Kijelentkezés", "navigation_bar.mutes": "Némított felhasználók", - "navigation_bar.personal": "Personal", + "navigation_bar.personal": "Személyes", "navigation_bar.pins": "Kitűzött tülkök", "navigation_bar.preferences": "Beállítások", - "navigation_bar.public_timeline": "Nyilvános időfolyam", - "navigation_bar.security": "Security", - "notification.favourite": "{name} kedvencnek jelölte az állapotod", + "navigation_bar.profile_directory": "Profilok", + "navigation_bar.public_timeline": "Föderációs idővonal", + "navigation_bar.security": "Biztonság", + "notification.favourite": "{name} kedvencnek jelölte egy tülködet", "notification.follow": "{name} követ téged", "notification.mention": "{name} megemlített", - "notification.poll": "A poll you have voted in has ended", - "notification.reblog": "{name} rebloggolta az állapotod", + "notification.poll": "Egy szavazás, melyben részt vettél, véget ért", + "notification.reblog": "{name} megtolta a tülködet", "notifications.clear": "Értesítések törlése", - "notifications.clear_confirmation": "Biztos benne, hogy véglegesen törölni akarja az összes értesítését?", - "notifications.column_settings.alert": "Asztali gépi értesítések", + "notifications.clear_confirmation": "Biztos, hogy véglegesen törölni akarod az összes értesítésed?", + "notifications.column_settings.alert": "Asztali értesítések", "notifications.column_settings.favourite": "Kedvencek:", - "notifications.column_settings.filter_bar.advanced": "Display all categories", - "notifications.column_settings.filter_bar.category": "Quick filter bar", - "notifications.column_settings.filter_bar.show": "Show", + "notifications.column_settings.filter_bar.advanced": "Minden kategória mutatása", + "notifications.column_settings.filter_bar.category": "Gyorskereső mező", + "notifications.column_settings.filter_bar.show": "Mutat", "notifications.column_settings.follow": "Új követők:", - "notifications.column_settings.mention": "Megemítéseim:", - "notifications.column_settings.poll": "Poll results:", + "notifications.column_settings.mention": "Megemlítéseid:", + "notifications.column_settings.poll": "Szavazás eredménye:", "notifications.column_settings.push": "Push értesítések", - "notifications.column_settings.reblog": "Rebloggolások:", + "notifications.column_settings.reblog": "Megtolások:", "notifications.column_settings.show": "Oszlopban mutatás", "notifications.column_settings.sound": "Hang lejátszása", - "notifications.filter.all": "All", - "notifications.filter.boosts": "Boosts", - "notifications.filter.favourites": "Favourites", - "notifications.filter.follows": "Follows", - "notifications.filter.mentions": "Mentions", - "notifications.filter.polls": "Poll results", - "notifications.group": "{count} notifications", - "poll.closed": "Closed", - "poll.refresh": "Refresh", - "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", - "poll.vote": "Vote", - "poll_button.add_poll": "Add a poll", - "poll_button.remove_poll": "Remove poll", - "privacy.change": "Státusz láthatóságának módosítása", - "privacy.direct.long": "Posztolás csak az említett felhasználóknak", - "privacy.direct.short": "Egyenesen", - "privacy.private.long": "Posztolás csak követőknek", + "notifications.filter.all": "Mind", + "notifications.filter.boosts": "Megtolások", + "notifications.filter.favourites": "Kedvencnek jelölések", + "notifications.filter.follows": "Követések", + "notifications.filter.mentions": "Megemlítések", + "notifications.filter.polls": "Szavazások eredményei", + "notifications.group": "{count} értesítés", + "poll.closed": "Lezárva", + "poll.refresh": "Frissítés", + "poll.total_votes": "{count, plural, one {# szavazat} other {# szavazat}}", + "poll.vote": "Szavazás", + "poll_button.add_poll": "Új szavazás", + "poll_button.remove_poll": "Szavazás törlése", + "privacy.change": "Tülk láthatóságának módosítása", + "privacy.direct.long": "Tülk csak az említett felhasználóknak", + "privacy.direct.short": "Közvetlen", + "privacy.private.long": "Tülk csak követőknek", "privacy.private.short": "Csak követőknek", - "privacy.public.long": "Posztolás a publikus idővonalakra", - "privacy.public.short": "Publikus", - "privacy.unlisted.long": "Do not show in public timelines", + "privacy.public.long": "Tülk a nyilvános idővonalra", + "privacy.public.short": "Nyilvános", + "privacy.unlisted.long": "Ne mutassuk nyilvános idővonalon", "privacy.unlisted.short": "Listázatlan", "regeneration_indicator.label": "Töltődik…", - "regeneration_indicator.sublabel": "Your home feed is being prepared!", - "relative_time.days": "{number}d", - "relative_time.hours": "{number}h", + "regeneration_indicator.sublabel": "A saját idővonalad épp készül!", + "relative_time.days": "{number}nap", + "relative_time.hours": "{number}ó", "relative_time.just_now": "most", - "relative_time.minutes": "{number}m", - "relative_time.seconds": "{number}s", + "relative_time.minutes": "{number}p", + "relative_time.seconds": "{number}mp", "reply_indicator.cancel": "Mégsem", - "report.forward": "Forward to {target}", - "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?", - "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:", - "report.placeholder": "További kommentek", - "report.submit": "Submit", - "report.target": "Reporting", + "report.forward": "Továbbítás neki {target}", + "report.forward_hint": "Ez a fiók egy másik szerverről van. Küldjünk oda is egy anonimizált bejelentést?", + "report.hint": "A bejelentést a szervered moderátorainak küldjük el. Megmagyarázhatod, miért jelented az alábbi problémát:", + "report.placeholder": "További megjegyzések", + "report.submit": "Küldés", + "report.target": "{target} jelentése", "search.placeholder": "Keresés", - "search_popout.search_format": "Fejlett keresés", - "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", + "search_popout.search_format": "Haladó keresés", + "search_popout.tips.full_text": "Egyszerű szöveg. Illeszkedő, általad írt tülköket, kedvencnek jelöléseket, megtolást, megemlítést, felhasználói nevet, megjelenített nevet, hashtageket ad majd vissza.", "search_popout.tips.hashtag": "hashtag", - "search_popout.tips.status": "status", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", + "search_popout.tips.status": "tülk", + "search_popout.tips.text": "Egyszerű szöveg. Illeszkedő megjelenített nevet, felhasználói nevet, hashtageket ad majd vissza", "search_popout.tips.user": "felhasználó", - "search_results.accounts": "People", - "search_results.hashtags": "Hashtags", - "search_results.statuses": "Toots", - "search_results.total": "{count, number} {count, plural, one {result} other {results}}", - "status.admin_account": "Open moderation interface for @{name}", - "status.admin_status": "Open this status in the moderation interface", - "status.block": "Block @{name}", - "status.cancel_reblog_private": "Unboost", - "status.cannot_reblog": "Ezen státusz nem rebloggolható", - "status.copy": "Copy link to status", + "search_results.accounts": "Emberek", + "search_results.hashtags": "Hashtagek", + "search_results.statuses": "Tülkök", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", + "search_results.total": "{count, number} {count, plural, one {találat} other {találat}}", + "status.admin_account": "Moderáció megnyitása @{name} felhasználóhoz", + "status.admin_status": "Tülk megnyitása moderációra", + "status.block": "@{name} letiltása", + "status.cancel_reblog_private": "Megtolás törlése", + "status.cannot_reblog": "Ez a tülk nem tolható meg", + "status.copy": "Link másolása tülkbe", "status.delete": "Törlés", - "status.detailed_status": "Detailed conversation view", - "status.direct": "Direct message @{name}", - "status.embed": "Beágyaz", + "status.detailed_status": "Részletes beszélgetési nézet", + "status.direct": "Közvetlen üzenet @{name} számára", + "status.embed": "Beágyazás", "status.favourite": "Kedvenc", - "status.filtered": "Filtered", + "status.filtered": "Megszűrt", "status.load_more": "Többet", "status.media_hidden": "Média elrejtve", - "status.mention": "Említés", + "status.mention": "@{name} említése", "status.more": "Többet", "status.mute": "@{name} némítása", "status.mute_conversation": "Beszélgetés némítása", - "status.open": "Státusz kinagyítása", + "status.open": "Tülk kibontása", "status.pin": "Kitűzés a profilra", - "status.pinned": "Pinned toot", - "status.read_more": "Read more", - "status.reblog": "Reblog", - "status.reblog_private": "Boost to original audience", - "status.reblogged_by": "{name} reblogolta", - "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", - "status.redraft": "Delete & re-draft", + "status.pinned": "Kitűzött tülk", + "status.read_more": "Bővebben", + "status.reblog": "Megtolás", + "status.reblog_private": "Megtolás az eredeti közönségnek", + "status.reblogged_by": "{name} megtolta", + "status.reblogs.empty": "Senki sem tolta még meg ezt a tülköt. Ha valaki megteszi, itt fog megjelenni.", + "status.redraft": "Törlés és újraírás", "status.reply": "Válasz", - "status.replyAll": "Válaszolj a beszélgetésre", - "status.report": "Report @{name}", - "status.sensitive_warning": "Érzékeny tartalom", + "status.replyAll": "Válasz a beszélgetésre", + "status.report": "@{name} jelentése", + "status.sensitive_warning": "Szenzitív tartalom", "status.share": "Megosztás", - "status.show_less": "Kevesebb", - "status.show_less_all": "Show less for all", + "status.show_less": "Kevesebbet", + "status.show_less_all": "Kevesebbet mindenhol", "status.show_more": "Többet", - "status.show_more_all": "Show more for all", - "status.show_thread": "Show thread", - "status.unmute_conversation": "Beszélgetés némításának elvonása", - "status.unpin": "Kitűzés eltávolítása a profilról", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", - "tabs_bar.federated_timeline": "Federált", - "tabs_bar.home": "Kezdőlap", - "tabs_bar.local_timeline": "Local", + "status.show_more_all": "Többet mindenhol", + "status.show_thread": "Szál mutatása", + "status.unmute_conversation": "Beszélgetés némításának kikapcsolása", + "status.unpin": "Kitűzés eltávolítása a profilodról", + "suggestions.dismiss": "Javaslat elvetése", + "suggestions.header": "Esetleg érdekelhet…", + "tabs_bar.federated_timeline": "Föderációs", + "tabs_bar.home": "Saját", + "tabs_bar.local_timeline": "Helyi", "tabs_bar.notifications": "Értesítések", - "tabs_bar.search": "Search", - "time_remaining.days": "{number, plural, one {# day} other {# days}} left", - "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", - "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", - "time_remaining.moments": "Moments remaining", - "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left", - "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking", - "ui.beforeunload": "A piszkozata el fog vesztődni ha elhagyja Mastodon-t.", - "upload_area.title": "Húzza ide a feltöltéshez", - "upload_button.label": "Média hozzáadása", - "upload_error.limit": "File upload limit exceeded.", - "upload_error.poll": "File upload not allowed with polls.", - "upload_form.description": "Describe for the visually impaired", - "upload_form.focus": "Crop", + "tabs_bar.search": "Keresés", + "time_remaining.days": "{number, plural, one {# nap} other {# nap}} van hátra", + "time_remaining.hours": "{number, plural, one {# óra} other {# óra}} van hátra", + "time_remaining.minutes": "{number, plural, one {# perc} other {# perc}} van hátra", + "time_remaining.moments": "Pillanatok vannak hátra", + "time_remaining.seconds": "{number, plural, one {# másodperc} other {# másodperc}} van hátra", + "trends.count_by_accounts": "{count} {rawCount, plural, one {résztvevő} other {résztvevő}} beszélget", + "ui.beforeunload": "A piszkozatod el fog veszni, ha elhagyod a Mastodon-t.", + "upload_area.title": "Húzd ide a feltöltéshez", + "upload_button.label": "Média hozzáadása (JPEG, PNG, GIF, WebM, MP4, MOV)", + "upload_error.limit": "Túllépted a fájl feltöltési limitet.", + "upload_error.poll": "Szavazásnál nem lehet fájlt feltölteni.", + "upload_form.description": "Leírás látáskorlátozottak számára", + "upload_form.focus": "Előnézet megváltoztatása", "upload_form.undo": "Mégsem", - "upload_progress.label": "Uploading...", - "video.close": "Close video", - "video.exit_fullscreen": "Exit full screen", - "video.expand": "Expand video", - "video.fullscreen": "Full screen", - "video.hide": "Hide video", - "video.mute": "Mute sound", + "upload_progress.label": "Feltöltés...", + "video.close": "Videó bezárása", + "video.exit_fullscreen": "Kilépés teljes képernyőből", + "video.expand": "Videó nagyítása", + "video.fullscreen": "Teljes képernyő", + "video.hide": "Videó elrejtése", + "video.mute": "Hang némitása", "video.pause": "Szünet", "video.play": "Lejátszás", - "video.unmute": "Hang kinémítása" + "video.unmute": "Hang némitásának vége" } diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json index e2e0aa881..afe9cfbc0 100644 --- a/app/javascript/mastodon/locales/hy.json +++ b/app/javascript/mastodon/locales/hy.json @@ -64,7 +64,7 @@ "column_header.show_settings": "Ցուցադրել կարգավորումները", "column_header.unpin": "Հանել", "column_subheading.settings": "Կարգավորումներ", - "community.column_settings.media_only": "Media Only", + "community.column_settings.media_only": "Media only", "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", "compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.hashtag_warning": "Այս թութը չի հաշվառվի որեւէ պիտակի տակ, քանզի այն ծածուկ է։ Միայն հրապարակային թթերը հնարավոր է որոնել պիտակներով։", @@ -156,6 +156,7 @@ "home.column_settings.basic": "Հիմնական", "home.column_settings.show_reblogs": "Ցուցադրել տարածածները", "home.column_settings.show_replies": "Ցուցադրել պատասխանները", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Նոր ցանկի վերնագիր", "lists.search": "Փնտրել քո հետեւած մարդկանց մեջ", "lists.subheading": "Քո ցանկերը", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Բեռնվում է…", "media_gallery.toggle_visible": "Ցուցադրել/թաքցնել", "missing_indicator.label": "Չգտնվեց", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {արդյունք} other {արդյունք}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json index 5b15327ed..7232f532b 100644 --- a/app/javascript/mastodon/locales/id.json +++ b/app/javascript/mastodon/locales/id.json @@ -1,5 +1,5 @@ { - "account.add_or_remove_from_list": "Add or Remove from lists", + "account.add_or_remove_from_list": "Tambah atau Hapus dari daftar", "account.badges.bot": "Bot", "account.block": "Blokir @{name}", "account.block_domain": "Sembunyikan segalanya dari {domain}", @@ -7,23 +7,23 @@ "account.direct": "Direct Message @{name}", "account.domain_blocked": "Domain disembunyikan", "account.edit_profile": "Ubah profil", - "account.endorse": "Feature on profile", + "account.endorse": "Tampilkan di profil", "account.follow": "Ikuti", "account.followers": "Pengikut", - "account.followers.empty": "No one follows this user yet.", + "account.followers.empty": "Tidak ada satupun yang mengkuti pengguna ini saat ini.", "account.follows": "Mengikuti", - "account.follows.empty": "This user doesn't follow anyone yet.", + "account.follows.empty": "Pengguna ini belum mengikuti siapapun.", "account.follows_you": "Mengikuti anda", "account.hide_reblogs": "Sembunyikan boosts dari @{name}", - "account.link_verified_on": "Ownership of this link was checked on {date}", - "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.", + "account.link_verified_on": "Kepemilikan tautan ini telah dicek pada {date}", + "account.locked_info": "Status privasi akun ini disetel untuk dikunci. Pemilik secara manual meninjau siapa yang dapat mengikuti mereka.", "account.media": "Media", "account.mention": "Balasan @{name}", "account.moved_to": "{name} telah pindah ke:", "account.mute": "Bisukan @{name}", "account.mute_notifications": "Sembunyikan notifikasi dari @{name}", "account.muted": "Dibisukan", - "account.posts": "Toots", + "account.posts": "Toot", "account.posts_with_replies": "Postingan dengan balasan", "account.report": "Laporkan @{name}", "account.requested": "Menunggu persetujuan. Klik untuk membatalkan permintaan", @@ -31,23 +31,23 @@ "account.show_reblogs": "Tampilkan boost dari @{name}", "account.unblock": "Hapus blokir @{name}", "account.unblock_domain": "Tampilkan {domain}", - "account.unendorse": "Don't feature on profile", + "account.unendorse": "Jangan tampilkan di profil", "account.unfollow": "Berhenti mengikuti", "account.unmute": "Berhenti membisukan @{name}", "account.unmute_notifications": "Munculkan notifikasi dari @{name}", - "alert.unexpected.message": "An unexpected error occurred.", + "alert.unexpected.message": "Terjadi kesalahan yang tidak terduga.", "alert.unexpected.title": "Oops!", "boost_modal.combo": "Anda dapat menekan {combo} untuk melewati ini", "bundle_column_error.body": "Kesalahan terjadi saat memuat komponen ini.", "bundle_column_error.retry": "Coba lagi", - "bundle_column_error.title": "Network error", + "bundle_column_error.title": "Kesalahan jaringan", "bundle_modal_error.close": "Tutup", "bundle_modal_error.message": "Kesalahan terjadi saat memuat komponen ini.", "bundle_modal_error.retry": "Coba lagi", "column.blocks": "Pengguna diblokir", "column.community": "Linimasa Lokal", - "column.direct": "Direct messages", - "column.domain_blocks": "Hidden domains", + "column.direct": "Pesan langsung", + "column.domain_blocks": "Topik tersembunyi", "column.favourites": "Favorit", "column.follow_requests": "Permintaan mengikuti", "column.home": "Beranda", @@ -64,41 +64,41 @@ "column_header.show_settings": "Tampilkan pengaturan", "column_header.unpin": "Lepaskan", "column_subheading.settings": "Pengaturan", - "community.column_settings.media_only": "Media Only", + "community.column_settings.media_only": "Hanya media", "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", - "compose_form.direct_message_warning_learn_more": "Learn more", + "compose_form.direct_message_warning_learn_more": "Pelajari selengkapnya", "compose_form.hashtag_warning": "Toot ini tidak akan ada dalam daftar tagar manapun karena telah di set sebagai tidak terdaftar. Hanya postingan publik yang bisa dicari dengan tagar.", "compose_form.lock_disclaimer": "Akun anda tidak {locked}. Semua orang dapat mengikuti anda untuk melihat postingan khusus untuk pengikut anda.", "compose_form.lock_disclaimer.lock": "terkunci", "compose_form.placeholder": "Apa yang ada di pikiran anda?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.poll.add_option": "Tambahkan pilihan", + "compose_form.poll.duration": "Durasi jajak pendapat", + "compose_form.poll.option_placeholder": "Pilihan {number}", + "compose_form.poll.remove_option": "Hapus opsi ini", "compose_form.publish": "Toot", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "Tandai sebagai media sensitif", "compose_form.sensitive.marked": "Sumber ini telah ditandai sebagai sumber sensitif.", "compose_form.sensitive.unmarked": "Sumber ini tidak ditandai sebagai sumber sensitif", "compose_form.spoiler.marked": "Teks disembunyikan dibalik peringatan", "compose_form.spoiler.unmarked": "Teks tidak tersembunyi", "compose_form.spoiler_placeholder": "Peringatan konten", "confirmation_modal.cancel": "Batal", - "confirmations.block.block_and_report": "Block & Report", + "confirmations.block.block_and_report": "Blokir & Laporkan", "confirmations.block.confirm": "Blokir", "confirmations.block.message": "Apa anda yakin ingin memblokir {name}?", "confirmations.delete.confirm": "Hapus", "confirmations.delete.message": "Apa anda yakin untuk menghapus status ini?", - "confirmations.delete_list.confirm": "Delete", + "confirmations.delete_list.confirm": "Hapus", "confirmations.delete_list.message": "Apakah anda yakin untuk menghapus daftar ini secara permanen?", "confirmations.domain_block.confirm": "Sembunyikan keseluruhan domain", "confirmations.domain_block.message": "Apakah anda benar benar yakin untuk memblokir keseluruhan {domain}? Dalam kasus tertentu beberapa pemblokiran atau penyembunyian lebih baik.", "confirmations.mute.confirm": "Bisukan", "confirmations.mute.message": "Apa anda yakin ingin membisukan {name}?", - "confirmations.redraft.confirm": "Delete & redraft", + "confirmations.redraft.confirm": "Hapus dan konsep ulang", "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.", - "confirmations.reply.confirm": "Reply", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.reply.confirm": "Balas", + "confirmations.reply.message": "Membalas sekarang akan menimpa pesan yang sedang Anda buat. Anda yakin ingin melanjutkan?", "confirmations.unfollow.confirm": "Berhenti mengikuti", "confirmations.unfollow.message": "Apakah anda ingin berhenti mengikuti {name}?", "embed.instructions": "Sematkan status ini di website anda dengan menyalin kode di bawah ini.", @@ -117,38 +117,38 @@ "emoji_button.search_results": "Hasil pencarian", "emoji_button.symbols": "Simbol", "emoji_button.travel": "Tempat Wisata", - "empty_column.account_timeline": "No toots here!", - "empty_column.account_unavailable": "Profile unavailable", - "empty_column.blocks": "You haven't blocked any users yet.", + "empty_column.account_timeline": "Tidak ada toot di sini!", + "empty_column.account_unavailable": "Profil tidak tersedia", + "empty_column.blocks": "Anda belum memblokir siapapun.", "empty_column.community": "Linimasa lokal masih kosong. Tulis sesuatu secara publik dan buat roda berputar!", - "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", - "empty_column.domain_blocks": "There are no hidden domains yet.", - "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", - "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", - "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", + "empty_column.direct": "Anda belum memiliki pesan langsung. Ketika Anda mengirim atau menerimanya, maka akan muncul di sini.", + "empty_column.domain_blocks": "Tidak ada topik tersembunyi.", + "empty_column.favourited_statuses": "Anda belum memiliki toot favorit. Ketika Anda mengirim atau menerimanya, maka akan muncul di sini.", + "empty_column.favourites": "Tidak ada seorangpun yang memfavoritkan toot ini. Ketika seseorang melakukannya, maka akan muncul disini.", + "empty_column.follow_requests": "Anda belum memiliki permintaan mengikuti. Ketika Anda menerimanya, maka akan muncul disini.", "empty_column.hashtag": "Tidak ada apapun dalam hashtag ini.", "empty_column.home": "Linimasa anda kosong! Kunjungi {public} atau gunakan pencarian untuk memulai dan bertemu pengguna lain.", "empty_column.home.public_timeline": "linimasa publik", "empty_column.list": "Tidak ada postingan di list ini. Ketika anggota dari list ini memposting status baru, status tersebut akan tampil disini.", - "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.", - "empty_column.mutes": "You haven't muted any users yet.", + "empty_column.lists": "Anda belum memiliki daftar. Ketika Anda membuatnya, maka akan muncul disini.", + "empty_column.mutes": "Anda belum membisukan siapapun.", "empty_column.notifications": "Anda tidak memiliki notifikasi apapun. Berinteraksi dengan orang lain untuk memulai percakapan.", "empty_column.public": "Tidak ada apapun disini! Tulis sesuatu, atau ikuti pengguna lain dari server lain untuk mengisi ini", "follow_request.authorize": "Izinkan", "follow_request.reject": "Tolak", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", - "getting_started.documentation": "Documentation", + "getting_started.developers": "Pengembang", + "getting_started.directory": "Direktori profil", + "getting_started.documentation": "Dokumentasi", "getting_started.heading": "Mulai", - "getting_started.invite": "Invite people", + "getting_started.invite": "Undang orang", "getting_started.open_source_notice": "Mastodon adalah perangkat lunak yang bersifat terbuka. Anda dapat berkontribusi atau melaporkan permasalahan/bug di Github {github}.", - "getting_started.security": "Security", - "getting_started.terms": "Terms of service", - "hashtag.column_header.tag_mode.all": "and {additional}", - "hashtag.column_header.tag_mode.any": "or {additional}", - "hashtag.column_header.tag_mode.none": "without {additional}", - "hashtag.column_settings.select.no_options_message": "No suggestions found", - "hashtag.column_settings.select.placeholder": "Enter hashtags…", + "getting_started.security": "Keamanan", + "getting_started.terms": "Ketentuan layanan", + "hashtag.column_header.tag_mode.all": "dan {additional}", + "hashtag.column_header.tag_mode.any": "atau {additional}", + "hashtag.column_header.tag_mode.none": "tanpa {additional}", + "hashtag.column_settings.select.no_options_message": "Tidak ada saran yang ditemukan", + "hashtag.column_settings.select.placeholder": "Masukkan tagar…", "hashtag.column_settings.tag_mode.all": "All of these", "hashtag.column_settings.tag_mode.any": "Any of these", "hashtag.column_settings.tag_mode.none": "None of these", @@ -156,6 +156,7 @@ "home.column_settings.basic": "Dasar", "home.column_settings.show_reblogs": "Tampilkan boost", "home.column_settings.show_replies": "Tampilkan balasan", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "New list title", "lists.search": "Search among people you follow", "lists.subheading": "Your lists", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Tunggu sebentar...", "media_gallery.toggle_visible": "Tampil/Sembunyikan", "missing_indicator.label": "Tidak ditemukan", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {hasil} other {hasil}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json index 61c65c12d..0eba158e2 100644 --- a/app/javascript/mastodon/locales/io.json +++ b/app/javascript/mastodon/locales/io.json @@ -64,7 +64,7 @@ "column_header.show_settings": "Show settings", "column_header.unpin": "Unpin", "column_subheading.settings": "Settings", - "community.column_settings.media_only": "Media Only", + "community.column_settings.media_only": "Media only", "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", "compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", @@ -156,6 +156,7 @@ "home.column_settings.basic": "Simpla", "home.column_settings.show_reblogs": "Montrar repeti", "home.column_settings.show_replies": "Montrar respondi", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "New list title", "lists.search": "Search among people you follow", "lists.subheading": "Your lists", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Kargante...", "media_gallery.toggle_visible": "Chanjar videbleso", "missing_indicator.label": "Ne trovita", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {rezulto} other {rezulti}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index ebdc42102..7925cef8c 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -4,7 +4,7 @@ "account.block": "Blocca @{name}", "account.block_domain": "Nascondi tutto da {domain}", "account.blocked": "Bloccato", - "account.direct": "Invia messaggio diretto a @{name}", + "account.direct": "Invia messaggio privato a @{name}", "account.domain_blocked": "Dominio nascosto", "account.edit_profile": "Modifica profilo", "account.endorse": "Metti in evidenza sul profilo", @@ -40,7 +40,7 @@ "boost_modal.combo": "Puoi premere {combo} per saltare questo passaggio la prossima volta", "bundle_column_error.body": "E' avvenuto un errore durante il caricamento di questo componente.", "bundle_column_error.retry": "Riprova", - "bundle_column_error.title": "Network error", + "bundle_column_error.title": "Errore di rete", "bundle_modal_error.close": "Chiudi", "bundle_modal_error.message": "C'è stato un errore mentre questo componente veniva caricato.", "bundle_modal_error.retry": "Riprova", @@ -71,20 +71,20 @@ "compose_form.lock_disclaimer": "Il tuo account non è {bloccato}. Chiunque può decidere di seguirti per vedere i tuoi post per soli seguaci.", "compose_form.lock_disclaimer.lock": "bloccato", "compose_form.placeholder": "A cosa stai pensando?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.poll.add_option": "Aggiungi una scelta", + "compose_form.poll.duration": "Durata del sondaggio", + "compose_form.poll.option_placeholder": "Scelta {number}", + "compose_form.poll.remove_option": "Rimuovi questa scelta", "compose_form.publish": "Toot", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "Segna media come sensibile", "compose_form.sensitive.marked": "Questo media è contrassegnato come sensibile", "compose_form.sensitive.unmarked": "Questo media non è contrassegnato come sensibile", "compose_form.spoiler.marked": "Il testo è nascosto dall'avviso", "compose_form.spoiler.unmarked": "Il testo non è nascosto", "compose_form.spoiler_placeholder": "Content warning", "confirmation_modal.cancel": "Annulla", - "confirmations.block.block_and_report": "Block & Report", + "confirmations.block.block_and_report": "Blocca & Segnala", "confirmations.block.confirm": "Blocca", "confirmations.block.message": "Sei sicuro di voler bloccare {name}?", "confirmations.delete.confirm": "Cancella", @@ -118,10 +118,10 @@ "emoji_button.symbols": "Simboli", "emoji_button.travel": "Viaggi e luoghi", "empty_column.account_timeline": "Non ci sono toot qui!", - "empty_column.account_unavailable": "Profile unavailable", + "empty_column.account_unavailable": "Profilo non disponibile", "empty_column.blocks": "Non hai ancora bloccato nessun utente.", "empty_column.community": "La timeline locale è vuota. Condividi qualcosa pubblicamente per dare inizio alla festa!", - "empty_column.direct": "Non hai ancora nessun messaggio diretto. Quando ne manderai o riceverai qualcuno, apparirà qui.", + "empty_column.direct": "Non hai ancora nessun messaggio privato. Quando ne manderai o riceverai qualcuno, apparirà qui.", "empty_column.domain_blocks": "Non vi sono domini nascosti.", "empty_column.favourited_statuses": "Non hai ancora segnato nessun toot come apprezzato. Quando lo farai, comparirà qui.", "empty_column.favourites": "Nessuno ha ancora segnato questo toot come apprezzato. Quando qualcuno lo farà, apparirà qui.", @@ -156,15 +156,16 @@ "home.column_settings.basic": "Semplice", "home.column_settings.show_reblogs": "Mostra post condivisi", "home.column_settings.show_replies": "Mostra risposte", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, one {# giorno} other {# giorni}}", + "intervals.full.hours": "{number, plural, one {# ora} other {# ore}}", + "intervals.full.minutes": "{number, plural, one {# minuto} other {# minuti}}", "introduction.federation.action": "Avanti", - "introduction.federation.federated.headline": "Federated", + "introduction.federation.federated.headline": "Federato", "introduction.federation.federated.text": "I post pubblici provenienti da altri server del fediverse saranno mostrati nella timeline federata.", "introduction.federation.home.headline": "Home", "introduction.federation.home.text": "I post scritti da persone che segui saranno mostrati nella timeline home. Puoi seguire chiunque su qualunque server!", - "introduction.federation.local.headline": "Local", + "introduction.federation.local.headline": "Locale", "introduction.federation.local.text": "I post pubblici scritti da persone sul tuo stesso server saranno mostrati nella timeline locale.", "introduction.interactions.action": "Finisci il tutorial!", "introduction.interactions.favourite.headline": "Apprezza", @@ -204,22 +205,24 @@ "keyboard_shortcuts.search": "per spostare il focus sulla ricerca", "keyboard_shortcuts.start": "per aprire la colonna \"Come iniziare\"", "keyboard_shortcuts.toggle_hidden": "per mostrare/nascondere il testo dei CW", + "keyboard_shortcuts.toggle_sensitivity": "mostrare/nascondere media", "keyboard_shortcuts.toot": "per iniziare a scrivere un toot completamente nuovo", "keyboard_shortcuts.unfocus": "per uscire dall'area di composizione o dalla ricerca", "keyboard_shortcuts.up": "per spostarsi in alto nella lista", "lightbox.close": "Chiudi", "lightbox.next": "Successivo", "lightbox.previous": "Precedente", - "lightbox.view_context": "View context", + "lightbox.view_context": "Mostra contesto", "lists.account.add": "Aggiungi alla lista", "lists.account.remove": "Togli dalla lista", - "lists.delete": "Delete list", + "lists.delete": "Elimina lista", "lists.edit": "Modifica lista", "lists.edit.submit": "Cambia titolo", "lists.new.create": "Aggiungi lista", "lists.new.title_placeholder": "Titolo della nuova lista", "lists.search": "Cerca tra le persone che segui", "lists.subheading": "Le tue liste", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Caricamento...", "media_gallery.toggle_visible": "Imposta visibilità", "missing_indicator.label": "Non trovato", @@ -236,20 +239,22 @@ "navigation_bar.favourites": "Apprezzati", "navigation_bar.filters": "Parole silenziate", "navigation_bar.follow_requests": "Richieste di amicizia", + "navigation_bar.follows_and_followers": "Follows and followers", "navigation_bar.info": "Informazioni su questo server", "navigation_bar.keyboard_shortcuts": "Tasti di scelta rapida", "navigation_bar.lists": "Liste", "navigation_bar.logout": "Esci", "navigation_bar.mutes": "Utenti silenziati", - "navigation_bar.personal": "Personal", + "navigation_bar.personal": "Personale", "navigation_bar.pins": "Toot fissati in cima", "navigation_bar.preferences": "Impostazioni", + "navigation_bar.profile_directory": "Directory dei profili", "navigation_bar.public_timeline": "Timeline federata", "navigation_bar.security": "Sicurezza", "notification.favourite": "{name} ha apprezzato il tuo post", "notification.follow": "{name} ha iniziato a seguirti", "notification.mention": "{name} ti ha menzionato", - "notification.poll": "A poll you have voted in has ended", + "notification.poll": "Un sondaggio in cui hai votato è terminato", "notification.reblog": "{name} ha condiviso il tuo post", "notifications.clear": "Cancella notifiche", "notifications.clear_confirmation": "Vuoi davvero cancellare tutte le notifiche?", @@ -260,7 +265,7 @@ "notifications.column_settings.filter_bar.show": "Mostra", "notifications.column_settings.follow": "Nuovi seguaci:", "notifications.column_settings.mention": "Menzioni:", - "notifications.column_settings.poll": "Poll results:", + "notifications.column_settings.poll": "Risultati del sondaggio:", "notifications.column_settings.push": "Notifiche push", "notifications.column_settings.reblog": "Post condivisi:", "notifications.column_settings.show": "Mostra in colonna", @@ -270,17 +275,17 @@ "notifications.filter.favourites": "Apprezzati", "notifications.filter.follows": "Seguaci", "notifications.filter.mentions": "Menzioni", - "notifications.filter.polls": "Poll results", + "notifications.filter.polls": "Risultati del sondaggio", "notifications.group": "{count} notifiche", "poll.closed": "Chiuso", "poll.refresh": "Aggiorna", "poll.total_votes": "{count, plural, one {# voto} other {# voti}}", "poll.vote": "Vota", - "poll_button.add_poll": "Add a poll", - "poll_button.remove_poll": "Remove poll", + "poll_button.add_poll": "Aggiungi un sondaggio", + "poll_button.remove_poll": "Rimuovi sondaggio", "privacy.change": "Modifica privacy del post", "privacy.direct.long": "Invia solo a utenti menzionati", - "privacy.direct.short": "Diretto", + "privacy.direct.short": "Diretto in privato", "privacy.private.long": "Invia solo ai seguaci", "privacy.private.short": "Privato", "privacy.public.long": "Invia alla timeline pubblica", @@ -289,8 +294,8 @@ "privacy.unlisted.short": "Non elencato", "regeneration_indicator.label": "Caricamento in corso…", "regeneration_indicator.sublabel": "Stiamo preparando il tuo home feed!", - "relative_time.days": "{number}d", - "relative_time.hours": "{number}h", + "relative_time.days": "{number}g", + "relative_time.hours": "{number}o", "relative_time.just_now": "ora", "relative_time.minutes": "{number}m", "relative_time.seconds": "{number}s", @@ -304,13 +309,14 @@ "search.placeholder": "Cerca", "search_popout.search_format": "Formato di ricerca avanzato", "search_popout.tips.full_text": "Testo semplice per trovare gli status che hai scritto, segnato come apprezzati, condiviso o in cui sei stato citato, e inoltre i nomi utente, nomi visualizzati e hashtag che lo contengono.", - "search_popout.tips.hashtag": "hashtag", - "search_popout.tips.status": "status", + "search_popout.tips.hashtag": "etichetta", + "search_popout.tips.status": "stato", "search_popout.tips.text": "Testo semplice per trovare nomi visualizzati, nomi utente e hashtag che lo contengono", "search_popout.tips.user": "utente", "search_results.accounts": "Gente", "search_results.hashtags": "Hashtag", "search_results.statuses": "Toot", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count} {count, plural, one {risultato} other {risultati}}", "status.admin_account": "Apri interfaccia di moderazione per @{name}", "status.admin_status": "Apri questo status nell'interfaccia di moderazione", @@ -320,7 +326,7 @@ "status.copy": "Copia link allo status", "status.delete": "Elimina", "status.detailed_status": "Vista conversazione dettagliata", - "status.direct": "Messaggio diretto @{name}", + "status.direct": "Messaggio privato @{name}", "status.embed": "Incorpora", "status.favourite": "Apprezzato", "status.filtered": "Filtrato", @@ -368,7 +374,7 @@ "upload_area.title": "Trascina per caricare", "upload_button.label": "Aggiungi file multimediale", "upload_error.limit": "Limite al caricamento di file superato.", - "upload_error.poll": "File upload not allowed with polls.", + "upload_error.poll": "Caricamento file non consentito nei sondaggi.", "upload_form.description": "Descrizione per utenti con disabilità visive", "upload_form.focus": "Modifica anteprima", "upload_form.undo": "Cancella", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index fb4a814c8..87d565c76 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -160,6 +160,7 @@ "home.column_settings.basic": "基本設定", "home.column_settings.show_reblogs": "ブースト表示", "home.column_settings.show_replies": "返信表示", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number}日", "intervals.full.hours": "{number}時間", "intervals.full.minutes": "{number}分", @@ -225,6 +226,7 @@ "lists.new.title_placeholder": "新規リスト名", "lists.search": "フォローしている人の中から検索", "lists.subheading": "あなたのリスト", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "読み込み中...", "media_gallery.toggle_visible": "表示切り替え", "missing_indicator.label": "見つかりません", @@ -318,6 +320,7 @@ "search_results.accounts": "人々", "search_results.hashtags": "ハッシュタグ", "search_results.statuses": "トゥート", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number}件の結果", "status.admin_account": "@{name} のモデレーション画面を開く", "status.admin_status": "このトゥートをモデレーション画面で開く", diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json index 237c11a66..781d84319 100644 --- a/app/javascript/mastodon/locales/ka.json +++ b/app/javascript/mastodon/locales/ka.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "ძირითადი", "home.column_settings.show_reblogs": "ბუსტების ჩვენება", "home.column_settings.show_replies": "პასუხების ჩვენება", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "ახალი სიის სათაური", "lists.search": "ძებნა ადამიანებს შორის რომელთაც მიჰყვებით", "lists.subheading": "თქვენი სიები", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "იტვირთება...", "media_gallery.toggle_visible": "ხილვადობის ჩართვა", "missing_indicator.label": "არაა ნაპოვნი", @@ -311,6 +313,7 @@ "search_results.accounts": "ხალხი", "search_results.hashtags": "ჰეშტეგები", "search_results.statuses": "ტუტები", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json index bae8dd121..40e075b1a 100644 --- a/app/javascript/mastodon/locales/kk.json +++ b/app/javascript/mastodon/locales/kk.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Негізгі", "home.column_settings.show_reblogs": "Бөлісулерді көрсету", "home.column_settings.show_replies": "Жауаптарды көрсету", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# күн} other {# күн}}", "intervals.full.hours": "{number, plural, one {# сағат} other {# сағат}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Жаңа тізім аты", "lists.search": "Сіз іздеген адамдар арасында іздеу", "lists.subheading": "Тізімдеріңіз", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Жүктеу...", "media_gallery.toggle_visible": "Көрінуді қосу", "missing_indicator.label": "Табылмады", @@ -311,6 +313,7 @@ "search_results.accounts": "Адамдар", "search_results.hashtags": "Хэштегтер", "search_results.statuses": "Жазбалар", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "@{name} үшін модерация интерфейсін аш", "status.admin_status": "Бұл жазбаны модерация интерфейсінде аш", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index bd7b9764d..d27a9d40c 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "기본 설정", "home.column_settings.show_reblogs": "부스트 표시", "home.column_settings.show_replies": "답글 표시", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number} 일", "intervals.full.hours": "{number} 시간", "intervals.full.minutes": "{number} 분", @@ -221,6 +222,7 @@ "lists.new.title_placeholder": "새 리스트의 이름", "lists.search": "팔로우 중인 사람들 중에서 찾기", "lists.subheading": "당신의 리스트", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "불러오는 중...", "media_gallery.toggle_visible": "표시 전환", "missing_indicator.label": "찾을 수 없습니다", @@ -313,6 +315,7 @@ "search_results.accounts": "사람", "search_results.hashtags": "해시태그", "search_results.statuses": "툿", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number}건의 결과", "status.admin_account": "@{name}에 대한 모더레이션 인터페이스 열기", "status.admin_status": "모더레이션 인터페이스에서 이 게시물 열기", @@ -325,7 +328,7 @@ "status.direct": "@{name}에게 다이렉트 메시지", "status.embed": "공유하기", "status.favourite": "즐겨찾기", - "status.filtered": "필터링 됨", + "status.filtered": "필터로 걸러짐", "status.load_more": "더 보기", "status.media_hidden": "미디어 숨겨짐", "status.mention": "답장", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json new file mode 100644 index 000000000..919129cc5 --- /dev/null +++ b/app/javascript/mastodon/locales/lt.json @@ -0,0 +1,391 @@ +{ + "account.add_or_remove_from_list": "Add or Remove from lists", + "account.badges.bot": "Bot", + "account.block": "Block @{name}", + "account.block_domain": "Hide everything from {domain}", + "account.blocked": "Blocked", + "account.direct": "Direct message @{name}", + "account.domain_blocked": "Domain hidden", + "account.edit_profile": "Edit profile", + "account.endorse": "Feature on profile", + "account.follow": "Follow", + "account.followers": "Followers", + "account.followers.empty": "No one follows this user yet.", + "account.follows": "Follows", + "account.follows.empty": "This user doesn't follow anyone yet.", + "account.follows_you": "Follows you", + "account.hide_reblogs": "Hide boosts from @{name}", + "account.link_verified_on": "Ownership of this link was checked on {date}", + "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.", + "account.media": "Media", + "account.mention": "Mention @{name}", + "account.moved_to": "{name} has moved to:", + "account.mute": "Mute @{name}", + "account.mute_notifications": "Mute notifications from @{name}", + "account.muted": "Muted", + "account.posts": "Toots", + "account.posts_with_replies": "Toots and replies", + "account.report": "Report @{name}", + "account.requested": "Awaiting approval. Click to cancel follow request", + "account.share": "Share @{name}'s profile", + "account.show_reblogs": "Show boosts from @{name}", + "account.unblock": "Unblock @{name}", + "account.unblock_domain": "Unhide {domain}", + "account.unendorse": "Don't feature on profile", + "account.unfollow": "Unfollow", + "account.unmute": "Unmute @{name}", + "account.unmute_notifications": "Unmute notifications from @{name}", + "alert.unexpected.message": "An unexpected error occurred.", + "alert.unexpected.title": "Oops!", + "boost_modal.combo": "You can press {combo} to skip this next time", + "bundle_column_error.body": "Something went wrong while loading this component.", + "bundle_column_error.retry": "Try again", + "bundle_column_error.title": "Network error", + "bundle_modal_error.close": "Close", + "bundle_modal_error.message": "Something went wrong while loading this component.", + "bundle_modal_error.retry": "Try again", + "column.blocks": "Blocked users", + "column.community": "Local timeline", + "column.direct": "Direct messages", + "column.domain_blocks": "Hidden domains", + "column.favourites": "Favourites", + "column.follow_requests": "Follow requests", + "column.home": "Home", + "column.lists": "Lists", + "column.mutes": "Muted users", + "column.notifications": "Notifications", + "column.pins": "Pinned toot", + "column.public": "Federated timeline", + "column_back_button.label": "Back", + "column_header.hide_settings": "Hide settings", + "column_header.moveLeft_settings": "Move column to the left", + "column_header.moveRight_settings": "Move column to the right", + "column_header.pin": "Pin", + "column_header.show_settings": "Show settings", + "column_header.unpin": "Unpin", + "column_subheading.settings": "Settings", + "community.column_settings.media_only": "Media only", + "compose_form.direct_message_warning": "This toot will only be sent to all the mentioned users.", + "compose_form.direct_message_warning_learn_more": "Learn more", + "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", + "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", + "compose_form.lock_disclaimer.lock": "locked", + "compose_form.placeholder": "What is on your mind?", + "compose_form.poll.add_option": "Add a choice", + "compose_form.poll.duration": "Poll duration", + "compose_form.poll.option_placeholder": "Choice {number}", + "compose_form.poll.remove_option": "Remove this choice", + "compose_form.publish": "Toot", + "compose_form.publish_loud": "{publish}!", + "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.marked": "Media is marked as sensitive", + "compose_form.sensitive.unmarked": "Media is not marked as sensitive", + "compose_form.spoiler.marked": "Text is hidden behind warning", + "compose_form.spoiler.unmarked": "Text is not hidden", + "compose_form.spoiler_placeholder": "Write your warning here", + "confirmation_modal.cancel": "Cancel", + "confirmations.block.block_and_report": "Block & Report", + "confirmations.block.confirm": "Block", + "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.delete.confirm": "Delete", + "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.delete_list.confirm": "Delete", + "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.", + "confirmations.mute.confirm": "Mute", + "confirmations.mute.message": "Are you sure you want to mute {name}?", + "confirmations.redraft.confirm": "Delete & redraft", + "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.", + "confirmations.reply.confirm": "Reply", + "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.unfollow.confirm": "Unfollow", + "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?", + "embed.instructions": "Embed this status on your website by copying the code below.", + "embed.preview": "Here is what it will look like:", + "emoji_button.activity": "Activity", + "emoji_button.custom": "Custom", + "emoji_button.flags": "Flags", + "emoji_button.food": "Food & Drink", + "emoji_button.label": "Insert emoji", + "emoji_button.nature": "Nature", + "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", + "emoji_button.objects": "Objects", + "emoji_button.people": "People", + "emoji_button.recent": "Frequently used", + "emoji_button.search": "Search...", + "emoji_button.search_results": "Search results", + "emoji_button.symbols": "Symbols", + "emoji_button.travel": "Travel & Places", + "empty_column.account_timeline": "No toots here!", + "empty_column.account_unavailable": "Profile unavailable", + "empty_column.blocks": "You haven't blocked any users yet.", + "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", + "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", + "empty_column.domain_blocks": "There are no hidden domains yet.", + "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", + "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", + "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", + "empty_column.hashtag": "There is nothing in this hashtag yet.", + "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", + "empty_column.home.public_timeline": "the public timeline", + "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", + "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.", + "empty_column.mutes": "You haven't muted any users yet.", + "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", + "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other servers to fill it up", + "follow_request.authorize": "Authorize", + "follow_request.reject": "Reject", + "getting_started.developers": "Developers", + "getting_started.directory": "Profile directory", + "getting_started.documentation": "Documentation", + "getting_started.heading": "Getting started", + "getting_started.invite": "Invite people", + "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", + "getting_started.security": "Security", + "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.select.no_options_message": "No suggestions found", + "hashtag.column_settings.select.placeholder": "Enter hashtags…", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", + "home.column_settings.basic": "Basic", + "home.column_settings.show_reblogs": "Show boosts", + "home.column_settings.show_replies": "Show replies", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, one {# day} other {# days}}", + "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", + "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", + "introduction.federation.action": "Next", + "introduction.federation.federated.headline": "Federated", + "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.", + "introduction.federation.home.headline": "Home", + "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!", + "introduction.federation.local.headline": "Local", + "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.", + "introduction.interactions.action": "Finish toot-orial!", + "introduction.interactions.favourite.headline": "Favourite", + "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", + "introduction.interactions.reblog.headline": "Boost", + "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", + "introduction.interactions.reply.headline": "Reply", + "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", + "introduction.welcome.action": "Let's go!", + "introduction.welcome.headline": "First steps", + "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.", + "keyboard_shortcuts.back": "to navigate back", + "keyboard_shortcuts.blocked": "to open blocked users list", + "keyboard_shortcuts.boost": "to boost", + "keyboard_shortcuts.column": "to focus a status in one of the columns", + "keyboard_shortcuts.compose": "to focus the compose textarea", + "keyboard_shortcuts.description": "Description", + "keyboard_shortcuts.direct": "to open direct messages column", + "keyboard_shortcuts.down": "to move down in the list", + "keyboard_shortcuts.enter": "to open status", + "keyboard_shortcuts.favourite": "to favourite", + "keyboard_shortcuts.favourites": "to open favourites list", + "keyboard_shortcuts.federated": "to open federated timeline", + "keyboard_shortcuts.heading": "Keyboard Shortcuts", + "keyboard_shortcuts.home": "to open home timeline", + "keyboard_shortcuts.hotkey": "Hotkey", + "keyboard_shortcuts.legend": "to display this legend", + "keyboard_shortcuts.local": "to open local timeline", + "keyboard_shortcuts.mention": "to mention author", + "keyboard_shortcuts.muted": "to open muted users list", + "keyboard_shortcuts.my_profile": "to open your profile", + "keyboard_shortcuts.notifications": "to open notifications column", + "keyboard_shortcuts.pinned": "to open pinned toots list", + "keyboard_shortcuts.profile": "to open author's profile", + "keyboard_shortcuts.reply": "to reply", + "keyboard_shortcuts.requests": "to open follow requests list", + "keyboard_shortcuts.search": "to focus search", + "keyboard_shortcuts.start": "to open \"get started\" column", + "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW", + "keyboard_shortcuts.toggle_sensitivity": "to show/hide media", + "keyboard_shortcuts.toot": "to start a brand new toot", + "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", + "keyboard_shortcuts.up": "to move up in the list", + "lightbox.close": "Close", + "lightbox.next": "Next", + "lightbox.previous": "Previous", + "lightbox.view_context": "View context", + "lists.account.add": "Add to list", + "lists.account.remove": "Remove from list", + "lists.delete": "Delete list", + "lists.edit": "Edit list", + "lists.edit.submit": "Change title", + "lists.new.create": "Add list", + "lists.new.title_placeholder": "New list title", + "lists.search": "Search among people you follow", + "lists.subheading": "Your lists", + "load_pending": "{count, plural, one {# new item} other {# new items}}", + "loading_indicator.label": "Loading...", + "media_gallery.toggle_visible": "Toggle visibility", + "missing_indicator.label": "Not found", + "missing_indicator.sublabel": "This resource could not be found", + "mute_modal.hide_notifications": "Hide notifications from this user?", + "navigation_bar.apps": "Mobile apps", + "navigation_bar.blocks": "Blocked users", + "navigation_bar.community_timeline": "Local timeline", + "navigation_bar.compose": "Compose new toot", + "navigation_bar.direct": "Direct messages", + "navigation_bar.discover": "Discover", + "navigation_bar.domain_blocks": "Hidden domains", + "navigation_bar.edit_profile": "Edit profile", + "navigation_bar.favourites": "Favourites", + "navigation_bar.filters": "Muted words", + "navigation_bar.follow_requests": "Follow requests", + "navigation_bar.follows_and_followers": "Follows and followers", + "navigation_bar.info": "About this server", + "navigation_bar.keyboard_shortcuts": "Hotkeys", + "navigation_bar.lists": "Lists", + "navigation_bar.logout": "Logout", + "navigation_bar.mutes": "Muted users", + "navigation_bar.personal": "Personal", + "navigation_bar.pins": "Pinned toots", + "navigation_bar.preferences": "Preferences", + "navigation_bar.profile_directory": "Profile directory", + "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.security": "Security", + "notification.favourite": "{name} favourited your status", + "notification.follow": "{name} followed you", + "notification.mention": "{name} mentioned you", + "notification.poll": "A poll you have voted in has ended", + "notification.reblog": "{name} boosted your status", + "notifications.clear": "Clear notifications", + "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?", + "notifications.column_settings.alert": "Desktop notifications", + "notifications.column_settings.favourite": "Favourites:", + "notifications.column_settings.filter_bar.advanced": "Display all categories", + "notifications.column_settings.filter_bar.category": "Quick filter bar", + "notifications.column_settings.filter_bar.show": "Show", + "notifications.column_settings.follow": "New followers:", + "notifications.column_settings.mention": "Mentions:", + "notifications.column_settings.poll": "Poll results:", + "notifications.column_settings.push": "Push notifications", + "notifications.column_settings.reblog": "Boosts:", + "notifications.column_settings.show": "Show in column", + "notifications.column_settings.sound": "Play sound", + "notifications.filter.all": "All", + "notifications.filter.boosts": "Boosts", + "notifications.filter.favourites": "Favourites", + "notifications.filter.follows": "Follows", + "notifications.filter.mentions": "Mentions", + "notifications.filter.polls": "Poll results", + "notifications.group": "{count} notifications", + "poll.closed": "Closed", + "poll.refresh": "Refresh", + "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", + "poll.vote": "Vote", + "poll_button.add_poll": "Add a poll", + "poll_button.remove_poll": "Remove poll", + "privacy.change": "Adjust status privacy", + "privacy.direct.long": "Post to mentioned users only", + "privacy.direct.short": "Direct", + "privacy.private.long": "Post to followers only", + "privacy.private.short": "Followers-only", + "privacy.public.long": "Post to public timelines", + "privacy.public.short": "Public", + "privacy.unlisted.long": "Do not show in public timelines", + "privacy.unlisted.short": "Unlisted", + "regeneration_indicator.label": "Loading…", + "regeneration_indicator.sublabel": "Your home feed is being prepared!", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", + "reply_indicator.cancel": "Cancel", + "report.forward": "Forward to {target}", + "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?", + "report.hint": "The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:", + "report.placeholder": "Additional comments", + "report.submit": "Submit", + "report.target": "Report {target}", + "search.placeholder": "Search", + "search_popout.search_format": "Advanced search format", + "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", + "search_popout.tips.hashtag": "hashtag", + "search_popout.tips.status": "status", + "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", + "search_popout.tips.user": "user", + "search_results.accounts": "People", + "search_results.hashtags": "Hashtags", + "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", + "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "status.admin_account": "Open moderation interface for @{name}", + "status.admin_status": "Open this status in the moderation interface", + "status.block": "Block @{name}", + "status.cancel_reblog_private": "Unboost", + "status.cannot_reblog": "This post cannot be boosted", + "status.copy": "Copy link to status", + "status.delete": "Delete", + "status.detailed_status": "Detailed conversation view", + "status.direct": "Direct message @{name}", + "status.embed": "Embed", + "status.favourite": "Favourite", + "status.filtered": "Filtered", + "status.load_more": "Load more", + "status.media_hidden": "Media hidden", + "status.mention": "Mention @{name}", + "status.more": "More", + "status.mute": "Mute @{name}", + "status.mute_conversation": "Mute conversation", + "status.open": "Expand this status", + "status.pin": "Pin on profile", + "status.pinned": "Pinned toot", + "status.read_more": "Read more", + "status.reblog": "Boost", + "status.reblog_private": "Boost to original audience", + "status.reblogged_by": "{name} boosted", + "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", + "status.redraft": "Delete & re-draft", + "status.reply": "Reply", + "status.replyAll": "Reply to thread", + "status.report": "Report @{name}", + "status.sensitive_warning": "Sensitive content", + "status.share": "Share", + "status.show_less": "Show less", + "status.show_less_all": "Show less for all", + "status.show_more": "Show more", + "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", + "status.unmute_conversation": "Unmute conversation", + "status.unpin": "Unpin from profile", + "suggestions.dismiss": "Dismiss suggestion", + "suggestions.header": "You might be interested in…", + "tabs_bar.federated_timeline": "Federated", + "tabs_bar.home": "Home", + "tabs_bar.local_timeline": "Local", + "tabs_bar.notifications": "Notifications", + "tabs_bar.search": "Search", + "time_remaining.days": "{number, plural, one {# day} other {# days}} left", + "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", + "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", + "time_remaining.moments": "Moments remaining", + "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left", + "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking", + "ui.beforeunload": "Your draft will be lost if you leave Mastodon.", + "upload_area.title": "Drag & drop to upload", + "upload_button.label": "Add media ({formats})", + "upload_error.limit": "File upload limit exceeded.", + "upload_error.poll": "File upload not allowed with polls.", + "upload_form.description": "Describe for the visually impaired", + "upload_form.focus": "Crop", + "upload_form.undo": "Delete", + "upload_progress.label": "Uploading...", + "video.close": "Close video", + "video.exit_fullscreen": "Exit full screen", + "video.expand": "Expand video", + "video.fullscreen": "Full screen", + "video.hide": "Hide video", + "video.mute": "Mute sound", + "video.pause": "Pause", + "video.play": "Play", + "video.unmute": "Unmute sound" +} diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index 755f24168..50e13613c 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Basic", "home.column_settings.show_reblogs": "Show boosts", "home.column_settings.show_replies": "Show replies", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "New list title", "lists.search": "Search among people you follow", "lists.subheading": "Your lists", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Loading...", "media_gallery.toggle_visible": "Toggle visibility", "missing_indicator.label": "Not found", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", @@ -366,7 +369,7 @@ "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "upload_area.title": "Drag & drop to upload", - "upload_button.label": "Add media (JPEG, PNG, GIF, WebM, MP4, MOV)", + "upload_button.label": "Add media ({formats})", "upload_error.limit": "File upload limit exceeded.", "upload_error.poll": "File upload not allowed with polls.", "upload_form.description": "Describe for the visually impaired", diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json index cc384e7ed..dad8153d0 100644 --- a/app/javascript/mastodon/locales/ms.json +++ b/app/javascript/mastodon/locales/ms.json @@ -64,7 +64,7 @@ "column_header.show_settings": "Show settings", "column_header.unpin": "Unpin", "column_subheading.settings": "Settings", - "community.column_settings.media_only": "Media Only", + "community.column_settings.media_only": "Media only", "compose_form.direct_message_warning": "This toot will only be sent to all the mentioned users.", "compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", @@ -156,6 +156,7 @@ "home.column_settings.basic": "Basic", "home.column_settings.show_reblogs": "Show boosts", "home.column_settings.show_replies": "Show replies", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "New list title", "lists.search": "Search among people you follow", "lists.subheading": "Your lists", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Loading...", "media_gallery.toggle_visible": "Toggle visibility", "missing_indicator.label": "Not found", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", @@ -366,7 +369,7 @@ "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "upload_area.title": "Drag & drop to upload", - "upload_button.label": "Add media (JPEG, PNG, GIF, WebM, MP4, MOV)", + "upload_button.label": "Add media ({formats})", "upload_error.limit": "File upload limit exceeded.", "upload_error.poll": "File upload not allowed with polls.", "upload_form.description": "Describe for the visually impaired", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 3faf2aef4..104cea32a 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Algemeen", "home.column_settings.show_reblogs": "Boosts tonen", "home.column_settings.show_replies": "Reacties tonen", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# dag} other {# dagen}}", "intervals.full.hours": "{number, plural, one {# uur} other {# uur}}", "intervals.full.minutes": "{number, plural, one {# minuut} other {# minuten}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Naam nieuwe lijst", "lists.search": "Zoek naar mensen die je volgt", "lists.subheading": "Jouw lijsten", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Laden…", "media_gallery.toggle_visible": "Media wel/niet tonen", "missing_indicator.label": "Niet gevonden", @@ -311,6 +313,7 @@ "search_results.accounts": "Gebruikers", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "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", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index f039bcbfd..99e1565a1 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -64,7 +64,7 @@ "column_header.show_settings": "Vis innstillinger", "column_header.unpin": "Løsne", "column_subheading.settings": "Innstillinger", - "community.column_settings.media_only": "Media Only", + "community.column_settings.media_only": "Media only", "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", "compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.hashtag_warning": "Denne tuten blir ikke listet under noen emneknagger da den er ulistet. Kun offentlige tuter kan søktes etter med emneknagg.", @@ -156,6 +156,7 @@ "home.column_settings.basic": "Enkel", "home.column_settings.show_reblogs": "Vis fremhevinger", "home.column_settings.show_replies": "Vis svar", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Ny listetittel", "lists.search": "Søk blant personer du følger", "lists.subheading": "Dine lister", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Laster...", "media_gallery.toggle_visible": "Veksle synlighet", "missing_indicator.label": "Ikke funnet", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {resultat} other {resultater}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index 7eaa422c9..34804da20 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -77,7 +77,7 @@ "compose_form.poll.remove_option": "Levar aquesta opcion", "compose_form.publish": "Tut", "compose_form.publish_loud": "{publish} !", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "Marcar coma sensible", "compose_form.sensitive.marked": "Lo mèdia es marcat coma sensible", "compose_form.sensitive.unmarked": "Lo mèdia es pas marcat coma sensible", "compose_form.spoiler.marked": "Lo tèxte es rescondut jos l’avertiment", @@ -156,6 +156,7 @@ "home.column_settings.basic": "Basic", "home.column_settings.show_reblogs": "Mostrar los partatges", "home.column_settings.show_replies": "Mostrar las responsas", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# jorn} other {# jorns}}", "intervals.full.hours": "{number, plural, one {# ora} other {# oras}}", "intervals.full.minutes": "{number, plural, one {# minuta} other {# minutas}}", @@ -204,13 +205,14 @@ "keyboard_shortcuts.search": "anar a la recèrca", "keyboard_shortcuts.start": "dobrir la colomna « Per començar »", "keyboard_shortcuts.toggle_hidden": "mostrar/amagar lo tèxte dels avertiments", + "keyboard_shortcuts.toggle_sensitivity": "per mostrar/rescondre los mèdias", "keyboard_shortcuts.toot": "començar un estatut tot novèl", "keyboard_shortcuts.unfocus": "quitar lo camp tèxte/de recèrca", "keyboard_shortcuts.up": "far montar dins la lista", "lightbox.close": "Tampar", "lightbox.next": "Seguent", "lightbox.previous": "Precedent", - "lightbox.view_context": "View context", + "lightbox.view_context": "Veire lo contèxt", "lists.account.add": "Ajustar a la lista", "lists.account.remove": "Levar de la lista", "lists.delete": "Suprimir la lista", @@ -220,6 +222,7 @@ "lists.new.title_placeholder": "Títol de la nòva lista", "lists.search": "Cercar demest lo monde que seguètz", "lists.subheading": "Vòstras listas", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Cargament…", "media_gallery.toggle_visible": "Modificar la visibilitat", "missing_indicator.label": "Pas trobat", @@ -236,6 +239,7 @@ "navigation_bar.favourites": "Favorits", "navigation_bar.filters": "Mots ignorats", "navigation_bar.follow_requests": "Demandas d’abonament", + "navigation_bar.follows_and_followers": "Abonament e seguidors", "navigation_bar.info": "Tocant aqueste servidor", "navigation_bar.keyboard_shortcuts": "Acorchis clavièr", "navigation_bar.lists": "Listas", @@ -244,6 +248,7 @@ "navigation_bar.personal": "Personal", "navigation_bar.pins": "Tuts penjats", "navigation_bar.preferences": "Preferéncias", + "navigation_bar.profile_directory": "Annuari de perfils", "navigation_bar.public_timeline": "Flux public global", "navigation_bar.security": "Seguretat", "notification.favourite": "{name} a ajustat a sos favorits", @@ -311,6 +316,7 @@ "search_results.accounts": "Gents", "search_results.hashtags": "Etiquetas", "search_results.statuses": "Tuts", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}", "status.admin_account": "Dobrir l’interfàcia de moderacion per @{name}", "status.admin_status": "Dobrir aqueste estatut dins l’interfàcia de moderacion", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 3b6fde738..52dbded56 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -160,6 +160,7 @@ "home.column_settings.basic": "Podstawowe", "home.column_settings.show_reblogs": "Pokazuj podbicia", "home.column_settings.show_replies": "Pokazuj odpowiedzi", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# dzień} few {# dni} many {# dni} other {# dni}}", "intervals.full.hours": "{number, plural, one {# godzina} few {# godziny} many {# godzin} other {# godzin}}", "intervals.full.minutes": "{number, plural, one {# minuta} few {# minuty} many {# minut} other {# minut}}", @@ -224,6 +225,7 @@ "lists.new.title_placeholder": "Wprowadź tytuł listy", "lists.search": "Szukaj wśród osób które śledzisz", "lists.subheading": "Twoje listy", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Ładowanie…", "media_gallery.toggle_visible": "Przełącz widoczność", "missing_indicator.label": "Nie znaleziono", @@ -316,6 +318,7 @@ "search_results.accounts": "Ludzie", "search_results.hashtags": "Hashtagi", "search_results.statuses": "Wpisy", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {wynik} few {wyniki} many {wyników} more {wyników}}", "status.admin_account": "Otwórz interfejs moderacyjny dla @{name}", "status.admin_status": "Otwórz ten wpis w interfejsie moderacyjnym", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 4cbd2296c..1fb700874 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -36,7 +36,7 @@ "account.unmute": "Não silenciar @{name}", "account.unmute_notifications": "Retirar silêncio das notificações vindas de @{name}", "alert.unexpected.message": "Um erro inesperado ocorreu.", - "alert.unexpected.title": "Oops!", + "alert.unexpected.title": "Eita!", "boost_modal.combo": "Você pode pressionar {combo} para ignorar este diálogo na próxima vez", "bundle_column_error.body": "Algo de errado aconteceu enquanto este componente era carregado.", "bundle_column_error.retry": "Tente novamente", @@ -77,7 +77,7 @@ "compose_form.poll.remove_option": "Remover essa opção", "compose_form.publish": "Publicar", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "Marcar mídia como sensível", "compose_form.sensitive.marked": "Mídia está marcada como sensível", "compose_form.sensitive.unmarked": "Mídia não está marcada como sensível", "compose_form.spoiler.marked": "O texto está escondido por um aviso de conteúdo", @@ -89,7 +89,7 @@ "confirmations.block.message": "Você tem certeza de que quer bloquear {name}?", "confirmations.delete.confirm": "Excluir", "confirmations.delete.message": "Você tem certeza de que quer excluir esta postagem?", - "confirmations.delete_list.confirm": "Delete", + "confirmations.delete_list.confirm": "Excluir", "confirmations.delete_list.message": "Você tem certeza que quer deletar permanentemente a lista?", "confirmations.domain_block.confirm": "Esconder o domínio inteiro", "confirmations.domain_block.message": "Você quer mesmo bloquear {domain} inteiro? Na maioria dos casos, silenciar ou bloquear alguns usuários é o suficiente e o recomendado. Você não vai ver conteúdo desse domínio em nenhuma das timelines públicas ou nas suas notificações. Seus seguidores desse domínio serão removidos.", @@ -156,13 +156,14 @@ "home.column_settings.basic": "Básico", "home.column_settings.show_reblogs": "Mostrar compartilhamentos", "home.column_settings.show_replies": "Mostrar as respostas", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# dia} other {# dias}}", "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", + "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}", "introduction.federation.action": "Próximo", - "introduction.federation.federated.headline": "Federated", + "introduction.federation.federated.headline": "Global", "introduction.federation.federated.text": "Posts públicos de outros servidores do fediverso vão aparecer na timeline global.", - "introduction.federation.home.headline": "Home", + "introduction.federation.home.headline": "Início", "introduction.federation.home.text": "Posts de pessoas que você segue vão aparecer na sua página inicial. Você pode seguir pessoas de qualquer servidor!", "introduction.federation.local.headline": "Local", "introduction.federation.local.text": "Posts públicos de pessoas no mesmo servidor que você vão aparecer na timeline local.", @@ -204,22 +205,24 @@ "keyboard_shortcuts.search": "para focar a pesquisa", "keyboard_shortcuts.start": "para abrir a coluna \"primeiros passos\"", "keyboard_shortcuts.toggle_hidden": "mostrar/esconder o texto com aviso de conteúdo", + "keyboard_shortcuts.toggle_sensitivity": "mostrar/esconder mídia", "keyboard_shortcuts.toot": "para compor um novo toot", "keyboard_shortcuts.unfocus": "para remover o foco da área de composição/pesquisa", "keyboard_shortcuts.up": "para mover para cima na lista", "lightbox.close": "Fechar", "lightbox.next": "Próximo", "lightbox.previous": "Anterior", - "lightbox.view_context": "View context", + "lightbox.view_context": "Ver contexto", "lists.account.add": "Adicionar a listas", "lists.account.remove": "Remover da lista", - "lists.delete": "Delete list", + "lists.delete": "Excluir lista", "lists.edit": "Editar lista", "lists.edit.submit": "Mudar o título", "lists.new.create": "Adicionar lista", "lists.new.title_placeholder": "Novo título da lista", "lists.search": "Procurar entre as pessoas que você segue", "lists.subheading": "Suas listas", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Carregando...", "media_gallery.toggle_visible": "Esconder/Mostrar", "missing_indicator.label": "Não encontrado", @@ -236,6 +239,7 @@ "navigation_bar.favourites": "Favoritos", "navigation_bar.filters": "Palavras silenciadas", "navigation_bar.follow_requests": "Seguidores pendentes", + "navigation_bar.follows_and_followers": "Seguindo e seguidores", "navigation_bar.info": "Mais informações", "navigation_bar.keyboard_shortcuts": "Atalhos de teclado", "navigation_bar.lists": "Listas", @@ -244,6 +248,7 @@ "navigation_bar.personal": "Pessoal", "navigation_bar.pins": "Postagens fixadas", "navigation_bar.preferences": "Preferências", + "navigation_bar.profile_directory": "Diretório de perfis", "navigation_bar.public_timeline": "Global", "navigation_bar.security": "Segurança", "notification.favourite": "{name} adicionou a sua postagem aos favoritos", @@ -311,6 +316,7 @@ "search_results.accounts": "Pessoas", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", "status.admin_account": "Abrir interface de moderação para @{name}", "status.admin_status": "Abrir esse status na interface de moderação", diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json index b980dfa1c..c6ea3f847 100644 --- a/app/javascript/mastodon/locales/pt.json +++ b/app/javascript/mastodon/locales/pt.json @@ -17,7 +17,7 @@ "account.hide_reblogs": "Esconder partilhas de @{name}", "account.link_verified_on": "A posse deste link foi verificada em {date}", "account.locked_info": "O estatuto de privacidade desta conta é fechado. O dono revê manualmente que a pode seguir.", - "account.media": "Media", + "account.media": "Média", "account.mention": "Mencionar @{name}", "account.moved_to": "{name} mudou a sua conta para:", "account.mute": "Silenciar @{name}", @@ -49,50 +49,50 @@ "column.direct": "Mensagens directas", "column.domain_blocks": "Domínios escondidos", "column.favourites": "Favoritos", - "column.follow_requests": "Seguidores Pendentes", + "column.follow_requests": "Seguidores pendentes", "column.home": "Início", "column.lists": "Listas", "column.mutes": "Utilizadores silenciados", "column.notifications": "Notificações", "column.pins": "Publicações fixas", - "column.public": "Cronologia federativa", + "column.public": "Cronologia federada", "column_back_button.label": "Voltar", - "column_header.hide_settings": "Esconder preferências", + "column_header.hide_settings": "Esconder configurações", "column_header.moveLeft_settings": "Mover coluna para a esquerda", "column_header.moveRight_settings": "Mover coluna para a direita", "column_header.pin": "Fixar", - "column_header.show_settings": "Mostrar preferências", + "column_header.show_settings": "Mostrar configurações", "column_header.unpin": "Desafixar", - "column_subheading.settings": "Preferências", - "community.column_settings.media_only": "Somente media", - "compose_form.direct_message_warning": "Esta publicação só será enviada para os utilizadores mencionados.", - "compose_form.direct_message_warning_learn_more": "Aprender mais", - "compose_form.hashtag_warning": "Esta pulbicacção não será listada em nenhuma hashtag por ser não listada. Somente publicações públicas podem ser pesquisadas por hashtag.", + "column_subheading.settings": "Configurações", + "community.column_settings.media_only": "Somente multimédia", + "compose_form.direct_message_warning": "Esta publicação será enviada apenas para os utilizadores mencionados.", + "compose_form.direct_message_warning_learn_more": "Conhecer mais", + "compose_form.hashtag_warning": "Este toot não será listado em nenhuma hashtag por ser não listado. Apenas toots públics podem ser pesquisados por hashtag.", "compose_form.lock_disclaimer": "A tua conta não está {locked}. Qualquer pessoa pode seguir-te e ver as publicações direcionadas apenas a seguidores.", - "compose_form.lock_disclaimer.lock": "fechada", + "compose_form.lock_disclaimer.lock": "bloqueado", "compose_form.placeholder": "Em que estás a pensar?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", - "compose_form.publish": "Publicar", - "compose_form.publish_loud": "{publicar}!", - "compose_form.sensitive.hide": "Mark media as sensitive", - "compose_form.sensitive.marked": "Media marcado como sensível", - "compose_form.sensitive.unmarked": "Media não está marcado como sensível", + "compose_form.poll.add_option": "Adicionar uma opção", + "compose_form.poll.duration": "Duração da votação", + "compose_form.poll.option_placeholder": "Opção {number}", + "compose_form.poll.remove_option": "Eliminar esta opção", + "compose_form.publish": "Toot", + "compose_form.publish_loud": "{publish}!", + "compose_form.sensitive.hide": "Marcar multimédia como sensível", + "compose_form.sensitive.marked": "Média marcada como sensível", + "compose_form.sensitive.unmarked": "Média não está marcada como sensível", "compose_form.spoiler.marked": "Texto escondido atrás de aviso", "compose_form.spoiler.unmarked": "O texto não está escondido", "compose_form.spoiler_placeholder": "Escreve o teu aviso aqui", "confirmation_modal.cancel": "Cancelar", - "confirmations.block.block_and_report": "Block & Report", + "confirmations.block.block_and_report": "Bloquear e denunciar", "confirmations.block.confirm": "Bloquear", "confirmations.block.message": "De certeza que queres bloquear {name}?", "confirmations.delete.confirm": "Eliminar", "confirmations.delete.message": "De certeza que queres eliminar esta publicação?", - "confirmations.delete_list.confirm": "Apagar", - "confirmations.delete_list.message": "Tens a certeza de que desejas apagar permanentemente esta lista?", + "confirmations.delete_list.confirm": "Eliminar", + "confirmations.delete_list.message": "Tens a certeza de que desejas eliminar permanentemente esta lista?", "confirmations.domain_block.confirm": "Esconder tudo deste domínio", - "confirmations.domain_block.message": "De certeza que queres bloquear completamente o domínio {domain}? Na maioria dos casos, silenciar ou bloquear alguns utilizadores é o suficiente e o recomendado. Não irás ver conteúdo daquele domínio em cronologia alguma, nem nas tuas notificações. Os teus seguidores daquele domínio serão removidos.", + "confirmations.domain_block.message": "De certeza que queres bloquear completamente o domínio {domain}? Na maioria dos casos, silenciar ou bloquear alguns utilizadores é suficiente e é o recomendado. Não irás ver conteúdo daquele domínio em cronologia alguma nem nas tuas notificações. Os teus seguidores daquele domínio serão removidos.", "confirmations.mute.confirm": "Silenciar", "confirmations.mute.message": "De certeza que queres silenciar {name}?", "confirmations.redraft.confirm": "Apagar & redigir", @@ -109,23 +109,23 @@ "emoji_button.food": "Comida & Bebida", "emoji_button.label": "Inserir Emoji", "emoji_button.nature": "Natureza", - "emoji_button.not_found": "Não tem emojos!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "Não tem emojis!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "Objectos", "emoji_button.people": "Pessoas", - "emoji_button.recent": "Regularmente utilizados", - "emoji_button.search": "Procurar...", + "emoji_button.recent": "Utilizados regularmente", + "emoji_button.search": "Pesquisar...", "emoji_button.search_results": "Resultados da pesquisa", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viagens & Lugares", - "empty_column.account_timeline": "Sem publicações!", - "empty_column.account_unavailable": "Profile unavailable", + "empty_column.account_timeline": "Sem toots por aqui!", + "empty_column.account_unavailable": "Perfil indisponível", "empty_column.blocks": "Ainda não bloqueaste qualquer utilizador.", - "empty_column.community": "Ainda não existe conteúdo local para mostrar!", + "empty_column.community": "A timeline local está vazia. Escreve algo publicamente para começar!", "empty_column.direct": "Ainda não tens qualquer mensagem directa. Quando enviares ou receberes alguma, ela irá aparecer aqui.", "empty_column.domain_blocks": "Ainda não há qualquer domínio escondido.", - "empty_column.favourited_statuses": "Ainda não tens quaisquer publicações favoritas. Quando tiveres alguma, ela irá aparecer aqui.", - "empty_column.favourites": "Ainda ninguém favorizou esta publicação. Quando alguém o fizer, ela irá aparecer aqui.", - "empty_column.follow_requests": "Ainda não tens pedido de seguimento algum. Quando receberes algum, ele irá aparecer aqui.", + "empty_column.favourited_statuses": "Ainda não tens quaisquer toots favoritos. Quando tiveres algum, ele irá aparecer aqui.", + "empty_column.favourites": "Ainda ninguém marcou este toot como favorito. Quando alguém o fizer, ele irá aparecer aqui.", + "empty_column.follow_requests": "Ainda não tens nenhum pedido de seguimento. Quando receberes algum, ele irá aparecer aqui.", "empty_column.hashtag": "Não foram encontradas publicações com essa hashtag.", "empty_column.home": "Ainda não segues qualquer utilizador. Visita {public} ou utiliza a pesquisa para procurar outros utilizadores.", "empty_column.home.public_timeline": "Cronologia pública", @@ -138,10 +138,10 @@ "follow_request.reject": "Rejeitar", "getting_started.developers": "Responsáveis pelo desenvolvimento", "getting_started.directory": "Directório de perfil", - "getting_started.documentation": "Documentation", + "getting_started.documentation": "Documentação", "getting_started.heading": "Primeiros passos", "getting_started.invite": "Convidar pessoas", - "getting_started.open_source_notice": "Mastodon é software de fonte aberta. Podes contribuir ou repostar problemas no GitHub do projecto: {github}.", + "getting_started.open_source_notice": "Mastodon é software de código aberto (open source). Podes contribuir ou reportar problemas no GitHub do projecto: {github}.", "getting_started.security": "Segurança", "getting_started.terms": "Termos de serviço", "hashtag.column_header.tag_mode.all": "e {additional}", @@ -154,28 +154,29 @@ "hashtag.column_settings.tag_mode.none": "Nenhum destes", "hashtag.column_settings.tag_toggle": "Incluir etiquetas adicionais para esta coluna", "home.column_settings.basic": "Básico", - "home.column_settings.show_reblogs": "Mostrar as partilhas", - "home.column_settings.show_replies": "Mostrar as respostas", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", + "home.column_settings.show_reblogs": "Mostrar boosts", + "home.column_settings.show_replies": "Mostrar respostas", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, one {# dia} other {# dias}}", + "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}", + "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}", "introduction.federation.action": "Seguinte", - "introduction.federation.federated.headline": "Federated", + "introduction.federation.federated.headline": "Federada", "introduction.federation.federated.text": "Publicações públicas de outros servidores do fediverse aparecerão na cronologia federativa.", - "introduction.federation.home.headline": "Home", + "introduction.federation.home.headline": "Início", "introduction.federation.home.text": "As publicações das pessoas que tu segues aparecerão na tua coluna inicial. Tu podes seguir qualquer pessoa em qualquer servidor!", "introduction.federation.local.headline": "Local", "introduction.federation.local.text": "Publicações públicas de pessoas que tu segues no teu servidor aparecerão na coluna local.", "introduction.interactions.action": "Terminar o tutorial!", "introduction.interactions.favourite.headline": "Favorito", - "introduction.interactions.favourite.text": "Tu podes guardar um toot para depois e deixar o autor saber que gostaste dele, favoritando-o.", - "introduction.interactions.reblog.headline": "Partilhar", + "introduction.interactions.favourite.text": "Podes guardar um toot para depois e deixar o autor saber que gostaste dele, marcando-o como favorito.", + "introduction.interactions.reblog.headline": "Boost", "introduction.interactions.reblog.text": "Podes partilhar os toots de outras pessoas com os teus seguidores partilhando-os.", "introduction.interactions.reply.headline": "Responder", "introduction.interactions.reply.text": "Tu podes responder a toots de outras pessoas e aos teus, o que os irá juntar numa conversa.", "introduction.welcome.action": "Vamos!", "introduction.welcome.headline": "Primeiros passos", - "introduction.welcome.text": "Bem-vindo ao fediverse! Em pouco tempo poderás enviar mensagens e falar com os teus amigos numa grande variedade de servidores. Mas este servidor, {domain}, é especial—ele alberga o teu perfil. Por isso, lembra-te do seu nome.", + "introduction.welcome.text": "Bem-vindo ao fediverso! Em pouco tempo poderás enviar mensagens e falar com os teus amigos numa grande variedade de servidores. Mas este servidor, {domain}, é especial—ele alberga o teu perfil. Por isso, lembra-te do seu nome.", "keyboard_shortcuts.back": "para voltar", "keyboard_shortcuts.blocked": "para abrir a lista de utilizadores bloqueados", "keyboard_shortcuts.boost": "para partilhar", @@ -184,10 +185,10 @@ "keyboard_shortcuts.description": "Descrição", "keyboard_shortcuts.direct": "para abrir a coluna das mensagens directas", "keyboard_shortcuts.down": "para mover para baixo na lista", - "keyboard_shortcuts.enter": "para expandir uma publicação", + "keyboard_shortcuts.enter": "para expandir um estado", "keyboard_shortcuts.favourite": "para adicionar aos favoritos", "keyboard_shortcuts.favourites": "para abrir a lista dos favoritos", - "keyboard_shortcuts.federated": "para abrir a cronologia federativa", + "keyboard_shortcuts.federated": "para abrir a cronologia federada", "keyboard_shortcuts.heading": "Atalhos do teclado", "keyboard_shortcuts.home": "para abrir a cronologia inicial", "keyboard_shortcuts.hotkey": "Atalho", @@ -204,30 +205,32 @@ "keyboard_shortcuts.search": "para focar na pesquisa", "keyboard_shortcuts.start": "para abrir a coluna dos \"primeiros passos\"", "keyboard_shortcuts.toggle_hidden": "para mostrar/esconder texto atrás de CW", - "keyboard_shortcuts.toot": "para compor um novo post", - "keyboard_shortcuts.unfocus": "para remover o foco da área de publicação/pesquisa", + "keyboard_shortcuts.toggle_sensitivity": "mostrar/ocultar média", + "keyboard_shortcuts.toot": "para compor um novo toot", + "keyboard_shortcuts.unfocus": "para remover o foco da área de texto/pesquisa", "keyboard_shortcuts.up": "para mover para cima na lista", "lightbox.close": "Fechar", "lightbox.next": "Próximo", "lightbox.previous": "Anterior", - "lightbox.view_context": "View context", + "lightbox.view_context": "Ver contexto", "lists.account.add": "Adicionar à lista", "lists.account.remove": "Remover da lista", - "lists.delete": "Delete list", + "lists.delete": "Remover lista", "lists.edit": "Editar lista", "lists.edit.submit": "Mudar o título", "lists.new.create": "Adicionar lista", - "lists.new.title_placeholder": "Novo título da lista", + "lists.new.title_placeholder": "Título da nova lista", "lists.search": "Pesquisa entre as pessoas que segues", "lists.subheading": "As tuas listas", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "A carregar...", - "media_gallery.toggle_visible": "Esconder/Mostrar", + "media_gallery.toggle_visible": "Mostrar/ocultar", "missing_indicator.label": "Não encontrado", "missing_indicator.sublabel": "Este recurso não foi encontrado", "mute_modal.hide_notifications": "Esconder notificações deste utilizador?", "navigation_bar.apps": "Aplicações móveis", "navigation_bar.blocks": "Utilizadores bloqueados", - "navigation_bar.community_timeline": "Local", + "navigation_bar.community_timeline": "Cronologia local", "navigation_bar.compose": "Escrever novo toot", "navigation_bar.direct": "Mensagens directas", "navigation_bar.discover": "Descobrir", @@ -236,21 +239,23 @@ "navigation_bar.favourites": "Favoritos", "navigation_bar.filters": "Palavras silenciadas", "navigation_bar.follow_requests": "Seguidores pendentes", + "navigation_bar.follows_and_followers": "Seguindo e seguidores", "navigation_bar.info": "Sobre este servidor", "navigation_bar.keyboard_shortcuts": "Atalhos de teclado", "navigation_bar.lists": "Listas", "navigation_bar.logout": "Sair", "navigation_bar.mutes": "Utilizadores silenciados", - "navigation_bar.personal": "Personal", - "navigation_bar.pins": "Posts fixos", + "navigation_bar.personal": "Pessoal", + "navigation_bar.pins": "Toots afixados", "navigation_bar.preferences": "Preferências", - "navigation_bar.public_timeline": "Global", + "navigation_bar.profile_directory": "Directório de perfis", + "navigation_bar.public_timeline": "Cronologia federada", "navigation_bar.security": "Segurança", - "notification.favourite": "{name} adicionou o teu post aos favoritos", - "notification.follow": "{name} seguiu-te", + "notification.favourite": "{name} adicionou o teu estado aos favoritos", + "notification.follow": "{name} começou a seguir-te", "notification.mention": "{name} mencionou-te", - "notification.poll": "A poll you have voted in has ended", - "notification.reblog": "{name} partilhou o teu post", + "notification.poll": "Uma votação em participaste chegou ao fim", + "notification.reblog": "{name} fez boost ao teu o teu estado", "notifications.clear": "Limpar notificações", "notifications.clear_confirmation": "Queres mesmo limpar todas as notificações?", "notifications.column_settings.alert": "Notificações no computador", @@ -260,24 +265,24 @@ "notifications.column_settings.filter_bar.show": "Mostrar", "notifications.column_settings.follow": "Novos seguidores:", "notifications.column_settings.mention": "Menções:", - "notifications.column_settings.poll": "Poll results:", + "notifications.column_settings.poll": "Resultados da votação:", "notifications.column_settings.push": "Notificações Push", - "notifications.column_settings.reblog": "Partilhas:", - "notifications.column_settings.show": "Mostrar nas colunas", + "notifications.column_settings.reblog": "Boosts:", + "notifications.column_settings.show": "Mostrar na coluna", "notifications.column_settings.sound": "Reproduzir som", "notifications.filter.all": "Todas", - "notifications.filter.boosts": "Partilhas", - "notifications.filter.favourites": "Favoritas", + "notifications.filter.boosts": "Boosts", + "notifications.filter.favourites": "Favoritos", "notifications.filter.follows": "Seguimento", "notifications.filter.mentions": "Referências", - "notifications.filter.polls": "Poll results", + "notifications.filter.polls": "Resultados da votação", "notifications.group": "{count} notificações", "poll.closed": "Fechado", "poll.refresh": "Recarregar", "poll.total_votes": "{contar, plural, um {# vote} outro {# votes}}", "poll.vote": "Votar", - "poll_button.add_poll": "Add a poll", - "poll_button.remove_poll": "Remove poll", + "poll_button.add_poll": "Adicionar votação", + "poll_button.remove_poll": "Remover votação", "privacy.change": "Ajustar a privacidade da mensagem", "privacy.direct.long": "Apenas para utilizadores mencionados", "privacy.direct.short": "Directo", @@ -297,26 +302,27 @@ "reply_indicator.cancel": "Cancelar", "report.forward": "Reenviar para {target}", "report.forward_hint": "A conta é de outro servidor. Enviar uma cópia anónima do relatório para lá também?", - "report.hint": "O relatório será enviado para os moderadores do teu servidor. Podes fornecer, em baixo, uma explicação do motivo pelo qual estás a relatar esta conta:", + "report.hint": "O relatório será enviado para os moderadores do teu servidor. Podes fornecer, em baixo, uma explicação do motivo pelo qual estás a denunciar esta conta:", "report.placeholder": "Comentários adicionais", "report.submit": "Enviar", "report.target": "Denunciar", "search.placeholder": "Pesquisar", "search_popout.search_format": "Formato avançado de pesquisa", - "search_popout.tips.full_text": "Texto simples devolve publicações que tu escreveste, favoritaste, partilhaste ou em que foste mencionado, tal como nomes de utilizador correspondentes, alcunhas e hashtags.", + "search_popout.tips.full_text": "Texto simples devolve publicações que tu escreveste, marcaste como favorita, partilhaste ou em que foste mencionado, tal como nomes de utilizador correspondentes, alcunhas e hashtags.", "search_popout.tips.hashtag": "hashtag", "search_popout.tips.status": "estado", "search_popout.tips.text": "O texto simples retorna a correspondência de nomes, utilizadores e hashtags", "search_popout.tips.user": "utilizador", "search_results.accounts": "Pessoas", "search_results.hashtags": "Hashtags", - "search_results.statuses": "Publicações", + "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", "status.admin_account": "Abrir a interface de moderação para @{name}", "status.admin_status": "Abrir esta publicação na interface de moderação", - "status.block": "Block @{name}", - "status.cancel_reblog_private": "Não partilhar", - "status.cannot_reblog": "Este post não pode ser partilhado", + "status.block": "Bloquear @{name}", + "status.cancel_reblog_private": "Remover boost", + "status.cannot_reblog": "Não é possível fazer boost a esta publicação", "status.copy": "Copiar o link para a publicação", "status.delete": "Eliminar", "status.detailed_status": "Vista de conversação detalhada", @@ -325,7 +331,7 @@ "status.favourite": "Adicionar aos favoritos", "status.filtered": "Filtrada", "status.load_more": "Carregar mais", - "status.media_hidden": "Media escondida", + "status.media_hidden": "Média escondida", "status.mention": "Mencionar @{name}", "status.more": "Mais", "status.mute": "Silenciar @{name}", @@ -335,15 +341,15 @@ "status.pinned": "Publicação fixa", "status.read_more": "Ler mais", "status.reblog": "Partilhar", - "status.reblog_private": "Partilhar com a audiência original", - "status.reblogged_by": "{name} partilhou", - "status.reblogs.empty": "Ainda ninguém partilhou esta publicação. Quando alguém o fizer, ela irá aparecer aqui.", + "status.reblog_private": "Fazer boost com a audiência original", + "status.reblogged_by": "{name} fez boost", + "status.reblogs.empty": "Ainda ninguém fez boost a este toot. Quando alguém o fizer, ele irá aparecer aqui.", "status.redraft": "Apagar & reescrever", "status.reply": "Responder", "status.replyAll": "Responder à conversa", "status.report": "Denunciar @{name}", "status.sensitive_warning": "Conteúdo sensível", - "status.share": "Compartilhar", + "status.share": "Partilhar", "status.show_less": "Mostrar menos", "status.show_less_all": "Mostrar menos para todas", "status.show_more": "Mostrar mais", @@ -353,22 +359,22 @@ "status.unpin": "Não fixar no perfil", "suggestions.dismiss": "Dispensar a sugestão", "suggestions.header": "Tu podes estar interessado em…", - "tabs_bar.federated_timeline": "Global", - "tabs_bar.home": "Home", + "tabs_bar.federated_timeline": "Federada", + "tabs_bar.home": "Início", "tabs_bar.local_timeline": "Local", "tabs_bar.notifications": "Notificações", "tabs_bar.search": "Pesquisar", "time_remaining.days": "{número, plural, um {# day} outro {# days}} faltam", "time_remaining.hours": "{número, plural, um {# hour} outro {# hours}} faltam", "time_remaining.minutes": "{número, plural, um {# minute} outro {# minutes}} faltam", - "time_remaining.moments": "Momentos em falta", + "time_remaining.moments": "Momentos restantes", "time_remaining.seconds": "{número, plural, um {# second} outro {# seconds}} faltam", "trends.count_by_accounts": "{count} {rawCount, plural, uma {person} outra {people}} a falar", - "ui.beforeunload": "O teu rascunho vai ser perdido se abandonares o Mastodon.", + "ui.beforeunload": "O teu rascunho será perdido se abandonares o Mastodon.", "upload_area.title": "Arraste e solte para enviar", "upload_button.label": "Adicionar media", "upload_error.limit": "Limite máximo do ficheiro a carregar excedido.", - "upload_error.poll": "File upload not allowed with polls.", + "upload_error.poll": "Carregamento de ficheiros não é permitido em votações.", "upload_form.description": "Descrição da imagem para pessoas com dificuldades visuais", "upload_form.focus": "Alterar previsualização", "upload_form.undo": "Apagar", @@ -376,7 +382,7 @@ "video.close": "Fechar vídeo", "video.exit_fullscreen": "Sair de full screen", "video.expand": "Expandir vídeo", - "video.fullscreen": "Full screen", + "video.fullscreen": "Ecrã completo", "video.hide": "Esconder vídeo", "video.mute": "Silenciar", "video.pause": "Pausar", diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json index 0021846d6..0e5e0ba9e 100644 --- a/app/javascript/mastodon/locales/ro.json +++ b/app/javascript/mastodon/locales/ro.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "De bază", "home.column_settings.show_reblogs": "Arată redistribuirile", "home.column_settings.show_replies": "Arată răspunsurile", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Titlu pentru noua listă", "lists.search": "Caută printre persoanale pe care le urmărești", "lists.subheading": "Listele tale", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Încărcare...", "media_gallery.toggle_visible": "Comutați vizibilitatea", "missing_indicator.label": "Nu a fost găsit", @@ -311,6 +313,7 @@ "search_results.accounts": "Oameni", "search_results.hashtags": "Hashtaguri", "search_results.statuses": "Postări", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index 9e8e4e324..8a7a39a06 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -13,20 +13,20 @@ "account.followers.empty": "Никто не подписан на этого пользователя.", "account.follows": "Подписки", "account.follows.empty": "Этот пользователь ни на кого не подписан.", - "account.follows_you": "Подписан(а) на Вас", - "account.hide_reblogs": "Скрыть продвижения от @{name}", + "account.follows_you": "Подписан(а) на вас", + "account.hide_reblogs": "Скрыть реблоги от @{name}", "account.link_verified_on": "Владение этой ссылкой было проверено {date}", "account.locked_info": "Это закрытый аккаунт. Его владелец вручную одобряет подписчиков.", "account.media": "Медиа", "account.mention": "Упомянуть", "account.moved_to": "Ищите {name} здесь:", - "account.mute": "Заглушить", + "account.mute": "Скрыть @{name}", "account.mute_notifications": "Скрыть уведомления от @{name}", - "account.muted": "Приглушён", + "account.muted": "Скрыт", "account.posts": "Посты", - "account.posts_with_replies": "Посты и ответы", + "account.posts_with_replies": "Посты с ответами", "account.report": "Пожаловаться", - "account.requested": "Ожидает подтверждения", + "account.requested": "Ожидает подтверждения. Нажмите для отмены", "account.share": "Поделиться профилем @{name}", "account.show_reblogs": "Показывать продвижения от @{name}", "account.unblock": "Разблокировать", @@ -52,7 +52,7 @@ "column.follow_requests": "Запросы на подписку", "column.home": "Главная", "column.lists": "Списки", - "column.mutes": "Список глушения", + "column.mutes": "Список скрытых пользователей", "column.notifications": "Уведомления", "column.pins": "Закреплённый пост", "column.public": "Глобальная лента", @@ -70,14 +70,14 @@ "compose_form.hashtag_warning": "Этот пост не будет показывается в поиске по хэштегу, т.к. он непубличный. Только публичные посты можно найти в поиске по хэштегу.", "compose_form.lock_disclaimer": "Ваш аккаунт не {locked}. Любой человек может подписаться на Вас и просматривать посты для подписчиков.", "compose_form.lock_disclaimer.lock": "закрыт", - "compose_form.placeholder": "О чем Вы думаете?", + "compose_form.placeholder": "О чем вы думаете?", "compose_form.poll.add_option": "Добавить", "compose_form.poll.duration": "Длительность опроса", "compose_form.poll.option_placeholder": "Вариант {number}", "compose_form.poll.remove_option": "Удалить этот вариант", - "compose_form.publish": "Трубить", + "compose_form.publish": "Запостить", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "Пометить медиафайл как чувствительный", "compose_form.sensitive.marked": "Медиафайлы не отмечены как чувствительные", "compose_form.sensitive.unmarked": "Медиафайлы не отмечены как чувствительные", "compose_form.spoiler.marked": "Текст скрыт за предупреждением", @@ -117,31 +117,31 @@ "emoji_button.search_results": "Результаты поиска", "emoji_button.symbols": "Символы", "emoji_button.travel": "Путешествия", - "empty_column.account_timeline": "Статусов нет!", + "empty_column.account_timeline": "Здесь нет постов!", "empty_column.account_unavailable": "Профиль недоступен", "empty_column.blocks": "Вы ещё никого не заблокировали.", "empty_column.community": "Локальная лента пуста. Напишите что-нибудь, чтобы разогреть народ!", - "empty_column.direct": "У Вас пока нет личных сообщений. Когда Вы начнёте их отправлять или получать, они появятся здесь.", + "empty_column.direct": "У вас пока нет личных сообщений. Как только вы отправите или получите одно, оно появится здесь.", "empty_column.domain_blocks": "Скрытых доменов пока нет.", - "empty_column.favourited_statuses": "Вы не добавили ни одного статуса в 'Избранное'. Как только Вы это сделаете, они появятся здесь.", - "empty_column.favourites": "Никто ещё не добавил этот статус в 'Избранное'. Как только кто-то это сделает, они появятся здесь.", + "empty_column.favourited_statuses": "Вы не добавили ни один пост в «Избранное». Как только вы это сделаете, он появится здесь.", + "empty_column.favourites": "Никто ещё не добавил этот пост в «Избранное». Как только кто-то это сделает, это отобразится здесь.", "empty_column.follow_requests": "Вам ещё не приходили запросы на подписку. Все новые запросы будут показаны здесь.", "empty_column.hashtag": "Статусов с таким хэштегом еще не существует.", - "empty_column.home": "Пока Вы ни на кого не подписаны. Полистайте {public} или используйте поиск, чтобы освоиться и завести новые знакомства.", + "empty_column.home": "Пока вы ни на кого не подписаны. Полистайте {public} или используйте поиск, чтобы освоиться и завести новые знакомства.", "empty_column.home.public_timeline": "публичные ленты", "empty_column.list": "В этом списке пока ничего нет.", - "empty_column.lists": "У Вас ещё нет списков. Все созданные Вами списки будут показаны здесь.", - "empty_column.mutes": "Вы ещё никого не заглушили.", - "empty_column.notifications": "У Вас еще нет уведомлений. Заведите знакомство с другими пользователями, чтобы начать разговор.", + "empty_column.lists": "У вас ещё нет списков. Созданные вами списки будут показаны здесь.", + "empty_column.mutes": "Вы ещё никого не скрывали.", + "empty_column.notifications": "У вас пока нет уведомлений. Взаимодействуйте с другими, чтобы завести разговор.", "empty_column.public": "Здесь ничего нет! Опубликуйте что-нибудь или подпишитесь на пользователей с других узлов, чтобы заполнить ленту.", "follow_request.authorize": "Авторизовать", "follow_request.reject": "Отказать", - "getting_started.developers": "Для разработчиков", + "getting_started.developers": "Разработчикам", "getting_started.directory": "Каталог профилей", "getting_started.documentation": "Документация", "getting_started.heading": "Добро пожаловать", "getting_started.invite": "Пригласить людей", - "getting_started.open_source_notice": "Mastodon - сервис с открытым исходным кодом. Вы можете помочь проекту или сообщить о проблемах на GitHub по адресу {github}.", + "getting_started.open_source_notice": "Mastodon — сервис с открытым исходным кодом. Вы можете внести вклад или сообщить о проблемах на GitHub: {github}.", "getting_started.security": "Безопасность", "getting_started.terms": "Условия использования", "hashtag.column_header.tag_mode.all": "и {additional}", @@ -156,9 +156,10 @@ "home.column_settings.basic": "Основные", "home.column_settings.show_reblogs": "Показывать продвижения", "home.column_settings.show_replies": "Показывать ответы", - "intervals.full.days": "{number, plural, one {# день} few {# дня} many {# дней} other {# дней}}", - "intervals.full.hours": "{number, plural, one {# час} few {# часа} many {# часов} other {# часов}}", - "intervals.full.minutes": "{number, plural, one {# минута} few {# минуты} many {# минут} other {# минут}}", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, one {# день} few {# дня} other {# дней}}", + "intervals.full.hours": "{number, plural, one {# час} few {# часа} other {# часов}}", + "intervals.full.minutes": "{number, plural, one {# минута} few {# минуты} other {# минут}}", "introduction.federation.action": "Далее", "introduction.federation.federated.headline": "Глобальная лента", "introduction.federation.federated.text": "Публичные статусы с других серверов федеративной сети расположатся в глобальной ленте.", @@ -167,7 +168,7 @@ "introduction.federation.local.headline": "Локальная лента", "introduction.federation.local.text": "Публичные статусы от людей с того же сервера, что и вы, будут отображены в локальной ленте.", "introduction.interactions.action": "Завершить обучение", - "introduction.interactions.favourite.headline": "Отметки \"нравится\"", + "introduction.interactions.favourite.headline": "Отметки «нравится»", "introduction.interactions.favourite.text": "Вы можете отметить статус, чтобы вернуться к нему позже и дать знать автору, что запись вам понравилась, поставив отметку \"нравится\".", "introduction.interactions.reblog.headline": "Продвижения", "introduction.interactions.reblog.text": "Вы можете делиться статусами других людей, продвигая их в своём аккаунте.", @@ -204,13 +205,14 @@ "keyboard_shortcuts.search": "перейти к поиску", "keyboard_shortcuts.start": "перейти к разделу \"добро пожаловать\"", "keyboard_shortcuts.toggle_hidden": "показать/скрыть текст за предупреждением", + "keyboard_shortcuts.toggle_sensitivity": "показать/скрыть медиафайлы", "keyboard_shortcuts.toot": "начать писать новый пост", "keyboard_shortcuts.unfocus": "убрать фокус с поля ввода/поиска", "keyboard_shortcuts.up": "вверх по списку", "lightbox.close": "Закрыть", "lightbox.next": "Далее", "lightbox.previous": "Назад", - "lightbox.view_context": "View context", + "lightbox.view_context": "Контекст", "lists.account.add": "Добавить в список", "lists.account.remove": "Убрать из списка", "lists.delete": "Удалить список", @@ -220,6 +222,7 @@ "lists.new.title_placeholder": "Заголовок списка", "lists.search": "Искать из ваших подписок", "lists.subheading": "Ваши списки", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Загрузка...", "media_gallery.toggle_visible": "Показать/скрыть", "missing_indicator.label": "Не найдено", @@ -236,14 +239,16 @@ "navigation_bar.favourites": "Понравившееся", "navigation_bar.filters": "Заглушенные слова", "navigation_bar.follow_requests": "Запросы на подписку", + "navigation_bar.follows_and_followers": "Подписки и подписчики", "navigation_bar.info": "Об узле", "navigation_bar.keyboard_shortcuts": "Сочетания клавиш", "navigation_bar.lists": "Списки", "navigation_bar.logout": "Выйти", - "navigation_bar.mutes": "Список глушения", + "navigation_bar.mutes": "Список скрытых пользователей", "navigation_bar.personal": "Личное", "navigation_bar.pins": "Закреплённые посты", "navigation_bar.preferences": "Опции", + "navigation_bar.profile_directory": "Каталог профилей", "navigation_bar.public_timeline": "Глобальная лента", "navigation_bar.security": "Безопасность", "notification.favourite": "{name} понравился Ваш статус", @@ -311,6 +316,7 @@ "search_results.accounts": "Люди", "search_results.hashtags": "Хэштеги", "search_results.statuses": "Посты", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {результат} few {результата} many {результатов} other {результатов}}", "status.admin_account": "Открыть интерфейс модератора для @{name}", "status.admin_status": "Открыть этот статус в интерфейсе модератора", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 88fc73d01..b50bd481f 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Základné", "home.column_settings.show_reblogs": "Zobraziť povýšené", "home.column_settings.show_replies": "Ukázať odpovede", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# deň} few {# dní} many {# dní} other {# dni}}", "intervals.full.hours": "{number, plural, one {# hodina} few {# hodín} many {# hodín} other {# hodiny}}", "intervals.full.minutes": "{number, plural, one {# minúta} few {# minút} many {# minút} other {# minúty}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Názov nového zoznamu", "lists.search": "Vyhľadávaj medzi užívateľmi, ktorých sleduješ", "lists.subheading": "Tvoje zoznamy", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Načítam...", "media_gallery.toggle_visible": "Zapni/Vypni viditeľnosť", "missing_indicator.label": "Nenájdené", @@ -251,7 +253,7 @@ "notification.mention": "{name} ťa spomenul/a", "notification.poll": "Anketa v ktorej si hlasoval/a sa skončila", "notification.reblog": "{name} zdieľal/a tvoj príspevok", - "notifications.clear": "Vyčistiť zoznam oboznámení", + "notifications.clear": "Vyčisti oboznámenia", "notifications.clear_confirmation": "Naozaj chceš nenávratne prečistiť všetky tvoje oboznámenia?", "notifications.column_settings.alert": "Oboznámenia na ploche", "notifications.column_settings.favourite": "Obľúbené:", @@ -311,6 +313,7 @@ "search_results.accounts": "Ľudia", "search_results.hashtags": "Haštagy", "search_results.statuses": "Príspevky", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {výsledok} many {výsledkov} other {výsledky}}", "status.admin_account": "Otvor moderovacie rozhranie užívateľa @{name}", "status.admin_status": "Otvor tento príspevok v moderovacom rozhraní", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index 4c07165cd..f79a7051a 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -13,10 +13,10 @@ "account.followers.empty": "Nihče ne sledi temu uporabniku.", "account.follows": "Sledi", "account.follows.empty": "Ta uporabnik še ne sledi nikomur.", - "account.follows_you": "Ti sledi", - "account.hide_reblogs": "Skrij sunke od @{name}", + "account.follows_you": "Sledi tebi", + "account.hide_reblogs": "Skrij spodbude od @{name}", "account.link_verified_on": "Lastništvo te povezave je bilo preverjeno {date}", - "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.", + "account.locked_info": "Stanje zasebnosti računa je nastavljeno na zaklenjeno. Lastnik ročno pregleda, kdo ga lahko spremlja.", "account.media": "Mediji", "account.mention": "Omeni @{name}", "account.moved_to": "{name} se je premaknil na:", @@ -28,16 +28,16 @@ "account.report": "Prijavi @{name}", "account.requested": "Čakanje na odobritev. Kliknite, da prekličete prošnjo za sledenje", "account.share": "Delite profil osebe @{name}", - "account.show_reblogs": "Pokaži delitve osebe @{name}", + "account.show_reblogs": "Pokaži spodbude osebe @{name}", "account.unblock": "Odblokiraj @{name}", "account.unblock_domain": "Razkrij {domain}", - "account.unendorse": "Don't feature on profile", + "account.unendorse": "Ne vključi v profil", "account.unfollow": "Prenehaj slediti", "account.unmute": "Odtišaj @{name}", "account.unmute_notifications": "Vklopi obvestila od @{name}", "alert.unexpected.message": "Zgodila se je nepričakovana napaka.", "alert.unexpected.title": "Uups!", - "boost_modal.combo": "Če želite naslednjič preskočiti to, lahko pritisnete {combo}", + "boost_modal.combo": "Če želite preskočiti to, lahko pritisnete {combo}", "bundle_column_error.body": "Med nalaganjem te komponente je prišlo do napake.", "bundle_column_error.retry": "Poskusi ponovno", "bundle_column_error.title": "Napaka omrežja", @@ -67,49 +67,49 @@ "community.column_settings.media_only": "Samo mediji", "compose_form.direct_message_warning": "Ta tut bo viden le vsem omenjenim uporabnikom.", "compose_form.direct_message_warning_learn_more": "Nauči se več", - "compose_form.hashtag_warning": "Ta tut ne bo naveden pod nobenim hashtagom, ker ni dodan hashtag. Samo javne tute lahko iščete pod hashtagom.", + "compose_form.hashtag_warning": "Ta tut ne bo naveden pod nobenim ključnikom, ker ni javen. Samo javne tute lahko iščete s ključniki.", "compose_form.lock_disclaimer": "Vaš račun ni {locked}. Vsakdo vam lahko sledi in si ogleda objave, ki so namenjene samo sledilcem.", "compose_form.lock_disclaimer.lock": "zaklenjen", "compose_form.placeholder": "O čem razmišljaš?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.poll.add_option": "Dodaj izbiro", + "compose_form.poll.duration": "Trajanje ankete", + "compose_form.poll.option_placeholder": "Izbira {number}", + "compose_form.poll.remove_option": "Odstrani to izbiro", "compose_form.publish": "Tutni", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "Označi medij kot občutljiv", "compose_form.sensitive.marked": "Medij je označen kot občutljiv", "compose_form.sensitive.unmarked": "Medij ni označen kot občutljiv", "compose_form.spoiler.marked": "Besedilo je skrito za opozorilom", "compose_form.spoiler.unmarked": "Besedilo ni skrito", - "compose_form.spoiler_placeholder": "Napišite opozorilo tukaj", + "compose_form.spoiler_placeholder": "Tukaj napišite opozorilo", "confirmation_modal.cancel": "Prekliči", - "confirmations.block.block_and_report": "Block & Report", - "confirmations.block.confirm": "Block", + "confirmations.block.block_and_report": "Blokiraj in Prijavi", + "confirmations.block.confirm": "Blokiraj", "confirmations.block.message": "Ali ste prepričani, da želite blokirati {name}?", - "confirmations.delete.confirm": "Delete", + "confirmations.delete.confirm": "Izbriši", "confirmations.delete.message": "Ali ste prepričani, da želite izbrisati to stanje?", - "confirmations.delete_list.confirm": "Delete", + "confirmations.delete_list.confirm": "Izbriši", "confirmations.delete_list.message": "Ali ste prepričani, da želite trajno izbrisati ta seznam?", "confirmations.domain_block.confirm": "Skrij celotno domeno", - "confirmations.domain_block.message": "Ali ste res, res prepričani, da želite blokirati celotno {domain}? V večini primerov je nekaj ciljnih blokiranj ali utišanj dovolj in boljše.", + "confirmations.domain_block.message": "Ali ste res, res prepričani, da želite blokirati celotno {domain}? V večini primerov je nekaj ciljnih blokiranj ali utišanj dovolj in boljše. Vsebino iz te domene ne boste videli v javnih časovnicah ali obvestilih. Vaši sledilci iz te domene bodo odstranjeni.", "confirmations.mute.confirm": "Utišanje", "confirmations.mute.message": "Ali ste prepričani, da želite utišati {name}?", "confirmations.redraft.confirm": "Izbriši in preoblikuj", - "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.", - "confirmations.reply.confirm": "Reply", + "confirmations.redraft.message": "Ali ste prepričani, da želite izbrisati ta status in ga preoblikovati? Vzljubi in spodbude bodo izgubljeni, odgovori na izvirno objavo pa bodo osiroteli.", + "confirmations.reply.confirm": "Odgovori", "confirmations.reply.message": "Odgovarjanje bo prepisalo sporočilo, ki ga trenutno sestavljate. Ali ste prepričani, da želite nadaljevati?", "confirmations.unfollow.confirm": "Prenehaj slediti", "confirmations.unfollow.message": "Ali ste prepričani, da ne želite več slediti {name}?", "embed.instructions": "Vstavi ta status na svojo spletno stran tako, da kopirate spodnjo kodo.", - "embed.preview": "Tukaj je, kako bo izgledalo:", + "embed.preview": "Tako bo izgledalo:", "emoji_button.activity": "Dejavnost", "emoji_button.custom": "Po meri", "emoji_button.flags": "Zastave", "emoji_button.food": "Hrana in Pijača", - "emoji_button.label": "Vstavi emojija", + "emoji_button.label": "Vstavi emotikon", "emoji_button.nature": "Narava", - "emoji_button.not_found": "Ni emojijev!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "Ni emotikonov!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "Predmeti", "emoji_button.people": "Ljudje", "emoji_button.recent": "Pogosto uporabljeni", @@ -117,228 +117,234 @@ "emoji_button.search_results": "Rezultati iskanja", "emoji_button.symbols": "Simboli", "emoji_button.travel": "Potovanja in Kraji", - "empty_column.account_timeline": "No toots here!", - "empty_column.account_unavailable": "Profile unavailable", + "empty_column.account_timeline": "Tukaj ni tutov!", + "empty_column.account_unavailable": "Profil ni na voljo", "empty_column.blocks": "Niste še blokirali nobenega uporabnika.", "empty_column.community": "Lokalna časovnica je prazna. Napišite nekaj javnega, da se bo žoga zakotalila!", - "empty_column.direct": "Nimate še nobenih neposrednih sporočil. Ko ga pošljete ali prejmete, se prikaže tukaj.", + "empty_column.direct": "Nimate še nobenih neposrednih sporočil. Ko ga boste poslali ali prejeli, se bo prikazal tukaj.", "empty_column.domain_blocks": "Še vedno ni skritih domen.", - "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", - "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", - "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", - "empty_column.hashtag": "V tem hashtagu še ni nič.", + "empty_column.favourited_statuses": "Nimate priljubljenih tutov. Ko boste vzljubili kakšnega, se bo prikazal tukaj.", + "empty_column.favourites": "Nihče še ni vzljubil tega tuta. Ko ga bo nekdo, se bo pojavil tukaj.", + "empty_column.follow_requests": "Nimate prošenj za sledenje. Ko boste prejeli kakšno, se bo prikazala tukaj.", + "empty_column.hashtag": "V tem ključniku še ni nič.", "empty_column.home": "Vaša domača časovnica je prazna! Obiščite {public} ali uporabite iskanje, da se boste srečali druge uporabnike.", "empty_column.home.public_timeline": "javna časovnica", "empty_column.list": "Na tem seznamu ni ničesar. Ko bodo člani tega seznama objavili nove statuse, se bodo pojavili tukaj.", - "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.", - "empty_column.mutes": "You haven't muted any users yet.", + "empty_column.lists": "Nimate seznamov. Ko ga boste ustvarili, se bo prikazal tukaj.", + "empty_column.mutes": "Niste utišali še nobenega uporabnika.", "empty_column.notifications": "Nimate še nobenih obvestil. Poveži se z drugimi, da začnete pogovor.", - "empty_column.public": "Tukaj ni ničesar! Da ga napolnite, napišite nekaj javnega ali pa ročno sledite uporabnikom iz drugih vozlišč", - "follow_request.authorize": "Odobri", + "empty_column.public": "Tukaj ni ničesar! Da ga napolnite, napišite nekaj javnega ali pa ročno sledite uporabnikom iz drugih strežnikov", + "follow_request.authorize": "Overi", "follow_request.reject": "Zavrni", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", - "getting_started.documentation": "Documentation", - "getting_started.heading": "Prvi koraki", - "getting_started.invite": "Invite people", - "getting_started.open_source_notice": "Mastodon je odprtokodna programska oprema. V GitHubu na {github} lahko prispevate ali poročate o napakah.", - "getting_started.security": "Security", - "getting_started.terms": "Terms of service", - "hashtag.column_header.tag_mode.all": "and {additional}", - "hashtag.column_header.tag_mode.any": "or {additional}", - "hashtag.column_header.tag_mode.none": "without {additional}", - "hashtag.column_settings.select.no_options_message": "No suggestions found", - "hashtag.column_settings.select.placeholder": "Enter hashtags…", - "hashtag.column_settings.tag_mode.all": "All of these", - "hashtag.column_settings.tag_mode.any": "Any of these", - "hashtag.column_settings.tag_mode.none": "None of these", - "hashtag.column_settings.tag_toggle": "Include additional tags in this column", + "getting_started.developers": "Razvijalci", + "getting_started.directory": "Imenik profilov", + "getting_started.documentation": "Dokumentacija", + "getting_started.heading": "Kako začeti", + "getting_started.invite": "Povabite osebe", + "getting_started.open_source_notice": "Mastodon je odprtokodna programska oprema. Na GitHubu na {github} lahko prispevate ali poročate o napakah.", + "getting_started.security": "Varnost", + "getting_started.terms": "Pogoji uporabe", + "hashtag.column_header.tag_mode.all": "in {additional}", + "hashtag.column_header.tag_mode.any": "ali {additional}", + "hashtag.column_header.tag_mode.none": "brez {additional}", + "hashtag.column_settings.select.no_options_message": "Ni najdenih predlogov", + "hashtag.column_settings.select.placeholder": "Vpiši ključnik…", + "hashtag.column_settings.tag_mode.all": "Vse od naštetega", + "hashtag.column_settings.tag_mode.any": "Karkoli od naštetega", + "hashtag.column_settings.tag_mode.none": "Nič od naštetega", + "hashtag.column_settings.tag_toggle": "Za ta stolpec vključi dodatne oznake", "home.column_settings.basic": "Osnovno", - "home.column_settings.show_reblogs": "Pokaži sunke", + "home.column_settings.show_reblogs": "Pokaži spodbude", "home.column_settings.show_replies": "Pokaži odgovore", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", - "introduction.federation.action": "Next", - "introduction.federation.federated.headline": "Federated", - "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.", - "introduction.federation.home.headline": "Home", - "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!", - "introduction.federation.local.headline": "Local", - "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.", - "introduction.interactions.action": "Finish tutorial!", - "introduction.interactions.favourite.headline": "Favourite", - "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", - "introduction.interactions.reblog.headline": "Boost", - "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", - "introduction.interactions.reply.headline": "Reply", - "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", - "introduction.welcome.action": "Let's go!", - "introduction.welcome.headline": "First steps", - "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.", - "keyboard_shortcuts.back": "za krmarjenje nazaj", - "keyboard_shortcuts.blocked": "to open blocked users list", - "keyboard_shortcuts.boost": "suniti", - "keyboard_shortcuts.column": "osredotočiti status v enega od stolpcev", - "keyboard_shortcuts.compose": "osredotočiti na sestavljanje besedila", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, one {# dan} two {# dni} few {# dni} other {# dni}}", + "intervals.full.hours": "{number, plural, one {# ura} two {# uri} few {# ure} other {# ur}}", + "intervals.full.minutes": "{number, plural, one {# minuta} two {# minuti} few {# minute} other {# minut}}", + "introduction.federation.action": "Naprej", + "introduction.federation.federated.headline": "Združeno", + "introduction.federation.federated.text": "Javne objave iz drugih strežnikov fediverse-a bodo prikazane v združeni časovnici.", + "introduction.federation.home.headline": "Domov", + "introduction.federation.home.text": "Objave oseb, ki jim sledite, bodo prikazane v vaši domači časovnici. Lahko sledite vsakomur na katerem koli strežniku!", + "introduction.federation.local.headline": "Lokalno", + "introduction.federation.local.text": "Javne objave ljudi na istem strežniku, se bodo prikazale na lokalni časovnici.", + "introduction.interactions.action": "Zaključi vadnico!", + "introduction.interactions.favourite.headline": "Vzljubi", + "introduction.interactions.favourite.text": "Tut lahko shranite za pozneje in ga vzljubite ter s tem pokažete avtorju, da vam je ta tut priljubljen.", + "introduction.interactions.reblog.headline": "Spodbudi", + "introduction.interactions.reblog.text": "Tute drugih ljudi lahko delite z vašimi sledilci, tako da spodbudite tute.", + "introduction.interactions.reply.headline": "Odgovori", + "introduction.interactions.reply.text": "Lahko odgovarjate na tuje in vaše tute, kar bo odgovore povezalo v pogovor.", + "introduction.welcome.action": "Gremo!", + "introduction.welcome.headline": "Prvi koraki", + "introduction.welcome.text": "Dobrodošli v fediverse-u! Čez nekaj trenutkov boste lahko oddajali sporočila in se pogovarjali s prijatelji prek različnih strežnikov. Vendar je ta strežnik {domain} poseben - gosti vaš profil, zato si zapomnite njegovo ime.", + "keyboard_shortcuts.back": "pojdi nazaj", + "keyboard_shortcuts.blocked": "odpri seznam blokiranih uporabnikov", + "keyboard_shortcuts.boost": "spodbudi", + "keyboard_shortcuts.column": "fokusiraj na status v enemu od stolpcev", + "keyboard_shortcuts.compose": "fokusiraj na območje za sestavljanje besedila", "keyboard_shortcuts.description": "Opis", - "keyboard_shortcuts.direct": "to open direct messages column", - "keyboard_shortcuts.down": "premakniti navzdol po seznamu", - "keyboard_shortcuts.enter": "odpreti status", - "keyboard_shortcuts.favourite": "to favourite", - "keyboard_shortcuts.favourites": "to open favourites list", - "keyboard_shortcuts.federated": "to open federated timeline", + "keyboard_shortcuts.direct": "odpri stolpec za neposredna sporočila", + "keyboard_shortcuts.down": "premakni se navzdol po seznamu", + "keyboard_shortcuts.enter": "odpri status", + "keyboard_shortcuts.favourite": "vzljubi", + "keyboard_shortcuts.favourites": "odpri seznam priljubljenih", + "keyboard_shortcuts.federated": "odpri združeno časovnico", "keyboard_shortcuts.heading": "Tipkovne bližnjice", - "keyboard_shortcuts.home": "to open home timeline", + "keyboard_shortcuts.home": "odpri domačo časovnico", "keyboard_shortcuts.hotkey": "Hitra tipka", - "keyboard_shortcuts.legend": "to display this legend", - "keyboard_shortcuts.local": "to open local timeline", - "keyboard_shortcuts.mention": "to mention author", - "keyboard_shortcuts.muted": "to open muted users list", - "keyboard_shortcuts.my_profile": "to open your profile", - "keyboard_shortcuts.notifications": "to open notifications column", - "keyboard_shortcuts.pinned": "to open pinned toots list", - "keyboard_shortcuts.profile": "to open author's profile", - "keyboard_shortcuts.reply": "to reply", - "keyboard_shortcuts.requests": "to open follow requests list", - "keyboard_shortcuts.search": "to focus search", - "keyboard_shortcuts.start": "to open \"get started\" column", - "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW", - "keyboard_shortcuts.toot": "da začnete povsem nov tut", - "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", - "keyboard_shortcuts.up": "to move up in the list", - "lightbox.close": "Close", - "lightbox.next": "Next", - "lightbox.previous": "Previous", - "lightbox.view_context": "View context", - "lists.account.add": "Add to list", - "lists.account.remove": "Remove from list", - "lists.delete": "Delete list", - "lists.edit": "Edit list", - "lists.edit.submit": "Change title", - "lists.new.create": "Add list", - "lists.new.title_placeholder": "New list title", - "lists.search": "Search among people you follow", - "lists.subheading": "Your lists", - "loading_indicator.label": "Loading...", - "media_gallery.toggle_visible": "Toggle visibility", - "missing_indicator.label": "Not found", - "missing_indicator.sublabel": "This resource could not be found", - "mute_modal.hide_notifications": "Hide notifications from this user?", - "navigation_bar.apps": "Mobile apps", - "navigation_bar.blocks": "Blocked users", - "navigation_bar.community_timeline": "Local timeline", - "navigation_bar.compose": "Compose new toot", - "navigation_bar.direct": "Direct messages", - "navigation_bar.discover": "Discover", - "navigation_bar.domain_blocks": "Hidden domains", - "navigation_bar.edit_profile": "Edit profile", - "navigation_bar.favourites": "Favourites", - "navigation_bar.filters": "Muted words", - "navigation_bar.follow_requests": "Follow requests", - "navigation_bar.info": "O tem vozlišču", - "navigation_bar.keyboard_shortcuts": "Keyboard shortcuts", - "navigation_bar.lists": "Lists", - "navigation_bar.logout": "Logout", - "navigation_bar.mutes": "Muted users", - "navigation_bar.personal": "Personal", + "keyboard_shortcuts.legend": "pokaži to legendo", + "keyboard_shortcuts.local": "odpri lokalno časovnico", + "keyboard_shortcuts.mention": "omeni avtorja", + "keyboard_shortcuts.muted": "odpri seznam utišanih uporabnikov", + "keyboard_shortcuts.my_profile": "odpri svoj profil", + "keyboard_shortcuts.notifications": "odpri stolpec z obvestili", + "keyboard_shortcuts.pinned": "odpri seznam pripetih tutov", + "keyboard_shortcuts.profile": "odpri avtorjev profil", + "keyboard_shortcuts.reply": "odgovori", + "keyboard_shortcuts.requests": "odpri seznam s prošnjami za sledenje", + "keyboard_shortcuts.search": "fokusiraj na iskanje", + "keyboard_shortcuts.start": "odpri stolpec \"začni\"", + "keyboard_shortcuts.toggle_hidden": "prikaži/skrij besedilo za CW", + "keyboard_shortcuts.toggle_sensitivity": "prikaži/skrij medije", + "keyboard_shortcuts.toot": "začni povsem nov tut", + "keyboard_shortcuts.unfocus": "odfokusiraj območje za sestavljanje besedila/iskanje", + "keyboard_shortcuts.up": "premakni se navzgor po seznamu", + "lightbox.close": "Zapri", + "lightbox.next": "Naslednji", + "lightbox.previous": "Prejšnji", + "lightbox.view_context": "Poglej kontekst", + "lists.account.add": "Dodaj na seznam", + "lists.account.remove": "Odstrani s seznama", + "lists.delete": "Izbriši seznam", + "lists.edit": "Uredi seznam", + "lists.edit.submit": "Spremeni naslov", + "lists.new.create": "Dodaj seznam", + "lists.new.title_placeholder": "Nov naslov seznama", + "lists.search": "Išči med ljudmi, katerim sledite", + "lists.subheading": "Vaši seznami", + "load_pending": "{count, plural, one {# new item} other {# new items}}", + "loading_indicator.label": "Nalaganje...", + "media_gallery.toggle_visible": "Preklopi vidljivost", + "missing_indicator.label": "Ni najdeno", + "missing_indicator.sublabel": "Tega vira ni bilo mogoče najti", + "mute_modal.hide_notifications": "Skrij obvestila tega uporabnika?", + "navigation_bar.apps": "Mobilne aplikacije", + "navigation_bar.blocks": "Blokirani uporabniki", + "navigation_bar.community_timeline": "Lokalna časovnica", + "navigation_bar.compose": "Sestavi nov tut", + "navigation_bar.direct": "Neposredna sporočila", + "navigation_bar.discover": "Odkrijte", + "navigation_bar.domain_blocks": "Skrite domene", + "navigation_bar.edit_profile": "Uredi profil", + "navigation_bar.favourites": "Priljubljeni", + "navigation_bar.filters": "Utišane besede", + "navigation_bar.follow_requests": "Prošnje za sledenje", + "navigation_bar.follows_and_followers": "Sledenja in sledilci", + "navigation_bar.info": "O tem strežniku", + "navigation_bar.keyboard_shortcuts": "Hitre tipke", + "navigation_bar.lists": "Seznami", + "navigation_bar.logout": "Odjava", + "navigation_bar.mutes": "Utišani uporabniki", + "navigation_bar.personal": "Osebno", "navigation_bar.pins": "Pripeti tuti", - "navigation_bar.preferences": "Preferences", - "navigation_bar.public_timeline": "Federated timeline", - "navigation_bar.security": "Security", - "notification.favourite": "{name} favourited your status", - "notification.follow": "{name} followed you", - "notification.mention": "{name} mentioned you", - "notification.poll": "A poll you have voted in has ended", - "notification.reblog": "{name} boosted your status", - "notifications.clear": "Clear notifications", - "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?", - "notifications.column_settings.alert": "Desktop notifications", - "notifications.column_settings.favourite": "Favourites:", - "notifications.column_settings.filter_bar.advanced": "Display all categories", - "notifications.column_settings.filter_bar.category": "Quick filter bar", - "notifications.column_settings.filter_bar.show": "Show", - "notifications.column_settings.follow": "New followers:", - "notifications.column_settings.mention": "Mentions:", - "notifications.column_settings.poll": "Poll results:", - "notifications.column_settings.push": "Push notifications", - "notifications.column_settings.reblog": "Boosts:", - "notifications.column_settings.show": "Show in column", - "notifications.column_settings.sound": "Play sound", - "notifications.filter.all": "All", - "notifications.filter.boosts": "Boosts", - "notifications.filter.favourites": "Favourites", - "notifications.filter.follows": "Follows", - "notifications.filter.mentions": "Mentions", - "notifications.filter.polls": "Poll results", - "notifications.group": "{count} notifications", - "poll.closed": "Closed", - "poll.refresh": "Refresh", - "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", - "poll.vote": "Vote", - "poll_button.add_poll": "Add a poll", - "poll_button.remove_poll": "Remove poll", - "privacy.change": "Adjust status privacy", - "privacy.direct.long": "Post to mentioned users only", - "privacy.direct.short": "Direct", - "privacy.private.long": "Post to followers only", - "privacy.private.short": "Followers-only", - "privacy.public.long": "Post to public timelines", - "privacy.public.short": "Public", - "privacy.unlisted.long": "Do not show in public timelines", - "privacy.unlisted.short": "Unlisted", - "regeneration_indicator.label": "Loading…", - "regeneration_indicator.sublabel": "Your home feed is being prepared!", + "navigation_bar.preferences": "Nastavitve", + "navigation_bar.profile_directory": "Imenik profilov", + "navigation_bar.public_timeline": "Združena časovnica", + "navigation_bar.security": "Varnost", + "notification.favourite": "{name} je vzljubil/a vaš status", + "notification.follow": "{name} vam sledi", + "notification.mention": "{name} vas je omenil/a", + "notification.poll": "Glasovanje, v katerem ste sodelovali, se je končalo", + "notification.reblog": "{name} je spodbudil/a vaš status", + "notifications.clear": "Počisti obvestila", + "notifications.clear_confirmation": "Ali ste prepričani, da želite trajno izbrisati vsa vaša obvestila?", + "notifications.column_settings.alert": "Namizna obvestila", + "notifications.column_settings.favourite": "Priljubljeni:", + "notifications.column_settings.filter_bar.advanced": "Prikaži vse kategorije", + "notifications.column_settings.filter_bar.category": "Vrstica za hitro filtriranje", + "notifications.column_settings.filter_bar.show": "Pokaži", + "notifications.column_settings.follow": "Novi sledilci:", + "notifications.column_settings.mention": "Omembe:", + "notifications.column_settings.poll": "Rezultati glasovanja:", + "notifications.column_settings.push": "Potisna obvestila", + "notifications.column_settings.reblog": "Spodbude:", + "notifications.column_settings.show": "Prikaži v stolpcu", + "notifications.column_settings.sound": "Predvajaj zvok", + "notifications.filter.all": "Vse", + "notifications.filter.boosts": "Spodbude", + "notifications.filter.favourites": "Priljubljeni", + "notifications.filter.follows": "Sledi", + "notifications.filter.mentions": "Omembe", + "notifications.filter.polls": "Rezultati glasovanj", + "notifications.group": "{count} obvestil", + "poll.closed": "Zaprto", + "poll.refresh": "Osveži", + "poll.total_votes": "{count, plural,one {# glas} other {# glasov}}", + "poll.vote": "Glasuj", + "poll_button.add_poll": "Dodaj anketo", + "poll_button.remove_poll": "Odstrani anketo", + "privacy.change": "Prilagodi zasebnost statusa", + "privacy.direct.long": "Objavi samo omenjenim uporabnikom", + "privacy.direct.short": "Neposredno", + "privacy.private.long": "Objavi samo sledilcem", + "privacy.private.short": "Samo sledilci", + "privacy.public.long": "Objavi na javne časovnice", + "privacy.public.short": "Javno", + "privacy.unlisted.long": "Ne objavi na javne časovnice", + "privacy.unlisted.short": "Ni prikazano", + "regeneration_indicator.label": "Nalaganje…", + "regeneration_indicator.sublabel": "Vaš domači vir se pripravlja!", "relative_time.days": "{number}d", "relative_time.hours": "{number}h", - "relative_time.just_now": "now", + "relative_time.just_now": "zdaj", "relative_time.minutes": "{number}m", "relative_time.seconds": "{number}s", - "reply_indicator.cancel": "Cancel", - "report.forward": "Forward to {target}", - "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?", - "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:", - "report.placeholder": "Additional comments", - "report.submit": "Submit", - "report.target": "Report {target}", - "search.placeholder": "Search", - "search_popout.search_format": "Advanced search format", - "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", - "search_popout.tips.hashtag": "hashtag", - "search_popout.tips.status": "status", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", - "search_popout.tips.user": "user", - "search_results.accounts": "People", - "search_results.hashtags": "Hashtags", + "reply_indicator.cancel": "Prekliči", + "report.forward": "Posreduj do {target}", + "report.forward_hint": "Račun je iz drugega strežnika. Pošljem anonimno kopijo poročila tudi na drugi strežnik?", + "report.hint": "Poročilo bo poslano moderatorjem vašega vozlišča. Spodaj lahko navedete, zakaj prijavljate ta račun:", + "report.placeholder": "Dodatni komentarji", + "report.submit": "Pošlji", + "report.target": "Prijavi {target}", + "search.placeholder": "Iskanje", + "search_popout.search_format": "Napredna oblika iskanja", + "search_popout.tips.full_text": "Enostavno besedilo vrne statuse, ki ste jih napisali, vzljubili, spodbudili ali ste bili v njih omenjeni, kot tudi ujemajoča se uporabniška imena, prikazna imena in ključnike.", + "search_popout.tips.hashtag": "ključnik", + "search_popout.tips.status": "stanje", + "search_popout.tips.text": "Enostavno besedilo vrne ujemajoča se prikazna imena, uporabniška imena in ključnike", + "search_popout.tips.user": "uporabnik", + "search_results.accounts": "Ljudje", + "search_results.hashtags": "Ključniki", "search_results.statuses": "Tuti", - "search_results.total": "{count, number} {count, plural, one {result} other {results}}", - "status.admin_account": "Open moderation interface for @{name}", - "status.admin_status": "Open this status in the moderation interface", - "status.block": "Block @{name}", - "status.cancel_reblog_private": "Unboost", - "status.cannot_reblog": "This post cannot be boosted", - "status.copy": "Copy link to status", - "status.delete": "Delete", - "status.detailed_status": "Detailed conversation view", - "status.direct": "Direct message @{name}", - "status.embed": "Embed", - "status.favourite": "Favourite", - "status.filtered": "Filtered", - "status.load_more": "Load more", - "status.media_hidden": "Media hidden", - "status.mention": "Mention @{name}", - "status.more": "More", - "status.mute": "Mute @{name}", - "status.mute_conversation": "Mute conversation", - "status.open": "Expand this status", - "status.pin": "Pin on profile", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", + "search_results.total": "{count, number} {count, plural, one {rezultat} other {rezultatov}}", + "status.admin_account": "Odpri vmesnik za moderiranje za @{name}", + "status.admin_status": "Odpri status v vmesniku za moderiranje", + "status.block": "Blokiraj @{name}", + "status.cancel_reblog_private": "Prekini spodbudo", + "status.cannot_reblog": "Te objave ni mogoče spodbuditi", + "status.copy": "Kopiraj povezavo do statusa", + "status.delete": "Izbriši", + "status.detailed_status": "Podroben pogled pogovora", + "status.direct": "Neposredno sporočilo @{name}", + "status.embed": "Vgradi", + "status.favourite": "Priljubljen", + "status.filtered": "Filtrirano", + "status.load_more": "Naloži več", + "status.media_hidden": "Mediji so skriti", + "status.mention": "Omeni @{name}", + "status.more": "Več", + "status.mute": "Utišaj @{name}", + "status.mute_conversation": "Utišaj pogovor", + "status.open": "Razširi ta status", + "status.pin": "Pripni na profil", "status.pinned": "Pripeti tut", - "status.read_more": "Read more", - "status.reblog": "Suni", - "status.reblog_private": "Suni v prvotno občinstvo", - "status.reblogged_by": "{name} sunjen", - "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", - "status.redraft": "Delete & re-draft", + "status.read_more": "Preberi več", + "status.reblog": "Spodbudi", + "status.reblog_private": "Spodbudi izvirnemu občinstvu", + "status.reblogged_by": "{name} spodbujen", + "status.reblogs.empty": "Nihče še ni spodbudil tega tuta. Ko se bo to zgodilo, se bodo pojavili tukaj.", + "status.redraft": "Izbriši in preoblikuj", "status.reply": "Odgovori", "status.replyAll": "Odgovori na objavo", "status.report": "Prijavi @{name}", @@ -348,29 +354,29 @@ "status.show_less_all": "Prikaži manj za vse", "status.show_more": "Prikaži več", "status.show_more_all": "Prikaži več za vse", - "status.show_thread": "Show thread", + "status.show_thread": "Prikaži objavo", "status.unmute_conversation": "Odtišaj pogovor", "status.unpin": "Odpni iz profila", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "Zavrni predlog", + "suggestions.header": "Morda bi vas zanimalo…", "tabs_bar.federated_timeline": "Združeno", "tabs_bar.home": "Domov", "tabs_bar.local_timeline": "Lokalno", "tabs_bar.notifications": "Obvestila", - "tabs_bar.search": "Poišči", - "time_remaining.days": "{number, plural, one {# day} other {# days}} left", - "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", - "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", - "time_remaining.moments": "Moments remaining", - "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left", - "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking", + "tabs_bar.search": "Iskanje", + "time_remaining.days": "{number, plural, one {# dan} other {# dni}} je ostalo", + "time_remaining.hours": "{number, plural, one {# ura} other {# ur}} je ostalo", + "time_remaining.minutes": "{number, plural, one {# minuta} other {# minut}} je ostalo", + "time_remaining.moments": "Preostali trenutki", + "time_remaining.seconds": "{number, plural, one {# sekunda} other {# sekund}} je ostalo", + "trends.count_by_accounts": "{count} {rawCount, plural, one {oseba} other {ljudi}} govori", "ui.beforeunload": "Vaš osnutek bo izgubljen, če zapustite Mastodona.", - "upload_area.title": "Povlecite in spustite za pošiljanje", - "upload_button.label": "Dodaj medij", - "upload_error.limit": "File upload limit exceeded.", - "upload_error.poll": "File upload not allowed with polls.", + "upload_area.title": "Za pošiljanje povlecite in spustite", + "upload_button.label": "Dodaj medije ({formats})", + "upload_error.limit": "Omejitev prenosa datoteke je presežena.", + "upload_error.poll": "Prenos datoteke z anketami ni dovoljen.", "upload_form.description": "Opišite za slabovidne", - "upload_form.focus": "Obreži", + "upload_form.focus": "Spremeni predogled", "upload_form.undo": "Izbriši", "upload_progress.label": "Pošiljanje...", "video.close": "Zapri video", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 95bb7bd9d..37abc9e30 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Bazë", "home.column_settings.show_reblogs": "Shfaq përforcime", "home.column_settings.show_replies": "Shfaq përgjigje", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Titull liste të re", "lists.search": "Kërkoni mes personash që ndiqni", "lists.subheading": "Listat tuaja", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Po ngarkohet…", "media_gallery.toggle_visible": "Ndërroni dukshmërinë", "missing_indicator.label": "S’u gjet", @@ -311,6 +313,7 @@ "search_results.accounts": "Persona", "search_results.hashtags": "Hashtagë", "search_results.statuses": "Mesazhe", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, një {result} {results} të tjera}", "status.admin_account": "Hap ndërfaqe moderimi për @{name}", "status.admin_status": "Hape këtë gjendje te ndërfaqja e moderimit", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 17ce3964c..ad907b3a0 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -64,7 +64,7 @@ "column_header.show_settings": "Prikaži postavke", "column_header.unpin": "Otkači", "column_subheading.settings": "Postavke", - "community.column_settings.media_only": "Media Only", + "community.column_settings.media_only": "Media only", "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", "compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", @@ -156,6 +156,7 @@ "home.column_settings.basic": "Osnovno", "home.column_settings.show_reblogs": "Prikaži i podržavanja", "home.column_settings.show_replies": "Prikaži odgovore", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Naslov nove liste", "lists.search": "Pretraži među ljudima koje pratite", "lists.subheading": "Vaše liste", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Učitavam...", "media_gallery.toggle_visible": "Uključi/isključi vidljivost", "missing_indicator.label": "Nije pronađeno", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {rezultat} few {rezultata} other {rezultata}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index 8c430f6b3..555f49b51 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Основно", "home.column_settings.show_reblogs": "Прикажи и подржавања", "home.column_settings.show_replies": "Прикажи одговоре", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Наслов нове листе", "lists.search": "Претражи међу људима које пратите", "lists.subheading": "Ваше листе", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Учитавам...", "media_gallery.toggle_visible": "Укључи/искључи видљивост", "missing_indicator.label": "Није пронађено", @@ -311,6 +313,7 @@ "search_results.accounts": "Људи", "search_results.hashtags": "Тарабе", "search_results.statuses": "Трубе", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {резултат} few {резултата} other {резултата}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 52bf6e826..37945aabe 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Grundläggande", "home.column_settings.show_reblogs": "Visa knuffar", "home.column_settings.show_replies": "Visa svar", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Ny listrubrik", "lists.search": "Sök bland personer du följer", "lists.subheading": "Dina listor", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Laddar...", "media_gallery.toggle_visible": "Växla synlighet", "missing_indicator.label": "Hittades inte", @@ -311,6 +313,7 @@ "search_results.accounts": "Människor", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, ett {result} andra {results}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json index cc384e7ed..87163e660 100644 --- a/app/javascript/mastodon/locales/ta.json +++ b/app/javascript/mastodon/locales/ta.json @@ -1,385 +1,391 @@ { - "account.add_or_remove_from_list": "Add or Remove from lists", - "account.badges.bot": "Bot", + "account.add_or_remove_from_list": "பட்டியல்களில் இருந்து சேர் அல்லது நீக்குக", + "account.badges.bot": "பாட்", "account.block": "Block @{name}", - "account.block_domain": "Hide everything from {domain}", - "account.blocked": "Blocked", - "account.direct": "Direct message @{name}", - "account.domain_blocked": "Domain hidden", - "account.edit_profile": "Edit profile", - "account.endorse": "Feature on profile", - "account.follow": "Follow", - "account.followers": "Followers", - "account.followers.empty": "No one follows this user yet.", - "account.follows": "Follows", - "account.follows.empty": "This user doesn't follow anyone yet.", - "account.follows_you": "Follows you", - "account.hide_reblogs": "Hide boosts from @{name}", - "account.link_verified_on": "Ownership of this link was checked on {date}", - "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.", + "account.block_domain": "எல்லாவற்றையும் மறைக்க {domain}", + "account.blocked": "தடைமுட்டுகள்", + "account.direct": "நேரடி செய்தி @{name}", + "account.domain_blocked": "டொமைன் மறைக்கப்பட்டது", + "account.edit_profile": "சுயவிவரத்தைத் திருத்தவும்", + "account.endorse": "சுயவிவரத்தில் அம்சம்", + "account.follow": "பின்பற்று", + "account.followers": "பின்பற்றுபவர்கள்", + "account.followers.empty": "இதுவரை யாரும் இந்த பயனரைப் பின்தொடரவில்லை.", + "account.follows": "பின்பற்று", + "account.follows.empty": "இந்த பயனர் இதுவரை யாரையும் பின்தொடரவில்லை.", + "account.follows_you": "நீ பின் தொடர்கிறாய்", + "account.hide_reblogs": "இருந்து ஊக்கியாக மறை @{name}", + "account.link_verified_on": "இந்த இணைப்பை உரிமையாளர் சரிபார்க்கப்பட்டது {date}", + "account.locked_info": "இந்தக் கணக்கு தனியுரிமை நிலை பூட்டப்பட்டுள்ளது. அவர்களைப் பின்தொடர்பவர் யார் என்பதை உரிமையாளர் கைமுறையாக மதிப்பாய்வு செய்கிறார்.", "account.media": "Media", - "account.mention": "Mention @{name}", - "account.moved_to": "{name} has moved to:", - "account.mute": "Mute @{name}", - "account.mute_notifications": "Mute notifications from @{name}", - "account.muted": "Muted", + "account.mention": "குறிப்பிடு @{name}", + "account.moved_to": "{name} நகர்த்தப்பட்டது:", + "account.mute": "ஊமையான @{name}", + "account.mute_notifications": "அறிவிப்புகளை முடக்கு @{name}", + "account.muted": "முடக்கியது", "account.posts": "Toots", - "account.posts_with_replies": "Toots and replies", + "account.posts_with_replies": "Toots மற்றும் பதில்கள்", "account.report": "Report @{name}", - "account.requested": "Awaiting approval. Click to cancel follow request", - "account.share": "Share @{name}'s profile", - "account.show_reblogs": "Show boosts from @{name}", - "account.unblock": "Unblock @{name}", - "account.unblock_domain": "Unhide {domain}", - "account.unendorse": "Don't feature on profile", - "account.unfollow": "Unfollow", - "account.unmute": "Unmute @{name}", - "account.unmute_notifications": "Unmute notifications from @{name}", - "alert.unexpected.message": "An unexpected error occurred.", - "alert.unexpected.title": "Oops!", - "boost_modal.combo": "You can press {combo} to skip this next time", - "bundle_column_error.body": "Something went wrong while loading this component.", - "bundle_column_error.retry": "Try again", + "account.requested": "ஒப்புதலுக்காக காத்திருக்கிறது. கோரிக்கையை ரத்துசெய்ய கிளிக் செய்க", + "account.share": "பங்கிடு @{name}'s மனித முகத்தின்", + "account.show_reblogs": "காட்டு boosts இருந்து @{name}", + "account.unblock": "விடுவி @{name}", + "account.unblock_domain": "காண்பி {domain}", + "account.unendorse": "சுயவிவரத்தில் அம்சம் இல்லை", + "account.unfollow": "பின்தொடராட்", + "account.unmute": "தடுப்புநீக்கு @{name}", + "account.unmute_notifications": "அறிவிப்புகளை அகற்றவும் @{name}", + "alert.unexpected.message": "எதிர் பாராத பிழை ஏற்பட்டு விட்டது.", + "alert.unexpected.title": "அச்சச்சோ!", + "boost_modal.combo": "நீங்கள் அழுத்தவும் {combo} அடுத்த முறை தவிர்க்கவும்", + "bundle_column_error.body": "இந்த கூறுகளை ஏற்றும்போது ஏதோ தவறு ஏற்பட்டது.", + "bundle_column_error.retry": "மீண்டும் முயற்சி செய்", "bundle_column_error.title": "Network error", - "bundle_modal_error.close": "Close", - "bundle_modal_error.message": "Something went wrong while loading this component.", - "bundle_modal_error.retry": "Try again", - "column.blocks": "Blocked users", - "column.community": "Local timeline", - "column.direct": "Direct messages", - "column.domain_blocks": "Hidden domains", - "column.favourites": "Favourites", - "column.follow_requests": "Follow requests", + "bundle_modal_error.close": "நெருக்கமாக", + "bundle_modal_error.message": "இந்த கூறுகளை ஏற்றும்போது ஏதோ தவறு ஏற்பட்டது.", + "bundle_modal_error.retry": "மீண்டும் முயற்சி செய்", + "column.blocks": "தடுக்கப்பட்ட பயனர்கள்", + "column.community": "உள்ளூர் காலக்கெடு", + "column.direct": "நேரடி செய்திகள்", + "column.domain_blocks": "மறைந்த களங்கள்", + "column.favourites": "விருப்பத்துக்குகந்த", + "column.follow_requests": "கோரிக்கைகளை பின்பற்றவும்", "column.home": "Home", - "column.lists": "Lists", - "column.mutes": "Muted users", + "column.lists": "குதிரை வீர்ர்கள்", + "column.mutes": "முடக்கப்பட்ட பயனர்கள்", "column.notifications": "Notifications", "column.pins": "Pinned toot", - "column.public": "Federated timeline", - "column_back_button.label": "Back", - "column_header.hide_settings": "Hide settings", - "column_header.moveLeft_settings": "Move column to the left", - "column_header.moveRight_settings": "Move column to the right", - "column_header.pin": "Pin", - "column_header.show_settings": "Show settings", - "column_header.unpin": "Unpin", - "column_subheading.settings": "Settings", - "community.column_settings.media_only": "Media Only", + "column.public": "கூட்டாட்சி காலக்கெடு", + "column_back_button.label": "ஆதரி", + "column_header.hide_settings": "அமைப்புகளை மறை", + "column_header.moveLeft_settings": "நெடுவரிசையை இடதுபுறமாக நகர்த்தவும்", + "column_header.moveRight_settings": "நெடுவரிசை வலது புறமாக நகர்த்து", + "column_header.pin": "குண்டூசி", + "column_header.show_settings": "அமைப்புகளைக் காட்டு", + "column_header.unpin": "பொருத்தப்படாத", + "column_subheading.settings": "அமைப்புகள்", + "community.column_settings.media_only": "மீடியா மட்டுமே", "compose_form.direct_message_warning": "This toot will only be sent to all the mentioned users.", - "compose_form.direct_message_warning_learn_more": "Learn more", - "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", - "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", - "compose_form.lock_disclaimer.lock": "locked", + "compose_form.direct_message_warning_learn_more": "மேலும் அறிக", + "compose_form.hashtag_warning": "இந்த toot பட்டியலிடப்படாதது போல எந்த ஹேஸ்டேக்கின் கீழ் பட்டியலிடப்படாது. ஹேஸ்டேக் மூலம் பொது டோட்டல்கள் மட்டுமே தேட முடியும்.", + "compose_form.lock_disclaimer": "உங்கள் கணக்கு அல்ல {locked}. உங்களுடைய பின்தொடர்பவர் மட்டும் இடுகைகளை யாராவது காணலாம்.", + "compose_form.lock_disclaimer.lock": "தாழிடு", "compose_form.placeholder": "What is on your mind?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.poll.add_option": "ஒரு விருப்பத்தைச் சேர்க்கவும்", + "compose_form.poll.duration": "வாக்கெடுப்பு காலம்", + "compose_form.poll.option_placeholder": "தேர்ந்தெடுப்ப {number}", + "compose_form.poll.remove_option": "இந்த விருப்பத்தை அகற்றவும்", "compose_form.publish": "Toot", "compose_form.publish_loud": "{publish}!", "compose_form.sensitive.hide": "Mark media as sensitive", - "compose_form.sensitive.marked": "Media is marked as sensitive", - "compose_form.sensitive.unmarked": "Media is not marked as sensitive", - "compose_form.spoiler.marked": "Text is hidden behind warning", - "compose_form.spoiler.unmarked": "Text is not hidden", - "compose_form.spoiler_placeholder": "Write your warning here", - "confirmation_modal.cancel": "Cancel", + "compose_form.sensitive.marked": "ஊடகம் உணர்திறன் என குறிக்கப்பட்டுள்ளது", + "compose_form.sensitive.unmarked": "ஊடகம் உணர்திறன் என குறிக்கப்படவில்லை", + "compose_form.spoiler.marked": "எச்சரிக்கை பின்னால் உரை மறைக்கப்பட்டுள்ளது", + "compose_form.spoiler.unmarked": "உரை மறைக்கப்படவில்லை", + "compose_form.spoiler_placeholder": "இங்கே உங்கள் எச்சரிக்கையை எழுதுங்கள்", + "confirmation_modal.cancel": "எதிராணை", "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Block", - "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.block.message": "நீங்கள் நிச்சயமாக தடைசெய்ய விரும்புகிறீர்களா {name}?", "confirmations.delete.confirm": "Delete", - "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.delete.message": "இந்த நிலையை நிச்சயமாக நீக்க விரும்புகிறீர்களா?", "confirmations.delete_list.confirm": "Delete", - "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?", - "confirmations.domain_block.confirm": "Hide entire domain", - "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.", - "confirmations.mute.confirm": "Mute", - "confirmations.mute.message": "Are you sure you want to mute {name}?", - "confirmations.redraft.confirm": "Delete & redraft", - "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.", - "confirmations.reply.confirm": "Reply", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", - "confirmations.unfollow.confirm": "Unfollow", - "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?", - "embed.instructions": "Embed this status on your website by copying the code below.", - "embed.preview": "Here is what it will look like:", - "emoji_button.activity": "Activity", - "emoji_button.custom": "Custom", - "emoji_button.flags": "Flags", - "emoji_button.food": "Food & Drink", + "confirmations.delete_list.message": "இந்த பட்டியலில் நிரந்தரமாக நீக்க விரும்புகிறீர்களா?", + "confirmations.domain_block.confirm": "முழு டொமைனை மறை", + "confirmations.domain_block.message": "நீங்கள் உண்மையில், நிச்சயமாக நீங்கள் முழு தடுக்க வேண்டும் நிச்சயமாக {domain}? பெரும்பாலான சந்தர்ப்பங்களில் ஒரு சில இலக்குகள் அல்லது மியூட்கள் போதுமானவை மற்றும் சிறந்தவை. எந்த பொது நேரத்திலும் அல்லது உங்கள் அறிவிப்புகளிலும் அந்தக் களத்திலிருந்து உள்ளடக்கத்தை நீங்கள் பார்க்க மாட்டீர்கள். அந்த களத்தில் இருந்து உங்கள் ஆதரவாளர்கள் அகற்றப்படுவார்கள்.", + "confirmations.mute.confirm": "ஊமையான", + "confirmations.mute.message": "நிச்சயமாக நீங்கள் முடக்க விரும்புகிறீர்களா {name}?", + "confirmations.redraft.confirm": "நீக்கு & redraft", + "confirmations.redraft.message": "நிச்சயமாக இந்த நிலையை நீக்கி, அதை மறுபடியும் உருவாக்க வேண்டுமா? பிடித்தவை மற்றும் ஊக்கங்கள் இழக்கப்படும், மற்றும் அசல் இடுகையில் பதில்கள் அனாதையான இருக்கும்.", + "confirmations.reply.confirm": "பதில்", + "confirmations.reply.message": "இப்போது பதில், தற்போது நீங்கள் உருவாக்கும் செய்தி மேலெழுதப்படும். நீங்கள் தொடர விரும்புகிறீர்களா?", + "confirmations.unfollow.confirm": "பின்தொடராட்", + "confirmations.unfollow.message": "நிச்சயமாக நீங்கள் பின்தொடர விரும்புகிறீர்களா {name}?", + "embed.instructions": "கீழே உள்ள குறியீட்டை நகலெடுப்பதன் மூலம் உங்கள் இணையதளத்தில் இந்த நிலையை உட்பொதிக்கவும்.", + "embed.preview": "இது போன்ற தோற்றத்தை இங்கு காணலாம்:", + "emoji_button.activity": "நடவடிக்கை", + "emoji_button.custom": "வழக்கம்", + "emoji_button.flags": "கொடி", + "emoji_button.food": "உணவு மற்றும் பானம்", "emoji_button.label": "Insert emoji", - "emoji_button.nature": "Nature", - "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", - "emoji_button.objects": "Objects", + "emoji_button.nature": "இயற்கை", + "emoji_button.not_found": "எமோஜோஸ் இல்லை! (╯°□°)╯︵ ┻━┻", + "emoji_button.objects": "மறுப்ப கூறு", "emoji_button.people": "People", - "emoji_button.recent": "Frequently used", - "emoji_button.search": "Search...", - "emoji_button.search_results": "Search results", + "emoji_button.recent": "அடிக்கடி பயன்படுத்தப்படும்", + "emoji_button.search": "தேடல்...", + "emoji_button.search_results": "தேடல் முடிவுகள்", "emoji_button.symbols": "Symbols", - "emoji_button.travel": "Travel & Places", - "empty_column.account_timeline": "No toots here!", - "empty_column.account_unavailable": "Profile unavailable", - "empty_column.blocks": "You haven't blocked any users yet.", - "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", - "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", - "empty_column.domain_blocks": "There are no hidden domains yet.", - "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", - "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", - "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", - "empty_column.hashtag": "There is nothing in this hashtag yet.", - "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", - "empty_column.home.public_timeline": "the public timeline", - "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", - "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.", - "empty_column.mutes": "You haven't muted any users yet.", - "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", - "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", - "follow_request.authorize": "Authorize", - "follow_request.reject": "Reject", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "emoji_button.travel": "சுற்றுலா மற்றும் இடங்கள்", + "empty_column.account_timeline": "இல்லை toots இங்கே!", + "empty_column.account_unavailable": "சுயவிவரம் கிடைக்கவில்லை", + "empty_column.blocks": "இதுவரை எந்த பயனர்களும் தடுக்கவில்லை.", + "empty_column.community": "உள்ளூர் காலக்கெடு காலியாக உள்ளது. பந்தை உருட்டிக்கொள்வதற்கு பகிரங்கமாக ஒன்றை எழுதுங்கள்!", + "empty_column.direct": "உங்களிடம் நேரடியான செய்திகள் எதுவும் இல்லை. நீங்கள் ஒன்றை அனுப்பி அல்லது பெறும் போது, அது இங்கே காண்பிக்கும்.", + "empty_column.domain_blocks": "இன்னும் மறைந்த களங்கள் இல்லை.", + "empty_column.favourited_statuses": "இதுவரை உங்களுக்கு பிடித்த டோட்டுகள் இல்லை. உங்களுக்கு பிடித்த ஒரு போது, அது இங்கே காண்பிக்கும்.", + "empty_column.favourites": "இதுவரை யாரும் இந்தத் தட்டுக்கு ஆதரவில்லை. யாராவது செய்தால், அவர்கள் இங்கே காண்பார்கள்.", + "empty_column.follow_requests": "உங்களுக்கு இன்னும் எந்தவொரு கோரிக்கைகளும் இல்லை. நீங்கள் ஒன்றைப் பெற்றுக்கொண்டால், அது இங்கே காண்பிக்கும்.", + "empty_column.hashtag": "இன்னும் இந்த ஹேஸ்டேக்கில் எதுவும் இல்லை.", + "empty_column.home": "உங்கள் வீட்டுக் காலம் காலியாக உள்ளது! வருகை {public} அல்லது தொடங்குவதற்கு தேடலைப் பயன்படுத்தலாம் மற்றும் பிற பயனர்களை சந்திக்கவும்.", + "empty_column.home.public_timeline": "பொது காலக்கெடு", + "empty_column.list": "இந்த பட்டியலில் இதுவரை எதுவும் இல்லை. இந்த பட்டியலின் உறுப்பினர்கள் புதிய நிலைகளை இடுகையிடுகையில், அவை இங்கே தோன்றும்.", + "empty_column.lists": "உங்களுக்கு இதுவரை எந்த பட்டியலும் இல்லை. நீங்கள் ஒன்றை உருவாக்கினால், அது இங்கே காண்பிக்கும்.", + "empty_column.mutes": "நீங்கள் இதுவரை எந்த பயனர்களையும் முடக்கியிருக்கவில்லை.", + "empty_column.notifications": "உங்களிடம் எந்த அறிவிப்புகளும் இல்லை. உரையாடலைத் தொடங்க பிறருடன் தொடர்புகொள்ளவும்.", + "empty_column.public": "இங்கே எதுவும் இல்லை! பகிரங்கமாக ஒன்றை எழுதவும் அல்லது மற்ற நிகழ்வுகளிலிருந்து பயனர்களை அதை நிரப்புவதற்கு கைமுறையாக பின்பற்றவும்", + "follow_request.authorize": "அதிகாரமளி", + "follow_request.reject": "விலக்கு", + "getting_started.developers": "உருவாக்குநர்கள்", + "getting_started.directory": "சுயவிவர அடைவு", "getting_started.documentation": "Documentation", - "getting_started.heading": "Getting started", - "getting_started.invite": "Invite people", - "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", - "getting_started.security": "Security", - "getting_started.terms": "Terms of service", - "hashtag.column_header.tag_mode.all": "and {additional}", - "hashtag.column_header.tag_mode.any": "or {additional}", - "hashtag.column_header.tag_mode.none": "without {additional}", - "hashtag.column_settings.select.no_options_message": "No suggestions found", - "hashtag.column_settings.select.placeholder": "Enter hashtags…", - "hashtag.column_settings.tag_mode.all": "All of these", - "hashtag.column_settings.tag_mode.any": "Any of these", - "hashtag.column_settings.tag_mode.none": "None of these", - "hashtag.column_settings.tag_toggle": "Include additional tags in this column", - "home.column_settings.basic": "Basic", - "home.column_settings.show_reblogs": "Show boosts", - "home.column_settings.show_replies": "Show replies", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", - "introduction.federation.action": "Next", + "getting_started.heading": "தொடங்குதல்", + "getting_started.invite": "நபர்களை அழைக்கவும்", + "getting_started.open_source_notice": "Mastodon திறந்த மூல மென்பொருள். GitHub இல் நீங்கள் பங்களிக்கவோ அல்லது புகார் அளிக்கவோ முடியும் {github}.", + "getting_started.security": "பத்திரம்", + "getting_started.terms": "சேவை விதிமுறைகள்", + "hashtag.column_header.tag_mode.all": "மற்றும் {additional}", + "hashtag.column_header.tag_mode.any": "அல்லது {additional}", + "hashtag.column_header.tag_mode.none": "இல்லாமல் {additional}", + "hashtag.column_settings.select.no_options_message": "பரிந்துரைகள் எதுவும் இல்லை", + "hashtag.column_settings.select.placeholder": "ஹாஷ்டேகுகளை உள்ளிடவும் …", + "hashtag.column_settings.tag_mode.all": "இவை அனைத்தும்", + "hashtag.column_settings.tag_mode.any": "இவை எதையும்", + "hashtag.column_settings.tag_mode.none": "இவற்றில் ஏதுமில்லை", + "hashtag.column_settings.tag_toggle": "இந்த நெடுவரிசையில் கூடுதல் குறிச்சொற்களை சேர்க்கவும்", + "home.column_settings.basic": "அடிப்படையான", + "home.column_settings.show_reblogs": "காட்டு boosts", + "home.column_settings.show_replies": "பதில்களைக் காண்பி", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, one {# day} மற்ற {# days}}", + "intervals.full.hours": "{number, plural, one {# hour} மற்ற {# hours}}", + "intervals.full.minutes": "{number, plural, one {# minute} மற்ற {# minutes}}", + "introduction.federation.action": "அடுத்த", "introduction.federation.federated.headline": "Federated", - "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.", + "introduction.federation.federated.text": "கூட்டமைப்பின் பிற சேவையகங்களிலிருந்து பொது பதிவுகள் கூட்டப்பட்ட காலக்கெடுவில் தோன்றும்.", "introduction.federation.home.headline": "Home", - "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!", + "introduction.federation.home.text": "நீங்கள் பின்பற்றும் நபர்களின் இடுகைகள் உங்கள் வீட்டு ஊட்டத்தில் தோன்றும். நீங்கள் எந்த சர்வரில் யாரையும் பின்பற்ற முடியும்!", "introduction.federation.local.headline": "Local", - "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.", - "introduction.interactions.action": "Finish tutorial!", - "introduction.interactions.favourite.headline": "Favourite", - "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", - "introduction.interactions.reblog.headline": "Boost", - "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", - "introduction.interactions.reply.headline": "Reply", - "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", - "introduction.welcome.action": "Let's go!", - "introduction.welcome.headline": "First steps", - "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.", - "keyboard_shortcuts.back": "to navigate back", - "keyboard_shortcuts.blocked": "to open blocked users list", - "keyboard_shortcuts.boost": "to boost", - "keyboard_shortcuts.column": "to focus a status in one of the columns", - "keyboard_shortcuts.compose": "to focus the compose textarea", + "introduction.federation.local.text": "உள்ளூர் சேவையகத்தில் தோன்றும் அதே சர்வரில் உள்ளவர்களின் பொது இடுகைகள்.", + "introduction.interactions.action": "பயிற்சி முடிக்க!", + "introduction.interactions.favourite.headline": "விருப்பத்துக்குகந்த", + "introduction.interactions.favourite.text": "நீங்கள் ஒரு காப்பாற்ற முடியும் toot பின்னர், மற்றும் ஆசிரியர் அதை நீங்கள் பிடித்திருக்கிறது என்று, அதை பிடித்திருக்கிறது என்று தெரியப்படுத்துங்கள்.", + "introduction.interactions.reblog.headline": "மதிப்பை உயர்த்து", + "introduction.interactions.reblog.text": "மற்றவர்களின் பகிர்ந்து கொள்ளலாம் toots உங்கள் ஆதரவாளர்களுடன் அவர்களை அதிகரிக்கும்.", + "introduction.interactions.reply.headline": "மறுமொழி கூறு", + "introduction.interactions.reply.text": "நீங்கள் மற்றவர்களுக்கும் உங்கள் சொந்த டோட்ட்களிற்கும் பதிலளிப்பீர்கள், இது ஒரு உரையாடலில் சங்கிலி ஒன்றாகச் சேரும்.", + "introduction.welcome.action": "போகலாம்!", + "introduction.welcome.headline": "முதல் படிகள்", + "introduction.welcome.text": "கூட்டாளிக்கு வருக! ஒரு சில நிமிடங்களில், பலவிதமான சேவையகங்களில் செய்திகளை உரையாட மற்றும் உங்கள் நண்பர்களிடம் பேச முடியும். ஆனால் இந்த சர்வர், {domain}, சிறப்பு - இது உங்கள் சுயவிவரத்தை வழங்குகிறது, எனவே அதன் பெயரை நினைவில் கொள்ளுங்கள்.", + "keyboard_shortcuts.back": "மீண்டும் செல்லவும்", + "keyboard_shortcuts.blocked": "தடுக்கப்பட்ட பயனர்களின் பட்டியலைத் திறக்க", + "keyboard_shortcuts.boost": "அதிகரிக்கும்", + "keyboard_shortcuts.column": "நெடுவரிசைகளில் ஒன்றில் நிலைக்கு கவனம் செலுத்த வேண்டும்", + "keyboard_shortcuts.compose": "தொகு உரைப்பகுதியை கவனத்தில் கொள்ளவும்", "keyboard_shortcuts.description": "Description", - "keyboard_shortcuts.direct": "to open direct messages column", - "keyboard_shortcuts.down": "to move down in the list", + "keyboard_shortcuts.direct": "நேரடி செய்திகள் பத்தி திறக்க", + "keyboard_shortcuts.down": "பட்டியலில் கீழே நகர்த்த", "keyboard_shortcuts.enter": "to open status", - "keyboard_shortcuts.favourite": "to favourite", - "keyboard_shortcuts.favourites": "to open favourites list", - "keyboard_shortcuts.federated": "to open federated timeline", + "keyboard_shortcuts.favourite": "பிடித்தது", + "keyboard_shortcuts.favourites": "பிடித்தவை பட்டியலை திறக்க", + "keyboard_shortcuts.federated": "ஒருங்கிணைந்த நேரத்தை திறக்க", "keyboard_shortcuts.heading": "Keyboard Shortcuts", - "keyboard_shortcuts.home": "to open home timeline", - "keyboard_shortcuts.hotkey": "Hotkey", - "keyboard_shortcuts.legend": "to display this legend", - "keyboard_shortcuts.local": "to open local timeline", - "keyboard_shortcuts.mention": "to mention author", - "keyboard_shortcuts.muted": "to open muted users list", - "keyboard_shortcuts.my_profile": "to open your profile", - "keyboard_shortcuts.notifications": "to open notifications column", - "keyboard_shortcuts.pinned": "to open pinned toots list", - "keyboard_shortcuts.profile": "to open author's profile", - "keyboard_shortcuts.reply": "to reply", - "keyboard_shortcuts.requests": "to open follow requests list", - "keyboard_shortcuts.search": "to focus search", - "keyboard_shortcuts.start": "to open \"get started\" column", - "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW", - "keyboard_shortcuts.toot": "to start a brand new toot", - "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", - "keyboard_shortcuts.up": "to move up in the list", - "lightbox.close": "Close", - "lightbox.next": "Next", - "lightbox.previous": "Previous", + "keyboard_shortcuts.home": "வீட்டு நேரத்தை திறக்க", + "keyboard_shortcuts.hotkey": "ஹாட் கீ", + "keyboard_shortcuts.legend": "இந்த புராணத்தை காட்சிப்படுத்த", + "keyboard_shortcuts.local": "உள்ளூர் காலவரிசை திறக்க", + "keyboard_shortcuts.mention": "எழுத்தாளர் குறிப்பிட வேண்டும்", + "keyboard_shortcuts.muted": "முடக்கப்பட்ட பயனர்களின் பட்டியலைத் திறக்க", + "keyboard_shortcuts.my_profile": "உங்கள் சுயவிவரத்தை திறக்க", + "keyboard_shortcuts.notifications": "அறிவிப்பு நெடுவரிசையைத் திறக்க", + "keyboard_shortcuts.pinned": "திறக்க பொருத்தப்பட்டன toots பட்டியல்", + "keyboard_shortcuts.profile": "ஆசிரியரின் சுயவிவரத்தைத் திறக்க", + "keyboard_shortcuts.reply": "பதிலளிக்க", + "keyboard_shortcuts.requests": "கோரிக்கைகள் பட்டியலைத் திறக்க", + "keyboard_shortcuts.search": "தேடல் கவனம் செலுத்த", + "keyboard_shortcuts.start": "'தொடங்குவதற்கு' நெடுவரிசை திறக்க", + "keyboard_shortcuts.toggle_hidden": "CW க்கு பின்னால் உரையை மறைக்க / மறைக்க", + "keyboard_shortcuts.toggle_sensitivity": "to show/hide media", + "keyboard_shortcuts.toot": "தொடங்க ஒரு புதிய toot", + "keyboard_shortcuts.unfocus": "உரை பகுதியை / தேடலை கவனம் செலுத்த வேண்டும்", + "keyboard_shortcuts.up": "பட்டியலில் மேலே செல்ல", + "lightbox.close": "நெருக்கமாக", + "lightbox.next": "அடுத்த", + "lightbox.previous": "சென்ற", "lightbox.view_context": "View context", - "lists.account.add": "Add to list", - "lists.account.remove": "Remove from list", + "lists.account.add": "பட்டியலில் சேர்", + "lists.account.remove": "பட்டியலில் இருந்து அகற்று", "lists.delete": "Delete list", - "lists.edit": "Edit list", - "lists.edit.submit": "Change title", - "lists.new.create": "Add list", - "lists.new.title_placeholder": "New list title", - "lists.search": "Search among people you follow", - "lists.subheading": "Your lists", - "loading_indicator.label": "Loading...", - "media_gallery.toggle_visible": "Toggle visibility", - "missing_indicator.label": "Not found", - "missing_indicator.sublabel": "This resource could not be found", - "mute_modal.hide_notifications": "Hide notifications from this user?", - "navigation_bar.apps": "Mobile apps", - "navigation_bar.blocks": "Blocked users", - "navigation_bar.community_timeline": "Local timeline", - "navigation_bar.compose": "Compose new toot", - "navigation_bar.direct": "Direct messages", - "navigation_bar.discover": "Discover", - "navigation_bar.domain_blocks": "Hidden domains", - "navigation_bar.edit_profile": "Edit profile", - "navigation_bar.favourites": "Favourites", - "navigation_bar.filters": "Muted words", - "navigation_bar.follow_requests": "Follow requests", - "navigation_bar.info": "About this instance", - "navigation_bar.keyboard_shortcuts": "Hotkeys", - "navigation_bar.lists": "Lists", - "navigation_bar.logout": "Logout", - "navigation_bar.mutes": "Muted users", + "lists.edit": "பட்டியலை திருத்து", + "lists.edit.submit": "தலைப்பு மாற்றவும்", + "lists.new.create": "பட்டியலில் சேர்", + "lists.new.title_placeholder": "புதிய பட்டியல் தலைப்பு", + "lists.search": "நீங்கள் பின்தொடரும் நபர்கள் மத்தியில் தேடுதல்", + "lists.subheading": "உங்கள் பட்டியல்கள்", + "load_pending": "{count, plural, one {# new item} other {# new items}}", + "loading_indicator.label": "ஏற்றுதல்...", + "media_gallery.toggle_visible": "நிலைமாற்று தெரியும்", + "missing_indicator.label": "கிடைக்கவில்லை", + "missing_indicator.sublabel": "இந்த ஆதாரத்தை காண முடியவில்லை", + "mute_modal.hide_notifications": "இந்த பயனரின் அறிவிப்புகளை மறைக்கவா?", + "navigation_bar.apps": "மொபைல் பயன்பாடுகள்", + "navigation_bar.blocks": "தடுக்கப்பட்ட பயனர்கள்", + "navigation_bar.community_timeline": "உள்ளூர் காலக்கெடு", + "navigation_bar.compose": "புதியவற்றை எழுதுக toot", + "navigation_bar.direct": "நேரடி செய்திகள்", + "navigation_bar.discover": "கண்டு பிடி", + "navigation_bar.domain_blocks": "மறைந்த களங்கள்", + "navigation_bar.edit_profile": "சுயவிவரத்தைத் திருத்தவும்", + "navigation_bar.favourites": "விருப்பத்துக்குகந்த", + "navigation_bar.filters": "முடக்கப்பட்ட வார்த்தைகள்", + "navigation_bar.follow_requests": "கோரிக்கைகளை பின்பற்றவும்", + "navigation_bar.follows_and_followers": "Follows and followers", + "navigation_bar.info": "இந்த நிகழ்வு பற்றி", + "navigation_bar.keyboard_shortcuts": "சுருக்குவிசைகள்", + "navigation_bar.lists": "குதிரை வீர்ர்கள்", + "navigation_bar.logout": "விடு பதிகை", + "navigation_bar.mutes": "முடக்கப்பட்ட பயனர்கள்", "navigation_bar.personal": "Personal", - "navigation_bar.pins": "Pinned toots", - "navigation_bar.preferences": "Preferences", - "navigation_bar.public_timeline": "Federated timeline", - "navigation_bar.security": "Security", - "notification.favourite": "{name} favourited your status", - "notification.follow": "{name} followed you", - "notification.mention": "{name} mentioned you", - "notification.poll": "A poll you have voted in has ended", - "notification.reblog": "{name} boosted your status", - "notifications.clear": "Clear notifications", - "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?", - "notifications.column_settings.alert": "Desktop notifications", - "notifications.column_settings.favourite": "Favourites:", - "notifications.column_settings.filter_bar.advanced": "Display all categories", - "notifications.column_settings.filter_bar.category": "Quick filter bar", - "notifications.column_settings.filter_bar.show": "Show", - "notifications.column_settings.follow": "New followers:", - "notifications.column_settings.mention": "Mentions:", - "notifications.column_settings.poll": "Poll results:", + "navigation_bar.pins": "பொருத்தப்பட்டன toots", + "navigation_bar.preferences": "விருப்பங்கள்", + "navigation_bar.profile_directory": "Profile directory", + "navigation_bar.public_timeline": "கூட்டாட்சி காலக்கெடு", + "navigation_bar.security": "பத்திரம்", + "notification.favourite": "{name} ஆர்வம் கொண்டவர், உங்கள் நிலை", + "notification.follow": "{name} நீங்கள் தொடர்ந்து வந்தீர்கள்", + "notification.mention": "{name} நீங்கள் குறிப்பிட்டுள்ளீர்கள்", + "notification.poll": "நீங்கள் வாக்களித்த வாக்கெடுப்பு முடிவடைந்தது", + "notification.reblog": "{name} உங்கள் நிலை அதிகரித்தது", + "notifications.clear": "அறிவிப்புகளை அழிக்கவும்", + "notifications.clear_confirmation": "உங்கள் எல்லா அறிவிப்புகளையும் நிரந்தரமாக அழிக்க விரும்புகிறீர்களா?", + "notifications.column_settings.alert": "டெஸ்க்டாப் அறிவிப்புகள்", + "notifications.column_settings.favourite": "பிடித்தவை:", + "notifications.column_settings.filter_bar.advanced": "எல்லா வகைகளையும் காட்டு", + "notifications.column_settings.filter_bar.category": "விரைவு வடிகட்டி பட்டை", + "notifications.column_settings.filter_bar.show": "காட்டு", + "notifications.column_settings.follow": "புதிய பின்பற்றுபவர்கள்:", + "notifications.column_settings.mention": "குறிப்பிடுகிறது:", + "notifications.column_settings.poll": "கருத்துக்கணிப்பு முடிவுகள்:", "notifications.column_settings.push": "Push notifications", - "notifications.column_settings.reblog": "Boosts:", - "notifications.column_settings.show": "Show in column", - "notifications.column_settings.sound": "Play sound", - "notifications.filter.all": "All", - "notifications.filter.boosts": "Boosts", - "notifications.filter.favourites": "Favourites", - "notifications.filter.follows": "Follows", - "notifications.filter.mentions": "Mentions", - "notifications.filter.polls": "Poll results", + "notifications.column_settings.reblog": "மதிப்பை உயர்த்து:", + "notifications.column_settings.show": "பத்தியில் காண்பி", + "notifications.column_settings.sound": "ஒலி விளையாட", + "notifications.filter.all": "எல்லா", + "notifications.filter.boosts": "மதிப்பை உயர்த்து", + "notifications.filter.favourites": "விருப்பத்துக்குகந்த", + "notifications.filter.follows": "பின்பற்று", + "notifications.filter.mentions": "குறிப்பிடுகிறார்", + "notifications.filter.polls": "கருத்துக்கணிப்பு முடிவுகள்", "notifications.group": "{count} notifications", - "poll.closed": "Closed", - "poll.refresh": "Refresh", - "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", - "poll.vote": "Vote", - "poll_button.add_poll": "Add a poll", - "poll_button.remove_poll": "Remove poll", - "privacy.change": "Adjust status privacy", - "privacy.direct.long": "Post to mentioned users only", - "privacy.direct.short": "Direct", - "privacy.private.long": "Post to followers only", - "privacy.private.short": "Followers-only", - "privacy.public.long": "Post to public timelines", + "poll.closed": "மூடிய", + "poll.refresh": "பத்துயிர்ப்ப?ட்டு", + "poll.total_votes": "{count, plural, one {# vote} மற்ற {# votes}}", + "poll.vote": "வாக்களி", + "poll_button.add_poll": "வாக்கெடுப்பைச் சேர்க்கவும்", + "poll_button.remove_poll": "வாக்கெடுப்பை அகற்று", + "privacy.change": "நிலை தனியுரிமை", + "privacy.direct.long": "குறிப்பிடப்பட்ட பயனர்களுக்கு மட்டுமே இடுகையிடவும்", + "privacy.direct.short": "நடத்து", + "privacy.private.long": "பின்தொடர்பவர்களுக்கு மட்டுமே இடுகை", + "privacy.private.short": "பின்பற்றுபவர்கள் மட்டும்", + "privacy.public.long": "பொது நேரங்களுக்கான இடுகை", "privacy.public.short": "Public", "privacy.unlisted.long": "Do not show in public timelines", - "privacy.unlisted.short": "Unlisted", - "regeneration_indicator.label": "Loading…", - "regeneration_indicator.sublabel": "Your home feed is being prepared!", + "privacy.unlisted.short": "பட்டியலிடப்படாத", + "regeneration_indicator.label": "சுமையேற்றம்…", + "regeneration_indicator.sublabel": "உங்கள் வீட்டு ஊட்டம் தயார் செய்யப்படுகிறது!", "relative_time.days": "{number}d", "relative_time.hours": "{number}h", - "relative_time.just_now": "now", + "relative_time.just_now": "இப்பொழுது", "relative_time.minutes": "{number}m", "relative_time.seconds": "{number}s", - "reply_indicator.cancel": "Cancel", - "report.forward": "Forward to {target}", - "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?", - "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:", - "report.placeholder": "Additional comments", + "reply_indicator.cancel": "எதிராணை", + "report.forward": "முன்னோக்கி {target}", + "report.forward_hint": "கணக்கு மற்றொரு சேவையகத்திலிருந்து வருகிறது. அறிக்கையின் அநாமதேய பிரதி ஒன்றை அனுப்பவும்.?", + "report.hint": "அறிக்கை உங்கள் மாதிரியாக மாற்றியமைக்கப்படும். கீழே உள்ள கணக்கை நீங்கள் ஏன் புகாரளிக்கிறீர்கள் என்பதற்கான விளக்கத்தை வழங்கலாம்:", + "report.placeholder": "கூடுதல் கருத்துரைகள்", "report.submit": "Submit", "report.target": "Report {target}", - "search.placeholder": "Search", - "search_popout.search_format": "Advanced search format", - "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", - "search_popout.tips.hashtag": "hashtag", + "search.placeholder": "தேடு", + "search_popout.search_format": "மேம்பட்ட தேடல் வடிவம்", + "search_popout.tips.full_text": "எளிமையான உரை நீங்கள் எழுதப்பட்ட, புகழ், அதிகரித்தது, அல்லது குறிப்பிட்டுள்ள, அதே போல் பயனர் பெயர்கள், காட்சி பெயர்கள், மற்றும் ஹேஸ்டேகைகளை கொண்டுள்ளது என்று நிலைகளை கொடுக்கிறது.", + "search_popout.tips.hashtag": "ஹேஸ்டேக்", "search_popout.tips.status": "status", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", + "search_popout.tips.text": "எளிய உரை காட்சி பெயர்கள், பயனர்பெயர்கள் மற்றும் ஹாஷ்டேட்களுடன் பொருந்துகிறது", "search_popout.tips.user": "user", "search_results.accounts": "People", - "search_results.hashtags": "Hashtags", + "search_results.hashtags": "ஹாஷ்டேக்குகளைச்", "search_results.statuses": "Toots", - "search_results.total": "{count, number} {count, plural, one {result} other {results}}", - "status.admin_account": "Open moderation interface for @{name}", - "status.admin_status": "Open this status in the moderation interface", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", + "search_results.total": "{count, number} {count, plural, one {result} மற்ற {results}}", + "status.admin_account": "மிதமான இடைமுகத்தை திறக்க @{name}", + "status.admin_status": "மிதமான இடைமுகத்தில் இந்த நிலையை திறக்கவும்", "status.block": "Block @{name}", - "status.cancel_reblog_private": "Unboost", - "status.cannot_reblog": "This post cannot be boosted", - "status.copy": "Copy link to status", + "status.cancel_reblog_private": "இல்லை பூஸ்ட்", + "status.cannot_reblog": "இந்த இடுகை அதிகரிக்க முடியாது", + "status.copy": "நிலைக்கு இணைப்பை நகலெடு", "status.delete": "Delete", - "status.detailed_status": "Detailed conversation view", - "status.direct": "Direct message @{name}", - "status.embed": "Embed", - "status.favourite": "Favourite", - "status.filtered": "Filtered", - "status.load_more": "Load more", - "status.media_hidden": "Media hidden", - "status.mention": "Mention @{name}", - "status.more": "More", - "status.mute": "Mute @{name}", - "status.mute_conversation": "Mute conversation", - "status.open": "Expand this status", - "status.pin": "Pin on profile", - "status.pinned": "Pinned toot", - "status.read_more": "Read more", - "status.reblog": "Boost", - "status.reblog_private": "Boost to original audience", - "status.reblogged_by": "{name} boosted", - "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", - "status.redraft": "Delete & re-draft", - "status.reply": "Reply", - "status.replyAll": "Reply to thread", + "status.detailed_status": "விரிவான உரையாடல் காட்சி", + "status.direct": "நேரடி செய்தி @{name}", + "status.embed": "கிடத்து", + "status.favourite": "விருப்பத்துக்குகந்த", + "status.filtered": "வடிகட்டு", + "status.load_more": "அதிகமாய் ஏற்று", + "status.media_hidden": "மீடியா மறைக்கப்பட்டது", + "status.mention": "குறிப்பிடு @{name}", + "status.more": "அதிக", + "status.mute": "ஊமையான @{name}", + "status.mute_conversation": "ஒலிதடு உரையாடல்", + "status.open": "இந்த நிலையை விரிவாக்கு", + "status.pin": "சுயவிவரத்தில் முள்", + "status.pinned": "பொருத்தப்பட்டன toot", + "status.read_more": "மேலும் வாசிக்க", + "status.reblog": "மதிப்பை உயர்த்து", + "status.reblog_private": "Boost அசல் பார்வையாளர்களுக்கு", + "status.reblogged_by": "{name} மதிப்பை உயர்த்து", + "status.reblogs.empty": "இதுவரை யாரும் இந்த மோதலை அதிகரிக்கவில்லை. யாராவது செய்தால், அவர்கள் இங்கே காண்பார்கள்.", + "status.redraft": "நீக்கு மற்றும் மீண்டும் வரைவு", + "status.reply": "பதில்", + "status.replyAll": "நூலுக்கு பதிலளிக்கவும்", "status.report": "Report @{name}", - "status.sensitive_warning": "Sensitive content", - "status.share": "Share", - "status.show_less": "Show less", - "status.show_less_all": "Show less for all", - "status.show_more": "Show more", - "status.show_more_all": "Show more for all", - "status.show_thread": "Show thread", - "status.unmute_conversation": "Unmute conversation", - "status.unpin": "Unpin from profile", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "status.sensitive_warning": "உணர்திறன் உள்ளடக்கம்", + "status.share": "பங்கிடு", + "status.show_less": "குறைவாகக் காண்பி", + "status.show_less_all": "அனைத்தையும் குறைவாக காட்டு", + "status.show_more": "மேலும் காட்ட", + "status.show_more_all": "அனைவருக்கும் மேலும் காட்டு", + "status.show_thread": "நூல் காட்டு", + "status.unmute_conversation": "ஊமையாக உரையாடல் இல்லை", + "status.unpin": "சுயவிவரத்திலிருந்து நீக்கவும்", + "suggestions.dismiss": "பரிந்துரை விலக்க", + "suggestions.header": "நீங்கள் ஆர்வமாக இருக்கலாம் …", "tabs_bar.federated_timeline": "Federated", "tabs_bar.home": "Home", "tabs_bar.local_timeline": "Local", "tabs_bar.notifications": "Notifications", - "tabs_bar.search": "Search", - "time_remaining.days": "{number, plural, one {# day} other {# days}} left", - "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", - "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", - "time_remaining.moments": "Moments remaining", - "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left", - "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking", - "ui.beforeunload": "Your draft will be lost if you leave Mastodon.", - "upload_area.title": "Drag & drop to upload", - "upload_button.label": "Add media (JPEG, PNG, GIF, WebM, MP4, MOV)", - "upload_error.limit": "File upload limit exceeded.", - "upload_error.poll": "File upload not allowed with polls.", - "upload_form.description": "Describe for the visually impaired", - "upload_form.focus": "Crop", + "tabs_bar.search": "தேடு", + "time_remaining.days": "{number, plural, one {# day} மற்ற {# days}} left", + "time_remaining.hours": "{number, plural, one {# hour} மற்ற {# hours}} left", + "time_remaining.minutes": "{number, plural, one {# minute} மற்ற {# minutes}} left", + "time_remaining.moments": "தருணங்கள் மீதமுள்ளன", + "time_remaining.seconds": "{number, plural, one {# second} மற்ற {# seconds}} left", + "trends.count_by_accounts": "{count} {rawCount, plural, one {person} மற்ற {people}} உரையாடு", + "ui.beforeunload": "நீங்கள் வெளியே சென்றால் உங்கள் வரைவு இழக்கப்படும் மஸ்தோடோன்.", + "upload_area.title": "பதிவேற்ற & இழுக்கவும்", + "upload_button.label": "மீடியாவைச் சேர்க்கவும் (JPEG, PNG, GIF, WebM, MP4, MOV)", + "upload_error.limit": "கோப்பு பதிவேற்ற வரம்பு மீறப்பட்டது.", + "upload_error.poll": "கோப்பு பதிவேற்றம் அனுமதிக்கப்படவில்லை.", + "upload_form.description": "பார்வையற்ற விவரிக்கவும்", + "upload_form.focus": "மாற்றம் முன்னோட்டம்", "upload_form.undo": "Delete", - "upload_progress.label": "Uploading...", - "video.close": "Close video", - "video.exit_fullscreen": "Exit full screen", - "video.expand": "Expand video", + "upload_progress.label": "ஏற்றுகிறது ...", + "video.close": "வீடியோவை மூடு", + "video.exit_fullscreen": "முழு திரையில் இருந்து வெளியேறவும்", + "video.expand": "வீடியோவை விரிவாக்கு", "video.fullscreen": "Full screen", - "video.hide": "Hide video", - "video.mute": "Mute sound", + "video.hide": "வீடியோவை மறை", + "video.mute": "ஒலி முடக்கவும்", "video.pause": "Pause", - "video.play": "Play", - "video.unmute": "Unmute sound" + "video.play": "விளையாடு", + "video.unmute": "ஒலி மெளனமாக இல்லை" } diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json index 39c697b0b..a1d719ec7 100644 --- a/app/javascript/mastodon/locales/te.json +++ b/app/javascript/mastodon/locales/te.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "ప్రాథమిక", "home.column_settings.show_reblogs": "బూస్ట్ లను చూపించు", "home.column_settings.show_replies": "ప్రత్యుత్తరాలను చూపించు", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "కొత్త జాబితా శీర్షిక", "lists.search": "మీరు అనుసరించే వ్యక్తులలో శోధించండి", "lists.subheading": "మీ జాబితాలు", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "లోడ్ అవుతోంది...", "media_gallery.toggle_visible": "దృశ్యమానతను టోగుల్ చేయండి", "missing_indicator.label": "దొరకలేదు", @@ -311,6 +313,7 @@ "search_results.accounts": "వ్యక్తులు", "search_results.hashtags": "హాష్ ట్యాగ్లు", "search_results.statuses": "టూట్లు", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "status.admin_account": "@{name} కొరకు సమన్వయ వినిమయసీమను తెరువు", "status.admin_status": "సమన్వయ వినిమయసీమలో ఈ స్టేటస్ ను తెరవండి", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 86997b70f..e8d7a27ed 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -11,12 +11,12 @@ "account.follow": "ติดตาม", "account.followers": "ผู้ติดตาม", "account.followers.empty": "ยังไม่มีใครติดตามผู้ใช้นี้", - "account.follows": "ติดตาม", + "account.follows": "การติดตาม", "account.follows.empty": "ผู้ใช้นี้ยังไม่ได้ติดตามใคร", "account.follows_you": "ติดตามคุณ", "account.hide_reblogs": "ซ่อนการดันจาก @{name}", "account.link_verified_on": "ตรวจสอบความเป็นเจ้าของของลิงก์นี้เมื่อ {date}", - "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.", + "account.locked_info": "มีการตั้งสถานะความเป็นส่วนตัวของบัญชีนี้เป็นล็อคอยู่ เจ้าของตรวจทานผู้ที่สามารถติดตามเขาด้วยตนเอง", "account.media": "สื่อ", "account.mention": "กล่าวถึง @{name}", "account.moved_to": "{name} ได้ย้ายไปยัง:", @@ -37,7 +37,7 @@ "account.unmute_notifications": "เลิกปิดเสียงการแจ้งเตือนจาก @{name}", "alert.unexpected.message": "เกิดข้อผิดพลาดที่ไม่คาดคิด", "alert.unexpected.title": "อุปส์!", - "boost_modal.combo": "You can press {combo} to skip this next time", + "boost_modal.combo": "คุณสามารถกด {combo} เพื่อข้ามสิ่งนี้ในครั้งถัดไป", "bundle_column_error.body": "มีบางอย่างผิดพลาดขณะโหลดส่วนประกอบนี้", "bundle_column_error.retry": "ลองอีกครั้ง", "bundle_column_error.title": "ข้อผิดพลาดเครือข่าย", @@ -65,23 +65,23 @@ "column_header.unpin": "ถอนหมุด", "column_subheading.settings": "การตั้งค่า", "community.column_settings.media_only": "สื่อเท่านั้น", - "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", + "compose_form.direct_message_warning": "จะส่งโพสต์นี้ไปยังผู้ใช้ที่กล่าวถึงเท่านั้น", "compose_form.direct_message_warning_learn_more": "เรียนรู้เพิ่มเติม", - "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", - "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", - "compose_form.lock_disclaimer.lock": "locked", - "compose_form.placeholder": "What is on your mind?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.hashtag_warning": "จะไม่แสดงรายการโพสต์นี้ภายใต้แฮชแท็กใด ๆ เนื่องจากไม่อยู่ในรายการ เฉพาะโพสต์สาธารณะเท่านั้นที่สามารถค้นหาโดยแฮชแท็ก", + "compose_form.lock_disclaimer": "บัญชีของคุณไม่ได้ {locked} ใครก็ตามสามารถติดตามคุณเพื่อดูโพสต์สำหรับผู้ติดตามเท่านั้นของคุณ", + "compose_form.lock_disclaimer.lock": "ล็อคอยู่", + "compose_form.placeholder": "คุณกำลังคิดอะไรอยู่?", + "compose_form.poll.add_option": "เพิ่มทางเลือก", + "compose_form.poll.duration": "ระยะเวลาการหยั่งเสียง", + "compose_form.poll.option_placeholder": "ทางเลือก {number}", + "compose_form.poll.remove_option": "เอาทางเลือกนี้ออก", "compose_form.publish": "โพสต์", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", - "compose_form.sensitive.marked": "Media is marked as sensitive", - "compose_form.sensitive.unmarked": "Media is not marked as sensitive", - "compose_form.spoiler.marked": "Text is hidden behind warning", - "compose_form.spoiler.unmarked": "Text is not hidden", + "compose_form.sensitive.hide": "ทำเครื่องหมายสื่อว่าละเอียดอ่อน", + "compose_form.sensitive.marked": "มีการทำเครื่องหมายสื่อว่าละเอียดอ่อน", + "compose_form.sensitive.unmarked": "ไม่มีการทำเครื่องหมายสื่อว่าละเอียดอ่อน", + "compose_form.spoiler.marked": "มีการซ่อนข้อความอยู่หลังคำเตือน", + "compose_form.spoiler.unmarked": "ไม่มีการซ่อนข้อความ", "compose_form.spoiler_placeholder": "เขียนคำเตือนของคุณที่นี่", "confirmation_modal.cancel": "ยกเลิก", "confirmations.block.block_and_report": "ปิดกั้นแล้วรายงาน", @@ -91,25 +91,25 @@ "confirmations.delete.message": "คุณแน่ใจหรือไม่ว่าต้องการลบสถานะนี้?", "confirmations.delete_list.confirm": "ลบ", "confirmations.delete_list.message": "คุณแน่ใจหรือไม่ว่าต้องการลบรายการนี้อย่างถาวร?", - "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.confirm": "ซ่อนทั้งโดเมน", "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "ปิดเสียง", "confirmations.mute.message": "คุณแน่ใจหรือไม่ว่าต้องการปิดเสียง {name}?", "confirmations.redraft.confirm": "ลบแล้วร่างใหม่", - "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.", + "confirmations.redraft.message": "คุณแน่ใจหรือไม่ว่าต้องการลบสถานะนี้แล้วร่างใหม่? รายการโปรดและการดันจะหายไป และการตอบกลับโพสต์ดั้งเดิมจะไม่มีความเกี่ยวพัน", "confirmations.reply.confirm": "ตอบกลับ", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.reply.message": "การตอบกลับตอนนี้จะเขียนทับข้อความที่คุณกำลังเขียน คุณแน่ใจหรือไม่ว่าต้องการดำเนินการต่อ?", "confirmations.unfollow.confirm": "เลิกติดตาม", "confirmations.unfollow.message": "คุณแน่ใจหรือไม่ว่าต้องการเลิกติดตาม {name}?", - "embed.instructions": "Embed this status on your website by copying the code below.", - "embed.preview": "Here is what it will look like:", + "embed.instructions": "ฝังสถานะนี้ในเว็บไซต์ของคุณโดยคัดลอกโค้ดด้านล่าง", + "embed.preview": "นี่คือลักษณะที่จะปรากฏ:", "emoji_button.activity": "กิจกรรม", "emoji_button.custom": "กำหนดเอง", "emoji_button.flags": "ธง", "emoji_button.food": "อาหารและเครื่องดื่ม", "emoji_button.label": "แทรกอีโมจิ", "emoji_button.nature": "ธรรมชาติ", - "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "ไม่มีอีโมโจ!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "วัตถุ", "emoji_button.people": "ผู้คน", "emoji_button.recent": "ที่ใช้บ่อย", @@ -118,22 +118,22 @@ "emoji_button.symbols": "สัญลักษณ์", "emoji_button.travel": "การเดินทางและสถานที่", "empty_column.account_timeline": "ไม่มีโพสต์ที่นี่!", - "empty_column.account_unavailable": "Profile unavailable", - "empty_column.blocks": "You haven't blocked any users yet.", - "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", - "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", + "empty_column.account_unavailable": "ไม่มีโปรไฟล์", + "empty_column.blocks": "คุณยังไม่ได้ปิดกั้นผู้ใช้ใด ๆ", + "empty_column.community": "เส้นเวลาในเว็บว่างเปล่า เขียนบางอย่างเป็นสาธารณะเพื่อเริ่มต้น!", + "empty_column.direct": "คุณยังไม่มีข้อความโดยตรงใด ๆ เมื่อคุณส่งหรือรับข้อความ ข้อความจะปรากฏที่นี่", "empty_column.domain_blocks": "ยังไม่มีโดเมนที่ซ่อนอยู่", - "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", - "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", - "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", - "empty_column.hashtag": "There is nothing in this hashtag yet.", - "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", + "empty_column.favourited_statuses": "คุณยังไม่มีโพสต์ที่ชื่นชอบใด ๆ เมื่อคุณชื่นชอบโพสต์ โพสต์จะปรากฏที่นี่", + "empty_column.favourites": "ยังไม่มีใครชื่นชอบโพสต์นี้ เมื่อใครสักคนชื่นชอบ เขาจะปรากฏที่นี่", + "empty_column.follow_requests": "คุณยังไม่มีคำขอติดตามใด ๆ เมื่อคุณได้รับคำขอ คำขอจะปรากฏที่นี่", + "empty_column.hashtag": "ยังไม่มีสิ่งใดในแฮชแท็กนี้", + "empty_column.home": "เส้นเวลาหน้าแรกของคุณว่างเปล่า! เยี่ยมชม {public} หรือใช้การค้นหาเพื่อเริ่มต้นใช้งานและพบปะผู้ใช้อื่น ๆ", "empty_column.home.public_timeline": "เส้นเวลาสาธารณะ", - "empty_column.list": "There is nothing in this list yet.", - "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.", - "empty_column.mutes": "You haven't muted any users yet.", - "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", - "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", + "empty_column.list": "ยังไม่มีสิ่งใดในรายการนี้ เมื่อสมาชิกของรายการนี้โพสต์สถานะใหม่ สถานะจะปรากฏที่นี่", + "empty_column.lists": "คุณยังไม่มีรายการใด ๆ เมื่อคุณสร้างรายการ รายการจะปรากฏที่นี่", + "empty_column.mutes": "คุณยังไม่ได้ปิดเสียงผู้ใช้ใด ๆ", + "empty_column.notifications": "คุณยังไม่มีการแจ้งเตือนใด ๆ โต้ตอบกับผู้อื่นเพื่อเริ่มการสนทนา", + "empty_column.public": "ไม่มีสิ่งใดที่นี่! เขียนบางอย่างเป็นสาธารณะ หรือติดตามผู้ใช้จากเซิร์ฟเวอร์อื่น ๆ ด้วยตนเองเพื่อเติมให้เต็ม", "follow_request.authorize": "อนุญาต", "follow_request.reject": "ปฏิเสธ", "getting_started.developers": "นักพัฒนา", @@ -141,7 +141,7 @@ "getting_started.documentation": "เอกสารประกอบ", "getting_started.heading": "เริ่มต้นใช้งาน", "getting_started.invite": "เชิญผู้คน", - "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", + "getting_started.open_source_notice": "Mastodon เป็นซอฟต์แวร์เปิดต้นฉบับ คุณสามารถมีส่วนร่วมหรือรายงานปัญหาใน GitHub ที่ {github}", "getting_started.security": "ความปลอดภัย", "getting_started.terms": "เงื่อนไขการให้บริการ", "hashtag.column_header.tag_mode.all": "และ {additional}", @@ -149,68 +149,70 @@ "hashtag.column_header.tag_mode.none": "โดยไม่มี {additional}", "hashtag.column_settings.select.no_options_message": "ไม่พบข้อเสนอแนะ", "hashtag.column_settings.select.placeholder": "ป้อนแฮชแท็ก…", - "hashtag.column_settings.tag_mode.all": "All of these", - "hashtag.column_settings.tag_mode.any": "Any of these", - "hashtag.column_settings.tag_mode.none": "None of these", - "hashtag.column_settings.tag_toggle": "Include additional tags in this column", + "hashtag.column_settings.tag_mode.all": "ทั้งหมดนี้", + "hashtag.column_settings.tag_mode.any": "ใดก็ตามนี้", + "hashtag.column_settings.tag_mode.none": "ไม่ใช่ทั้งหมดนี้", + "hashtag.column_settings.tag_toggle": "รวมแท็กเพิ่มเติมสำหรับคอลัมน์นี้", "home.column_settings.basic": "พื้นฐาน", "home.column_settings.show_reblogs": "แสดงการดัน", "home.column_settings.show_replies": "แสดงการตอบกลับ", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number, plural, other {# วัน}}", + "intervals.full.hours": "{number, plural, other {# ชั่วโมง}}", + "intervals.full.minutes": "{number, plural, other {# นาที}}", "introduction.federation.action": "ถัดไป", - "introduction.federation.federated.headline": "Federated", - "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.", - "introduction.federation.home.headline": "Home", - "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!", - "introduction.federation.local.headline": "Local", - "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.", - "introduction.interactions.action": "Finish tutorial!", - "introduction.interactions.favourite.headline": "Favourite", + "introduction.federation.federated.headline": "ที่ติดต่อกับภายนอก", + "introduction.federation.federated.text": "โพสต์สาธารณะจากเซิร์ฟเวอร์อื่น ๆ ของ Fediverse จะปรากฏในเส้นเวลาที่ติดต่อกับภายนอก", + "introduction.federation.home.headline": "หน้าแรก", + "introduction.federation.home.text": "โพสต์จากผู้คนที่คุณติดตามจะปรากฏในฟีดหน้าแรกของคุณ คุณสามารถติดตามใครก็ตามในเซิร์ฟเวอร์ใดก็ตาม!", + "introduction.federation.local.headline": "ในเว็บ", + "introduction.federation.local.text": "โพสต์สาธารณะจากผู้คนในเซิร์ฟเวอร์เดียวกันกับคุณจะปรากฏในเส้นเวลาในเว็บ", + "introduction.interactions.action": "เสร็จสิ้นบทช่วยสอน!", + "introduction.interactions.favourite.headline": "ชื่นชอบ", "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", - "introduction.interactions.reblog.headline": "Boost", + "introduction.interactions.reblog.headline": "ดัน", "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", - "introduction.interactions.reply.headline": "Reply", + "introduction.interactions.reply.headline": "ตอบกลับ", "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", - "introduction.welcome.action": "Let's go!", - "introduction.welcome.headline": "First steps", + "introduction.welcome.action": "ไปกันเลย!", + "introduction.welcome.headline": "ขั้นตอนแรก", "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.", - "keyboard_shortcuts.back": "to navigate back", - "keyboard_shortcuts.blocked": "to open blocked users list", - "keyboard_shortcuts.boost": "to boost", - "keyboard_shortcuts.column": "to focus a status in one of the columns", - "keyboard_shortcuts.compose": "to focus the compose textarea", + "keyboard_shortcuts.back": "เพื่อนำทางย้อนกลับ", + "keyboard_shortcuts.blocked": "เพื่อเปิดรายการผู้ใช้ที่ปิดกั้นอยู่", + "keyboard_shortcuts.boost": "เพื่อดัน", + "keyboard_shortcuts.column": "เพื่อโฟกัสสถานะในหนึ่งในคอลัมน์", + "keyboard_shortcuts.compose": "เพื่อโฟกัสพื้นที่เขียนข้อความ", "keyboard_shortcuts.description": "คำอธิบาย", - "keyboard_shortcuts.direct": "to open direct messages column", - "keyboard_shortcuts.down": "to move down in the list", - "keyboard_shortcuts.enter": "to open status", - "keyboard_shortcuts.favourite": "to favourite", - "keyboard_shortcuts.favourites": "to open favourites list", - "keyboard_shortcuts.federated": "to open federated timeline", - "keyboard_shortcuts.heading": "Keyboard Shortcuts", - "keyboard_shortcuts.home": "to open home timeline", + "keyboard_shortcuts.direct": "เพื่อเปิดคอลัมน์ข้อความโดยตรง", + "keyboard_shortcuts.down": "เพื่อย้ายลงในรายการ", + "keyboard_shortcuts.enter": "เพื่อเปิดสถานะ", + "keyboard_shortcuts.favourite": "เพื่อชื่นชอบ", + "keyboard_shortcuts.favourites": "เพื่อเปิดรายการโปรด", + "keyboard_shortcuts.federated": "เพื่อเปิดเส้นเวลาที่ติดต่อกับภายนอก", + "keyboard_shortcuts.heading": "แป้นพิมพ์ลัด", + "keyboard_shortcuts.home": "เพื่อเปิดเส้นเวลาหน้าแรก", "keyboard_shortcuts.hotkey": "ปุ่มลัด", - "keyboard_shortcuts.legend": "to display this legend", - "keyboard_shortcuts.local": "to open local timeline", - "keyboard_shortcuts.mention": "to mention author", - "keyboard_shortcuts.muted": "to open muted users list", - "keyboard_shortcuts.my_profile": "to open your profile", - "keyboard_shortcuts.notifications": "to open notifications column", - "keyboard_shortcuts.pinned": "to open pinned toots list", - "keyboard_shortcuts.profile": "to open author's profile", - "keyboard_shortcuts.reply": "to reply", - "keyboard_shortcuts.requests": "to open follow requests list", - "keyboard_shortcuts.search": "to focus search", - "keyboard_shortcuts.start": "to open \"get started\" column", - "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW", - "keyboard_shortcuts.toot": "to start a brand new toot", - "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", - "keyboard_shortcuts.up": "to move up in the list", + "keyboard_shortcuts.legend": "เพื่อแสดงคำอธิบายนี้", + "keyboard_shortcuts.local": "เพื่อเปิดเส้นเวลาในเว็บ", + "keyboard_shortcuts.mention": "เพื่อกล่าวถึงผู้สร้าง", + "keyboard_shortcuts.muted": "เพื่อเปิดรายการผู้ใช้ที่ปิดเสียงอยู่", + "keyboard_shortcuts.my_profile": "เพื่อเปิดโปรไฟล์ของคุณ", + "keyboard_shortcuts.notifications": "เพื่อเปิดคอลัมน์การแจ้งเตือน", + "keyboard_shortcuts.pinned": "เพื่อเปิดรายการโพสต์ที่ปักหมุด", + "keyboard_shortcuts.profile": "เพื่อเปิดโปรไฟล์ของผู้สร้าง", + "keyboard_shortcuts.reply": "เพื่อตอบกลับ", + "keyboard_shortcuts.requests": "เพื่อเปิดรายการคำขอติดตาม", + "keyboard_shortcuts.search": "เพื่อโฟกัสการค้นหา", + "keyboard_shortcuts.start": "เพื่อเปิดคอลัมน์ \"เริ่มต้นใช้งาน\"", + "keyboard_shortcuts.toggle_hidden": "เพื่อแสดง/ซ่อนข้อความที่อยู่หลังคำเตือนเนื้อหา", + "keyboard_shortcuts.toggle_sensitivity": "เพื่อแสดง/ซ่อนสื่อ", + "keyboard_shortcuts.toot": "เพื่อเริ่มโพสต์ใหม่", + "keyboard_shortcuts.unfocus": "เพื่อเลิกโฟกัสพื้นที่เขียนข้อความ/การค้นหา", + "keyboard_shortcuts.up": "เพื่อย้ายขึ้นในรายการ", "lightbox.close": "ปิด", "lightbox.next": "ถัดไป", "lightbox.previous": "ก่อนหน้า", - "lightbox.view_context": "View context", + "lightbox.view_context": "ดูบริบท", "lists.account.add": "เพิ่มไปยังรายการ", "lists.account.remove": "เอาออกจากรายการ", "lists.delete": "ลบรายการ", @@ -220,6 +222,7 @@ "lists.new.title_placeholder": "ชื่อเรื่องรายการใหม่", "lists.search": "ค้นหาในหมู่ผู้คนที่คุณติดตาม", "lists.subheading": "รายการของคุณ", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "กำลังโหลด...", "media_gallery.toggle_visible": "เปิด/ปิดการมองเห็น", "missing_indicator.label": "ไม่พบ", @@ -236,6 +239,7 @@ "navigation_bar.favourites": "รายการโปรด", "navigation_bar.filters": "คำที่ปิดเสียงอยู่", "navigation_bar.follow_requests": "คำขอติดตาม", + "navigation_bar.follows_and_followers": "การติดตามและผู้ติดตาม", "navigation_bar.info": "เกี่ยวกับเซิร์ฟเวอร์นี้", "navigation_bar.keyboard_shortcuts": "ปุ่มลัด", "navigation_bar.lists": "รายการ", @@ -244,23 +248,24 @@ "navigation_bar.personal": "ส่วนบุคคล", "navigation_bar.pins": "โพสต์ที่ปักหมุด", "navigation_bar.preferences": "การกำหนดลักษณะ", + "navigation_bar.profile_directory": "ไดเรกทอรีโปรไฟล์", "navigation_bar.public_timeline": "เส้นเวลาที่ติดต่อกับภายนอก", "navigation_bar.security": "ความปลอดภัย", "notification.favourite": "{name} ได้ชื่นชอบสถานะของคุณ", "notification.follow": "{name} ได้ติดตามคุณ", "notification.mention": "{name} ได้กล่าวถึงคุณ", - "notification.poll": "A poll you have voted in has ended", + "notification.poll": "การหยั่งเสียงที่คุณได้ลงคะแนนได้สิ้นสุดแล้ว", "notification.reblog": "{name} ได้ดันสถานะของคุณ", "notifications.clear": "ล้างการแจ้งเตือน", "notifications.clear_confirmation": "คุณแน่ใจหรือไม่ว่าต้องการล้างการแจ้งเตือนทั้งหมดของคุณอย่างถาวร?", - "notifications.column_settings.alert": "Desktop notifications", + "notifications.column_settings.alert": "การแจ้งเตือนบนเดสก์ท็อป", "notifications.column_settings.favourite": "รายการโปรด:", "notifications.column_settings.filter_bar.advanced": "แสดงหมวดหมู่ทั้งหมด", "notifications.column_settings.filter_bar.category": "แถบตัวกรองด่วน", "notifications.column_settings.filter_bar.show": "แสดง", "notifications.column_settings.follow": "ผู้ติดตามใหม่:", "notifications.column_settings.mention": "การกล่าวถึง:", - "notifications.column_settings.poll": "Poll results:", + "notifications.column_settings.poll": "ผลลัพธ์การหยั่งเสียง:", "notifications.column_settings.push": "การแจ้งเตือนแบบผลัก", "notifications.column_settings.reblog": "การดัน:", "notifications.column_settings.show": "แสดงในคอลัมน์", @@ -270,15 +275,15 @@ "notifications.filter.favourites": "รายการโปรด", "notifications.filter.follows": "การติดตาม", "notifications.filter.mentions": "การกล่าวถึง", - "notifications.filter.polls": "Poll results", + "notifications.filter.polls": "ผลลัพธ์การหยั่งเสียง", "notifications.group": "{count} การแจ้งเตือน", "poll.closed": "ปิดแล้ว", - "poll.refresh": "Refresh", - "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", - "poll.vote": "Vote", - "poll_button.add_poll": "Add a poll", - "poll_button.remove_poll": "Remove poll", - "privacy.change": "Adjust status privacy", + "poll.refresh": "รีเฟรช", + "poll.total_votes": "{count, plural, other {# การลงคะแนน}}", + "poll.vote": "ลงคะแนน", + "poll_button.add_poll": "เพิ่มการหยั่งเสียง", + "poll_button.remove_poll": "เอาการหยั่งเสียงออก", + "privacy.change": "ปรับเปลี่ยนความเป็นส่วนตัวของสถานะ", "privacy.direct.long": "โพสต์ไปยังผู้ใช้ที่กล่าวถึงเท่านั้น", "privacy.direct.short": "โดยตรง", "privacy.private.long": "โพสต์ไปยังผู้ติดตามเท่านั้น", @@ -288,7 +293,7 @@ "privacy.unlisted.long": "ไม่โพสต์ไปยังเส้นเวลาสาธารณะ", "privacy.unlisted.short": "ไม่อยู่ในรายการ", "regeneration_indicator.label": "กำลังโหลด…", - "regeneration_indicator.sublabel": "Your home feed is being prepared!", + "regeneration_indicator.sublabel": "กำลังเตรียมฟีดหน้าแรกของคุณ!", "relative_time.days": "{number} วัน", "relative_time.hours": "{number} ชั่วโมง", "relative_time.just_now": "ตอนนี้", @@ -296,22 +301,23 @@ "relative_time.seconds": "{number} วินาที", "reply_indicator.cancel": "ยกเลิก", "report.forward": "ส่งต่อไปยัง {target}", - "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?", - "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:", + "report.forward_hint": "บัญชีมาจากเซิร์ฟเวอร์อื่น ส่งสำเนาของรายงานที่ไม่ระบุตัวตนไปที่นั่นด้วย?", + "report.hint": "จะส่งรายงานไปยังผู้ควบคุมเซิร์ฟเวอร์ของคุณ คุณสามารถให้คำอธิบายเหตุผลที่คุณรายงานบัญชีนี้ด้านล่าง:", "report.placeholder": "ความคิดเห็นเพิ่มเติม", "report.submit": "ส่ง", "report.target": "กำลังรายงาน {target}", "search.placeholder": "ค้นหา", "search_popout.search_format": "รูปแบบการค้นหาขั้นสูง", - "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", + "search_popout.tips.full_text": "ข้อความแบบง่ายส่งคืนสถานะที่คุณได้เขียน ชื่นชอบ ดัน หรือได้รับการกล่าวถึง ตลอดจนชื่อผู้ใช้, ชื่อที่แสดง และแฮชแท็กที่ตรงกัน", "search_popout.tips.hashtag": "แฮชแท็ก", "search_popout.tips.status": "สถานะ", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", + "search_popout.tips.text": "ข้อความแบบง่ายส่งคืนชื่อที่แสดง, ชื่อผู้ใช้ และแฮชแท็กที่ตรงกัน", "search_popout.tips.user": "ผู้ใช้", "search_results.accounts": "ผู้คน", "search_results.hashtags": "แฮชแท็ก", "search_results.statuses": "โพสต์", - "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", + "search_results.total": "{count, number} {count, plural, other {ผลลัพธ์}}", "status.admin_account": "เปิดส่วนติดต่อการควบคุมสำหรับ @{name}", "status.admin_status": "เปิดสถานะนี้ในส่วนติดต่อการควบคุม", "status.block": "ปิดกั้น @{name}", @@ -321,7 +327,7 @@ "status.delete": "ลบ", "status.detailed_status": "มุมมองการสนทนาโดยละเอียด", "status.direct": "ส่งข้อความโดยตรงถึง @{name}", - "status.embed": "Embed", + "status.embed": "ฝัง", "status.favourite": "ชื่นชอบ", "status.filtered": "กรองอยู่", "status.load_more": "โหลดเพิ่มเติม", @@ -337,7 +343,7 @@ "status.reblog": "ดัน", "status.reblog_private": "ดันไปยังผู้ชมดั้งเดิม", "status.reblogged_by": "{name} ได้ดัน", - "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", + "status.reblogs.empty": "ยังไม่มีใครดันโพสต์นี้ เมื่อใครสักคนดัน เขาจะปรากฏที่นี่", "status.redraft": "ลบแล้วร่างใหม่", "status.reply": "ตอบกลับ", "status.replyAll": "ตอบกลับกระทู้", @@ -358,18 +364,18 @@ "tabs_bar.local_timeline": "ในเว็บ", "tabs_bar.notifications": "การแจ้งเตือน", "tabs_bar.search": "ค้นหา", - "time_remaining.days": "{number, plural, one {# day} other {# days}} left", - "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", - "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", - "time_remaining.moments": "Moments remaining", - "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left", + "time_remaining.days": "เหลืออีก {number, plural, other {# วัน}}", + "time_remaining.hours": "เหลืออีก {number, plural, other {# ชั่วโมง}}", + "time_remaining.minutes": "เหลืออีก {number, plural, other {# นาที}}", + "time_remaining.moments": "ช่วงเวลาที่เหลือ", + "time_remaining.seconds": "เหลืออีก {number, plural, other {# วินาที}}", "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking", "ui.beforeunload": "แบบร่างของคุณจะหายไปหากคุณออกจาก Mastodon", "upload_area.title": "ลากแล้วปล่อยเพื่ออัปโหลด", "upload_button.label": "เพิ่มสื่อ (JPEG, PNG, GIF, WebM, MP4, MOV)", "upload_error.limit": "เกินขีดจำกัดการอัปโหลดไฟล์", - "upload_error.poll": "File upload not allowed with polls.", - "upload_form.description": "Describe for the visually impaired", + "upload_error.poll": "ไม่อนุญาตให้อัปโหลดไฟล์กับการลงคะแนน", + "upload_form.description": "อธิบายสำหรับผู้บกพร่องทางการมองเห็น", "upload_form.focus": "ตัวอย่างการเปลี่ยนแปลง", "upload_form.undo": "ลบ", "upload_progress.label": "กำลังอัปโหลด...", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index c3a0791b5..dd604f8c4 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Temel", "home.column_settings.show_reblogs": "Boost edilenleri göster", "home.column_settings.show_replies": "Cevapları göster", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Yeni liste başlığı", "lists.search": "Takip ettiğiniz kişiler arasından arayın", "lists.subheading": "Listeleriniz", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Yükleniyor...", "media_gallery.toggle_visible": "Görünürlüğü değiştir", "missing_indicator.label": "Bulunamadı", @@ -311,6 +313,7 @@ "search_results.accounts": "İnsanlar", "search_results.hashtags": "Hashtagler", "search_results.statuses": "Gönderiler", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {sonuç} other {sonuçlar}}", "status.admin_account": "@{name} için denetim arayüzünü açın", "status.admin_status": "Denetim arayüzünde bu durumu açın", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index d02b652ff..17dc0635b 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "Основні", "home.column_settings.show_reblogs": "Показувати передмухи", "home.column_settings.show_replies": "Показувати відповіді", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "Нова назва списку", "lists.search": "Шукати серед людей, на яких ви підписані", "lists.subheading": "Ваші списки", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "Завантаження...", "media_gallery.toggle_visible": "Показати/приховати", "missing_indicator.label": "Не знайдено", @@ -311,6 +313,7 @@ "search_results.accounts": "People", "search_results.hashtags": "Hashtags", "search_results.statuses": "Toots", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} {count, plural, one {результат} few {результати} many {результатів} other {результатів}}", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 960d4bb95..bb774f1aa 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -1,5 +1,5 @@ { - "account.add_or_remove_from_list": "Add or Remove from lists", + "account.add_or_remove_from_list": "从列表中添加或删除", "account.badges.bot": "机器人", "account.block": "屏蔽 @{name}", "account.block_domain": "隐藏来自 {domain} 的内容", @@ -7,16 +7,16 @@ "account.direct": "发送私信给 @{name}", "account.domain_blocked": "网站已屏蔽", "account.edit_profile": "修改个人资料", - "account.endorse": "Feature on profile", + "account.endorse": "在个人资料中推荐此用户", "account.follow": "关注", "account.followers": "关注者", - "account.followers.empty": "No one follows this user yet.", + "account.followers.empty": "目前无人关注此用户。", "account.follows": "正在关注", - "account.follows.empty": "This user doesn't follow anyone yet.", + "account.follows.empty": "此用户目前尚未关注任何人。", "account.follows_you": "关注了你", "account.hide_reblogs": "隐藏来自 @{name} 的转嘟", - "account.link_verified_on": "Ownership of this link was checked on {date}", - "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.", + "account.link_verified_on": "此链接的所有权已在 {date} 检查", + "account.locked_info": "此账户已锁嘟。账户的主人会手动审核关注者。", "account.media": "媒体", "account.mention": "提及 @{name}", "account.moved_to": "{name} 已经迁移到:", @@ -29,9 +29,9 @@ "account.requested": "正在等待对方同意。点击以取消发送关注请求", "account.share": "分享 @{name} 的个人资料", "account.show_reblogs": "显示来自 @{name} 的转嘟", - "account.unblock": "不再屏蔽 @{name}", + "account.unblock": "解除屏蔽 @{name}", "account.unblock_domain": "不再隐藏来自 {domain} 的内容", - "account.unendorse": "Don't feature on profile", + "account.unendorse": "不在个人资料中推荐此用户", "account.unfollow": "取消关注", "account.unmute": "不再隐藏 @{name}", "account.unmute_notifications": "不再隐藏来自 @{name} 的通知", @@ -48,7 +48,7 @@ "column.community": "本站时间轴", "column.direct": "私信", "column.domain_blocks": "已屏蔽的网站", - "column.favourites": "收藏过的嘟文", + "column.favourites": "收藏", "column.follow_requests": "关注请求", "column.home": "主页", "column.lists": "列表", @@ -71,20 +71,20 @@ "compose_form.lock_disclaimer": "你的帐户没有{locked}。任何人都可以在关注你后立即查看仅关注者可见的嘟文。", "compose_form.lock_disclaimer.lock": "开启保护", "compose_form.placeholder": "在想啥?", - "compose_form.poll.add_option": "Add a choice", - "compose_form.poll.duration": "Poll duration", - "compose_form.poll.option_placeholder": "Choice {number}", - "compose_form.poll.remove_option": "Remove this choice", + "compose_form.poll.add_option": "添加一个选项", + "compose_form.poll.duration": "投票持续时间", + "compose_form.poll.option_placeholder": "选项 {number}", + "compose_form.poll.remove_option": "移除这个选项", "compose_form.publish": "嘟嘟", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.hide": "Mark media as sensitive", + "compose_form.sensitive.hide": "标记媒体为敏感内容", "compose_form.sensitive.marked": "媒体已被标记为敏感内容", "compose_form.sensitive.unmarked": "媒体未被标记为敏感内容", "compose_form.spoiler.marked": "正文已被折叠在警告信息之后", "compose_form.spoiler.unmarked": "正文未被折叠", "compose_form.spoiler_placeholder": "折叠部分的警告消息", "confirmation_modal.cancel": "取消", - "confirmations.block.block_and_report": "Block & Report", + "confirmations.block.block_and_report": "屏蔽与举报", "confirmations.block.confirm": "屏蔽", "confirmations.block.message": "你确定要屏蔽 {name} 吗?", "confirmations.delete.confirm": "删除", @@ -92,13 +92,13 @@ "confirmations.delete_list.confirm": "删除", "confirmations.delete_list.message": "你确定要永久删除这个列表吗?", "confirmations.domain_block.confirm": "隐藏整个网站的内容", - "confirmations.domain_block.message": "你真的确定要隐藏所有来自 {domain} 的内容吗?多数情况下,屏蔽或隐藏几个特定的用户应该就能满足你的需要了。来自该网站的内容将不再出现在你的公共时间轴或通知列表里。来自该网站的关注者将会被移除。", + "confirmations.domain_block.message": "你真的确定要隐藏所有来自 {domain} 的内容吗?多数情况下,屏蔽或隐藏几个特定的用户就已经足够了。来自该网站的内容将不再出现在你的任何公共时间轴或通知列表里。来自该网站的关注者将会被移除。", "confirmations.mute.confirm": "隐藏", "confirmations.mute.message": "你确定要隐藏 {name} 吗?", "confirmations.redraft.confirm": "删除并重新编辑", - "confirmations.redraft.message": "你确定要删除这条嘟文并重新编辑它吗?所有相关的回复、转嘟和收藏都会被清除。", - "confirmations.reply.confirm": "Reply", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.redraft.message": "你确定要删除这条嘟文并重新编辑它吗?所有相关的转嘟和收藏都会被清除,回复将会失去关联。", + "confirmations.reply.confirm": "回复", + "confirmations.reply.message": "回复此消息将会覆盖当前正在编辑的信息。确定继续吗?", "confirmations.unfollow.confirm": "取消关注", "confirmations.unfollow.message": "你确定要取消关注 {name} 吗?", "embed.instructions": "要在你的网站上嵌入这条嘟文,请复制以下代码。", @@ -117,167 +117,172 @@ "emoji_button.search_results": "搜索结果", "emoji_button.symbols": "符号", "emoji_button.travel": "旅行和地点", - "empty_column.account_timeline": "No toots here!", - "empty_column.account_unavailable": "Profile unavailable", - "empty_column.blocks": "You haven't blocked any users yet.", - "empty_column.community": "本站时间轴暂时没有内容,快嘟几个来抢头香啊!", + "empty_column.account_timeline": "这里没有嘟文!", + "empty_column.account_unavailable": "个人资料不可用", + "empty_column.blocks": "你目前没有屏蔽任何用户。", + "empty_column.community": "本站时间轴暂时没有内容,快写点什么让它动起来吧!", "empty_column.direct": "你还没有使用过私信。当你发出或者收到私信时,它会在这里显示。", - "empty_column.domain_blocks": "There are no hidden domains yet.", - "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", - "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", - "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", + "empty_column.domain_blocks": "目前没有被隐藏的站点。", + "empty_column.favourited_statuses": "你还没有收藏过任何嘟文。收藏过的嘟文会显示在这里。", + "empty_column.favourites": "没有人收藏过这条嘟文。如果有人收藏了,就会显示在这里。", + "empty_column.follow_requests": "你没有收到新的关注请求。收到了之后就会显示在这里。", "empty_column.hashtag": "这个话题标签下暂时没有内容。", - "empty_column.home": "你还没有关注任何用户。快看看{public},向其他用户搭讪吧。", + "empty_column.home": "你还没有关注任何用户。快看看{public},向其他人问个好吧。", "empty_column.home.public_timeline": "公共时间轴", "empty_column.list": "这个列表中暂时没有内容。列表中用户所发送的的新嘟文将会在这里显示。", - "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.", - "empty_column.mutes": "You haven't muted any users yet.", - "empty_column.notifications": "你还没有收到过任何通知,快向其他用户搭讪吧。", - "empty_column.public": "这里神马都没有!写一些公开的嘟文,或者关注其他实例的用户后,这里就会有嘟文出现了哦!", + "empty_column.lists": "你还没有创建过列表。你创建的列表会在这里显示。", + "empty_column.mutes": "你没有隐藏任何用户。", + "empty_column.notifications": "你还没有收到过任何通知,快和其他用户互动吧。", + "empty_column.public": "这里什么都没有!写一些公开的嘟文,或者关注其他服务器的用户后,这里就会有嘟文出现了", "follow_request.authorize": "同意", "follow_request.reject": "拒绝", "getting_started.developers": "开发", - "getting_started.directory": "Profile directory", + "getting_started.directory": "用户目录", "getting_started.documentation": "文档", "getting_started.heading": "开始使用", "getting_started.invite": "邀请用户", - "getting_started.open_source_notice": "Mastodon 是一个开源软件。欢迎前往 GitHub({github})贡献代码或反馈问题。", + "getting_started.open_source_notice": "Mastodon 是开源软件。欢迎前往 GitHub({github})贡献代码或反馈问题。", "getting_started.security": "帐户安全", "getting_started.terms": "使用条款", - "hashtag.column_header.tag_mode.all": "and {additional}", - "hashtag.column_header.tag_mode.any": "or {additional}", - "hashtag.column_header.tag_mode.none": "without {additional}", - "hashtag.column_settings.select.no_options_message": "No suggestions found", - "hashtag.column_settings.select.placeholder": "Enter hashtags…", - "hashtag.column_settings.tag_mode.all": "All of these", - "hashtag.column_settings.tag_mode.any": "Any of these", - "hashtag.column_settings.tag_mode.none": "None of these", - "hashtag.column_settings.tag_toggle": "Include additional tags in this column", + "hashtag.column_header.tag_mode.all": "以及 {additional}", + "hashtag.column_header.tag_mode.any": "或是 {additional}", + "hashtag.column_header.tag_mode.none": "而不用 {additional}", + "hashtag.column_settings.select.no_options_message": "没有找到建议", + "hashtag.column_settings.select.placeholder": "输入话题标签…", + "hashtag.column_settings.tag_mode.all": "全部", + "hashtag.column_settings.tag_mode.any": "任一", + "hashtag.column_settings.tag_mode.none": "全都不要", + "hashtag.column_settings.tag_toggle": "在此栏加入额外的标签", "home.column_settings.basic": "基本设置", "home.column_settings.show_reblogs": "显示转嘟", "home.column_settings.show_replies": "显示回复", - "intervals.full.days": "{number, plural, one {# day} other {# days}}", - "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", - "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", - "introduction.federation.action": "Next", - "introduction.federation.federated.headline": "Federated", - "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.", - "introduction.federation.home.headline": "Home", - "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!", - "introduction.federation.local.headline": "Local", - "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.", - "introduction.interactions.action": "Finish tutorial!", - "introduction.interactions.favourite.headline": "Favourite", - "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", - "introduction.interactions.reblog.headline": "Boost", - "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", - "introduction.interactions.reply.headline": "Reply", - "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", - "introduction.welcome.action": "Let's go!", - "introduction.welcome.headline": "First steps", - "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.", + "home.column_settings.update_live": "Update in real-time", + "intervals.full.days": "{number} 天", + "intervals.full.hours": "{number} 小时", + "intervals.full.minutes": "{number} 分钟", + "introduction.federation.action": "下一步", + "introduction.federation.federated.headline": "跨站", + "introduction.federation.federated.text": "联邦宇宙中其他服务器的公开嘟文会显示在跨站时间轴中。", + "introduction.federation.home.headline": "主页", + "introduction.federation.home.text": "你所关注的用户的动态会显示在主页里。你可以关注任何服务器上的任何人!", + "introduction.federation.local.headline": "本站", + "introduction.federation.local.text": "你所关注的用户的动态会显示在主页里,你可以关注任何服务器上的任何人。", + "introduction.interactions.action": "教程结束!", + "introduction.interactions.favourite.headline": "收藏", + "introduction.interactions.favourite.text": "你可以保存嘟文以便以后阅读。或者通过收藏功能告诉作者你点了个赞。", + "introduction.interactions.reblog.headline": "转嘟", + "introduction.interactions.reblog.text": "通过转嘟,你可以向你的关注者分享其他人的嘟文。", + "introduction.interactions.reply.headline": "回复", + "introduction.interactions.reply.text": "你可以回复其他嘟文,这些回复会像对话一样关联在一起。", + "introduction.welcome.action": "让我们开始吧!", + "introduction.welcome.headline": "首先", + "introduction.welcome.text": "欢迎来到联邦宇宙!很快,您就可以发布信息并和您的朋友交流,这些消息将发送到联邦中的各个服务器中。但是这台服务器,{domain},是特殊的——它保存了你的个人资料,所以请记住它的名字。", "keyboard_shortcuts.back": "返回上一页", - "keyboard_shortcuts.blocked": "to open blocked users list", + "keyboard_shortcuts.blocked": "打开被屏蔽用户列表", "keyboard_shortcuts.boost": "转嘟", - "keyboard_shortcuts.column": "选择第 X 栏中的嘟文", + "keyboard_shortcuts.column": "选择某一栏中的嘟文", "keyboard_shortcuts.compose": "选择嘟文撰写框", "keyboard_shortcuts.description": "说明", - "keyboard_shortcuts.direct": "to open direct messages column", + "keyboard_shortcuts.direct": "打开私信栏", "keyboard_shortcuts.down": "在列表中让光标下移", "keyboard_shortcuts.enter": "展开嘟文", "keyboard_shortcuts.favourite": "收藏嘟文", - "keyboard_shortcuts.favourites": "to open favourites list", - "keyboard_shortcuts.federated": "to open federated timeline", + "keyboard_shortcuts.favourites": "打开收藏列表", + "keyboard_shortcuts.federated": "打开跨站时间轴", "keyboard_shortcuts.heading": "快捷键列表", - "keyboard_shortcuts.home": "to open home timeline", + "keyboard_shortcuts.home": "打开主页时间轴", "keyboard_shortcuts.hotkey": "快捷键", "keyboard_shortcuts.legend": "显示此列表", - "keyboard_shortcuts.local": "to open local timeline", + "keyboard_shortcuts.local": "打开本站时间轴", "keyboard_shortcuts.mention": "提及嘟文作者", - "keyboard_shortcuts.muted": "to open muted users list", - "keyboard_shortcuts.my_profile": "to open your profile", - "keyboard_shortcuts.notifications": "to open notifications column", - "keyboard_shortcuts.pinned": "to open pinned toots list", - "keyboard_shortcuts.profile": "to open author's profile", + "keyboard_shortcuts.muted": "打开隐藏用户列表", + "keyboard_shortcuts.my_profile": "打开你的个人资料", + "keyboard_shortcuts.notifications": "打开通知栏", + "keyboard_shortcuts.pinned": "打开置顶嘟文列表", + "keyboard_shortcuts.profile": "打开作者的个人资料", "keyboard_shortcuts.reply": "回复嘟文", - "keyboard_shortcuts.requests": "to open follow requests list", + "keyboard_shortcuts.requests": "打开关注请求列表", "keyboard_shortcuts.search": "选择搜索框", - "keyboard_shortcuts.start": "to open \"get started\" column", + "keyboard_shortcuts.start": "打开“开始使用”栏", "keyboard_shortcuts.toggle_hidden": "显示或隐藏被折叠的正文", + "keyboard_shortcuts.toggle_sensitivity": "显示/隐藏媒体", "keyboard_shortcuts.toot": "发送新嘟文", "keyboard_shortcuts.unfocus": "取消输入", "keyboard_shortcuts.up": "在列表中让光标上移", "lightbox.close": "关闭", - "lightbox.next": "下一步", - "lightbox.previous": "上一步", - "lightbox.view_context": "View context", + "lightbox.next": "下一个", + "lightbox.previous": "上一个", + "lightbox.view_context": "查看上下文", "lists.account.add": "添加到列表", - "lists.account.remove": "从列表中删除", + "lists.account.remove": "从列表中移除", "lists.delete": "删除列表", "lists.edit": "编辑列表", - "lists.edit.submit": "Change title", + "lists.edit.submit": "更改标题", "lists.new.create": "新建列表", "lists.new.title_placeholder": "新列表的标题", "lists.search": "搜索你关注的人", "lists.subheading": "你的列表", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "加载中……", "media_gallery.toggle_visible": "切换显示/隐藏", "missing_indicator.label": "找不到内容", "missing_indicator.sublabel": "无法找到此资源", - "mute_modal.hide_notifications": "同时隐藏来自这个用户的通知", - "navigation_bar.apps": "Mobile apps", + "mute_modal.hide_notifications": "同时隐藏来自这个用户的通知?", + "navigation_bar.apps": "移动应用", "navigation_bar.blocks": "已屏蔽的用户", "navigation_bar.community_timeline": "本站时间轴", - "navigation_bar.compose": "Compose new toot", + "navigation_bar.compose": "撰写新嘟文", "navigation_bar.direct": "私信", "navigation_bar.discover": "发现", "navigation_bar.domain_blocks": "已屏蔽的网站", "navigation_bar.edit_profile": "修改个人资料", "navigation_bar.favourites": "收藏的内容", - "navigation_bar.filters": "Muted words", + "navigation_bar.filters": "屏蔽关键词", "navigation_bar.follow_requests": "关注请求", + "navigation_bar.follows_and_followers": "关注管理", "navigation_bar.info": "关于本站", "navigation_bar.keyboard_shortcuts": "快捷键列表", "navigation_bar.lists": "列表", - "navigation_bar.logout": "注销", + "navigation_bar.logout": "登出", "navigation_bar.mutes": "已隐藏的用户", "navigation_bar.personal": "个人", "navigation_bar.pins": "置顶嘟文", "navigation_bar.preferences": "首选项", + "navigation_bar.profile_directory": "用户目录", "navigation_bar.public_timeline": "跨站公共时间轴", "navigation_bar.security": "安全", "notification.favourite": "{name} 收藏了你的嘟文", "notification.follow": "{name} 开始关注你", - "notification.mention": "{name} 提及你", - "notification.poll": "A poll you have voted in has ended", + "notification.mention": "{name} 提及了你", + "notification.poll": "你参与的一个投票已经结束", "notification.reblog": "{name} 转嘟了你的嘟文", "notifications.clear": "清空通知列表", "notifications.clear_confirmation": "你确定要永久清空通知列表吗?", "notifications.column_settings.alert": "桌面通知", "notifications.column_settings.favourite": "当你的嘟文被收藏时:", - "notifications.column_settings.filter_bar.advanced": "Display all categories", - "notifications.column_settings.filter_bar.category": "Quick filter bar", - "notifications.column_settings.filter_bar.show": "Show", + "notifications.column_settings.filter_bar.advanced": "显示所有类别", + "notifications.column_settings.filter_bar.category": "快速过滤栏", + "notifications.column_settings.filter_bar.show": "显示", "notifications.column_settings.follow": "当有人关注你时:", "notifications.column_settings.mention": "当有人在嘟文中提及你时:", - "notifications.column_settings.poll": "Poll results:", + "notifications.column_settings.poll": "投票结果:", "notifications.column_settings.push": "推送通知", "notifications.column_settings.reblog": "当有人转嘟了你的嘟文时:", "notifications.column_settings.show": "在通知栏显示", "notifications.column_settings.sound": "播放音效", - "notifications.filter.all": "All", - "notifications.filter.boosts": "Boosts", - "notifications.filter.favourites": "Favourites", - "notifications.filter.follows": "Follows", - "notifications.filter.mentions": "Mentions", - "notifications.filter.polls": "Poll results", + "notifications.filter.all": "全部", + "notifications.filter.boosts": "转嘟", + "notifications.filter.favourites": "收藏", + "notifications.filter.follows": "关注", + "notifications.filter.mentions": "提及", + "notifications.filter.polls": "投票结果", "notifications.group": "{count} 条通知", - "poll.closed": "Closed", - "poll.refresh": "Refresh", - "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", - "poll.vote": "Vote", - "poll_button.add_poll": "Add a poll", - "poll_button.remove_poll": "Remove poll", + "poll.closed": "已关闭", + "poll.refresh": "刷新", + "poll.total_votes": "{count} 票", + "poll.vote": "投票", + "poll_button.add_poll": "发起投票", + "poll_button.remove_poll": "移除投票", "privacy.change": "设置嘟文可见范围", "privacy.direct.long": "只有被提及的用户能看到", "privacy.direct.short": "私信", @@ -296,34 +301,35 @@ "relative_time.seconds": "{number}秒", "reply_indicator.cancel": "取消", "report.forward": "发送举报至 {target}", - "report.forward_hint": "这名用户来自另一个实例。是否要向那个实例发送一条匿名的举报?", - "report.hint": "举报将会发送给你所在实例的监察员。你可以在下面填写举报这个用户的理由:", - "report.placeholder": "附言", + "report.forward_hint": "这名用户来自另一个服务器。是否要向那个服务器发送一条匿名的举报?", + "report.hint": "举报将会发送给你所在服务器的监察员。你可以在下面填写举报该用户的理由:", + "report.placeholder": "备注", "report.submit": "提交", "report.target": "举报 {target}", "search.placeholder": "搜索", "search_popout.search_format": "高级搜索格式", - "search_popout.tips.full_text": "输入其他内容将会返回所有你撰写、收藏、转嘟过或提及到你的嘟文,同时也会在用户名、昵称和话题标签中进行搜索。", + "search_popout.tips.full_text": "输入关键词检索所有你发送、收藏、转嘟过或提及到你的嘟文,以及其他用户公开的用户名、昵称和话题标签。", "search_popout.tips.hashtag": "话题标签", "search_popout.tips.status": "嘟文", - "search_popout.tips.text": "输入其他内容将会返回昵称、用户名和话题标签", + "search_popout.tips.text": "输入关键词检索昵称、用户名和话题标签", "search_popout.tips.user": "用户", "search_results.accounts": "用户", "search_results.hashtags": "话题标签", "search_results.statuses": "嘟文", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "共 {count, number} 个结果", - "status.admin_account": "Open moderation interface for @{name}", - "status.admin_status": "Open this status in the moderation interface", + "status.admin_account": "打开 @{name} 的管理界面", + "status.admin_status": "打开这条嘟文的管理界面", "status.block": "屏蔽 @{name}", "status.cancel_reblog_private": "取消转嘟", - "status.cannot_reblog": "无法转嘟这条嘟文", - "status.copy": "Copy link to status", + "status.cannot_reblog": "这条嘟文不允许被转嘟", + "status.copy": "复制嘟文链接", "status.delete": "删除", - "status.detailed_status": "Detailed conversation view", + "status.detailed_status": "对话详情", "status.direct": "发送私信给 @{name}", "status.embed": "嵌入", "status.favourite": "收藏", - "status.filtered": "Filtered", + "status.filtered": "已过滤", "status.load_more": "加载更多", "status.media_hidden": "隐藏媒体内容", "status.mention": "提及 @{name}", @@ -333,11 +339,11 @@ "status.open": "展开嘟文", "status.pin": "在个人资料页面置顶", "status.pinned": "置顶嘟文", - "status.read_more": "Read more", + "status.read_more": "阅读全文", "status.reblog": "转嘟", - "status.reblog_private": "转嘟给原有关注者", + "status.reblog_private": "转嘟(可见者不变)", "status.reblogged_by": "{name} 转嘟了", - "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", + "status.reblogs.empty": "没有人转嘟过此条嘟文。如果有人转嘟了,就会显示在这里。", "status.redraft": "删除并重新编辑", "status.reply": "回复", "status.replyAll": "回复所有人", @@ -348,31 +354,31 @@ "status.show_less_all": "隐藏所有内容", "status.show_more": "显示内容", "status.show_more_all": "显示所有内容", - "status.show_thread": "Show thread", + "status.show_thread": "显示全部对话", "status.unmute_conversation": "不再隐藏此对话", "status.unpin": "在个人资料页面取消置顶", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "关闭建议", + "suggestions.header": "您可能会感兴趣…", "tabs_bar.federated_timeline": "跨站", "tabs_bar.home": "主页", "tabs_bar.local_timeline": "本站", "tabs_bar.notifications": "通知", "tabs_bar.search": "搜索", - "time_remaining.days": "{number, plural, one {# day} other {# days}} left", - "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", - "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", - "time_remaining.moments": "Moments remaining", - "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left", + "time_remaining.days": "剩余 {number, plural, one {# 天} other {# 天}}", + "time_remaining.hours": "剩余 {number, plural, one {# 小时} other {# 小时}}", + "time_remaining.minutes": "剩余 {number, plural, one {# 分钟} other {# 分钟}}", + "time_remaining.moments": "即将结束", + "time_remaining.seconds": "剩余 {number, plural, one {# 秒} other {# 秒}}", "trends.count_by_accounts": "{count} 人正在讨论", - "ui.beforeunload": "如果你现在离开 Mastodon,你的草稿内容将会被丢弃。", + "ui.beforeunload": "如果你现在离开 Mastodon,你的草稿内容将会丢失。", "upload_area.title": "将文件拖放到此处开始上传", - "upload_button.label": "上传媒体文件", - "upload_error.limit": "File upload limit exceeded.", - "upload_error.poll": "File upload not allowed with polls.", + "upload_button.label": "上传媒体文件 (JPEG, PNG, GIF, WebM, MP4, MOV)", + "upload_error.limit": "文件大小超过限制。", + "upload_error.poll": "投票中不允许上传文件。", "upload_form.description": "为视觉障碍人士添加文字说明", - "upload_form.focus": "剪裁", - "upload_form.undo": "取消上传", - "upload_progress.label": "上传中…", + "upload_form.focus": "设置缩略图", + "upload_form.undo": "删除", + "upload_progress.label": "上传中……", "video.close": "关闭视频", "video.exit_fullscreen": "退出全屏", "video.expand": "展开视频", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index a2d7b0e82..ae91cc2eb 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "基本", "home.column_settings.show_reblogs": "顯示被轉推的文章", "home.column_settings.show_replies": "顯示回應文章", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "新列表標題", "lists.search": "從你關注的用戶中搜索", "lists.subheading": "列表", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "載入中...", "media_gallery.toggle_visible": "打開或關上", "missing_indicator.label": "找不到內容", @@ -311,6 +313,7 @@ "search_results.accounts": "使用者", "search_results.hashtags": "標籤", "search_results.statuses": "文章", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} 項結果", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this status in the moderation interface", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 7b01ce4dd..da43e3b22 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -156,6 +156,7 @@ "home.column_settings.basic": "基本", "home.column_settings.show_reblogs": "顯示轉推", "home.column_settings.show_replies": "顯示回覆", + "home.column_settings.update_live": "Update in real-time", "intervals.full.days": "{number, plural, one {# 天} other {# 天}}", "intervals.full.hours": "{number, plural, one {# 小時} other {# 小時}}", "intervals.full.minutes": "{number, plural, one {# 分鐘} other {# 分鐘}}", @@ -220,6 +221,7 @@ "lists.new.title_placeholder": "新名單標題", "lists.search": "搜尋您關注的使用者", "lists.subheading": "您的名單", + "load_pending": "{count, plural, one {# new item} other {# new items}}", "loading_indicator.label": "讀取中...", "media_gallery.toggle_visible": "切換可見性", "missing_indicator.label": "找不到", @@ -311,6 +313,7 @@ "search_results.accounts": "使用者", "search_results.hashtags": "主題標籤", "search_results.statuses": "嘟文", + "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.total": "{count, number} 項結果", "status.admin_account": "開啟 @{name} 的管理介面", "status.admin_status": "在管理介面開啟此嘟文", diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js index 3135636cf..14317cbf4 100644 --- a/app/javascript/packs/public.js +++ b/app/javascript/packs/public.js @@ -108,14 +108,6 @@ function main() { if (parallaxComponents.length > 0 ) { new Rellax('.parallax', { speed: -1 }); } - - if (document.body.classList.contains('with-modals')) { - const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth; - const scrollbarWidthStyle = document.createElement('style'); - scrollbarWidthStyle.id = 'scrollbar-width'; - document.head.appendChild(scrollbarWidthStyle); - scrollbarWidthStyle.sheet.insertRule(`body.with-modals--active { margin-right: ${scrollbarWidth}px; }`, 0); - } }); delegate(document, '.webapp-btn', 'click', ({ target, button }) => { diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss index fe3edca47..b565f625a 100644 --- a/app/javascript/styles/application.scss +++ b/app/javascript/styles/application.scss @@ -13,7 +13,7 @@ @import 'mastodon/widgets'; @import 'mastodon/forms'; @import 'mastodon/accounts'; -@import 'mastodon/stream_entries'; +@import 'mastodon/statuses'; @import 'mastodon/boost'; @import 'mastodon/components'; @import 'mastodon/polls'; diff --git a/app/javascript/styles/mastodon/basics.scss b/app/javascript/styles/mastodon/basics.scss index b5a77ce94..7df76bdff 100644 --- a/app/javascript/styles/mastodon/basics.scss +++ b/app/javascript/styles/mastodon/basics.scss @@ -8,7 +8,7 @@ body { font-family: $font-sans-serif, sans-serif; - background: darken($ui-base-color, 8%); + background: darken($ui-base-color, 7%); font-size: 13px; line-height: 18px; font-weight: 400; @@ -35,11 +35,19 @@ body { } &.app-body { - position: absolute; - width: 100%; - height: 100%; padding: 0; - background: $ui-base-color; + + &.layout-single-column { + height: auto; + min-height: 100%; + overflow-y: scroll; + } + + &.layout-multiple-columns { + position: absolute; + width: 100%; + height: 100%; + } &.with-modals--active { overflow-y: hidden; @@ -56,7 +64,6 @@ body { &--active { overflow-y: hidden; - margin-right: 13px; } } @@ -134,9 +141,22 @@ button { & > div { display: flex; width: 100%; - height: 100%; align-items: center; justify-content: center; outline: 0 !important; } } + +.layout-single-column .app-holder { + &, + & > div { + min-height: 100%; + } +} + +.layout-multiple-columns .app-holder { + &, + & > div { + height: 100%; + } +} diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 578e98990..e868ff3bc 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1813,6 +1813,7 @@ a.account__display-name { justify-content: center; width: 100%; height: 100%; + min-height: 100vh; &__pane { height: 100%; @@ -1826,6 +1827,7 @@ a.account__display-name { } &__inner { + position: fixed; width: 285px; pointer-events: auto; height: 100%; @@ -1880,7 +1882,6 @@ a.account__display-name { flex-direction: column; width: 100%; height: 100%; - background: darken($ui-base-color, 7%); } .drawer { @@ -2021,6 +2022,10 @@ a.account__display-name { top: 15px; } + .scrollable { + overflow: visible; + } + @media screen and (min-width: $no-gap-breakpoint) { padding: 10px 0; } diff --git a/app/javascript/styles/mastodon/containers.scss b/app/javascript/styles/mastodon/containers.scss index 3564bf07b..2b6794ee2 100644 --- a/app/javascript/styles/mastodon/containers.scss +++ b/app/javascript/styles/mastodon/containers.scss @@ -145,6 +145,10 @@ min-height: 100%; } + .flash-message { + margin-bottom: 10px; + } + @media screen and (max-width: 738px) { grid-template-columns: minmax(0, 50%) minmax(0, 50%); diff --git a/app/javascript/styles/mastodon/stream_entries.scss b/app/javascript/styles/mastodon/statuses.scss index 19ce0ab8f..19ce0ab8f 100644 --- a/app/javascript/styles/mastodon/stream_entries.scss +++ b/app/javascript/styles/mastodon/statuses.scss diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index b82bfec21..569868c87 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -81,10 +81,10 @@ class ActivityPub::Activity::Create < ActivityPub::Activity resolve_thread(@status) fetch_replies(@status) - + check_for_spam distribute(@status) return if @options[:imported] - forward_for_reply if @status.public_visibility? || @status.unlisted_visibility? + forward_for_reply if @status.distributable? end def find_existing_status @@ -513,6 +513,18 @@ class ActivityPub::Activity::Create < ActivityPub::Activity Account.local.where(username: local_usernames).exists? end + def check_for_spam + spam_check = SpamCheck.new(@status) + + return if spam_check.skip? + + if spam_check.spam? + spam_check.flag! + else + spam_check.remember! + end + end + def forward_for_reply return unless @json['signature'].present? && reply_to_local? ActivityPub::RawDistributionWorker.perform_async(Oj.dump(@json), replied_to_status.account_id, [@account.preferred_inbox_url]) diff --git a/app/lib/activitypub/activity/delete.rb b/app/lib/activitypub/activity/delete.rb index b39c163f5..5a962cd6a 100644 --- a/app/lib/activitypub/activity/delete.rb +++ b/app/lib/activitypub/activity/delete.rb @@ -30,7 +30,7 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity return if @status.nil? - if @status.public_visibility? || @status.unlisted_visibility? + if @status.distributable? forward_for_reply forward_for_reblogs end diff --git a/app/lib/activitypub/activity/follow.rb b/app/lib/activitypub/activity/follow.rb index 73336fde0..9e94857a7 100644 --- a/app/lib/activitypub/activity/follow.rb +++ b/app/lib/activitypub/activity/follow.rb @@ -9,7 +9,7 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) || @account.requested?(target_account) - if (rejecting_unknown? && !known?) || target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved? + if (rejecting_unknown? && !known?) || target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved? || target_account.instance_actor? reject_follow_request!(target_account) return end diff --git a/app/lib/activitypub/adapter.rb b/app/lib/activitypub/adapter.rb index 1a4502bcd..3e0bbaa6a 100644 --- a/app/lib/activitypub/adapter.rb +++ b/app/lib/activitypub/adapter.rb @@ -65,6 +65,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base def serializable_hash(options = nil) options = serialization_options(options) serialized_hash = serializer.serializable_hash(options) + serialized_hash = serialized_hash.select { |k, _| options[:fields].include?(k) } if options[:fields] serialized_hash = self.class.transform_key_casing!(serialized_hash, instance_options) { '@context' => serialized_context }.merge(serialized_hash) diff --git a/app/lib/activitypub/tag_manager.rb b/app/lib/activitypub/tag_manager.rb index 7d1e46600..22e26d116 100644 --- a/app/lib/activitypub/tag_manager.rb +++ b/app/lib/activitypub/tag_manager.rb @@ -17,7 +17,7 @@ class ActivityPub::TagManager case target.object_type when :person - short_account_url(target) + target.instance_actor? ? about_more_url(instance_actor: true) : short_account_url(target) when :note, :comment, :activity return activity_account_status_url(target.account, target) if target.reblog? short_account_status_url(target.account, target) @@ -29,7 +29,7 @@ class ActivityPub::TagManager case target.object_type when :person - account_url(target) + target.instance_actor? ? instance_actor_url : account_url(target) when :note, :comment, :activity return activity_account_status_url(target.account, target) if target.reblog? account_status_url(target.account, target) @@ -51,7 +51,7 @@ class ActivityPub::TagManager def replies_uri_for(target, page_params = nil) raise ArgumentError, 'target must be a local activity' unless %i(note comment activity).include?(target.object_type) && target.local? - replies_account_status_url(target.account, target, page_params) + account_status_replies_url(target.account, target, page_params) end # Primary audience of a status @@ -119,6 +119,7 @@ class ActivityPub::TagManager def uri_to_local_id(uri, param = :id) path_params = Rails.application.routes.recognize_path(uri) + path_params[:username] = Rails.configuration.x.local_domain if path_params[:controller] == 'instance_actors' path_params[param] end diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index 5a1572c05..b81ef8668 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -532,7 +532,7 @@ class Formatter gaps = [] total_offset = 0 - escaped = html.gsub(/<[^>]*>/) do |match| + 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] @@ -604,7 +604,7 @@ class Formatter end def mention_html(account) - "<span class=\"h-card\"><a href=\"#{encode(TagManager.instance.url_for(account))}\" class=\"u-url mention\">@<span>#{encode(account.username)}</span></a></span>" + "<span class=\"h-card\"><a href=\"#{encode(ActivityPub::TagManager.instance.url_for(account))}\" class=\"u-url mention\">@<span>#{encode(account.username)}</span></a></span>" end def anchor_html(text, url) diff --git a/app/lib/request.rb b/app/lib/request.rb index c84daaa69..7a8141c7e 100644 --- a/app/lib/request.rb +++ b/app/lib/request.rb @@ -33,8 +33,8 @@ class Request set_digest! if options.key?(:body) end - def on_behalf_of(account, key_id_format = :acct, sign_with: nil) - raise ArgumentError unless account.local? + def on_behalf_of(account, key_id_format = :uri, sign_with: nil) + raise ArgumentError, 'account must not be nil' if account.nil? @account = account @keypair = sign_with.present? ? OpenSSL::PKey::RSA.new(sign_with) : @account.keypair @@ -52,7 +52,7 @@ class Request begin response = http_client.headers(headers).public_send(@verb, @url.to_s, @options) rescue => e - raise e.class, "#{e.message} on #{@url}", e.backtrace[0] + raise e.class, "#{e.message} on #{@url}", e.backtrace end begin diff --git a/app/lib/spam_check.rb b/app/lib/spam_check.rb new file mode 100644 index 000000000..0cf1b8790 --- /dev/null +++ b/app/lib/spam_check.rb @@ -0,0 +1,173 @@ +# frozen_string_literal: true + +class SpamCheck + include Redisable + include ActionView::Helpers::TextHelper + + NILSIMSA_COMPARE_THRESHOLD = 95 + NILSIMSA_MIN_SIZE = 10 + EXPIRE_SET_AFTER = 1.week.seconds + + def initialize(status) + @account = status.account + @status = status + end + + def skip? + disabled? || already_flagged? || trusted? || no_unsolicited_mentions? || solicited_reply? + end + + def spam? + if insufficient_data? + false + elsif nilsimsa? + any_other_digest?('nilsimsa') { |_, other_digest| nilsimsa_compare_value(digest, other_digest) >= NILSIMSA_COMPARE_THRESHOLD } + else + any_other_digest?('md5') { |_, other_digest| other_digest == digest } + end + end + + def flag! + auto_silence_account! + auto_report_status! + end + + def remember! + # The scores in sorted sets don't actually have enough bits to hold an exact + # value of our snowflake IDs, so we use it only for its ordering property. To + # get the correct status ID back, we have to save it in the string value + + redis.zadd(redis_key, @status.id, digest_with_algorithm) + redis.zremrangebyrank(redis_key, '0', '-10') + redis.expire(redis_key, EXPIRE_SET_AFTER) + end + + def reset! + redis.del(redis_key) + end + + def hashable_text + return @hashable_text if defined?(@hashable_text) + + @hashable_text = @status.text + @hashable_text = remove_mentions(@hashable_text) + @hashable_text = strip_tags(@hashable_text) unless @status.local? + @hashable_text = normalize_unicode(@status.spoiler_text + ' ' + @hashable_text) + @hashable_text = remove_whitespace(@hashable_text) + end + + def insufficient_data? + hashable_text.blank? + end + + def digest + @digest ||= begin + if nilsimsa? + Nilsimsa.new(hashable_text).hexdigest + else + Digest::MD5.hexdigest(hashable_text) + end + end + end + + def digest_with_algorithm + if nilsimsa? + ['nilsimsa', digest, @status.id].join(':') + else + ['md5', digest, @status.id].join(':') + end + end + + private + + def disabled? + !Setting.spam_check_enabled + end + + def remove_mentions(text) + return text.gsub(Account::MENTION_RE, '') if @status.local? + + Nokogiri::HTML.fragment(text).tap do |html| + mentions = @status.mentions.map { |mention| ActivityPub::TagManager.instance.url_for(mention.account) } + + html.traverse do |element| + element.unlink if element.name == 'a' && mentions.include?(element['href']) + end + end.to_s + end + + def normalize_unicode(text) + text.unicode_normalize(:nfkc).downcase + end + + def remove_whitespace(text) + text.gsub(/\s+/, ' ').strip + end + + def auto_silence_account! + @account.silence! + end + + def auto_report_status! + status_ids = Status.where(visibility: %i(public unlisted)).where(id: matching_status_ids).pluck(:id) + [@status.id] if @status.distributable? + ReportService.new.call(Account.representative, @account, status_ids: status_ids, comment: I18n.t('spam_check.spam_detected_and_silenced')) + end + + def already_flagged? + @account.silenced? + end + + def trusted? + @account.trust_level > Account::TRUST_LEVELS[:untrusted] + end + + def no_unsolicited_mentions? + @status.mentions.all? { |mention| mention.silent? || (!@account.local? && !mention.account.local?) || mention.account.following?(@account) } + end + + def solicited_reply? + !@status.thread.nil? && @status.thread.mentions.where(account: @account).exists? + end + + def nilsimsa_compare_value(first, second) + first = [first].pack('H*') + second = [second].pack('H*') + bits = 0 + + 0.upto(31) do |i| + bits += Nilsimsa::POPC[255 & (first[i].ord ^ second[i].ord)].ord + end + + 128 - bits # -128 <= Nilsimsa Compare Value <= 128 + end + + def nilsimsa? + hashable_text.size > NILSIMSA_MIN_SIZE + end + + def other_digests + redis.zrange(redis_key, 0, -1) + end + + def any_other_digest?(filter_algorithm) + other_digests.any? do |record| + algorithm, other_digest, status_id = record.split(':') + + next unless algorithm == filter_algorithm + + yield algorithm, other_digest, status_id + end + end + + def matching_status_ids + if nilsimsa? + other_digests.select { |record| record.start_with?('nilsimsa') && nilsimsa_compare_value(digest, record.split(':')[1]) >= NILSIMSA_COMPARE_THRESHOLD }.map { |record| record.split(':')[2] }.compact + else + other_digests.select { |record| record.start_with?('md5') && record.split(':')[1] == digest }.map { |record| record.split(':')[2] }.compact + end + end + + def redis_key + @redis_key ||= "spam_check:#{@account.id}" + end +end diff --git a/app/lib/status_finder.rb b/app/lib/status_finder.rb index 4d1aed297..22ced8bf8 100644 --- a/app/lib/status_finder.rb +++ b/app/lib/status_finder.rb @@ -13,8 +13,6 @@ class StatusFinder raise ActiveRecord::RecordNotFound unless TagManager.instance.local_url?(url) case recognized_params[:controller] - when 'stream_entries' - StreamEntry.find(recognized_params[:id]).status when 'statuses' Status.find(recognized_params[:id]) else diff --git a/app/lib/tag_manager.rb b/app/lib/tag_manager.rb index fb364cb98..c88cf4994 100644 --- a/app/lib/tag_manager.rb +++ b/app/lib/tag_manager.rb @@ -24,24 +24,16 @@ class TagManager def same_acct?(canonical, needle) return true if canonical.casecmp(needle).zero? + username, domain = needle.split('@') + local_domain?(domain) && canonical.casecmp(username).zero? end def local_url?(url) uri = Addressable::URI.parse(url).normalize domain = uri.host + (uri.port ? ":#{uri.port}" : '') - TagManager.instance.web_domain?(domain) - end - - def url_for(target) - return target.url if target.respond_to?(:local?) && !target.local? - case target.object_type - when :person - short_account_url(target) - when :note, :comment, :activity - short_account_status_url(target.account, target) - end + TagManager.instance.web_domain?(domain) end end diff --git a/app/lib/webfinger_resource.rb b/app/lib/webfinger_resource.rb index a54a702a2..22d78874a 100644 --- a/app/lib/webfinger_resource.rb +++ b/app/lib/webfinger_resource.rb @@ -23,11 +23,17 @@ class WebfingerResource def username_from_url if account_show_page? path_params[:username] + elsif instance_actor_page? + Rails.configuration.x.local_domain else raise ActiveRecord::RecordNotFound end end + def instance_actor_page? + path_params[:controller] == 'instance_actors' + end + def account_show_page? path_params[:controller] == 'accounts' && path_params[:action] == 'show' end diff --git a/app/mailers/admin_mailer.rb b/app/mailers/admin_mailer.rb index db154cad5..9ab3e2bbd 100644 --- a/app/mailers/admin_mailer.rb +++ b/app/mailers/admin_mailer.rb @@ -3,7 +3,7 @@ class AdminMailer < ApplicationMailer layout 'plain_mailer' - helper :stream_entries + helper :statuses def new_report(recipient, report) @report = report diff --git a/app/mailers/notification_mailer.rb b/app/mailers/notification_mailer.rb index 66fa337c1..723d901fc 100644 --- a/app/mailers/notification_mailer.rb +++ b/app/mailers/notification_mailer.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class NotificationMailer < ApplicationMailer - helper :stream_entries + helper :statuses add_template_helper RoutingHelper diff --git a/app/models/account.rb b/app/models/account.rb index 9cfacc1c0..63b026467 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -55,6 +55,7 @@ # force_private :boolean default(FALSE), not null # unboostable :boolean default(FALSE), not null # block_anon :boolean default(FALSE), not null +# trust_level :integer # class Account < ApplicationRecord @@ -77,6 +78,13 @@ class Account < ApplicationRecord MAX_FIELDS = (ENV['MAX_PROFILE_FIELDS'] || 4).to_i LOCAL_DOMAINS = ENV.fetch('LOCAL_DOMAINS', '').chomp.split(/\.?\s+/).freeze + TRUST_LEVELS = { + untrusted: 0, + trusted: 1, + }.freeze + +# TODO: Remove this line if commenting it doesn't cause the server to catch on fire +# enum protocol: [:ostatus, :activitypub] validates :username, presence: true @@ -85,7 +93,7 @@ class Account < ApplicationRecord validates :username, format: { with: /\A#{USERNAME_RE}\z/i }, if: -> { !local? && will_save_change_to_username? } # Local user validations - validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 66 }, if: -> { local? && will_save_change_to_username? } + validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 66 }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' } validates_with UniqueUsernameValidator, if: -> { local? && will_save_change_to_username? } validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? } validates :display_name, length: { maximum: MAX_DISPLAY_NAME_LENGTH }, if: -> { local? && will_save_change_to_display_name? } @@ -191,6 +199,10 @@ class Account < ApplicationRecord %w(Application Service).include? actor_type end + def instance_actor? + id == -99 + end + alias bot bot? def bot=(val) @@ -217,9 +229,12 @@ class Account < ApplicationRecord last_webfingered_at.nil? || last_webfingered_at <= 1.day.ago end + def trust_level + self[:trust_level] || 0 + end + def refresh! - return if local? - ResolveAccountService.new.call(acct) + ResolveAccountService.new.call(acct) unless local? end def mark_unknown! @@ -276,21 +291,19 @@ class Account < ApplicationRecord silenced_at.present? end - def silence!(date = nil) - date ||= Time.now.utc + def silence!(date = Time.now.utc) update!(silenced_at: date) end def unsilence! - update!(silenced_at: nil) + update!(silenced_at: nil, trust_level: trust_level == TRUST_LEVELS[:untrusted] ? TRUST_LEVELS[:trusted] : trust_level) end def suspended? suspended_at.present? end - def suspend!(date = nil) - date ||= Time.now.utc + def suspend!(date = Time.now.utc) transaction do user&.disable! if local? update!(suspended_at: date) @@ -400,24 +413,14 @@ class Account < ApplicationRecord self.fields = tmp end +## TODO: See if I need to follow the below advice # needs to be removed after migration - def vars - self[:vars] - end - - def magic_key - modulus, exponent = [keypair.public_key.n, keypair.public_key.e].map do |component| - result = [] - - until component.zero? - result << [component % 256].pack('C') - component >>= 8 - end - - result.reverse.join - end +# def vars +# self[:vars] +# end - (['RSA'] + [modulus, exponent].map { |n| Base64.urlsafe_encode64(n) }).join('.') + def subscription(webhook_url) + @subscription ||= OStatus2::Subscription.new(remote_url, secret: secret, webhook: webhook_url, hub: hub_url) end def save_with_optional_media! @@ -626,7 +629,7 @@ class Account < ApplicationRecord end def generate_keys - return unless local? && !Rails.env.test? + return unless local? && private_key.blank? && public_key.blank? keypair = OpenSSL::PKey::RSA.new(2048) self.private_key = keypair.to_pem diff --git a/app/models/concerns/account_associations.rb b/app/models/concerns/account_associations.rb index 19190f0c5..f60edbfcb 100644 --- a/app/models/concerns/account_associations.rb +++ b/app/models/concerns/account_associations.rb @@ -11,7 +11,6 @@ module AccountAssociations has_many :identity_proofs, class_name: 'AccountIdentityProof', dependent: :destroy, inverse_of: :account # Timelines - has_many :stream_entries, inverse_of: :account, dependent: :destroy has_many :statuses, inverse_of: :account, dependent: :destroy has_many :favourites, inverse_of: :account, dependent: :destroy has_many :bookmarks, inverse_of: :account, dependent: :destroy diff --git a/app/models/concerns/account_finder_concern.rb b/app/models/concerns/account_finder_concern.rb index ccd7bfa12..a54c2174d 100644 --- a/app/models/concerns/account_finder_concern.rb +++ b/app/models/concerns/account_finder_concern.rb @@ -13,7 +13,7 @@ module AccountFinderConcern end def representative - find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')) || Account.local.without_suspended.first + Account.find(-99) end def find_local(username) diff --git a/app/models/concerns/streamable.rb b/app/models/concerns/streamable.rb deleted file mode 100644 index 7c9edb8ef..000000000 --- a/app/models/concerns/streamable.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -module Streamable - extend ActiveSupport::Concern - - included do - has_one :stream_entry, as: :activity - - after_create do - account.stream_entries.create!(activity: self, hidden: hidden?) if needs_stream_entry? - end - end - - def title - super - end - - def content - title - end - - def target - super - end - - def object_type - :activity - end - - def thread - super - end - - def hidden? - false - end - - private - - def needs_stream_entry? - account.local? - end -end diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index 8eea46b18..f4631f901 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -37,6 +37,7 @@ class Form::AdminSettings auto_reject_unknown auto_mark_known werewolf_status + spam_check_enabled ).freeze BOOLEAN_KEYS = %i( @@ -55,6 +56,7 @@ class Form::AdminSettings auto_reject_unknown auto_mark_known werewolf_status + spam_check_enabled ).freeze UPLOAD_KEYS = %i( diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index b5f7741b6..2c195c523 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -26,14 +26,14 @@ class MediaAttachment < ApplicationRecord enum type: [:image, :gifv, :video, :audio, :unknown] - IMAGE_FILE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp'].freeze - VIDEO_FILE_EXTENSIONS = ['.webm', '.mp4', '.m4v', '.mov'].freeze - AUDIO_FILE_EXTENSIONS = ['.mp3', '.m4a', '.wav', '.ogg', '.aac'].freeze - - IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze - VIDEO_MIME_TYPES = ['video/webm', 'video/mp4', 'video/quicktime'].freeze - VIDEO_CONVERTIBLE_MIME_TYPES = ['video/webm', 'video/quicktime'].freeze - AUDIO_MIME_TYPES = ['audio/mpeg', 'audio/mp3', 'audio/mp4', 'audio/vnd.wav', 'audio/wav', 'audio/x-wav', 'audio/x-wave', 'audio/ogg', 'audio/flac',].freeze + IMAGE_FILE_EXTENSIONS = %w(.jpg .jpeg .png .gif .webp).freeze + VIDEO_FILE_EXTENSIONS = %w(.webm .mp4 .m4v .mov).freeze + AUDIO_FILE_EXTENSIONS = %w(.ogg .oga .mp3 .wav .flac .opus .aac .m4a .3gp).freeze + + IMAGE_MIME_TYPES = %w(image/jpeg image/png image/gif image/webp).freeze + VIDEO_MIME_TYPES = %w(video/webm video/mp4 video/quicktime video/ogg).freeze + VIDEO_CONVERTIBLE_MIME_TYPES = %w(video/webm video/quicktime).freeze + AUDIO_MIME_TYPES = %w(audio/wave audio/wav audio/x-wav audio/x-pn-wave audio/ogg audio/mpeg audio/mp3 audio/webm audio/flac audio/aac audio/m4a audio/3gpp).freeze BLURHASH_OPTIONS = { x_comp: 4, diff --git a/app/models/status.rb b/app/models/status.rb index 5954e7868..1c1f533bf 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -37,7 +37,6 @@ class Status < ApplicationRecord before_destroy :unlink_from_conversations include Paginable - include Streamable include Cacheable include StatusThreadingConcern @@ -78,7 +77,6 @@ class Status < ApplicationRecord has_and_belongs_to_many :preview_cards has_one :notification, as: :activity, dependent: :destroy - has_one :stream_entry, as: :activity, inverse_of: :status has_one :status_stat, inverse_of: :status has_one :poll, inverse_of: :status, dependent: :destroy has_one :destructing_status, inverse_of: :status, dependent: :destroy @@ -148,13 +146,11 @@ class Status < ApplicationRecord :status_stat, :tags, :preview_cards, - :stream_entry, :preloadable_poll, account: :account_stat, active_mentions: { account: :account_stat }, reblog: [ :application, - :stream_entry, :tags, :preview_cards, :media_attachments, @@ -253,7 +249,7 @@ class Status < ApplicationRecord end def hidden? - private_visibility? || direct_visibility? || limited_visibility? + !distributable? end def distributable? @@ -750,7 +746,8 @@ class Status < ApplicationRecord end def update_statistics - return unless public_visibility? || unlisted_visibility? + return unless distributable? + ActivityTracker.increment('activity:statuses:local') end @@ -759,7 +756,7 @@ class Status < ApplicationRecord account&.increment_count!(:statuses_count) reblog&.increment_count!(:reblogs_count) if reblog? - thread&.increment_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?) + thread&.increment_count!(:replies_count) if in_reply_to_id.present? && distributable? end def decrement_counter_caches @@ -767,7 +764,7 @@ class Status < ApplicationRecord account&.decrement_count!(:statuses_count) reblog&.decrement_count!(:reblogs_count) if reblog? - thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?) + thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && distributable? end def unlink_from_conversations diff --git a/app/models/stream_entry.rb b/app/models/stream_entry.rb deleted file mode 100644 index edd30487e..000000000 --- a/app/models/stream_entry.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true -# == Schema Information -# -# Table name: stream_entries -# -# id :bigint(8) not null, primary key -# activity_id :bigint(8) -# activity_type :string -# created_at :datetime not null -# updated_at :datetime not null -# hidden :boolean default(FALSE), not null -# account_id :bigint(8) -# - -class StreamEntry < ApplicationRecord - include Paginable - - belongs_to :account, inverse_of: :stream_entries - belongs_to :activity, polymorphic: true - belongs_to :status, foreign_type: 'Status', foreign_key: 'activity_id', inverse_of: :stream_entry - - validates :account, :activity, presence: true - - STATUS_INCLUDES = [:account, :stream_entry, :conversation, :media_attachments, :tags, mentions: :account, reblog: [:stream_entry, :account, :conversation, :media_attachments, :tags, mentions: :account], thread: [:stream_entry, :account]].freeze - - default_scope { where(activity_type: 'Status') } - scope :recent, -> { reorder(id: :desc) } - scope :with_includes, -> { includes(:account, status: STATUS_INCLUDES) } - - delegate :target, :title, :content, :thread, :local_only?, - to: :status, - allow_nil: true - - def object_type - orphaned? || targeted? ? :activity : status.object_type - end - - def verb - orphaned? ? :delete : status.verb - end - - def targeted? - [:follow, :request_friend, :authorize, :reject, :unfollow, :block, :unblock, :share, :favorite].include? verb - end - - def threaded? - (verb == :favorite || object_type == :comment) && !thread.nil? - end - - def mentions - orphaned? ? [] : status.active_mentions.map(&:account) - end - - private - - def orphaned? - status.nil? - end -end diff --git a/app/models/tag.rb b/app/models/tag.rb index 87894a7b2..a1265b2a5 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -21,10 +21,10 @@ class Tag < ApplicationRecord has_one :account_tag_stat, dependent: :destroy - HASHTAG_NAME_RE = '[[:word:]:._\-]*[[:alpha:]:._·\-][[:word:]:._\-]*' + HASHTAG_NAME_RE = '([[:word:]_][[:word:]_·]*[[:alpha:]_·][[:word:]_·]*[[:word:]_])|([[:word:]_]*[[:alpha:]][[:word:]_]*)' HASHTAG_RE = /(?:^|[^\/\)\w])#(#{HASHTAG_NAME_RE})/i - validates :name, presence: true, uniqueness: true, format: { with: /\A#{HASHTAG_NAME_RE}\z/i } + validates :name, presence: true, uniqueness: true, format: { with: /\A(#{HASHTAG_NAME_RE})\z/i } scope :discoverable, -> { joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).where(account_tag_stats: { hidden: false }).order(Arel.sql('account_tag_stats.accounts_count desc')) } scope :hidden, -> { where(account_tag_stats: { hidden: true }) } diff --git a/app/models/user.rb b/app/models/user.rb index 96b6f1f58..733a34ef4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -179,6 +179,8 @@ class User < ApplicationRecord :aggregate_reblogs, :show_application, :default_content_type, + :use_blurhash, + :use_pending_items, :theme, :advanced_layout, diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb index 311ecf5ed..d5dad6350 100644 --- a/app/policies/status_policy.rb +++ b/app/policies/status_policy.rb @@ -19,7 +19,7 @@ class StatusPolicy < ApplicationPolicy if private? following_author? && still_accessible? else - author_allows_anon? && still_accessible? && !author_blocking? || following_author? + author_allows_anon? && still_accessible? && (!author_blocking? && !author_blocking_domain?) || following_author? end end @@ -65,6 +65,12 @@ class StatusPolicy < ApplicationPolicy end end + def author_blocking_domain? + return false if current_account.nil? || current_account.domain.nil? + + author.domain_blocking?(current_account.domain) + end + def blocking_author? return false if current_account.nil? diff --git a/app/serializers/activitypub/activity_serializer.rb b/app/serializers/activitypub/activity_serializer.rb index 799f9329f..7e9367328 100644 --- a/app/serializers/activitypub/activity_serializer.rb +++ b/app/serializers/activitypub/activity_serializer.rb @@ -4,6 +4,7 @@ class ActivityPub::ActivitySerializer < ActivityPub::Serializer attributes :id, :type, :actor, :published, :updated, :to, :cc has_one :proper, key: :object, serializer: ActivityPub::NoteSerializer, if: :serialize_object? + attribute :proper_uri, key: :object, unless: :serialize_object? def id diff --git a/app/serializers/activitypub/actor_serializer.rb b/app/serializers/activitypub/actor_serializer.rb index a7260fa15..81a41b917 100644 --- a/app/serializers/activitypub/actor_serializer.rb +++ b/app/serializers/activitypub/actor_serializer.rb @@ -52,11 +52,17 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer end def id - account_url(object) + object.instance_actor? ? instance_actor_url : account_url(object) end def type - object.bot? ? 'Service' : 'Person' + if object.instance_actor? + 'Application' + elsif object.bot? + 'Service' + else + 'Person' + end end def following @@ -68,7 +74,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer end def inbox - account_inbox_url(object) + object.instance_actor? ? instance_actor_inbox_url : account_inbox_url(object) end def outbox @@ -108,7 +114,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer end def url - short_account_url(object) + object.instance_actor? ? about_more_url(instance_actor: true) : short_account_url(object) end def avatar_exists? diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb index 5c1dc64dc..a81ad393d 100644 --- a/app/serializers/rest/account_serializer.rb +++ b/app/serializers/rest/account_serializer.rb @@ -39,7 +39,7 @@ class REST::AccountSerializer < ActiveModel::Serializer end def url - TagManager.instance.url_for(object) + ActivityPub::TagManager.instance.url_for(object) end def avatar diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb index a071d2375..de8d08528 100644 --- a/app/serializers/rest/status_serializer.rb +++ b/app/serializers/rest/status_serializer.rb @@ -86,7 +86,7 @@ class REST::StatusSerializer < ActiveModel::Serializer end def uri - OStatus::TagManager.instance.uri_for(object) + ActivityPub::TagManager.instance.uri_for(object) end def content @@ -98,7 +98,7 @@ class REST::StatusSerializer < ActiveModel::Serializer end def url - TagManager.instance.url_for(object) + ActivityPub::TagManager.instance.url_for(object) end def favourited @@ -184,7 +184,7 @@ class REST::StatusSerializer < ActiveModel::Serializer end def url - TagManager.instance.url_for(object.account) + ActivityPub::TagManager.instance.url_for(object.account) end def acct diff --git a/app/serializers/rss/account_serializer.rb b/app/serializers/rss/account_serializer.rb index 88eca79ed..278affe13 100644 --- a/app/serializers/rss/account_serializer.rb +++ b/app/serializers/rss/account_serializer.rb @@ -2,7 +2,7 @@ class RSS::AccountSerializer include ActionView::Helpers::NumberHelper - include StreamEntriesHelper + include StatusesHelper include RoutingHelper def render(account, statuses) @@ -10,7 +10,7 @@ class RSS::AccountSerializer builder.title("#{display_name(account)} (@#{account.local_username_and_domain})") .description(account_description(account)) - .link(TagManager.instance.url_for(account)) + .link(ActivityPub::TagManager.instance.url_for(account)) .logo(full_pack_url('media/images/logo.svg')) .accent_color('2b90d9') @@ -20,7 +20,7 @@ class RSS::AccountSerializer statuses.each do |status| builder.item do |item| item.title(status.title) - .link(TagManager.instance.url_for(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) diff --git a/app/serializers/rss/tag_serializer.rb b/app/serializers/rss/tag_serializer.rb index 644380149..e8562ee87 100644 --- a/app/serializers/rss/tag_serializer.rb +++ b/app/serializers/rss/tag_serializer.rb @@ -3,7 +3,7 @@ class RSS::TagSerializer include ActionView::Helpers::NumberHelper include ActionView::Helpers::SanitizeHelper - include StreamEntriesHelper + include StatusesHelper include RoutingHelper def render(tag, statuses) @@ -18,7 +18,7 @@ class RSS::TagSerializer statuses.each do |status| builder.item do |item| item.title(status.title) - .link(TagManager.instance.url_for(status)) + .link(ActivityPub::TagManager.instance.url_for(status)) .pub_date(status.created_at) .description(status.spoiler_text.presence || Formatter.instance.format(status).to_str) diff --git a/app/serializers/webfinger_serializer.rb b/app/serializers/webfinger_serializer.rb index 882fcf948..ca4beca37 100644 --- a/app/serializers/webfinger_serializer.rb +++ b/app/serializers/webfinger_serializer.rb @@ -10,14 +10,26 @@ class WebfingerSerializer < ActiveModel::Serializer end def aliases - [short_account_url(object), account_url(object)] + if object.instance_actor? + [instance_actor_url] + else + [short_account_url(object), account_url(object)] + end end def links - [ - { rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: short_account_url(object) }, - { rel: 'self', type: 'application/activity+json', href: account_url(object) }, - { rel: 'magic-public-key', href: "data:application/magic-public-key,#{object.magic_key}" }, - ] + if object.instance_actor? + [ + { rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: about_more_url(instance_actor: true) }, + { rel: 'self', type: 'application/activity+json', href: instance_actor_url }, + ] + else + [ + { rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: short_account_url(object) }, + # TODO: Make sure commenting the next line doesn't cause other instances to catch on fire +# { rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(object, format: 'atom') }, + { rel: 'self', type: 'application/activity+json', href: account_url(object) }, + ] + end end end diff --git a/app/services/activitypub/fetch_featured_collection_service.rb b/app/services/activitypub/fetch_featured_collection_service.rb index 6a137b520..2c2770466 100644 --- a/app/services/activitypub/fetch_featured_collection_service.rb +++ b/app/services/activitypub/fetch_featured_collection_service.rb @@ -4,13 +4,12 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService include JsonLdHelper def call(account) - return if account.featured_collection_url.blank? + return if account.featured_collection_url.blank? || account.suspended? || account.local? @account = account @json = fetch_resource(@account.featured_collection_url, true) return unless supported_context? - return if @account.suspended? || @account.local? case @json['type'] when 'Collection', 'CollectionPage' diff --git a/app/services/activitypub/fetch_remote_account_service.rb b/app/services/activitypub/fetch_remote_account_service.rb index df1e79d7d..381726c35 100644 --- a/app/services/activitypub/fetch_remote_account_service.rb +++ b/app/services/activitypub/fetch_remote_account_service.rb @@ -3,19 +3,23 @@ class ActivityPub::FetchRemoteAccountService < BaseService include JsonLdHelper include AutorejectHelper + include DomainControlHelper SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze # Does a WebFinger roundtrip on each call, unless `only_key` is true def call(uri, id: true, prefetched_body: nil, break_on_redirect: false, only_key: false) + return if domain_not_allowed?(uri) return ActivityPub::TagManager.instance.uri_to_resource(uri, Account) if ActivityPub::TagManager.instance.local_uri?(uri) return if autoreject?(uri) - @json = if prefetched_body.nil? - fetch_resource(uri, id) - else - body_to_json(prefetched_body, compare_id: id ? uri : nil) - end + @json = begin + if prefetched_body.nil? + fetch_resource(uri, id) + else + body_to_json(prefetched_body, compare_id: id ? uri : nil) + end + end return if autoreject? return if !supported_context? || !expected_type? || (break_on_redirect && @json['movedTo'].present?) diff --git a/app/services/activitypub/fetch_remote_poll_service.rb b/app/services/activitypub/fetch_remote_poll_service.rb index 854a32d05..1c79ecf11 100644 --- a/app/services/activitypub/fetch_remote_poll_service.rb +++ b/app/services/activitypub/fetch_remote_poll_service.rb @@ -5,7 +5,9 @@ class ActivityPub::FetchRemotePollService < BaseService def call(poll, on_behalf_of = nil) json = fetch_resource(poll.status.uri, true, on_behalf_of) + return unless supported_context?(json) + ActivityPub::ProcessPollService.new.call(poll, json) end end diff --git a/app/services/activitypub/fetch_remote_status_service.rb b/app/services/activitypub/fetch_remote_status_service.rb index 423c7bc9a..9795cf651 100644 --- a/app/services/activitypub/fetch_remote_status_service.rb +++ b/app/services/activitypub/fetch_remote_status_service.rb @@ -7,20 +7,19 @@ class ActivityPub::FetchRemoteStatusService < BaseService # Should be called when uri has already been checked for locality def call(uri, id: true, prefetched_body: nil, on_behalf_of: nil, announced_by: nil, requested: false) return if autoreject?(uri) - - @json = if prefetched_body.nil? - fetch_resource(uri, id, on_behalf_of) - else - body_to_json(prefetched_body, compare_id: id ? uri : nil) - end + @json = begin + if prefetched_body.nil? + fetch_resource(uri, id, on_behalf_of) + else + body_to_json(prefetched_body, compare_id: id ? uri : nil) + end + end return if autoreject? - return unless supported_context? && expected_type? - - return if actor_id.nil? || !trustworthy_attribution?(@json['id'], actor_id) + return if !(supported_context? && expected_type?) || actor_id.nil? || !trustworthy_attribution?(@json['id'], actor_id) actor = ActivityPub::TagManager.instance.uri_to_resource(actor_id, Account) - actor = ActivityPub::FetchRemoteAccountService.new.call(actor_id, id: true) if actor.nil? || needs_update(actor) + actor = ActivityPub::FetchRemoteAccountService.new.call(actor_id, id: true) if actor.nil? || needs_update?(actor) return if actor.nil? || actor.suspended? @@ -50,7 +49,7 @@ class ActivityPub::FetchRemoteStatusService < BaseService equals_or_includes_any?(@json['type'], ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES) end - def needs_update(actor) + def needs_update?(actor) actor.possibly_stale? end diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index 165c3e9ba..c4671a744 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -3,11 +3,12 @@ class ActivityPub::ProcessAccountService < BaseService include JsonLdHelper include LogHelper + include DomainControlHelper # Should be called with confirmed valid JSON # and WebFinger-resolved username and domain def call(username, domain, json, options = {}) - return if json['inbox'].blank? || unsupported_uri_scheme?(json['id']) + return if json['inbox'].blank? || unsupported_uri_scheme?(json['id']) || domain_not_allowed?(domain) @options = options @json = json diff --git a/app/services/activitypub/process_collection_service.rb b/app/services/activitypub/process_collection_service.rb index 881df478b..a2a2e7071 100644 --- a/app/services/activitypub/process_collection_service.rb +++ b/app/services/activitypub/process_collection_service.rb @@ -8,9 +8,7 @@ class ActivityPub::ProcessCollectionService < BaseService @json = Oj.load(body, mode: :strict) @options = options - return unless supported_context? - return if different_actor? && verify_account!.nil? - return if @account.suspended? || @account.local? + return if !supported_context? || (different_actor? && verify_account!.nil?) || @account.suspended? || @account.local? case @json['type'] when 'Collection', 'CollectionPage' diff --git a/app/services/activitypub/process_poll_service.rb b/app/services/activitypub/process_poll_service.rb index 61357abd3..2fbce65b9 100644 --- a/app/services/activitypub/process_poll_service.rb +++ b/app/services/activitypub/process_poll_service.rb @@ -5,6 +5,7 @@ class ActivityPub::ProcessPollService < BaseService def call(poll, json) @json = json + return unless expected_type? previous_expires_at = poll.expires_at diff --git a/app/services/authorize_follow_service.rb b/app/services/authorize_follow_service.rb index 77a389cc3..49bef727e 100644 --- a/app/services/authorize_follow_service.rb +++ b/app/services/authorize_follow_service.rb @@ -11,7 +11,7 @@ class AuthorizeFollowService < BaseService follow_request.authorize! end - create_notification(follow_request) unless source_account.local? + create_notification(follow_request) if !source_account.local? && source_account.activitypub? follow_request end diff --git a/app/services/batched_remove_status_service.rb b/app/services/batched_remove_status_service.rb index 3110cb511..09d094c15 100644 --- a/app/services/batched_remove_status_service.rb +++ b/app/services/batched_remove_status_service.rb @@ -10,12 +10,12 @@ class BatchedRemoveStatusService < BaseService # @param [Hash] options # @option [Boolean] :skip_side_effects def call(statuses, **options) - statuses = Status.where(id: statuses.map(&:id)).includes(:account, :stream_entry).flat_map { |status| [status] + status.reblogs.includes(:account, :stream_entry).to_a } + statuses = Status.where(id: statuses.map(&:id)).includes(:account).flat_map { |status| [status] + status.reblogs.includes(:account).to_a } @mentions = statuses.each_with_object({}) { |s, h| h[s.id] = s.active_mentions.includes(:account).to_a } @tags = statuses.each_with_object({}) { |s, h| h[s.id] = s.tags.pluck(:name) } - @json_payloads = statuses.each_with_object({}) { |s, h| h[s.id] = Oj.dump(event: :delete, payload: s.id.to_s) } + @json_payloads = statuses.each_with_object({}) { |s, h| h[s.id] = Oj.dump(event: :delete, payload: s.id.to_s) } # Ensure that rendered XML reflects destroyed state statuses.each do |status| @@ -89,9 +89,12 @@ class BatchedRemoveStatusService < BaseService payload = @json_payloads[status.id] redis.pipelined do @mentions[status.id].each do |mention| - redis.publish("timeline:direct:#{mention.account.id}", payload) if mention.account.local? +# TODO: Pull https://github.com/ThibG/mastodon/commit/ca17bae904783dfb1f4899a533d28a79da0c6fe9 + redis.publish("timeline:direct:#{mention.account.id}", payload) if mention.account.local? +# FeedManager.instance.unpush_from_direct(mention.account, status) if mention.account.local? end redis.publish("timeline:direct:#{status.account.id}", payload) if status.account.local? +# FeedManager.instance.unpush_from_direct(status.account, status) if status.account.local? end end end diff --git a/app/services/block_service.rb b/app/services/block_service.rb index 0057dfb4a..da06361c2 100644 --- a/app/services/block_service.rb +++ b/app/services/block_service.rb @@ -13,7 +13,7 @@ class BlockService < BaseService block = account.block!(target_account) BlockWorker.perform_async(account.id, target_account.id) - create_notification(block) unless target_account.local? + create_notification(block) if !target_account.local? && target_account.activitypub? block end diff --git a/app/services/concerns/payloadable.rb b/app/services/concerns/payloadable.rb index 13d9c3548..953740faa 100644 --- a/app/services/concerns/payloadable.rb +++ b/app/services/concerns/payloadable.rb @@ -14,6 +14,6 @@ module Payloadable end def signing_enabled? - true + ENV['AUTHORIZED_FETCH'] != 'true' end end diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index cd0b77426..0c401ea83 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -34,7 +34,7 @@ class FetchLinkCardService < BaseService end attach_card if @card&.persisted? - rescue HTTP::Error, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e + rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e Rails.logger.debug "Error fetching link #{@url}: #{e}" nil end @@ -89,7 +89,7 @@ class FetchLinkCardService < BaseService def mention_link?(a) @status.mentions.any? do |mention| - a['href'] == TagManager.instance.url_for(mention.account) + a['href'] == ActivityPub::TagManager.instance.url_for(mention.account) end end diff --git a/app/services/fetch_remote_account_service.rb b/app/services/fetch_remote_account_service.rb index aed6a90c8..1227bf276 100644 --- a/app/services/fetch_remote_account_service.rb +++ b/app/services/fetch_remote_account_service.rb @@ -3,7 +3,7 @@ class FetchRemoteAccountService < BaseService def call(url, prefetched_body = nil) if prefetched_body.nil? - resource_url, resource_options = FetchAtomService.new.call(url) + resource_url, resource_options = FetchResourceService.new.call(url) else resource_url = url resource_options = { prefetched_body: prefetched_body } diff --git a/app/services/fetch_remote_status_service.rb b/app/services/fetch_remote_status_service.rb index e8f9a671b..4d28a492d 100644 --- a/app/services/fetch_remote_status_service.rb +++ b/app/services/fetch_remote_status_service.rb @@ -3,7 +3,7 @@ class FetchRemoteStatusService < BaseService def call(url, prefetched_body = nil, announced_by: nil, requested: false) if prefetched_body.nil? - resource_url, resource_options = FetchAtomService.new.call(url) + resource_url, resource_options = FetchResourceService.new.call(url) resource_options = {} if resource_options.nil? else resource_url = url diff --git a/app/services/fetch_atom_service.rb b/app/services/fetch_resource_service.rb index b6a33706f..3676d899d 100644 --- a/app/services/fetch_atom_service.rb +++ b/app/services/fetch_resource_service.rb @@ -1,19 +1,16 @@ # frozen_string_literal: true -class FetchAtomService < BaseService +class FetchResourceService < BaseService include JsonLdHelper - include AutorejectHelper + + ACCEPT_HEADER = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", text/html' def call(url) return if url.blank? - return if autoreject?(url) - result = process(url) - rescue OpenSSL::SSL::SSLError => e - Rails.logger.debug "SSL error: #{e}" - nil - rescue HTTP::ConnectionError => e - Rails.logger.debug "HTTP ConnectionError: #{e}" + process(url) + rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e + Rails.logger.debug "Error fetching resource #{@url}: #{e}" nil end @@ -21,13 +18,12 @@ class FetchAtomService < BaseService def process(url, terminal = false) @url = url + perform_request { |response| process_response(response, terminal) } end def perform_request(&block) - accept = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", text/html' - - Request.new(:get, @url).add_headers('Accept' => accept).perform(&block) + Request.new(:get, @url).add_headers('Accept' => ACCEPT_HEADER).on_behalf_of(Account.representative).perform(&block) end def process_response(response, terminal = false) @@ -36,13 +32,8 @@ class FetchAtomService < BaseService if ['application/activity+json', 'application/ld+json'].include?(response.mime_type) body = response.body_with_limit json = body_to_json(body) - if supported_context?(json) && equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) && json['inbox'].present? - [json['id'], { prefetched_body: body, id: true }] - elsif supported_context?(json) && expected_type?(json) - [json['id'], { prefetched_body: body, id: true }] - else - nil - end + + [json['id'], { prefetched_body: body, id: true }, :activitypub] if supported_context?(json) && (equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) || expected_type?(json)) elsif !terminal link_header = response['Link'] && parse_link_header(response) @@ -59,28 +50,19 @@ class FetchAtomService < BaseService end def process_html(response) - page = Nokogiri::HTML(response.body_with_limit) - + page = Nokogiri::HTML(response.body_with_limit) json_link = page.xpath('//link[@rel="alternate"]').find { |link| ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(link['type']) } - result = process(json_link['href'], terminal: true) unless json_link.nil? - result ||= nil - result + process(json_link['href'], terminal: true) unless json_link.nil? end def process_link_headers(link_header) json_link = link_header.find_link(%w(rel alternate), %w(type application/activity+json)) || link_header.find_link(%w(rel alternate), ['type', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"']) - result = process(json_link.href, terminal: true) unless json_link.nil? - result ||= nil - result + process(json_link.href, terminal: true) unless json_link.nil? end def parse_link_header(response) LinkHeader.parse(response['Link'].is_a?(Array) ? response['Link'].first : response['Link']) end - - def object_uri - nil - end end diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index 93f5b6b16..e3f4bf19d 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -13,7 +13,7 @@ class FollowService < BaseService target_account = ResolveAccountService.new.call(target_account, skip_webfinger: true) raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended? - raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) || target_account.moved? + raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) || target_account.moved? || (!target_account.local? && target_account.ostatus?) target_account.mark_known! unless !Setting.auto_mark_known || target_account.known? @@ -35,9 +35,11 @@ class FollowService < BaseService ActivityTracker.increment('activity:interactions') if target_account.local? && !target_account.locked? - follow = source_account.follow!(target_account, reblogs: reblogs) - LocalNotificationWorker.perform_async(target_account.id, follow.id, follow.class.name) - follow + direct_follow(source_account, target_account, reblogs: reblogs) +# follow = source_account.follow!(target_account, reblogs: reblogs) +# LocalNotificationWorker.perform_async(target_account.id, follow.id, follow.class.name) +# MergeWorker.perform_async(target_account.id, source_account.id) +# follow else request_follow(source_account, target_account, reblogs: reblogs) end @@ -50,13 +52,22 @@ class FollowService < BaseService if target_account.local? LocalNotificationWorker.perform_async(target_account.id, follow_request.id, follow_request.class.name) - else + elsif target_account.activitypub? ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), source_account.id, target_account.inbox_url) end follow_request end + def direct_follow(source_account, target_account, reblogs: true) + follow = source_account.follow!(target_account, reblogs: reblogs) + + LocalNotificationWorker.perform_async(target_account.id, follow.id, follow.class.name) + MergeWorker.perform_async(target_account.id, source_account.id) + + follow + end + def build_json(follow_request) Oj.dump(serialize_payload(follow_request, ActivityPub::FollowSerializer)) end diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index 2a065f58b..6718b5a69 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -254,6 +254,13 @@ class PostStatusService < BaseService end end + def postprocess_status! + LinkCrawlWorker.perform_async(@status.id) unless @status.spoiler_text? + DistributionWorker.perform_async(@status.id) + ActivityPub::DistributionWorker.perform_async(@status.id) unless @status.local_only? + PollExpirationNotifyWorker.perform_at(@status.poll.expires_at, @status.poll.id) if @status.poll + end + def validate_media! return if @options[:media_ids].blank? || !@options[:media_ids].is_a?(Enumerable) diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb index 54a0adf45..74cbdd31c 100644 --- a/app/services/reblog_service.rb +++ b/app/services/reblog_service.rb @@ -26,6 +26,8 @@ class ReblogService < BaseService reblog = account.statuses.create!(reblog: reblogged_status, text: '', visibility: visibility) end + DistributionWorker.perform_async(reblog.id) + ActivityPub::DistributionWorker.perform_async(reblog.id) unless reblogged_status.local_only? if !options[:distribute] && account&.user&.boost_interval? QueuedBoost.find_or_create_by!(account_id: account.id, status_id: reblogged_status.id) if account&.user&.boost_interval? diff --git a/app/services/reject_follow_service.rb b/app/services/reject_follow_service.rb index 2e51b11d7..bc0000c8c 100644 --- a/app/services/reject_follow_service.rb +++ b/app/services/reject_follow_service.rb @@ -6,7 +6,7 @@ class RejectFollowService < BaseService def call(source_account, target_account) follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account) follow_request.reject! - create_notification(follow_request) unless source_account.local? + create_notification(follow_request) if !source_account.local? && source_account.activitypub? follow_request end diff --git a/app/services/remove_status_service.rb b/app/services/remove_status_service.rb index 797794a19..51d200361 100644 --- a/app/services/remove_status_service.rb +++ b/app/services/remove_status_service.rb @@ -7,14 +7,13 @@ class RemoveStatusService < BaseService MIN_SCHEDULE_OFFSET = 60.seconds.freeze def call(status, **options) - @payload = Oj.dump(event: :delete, payload: status.id.to_s) - @status = status - @account = status.account - @tags = status.tags.pluck(:name).to_a - @mentions = status.active_mentions.includes(:account).to_a - @reblogs = status.reblogs.includes(:account).to_a - @stream_entry = status.stream_entry - @options = options + @payload = Oj.dump(event: :delete, payload: status.id.to_s) + @status = status + @account = status.account + @tags = status.tags.pluck(:name).to_a + @mentions = status.active_mentions.includes(:account).to_a + @reblogs = status.reblogs.includes(:account).to_a + @options = options unless options[:defederate_only] RedisLock.acquire(lock_options) do |lock| @@ -29,6 +28,7 @@ class RemoveStatusService < BaseService remove_from_public remove_from_media if status.media_attachments.any? remove_from_direct if status.direct_visibility? + remove_from_spam_check @status.destroy! else @@ -162,6 +162,10 @@ class RemoveStatusService < BaseService Redis.current.publish("timeline:direct:#{@account.id}", @payload) if @account.local? end + def remove_from_spam_check + redis.zremrangebyscore("spam_check:#{@status.account_id}", @status.id, @status.id) + end + def lock_options { redis: Redis.current, key: "distribute:#{@status.id}" } end diff --git a/app/services/resolve_account_service.rb b/app/services/resolve_account_service.rb index 415abd78f..7c03bfc3e 100644 --- a/app/services/resolve_account_service.rb +++ b/app/services/resolve_account_service.rb @@ -2,88 +2,114 @@ class ResolveAccountService < BaseService include JsonLdHelper + include DomainControlHelper - DFRN_NS = 'http://purl.org/macgirvin/dfrn/1.0' + class WebfingerRedirectError < StandardError; end - # Find or create a local account for a remote user. - # When creating, look up the user's webfinger and fetch all - # important information from their feed - # @param [String, Account] uri User URI in the form of username@domain + # Find or create an account record for a remote user. When creating, + # look up the user's webfinger and fetch ActivityPub data + # @param [String, Account] uri URI in the username@domain format or account record # @param [Hash] options + # @option options [Boolean] :redirected Do not follow further Webfinger redirects + # @option options [Boolean] :skip_webfinger Do not attempt to refresh account data # @return [Account] def call(uri, options = {}) + return if uri.blank? + + process_options!(uri, options) + + # First of all we want to check if we've got the account + # record with the URI already, and if so, we can exit early + + return if domain_not_allowed?(@domain) + + @account ||= Account.find_remote(@username, @domain) + + return @account if @account&.local? || !webfinger_update_due? + + # At this point we are in need of a Webfinger query, which may + # yield us a different username/domain through a redirect + + process_webfinger!(@uri) + + # Because the username/domain pair may be different than what + # we already checked, we need to check if we've already got + # the record with that URI, again + + return if domain_not_allowed?(@domain) + + @account ||= Account.find_remote(@username, @domain) + + return @account if @account&.local? || !webfinger_update_due? + + # Now it is certain, it is definitely a remote account, and it + # either needs to be created, or updated from fresh data + + process_account! + rescue Goldfinger::Error, WebfingerRedirectError, Oj::ParseError => e + Rails.logger.debug "Webfinger query for #{@uri} failed: #{e}" + nil + end + + private + + def process_options!(uri, options) @options = options if uri.is_a?(Account) @account = uri @username = @account.username @domain = @account.domain - uri = "#{@username}@#{@domain}" - - return @account if @account.local? || !webfinger_update_due? + @uri = [@username, @domain].compact.join('@') else + @uri = uri @username, @domain = uri.split('@') - - return Account.find_local(@username) if TagManager.instance.local_domain?(@domain) - - @account = Account.find_remote(@username, @domain) - - return @account unless webfinger_update_due? end - Rails.logger.debug "Looking up webfinger for #{uri}" - - @webfinger = Goldfinger.finger("acct:#{uri}") + @domain = nil if TagManager.instance.local_domain?(@domain) + end + def process_webfinger!(uri, redirected = false) + @webfinger = Goldfinger.finger("acct:#{@uri}") confirmed_username, confirmed_domain = @webfinger.subject.gsub(/\Aacct:/, '').split('@') if confirmed_username.casecmp(@username).zero? && confirmed_domain.casecmp(@domain).zero? @username = confirmed_username @domain = confirmed_domain - elsif options[:redirected].nil? - return call("#{confirmed_username}@#{confirmed_domain}", options.merge(redirected: true)) + @uri = uri + elsif !redirected + return process_webfinger!("#{confirmed_username}@#{confirmed_domain}", true) else - Rails.logger.debug 'Requested and returned acct URIs do not match' - return + raise WebfingerRedirectError, "The URI #{uri} tries to hijack #{@username}@#{@domain}" end + @domain = nil if TagManager.instance.local_domain?(@domain) + end + + def process_account! return unless activitypub_ready? - return Account.find_local(@username) if TagManager.instance.local_domain?(@domain) RedisLock.acquire(lock_options) do |lock| if lock.acquired? @account = Account.find_remote(@username, @domain) - handle_activitypub if activitypub_ready? + + next if (@account.present? && !@account.activitypub?) || actor_json.nil? + + @account = ActivityPub::ProcessAccountService.new.call(@username, @domain, actor_json) else raise Mastodon::RaceConditionError end end @account - rescue Goldfinger::Error => e - Rails.logger.debug "Webfinger query for #{uri} unsuccessful: #{e}" - nil end - private - def webfinger_update_due? @account.nil? || @account.inbox_url.blank? || (!@options[:skip_webfinger] && @account.possibly_stale?) end def activitypub_ready? - !@webfinger.link('self').nil? && - ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(@webfinger.link('self').type) && - !actor_json.nil? && - actor_json['inbox'].present? - end - - def handle_activitypub - return if actor_json.nil? - - @account = ActivityPub::ProcessAccountService.new.call(@username, @domain, actor_json) - rescue Oj::ParseError - nil + !@webfinger.link('self').nil? && ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(@webfinger.link('self').type) end def actor_url diff --git a/app/services/resolve_url_service.rb b/app/services/resolve_url_service.rb index 0c265b0db..bab420945 100644 --- a/app/services/resolve_url_service.rb +++ b/app/services/resolve_url_service.rb @@ -4,37 +4,39 @@ class ResolveURLService < BaseService include JsonLdHelper include Authorization - attr_reader :url - def call(url, on_behalf_of: nil) - @url = url + @url = url @on_behalf_of = on_behalf_of - return process_local_url if local_url? - - process_url unless fetched_atom_feed.nil? + if local_url? + process_local_url + elsif !fetched_resource.nil? + process_url + end end private def process_url - if equals_or_includes_any?(type, %w(Application Group Organization Person Service)) - FetchRemoteAccountService.new.call(atom_url, body) - elsif equals_or_includes_any?(type, %w(Note Article Image Video Page Question)) - FetchRemoteStatusService.new.call(atom_url, body, requested: true) + if equals_or_includes_any?(type, ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) + FetchRemoteAccountService.new.call(resource_url, body) + elsif equals_or_includes_any?(type, ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES) + status = FetchRemoteStatusService.new.call(atom_url, body, requested: true) + authorize_with @on_behalf_of, status, :show? unless status.nil? + status end end - def fetched_atom_feed - @_fetched_atom_feed ||= FetchAtomService.new.call(url) + def fetched_resource + @fetched_resource ||= FetchResourceService.new.call(@url) end - def atom_url - fetched_atom_feed.first + def resource_url + fetched_resource.first end def body - fetched_atom_feed.second[:prefetched_body] + fetched_resource.second[:prefetched_body] end def type @@ -42,7 +44,7 @@ class ResolveURLService < BaseService end def json_data - @_json_data ||= body_to_json(body) + @json_data ||= body_to_json(body) end def local_url? @@ -54,10 +56,7 @@ class ResolveURLService < BaseService return unless recognized_params[:action] == 'show' - if recognized_params[:controller] == 'stream_entries' - status = StreamEntry.find_by(id: recognized_params[:id])&.status - check_local_status(status) - elsif recognized_params[:controller] == 'statuses' + if recognized_params[:controller] == 'statuses' status = Status.find_by(id: recognized_params[:id]) check_local_status(status) elsif recognized_params[:controller] == 'accounts' @@ -67,10 +66,10 @@ class ResolveURLService < BaseService def check_local_status(status) return if status.nil? + authorize_with @on_behalf_of, status, :show? status rescue Mastodon::NotPermittedError - # Do not disclose the existence of status the user is not authorized to see nil end end diff --git a/app/services/suspend_account_service.rb b/app/services/suspend_account_service.rb index f79257334..b592629a1 100644 --- a/app/services/suspend_account_service.rb +++ b/app/services/suspend_account_service.rb @@ -25,6 +25,7 @@ class SuspendAccountService < BaseService scheduled_statuses status_pins stream_entries + subscriptions ).freeze ASSOCIATIONS_ON_DESTROY = %w( diff --git a/app/services/unblock_service.rb b/app/services/unblock_service.rb index 24f567603..c263ac8af 100644 --- a/app/services/unblock_service.rb +++ b/app/services/unblock_service.rb @@ -7,7 +7,7 @@ class UnblockService < BaseService return unless account.blocking?(target_account) unblock = account.unblock!(target_account) - create_notification(unblock) unless target_account.local? + create_notification(unblock) if !target_account.local? && target_account.activitypub? unblock end diff --git a/app/services/unfavourite_service.rb b/app/services/unfavourite_service.rb index 88c288126..37917a64f 100644 --- a/app/services/unfavourite_service.rb +++ b/app/services/unfavourite_service.rb @@ -6,7 +6,7 @@ class UnfavouriteService < BaseService def call(account, status) favourite = Favourite.find_by!(account: account, status: status) favourite.destroy! - create_notification(favourite) unless status.local? + create_notification(favourite) if !status.account.local? && status.account.activitypub? favourite end diff --git a/app/services/unfollow_service.rb b/app/services/unfollow_service.rb index 4404492a7..b7033d7eb 100644 --- a/app/services/unfollow_service.rb +++ b/app/services/unfollow_service.rb @@ -21,8 +21,8 @@ class UnfollowService < BaseService return unless follow follow.destroy! - create_notification(follow) unless @target_account.local? - create_reject_notification(follow) if @target_account.local? && !@source_account.local? + create_notification(follow) if !@target_account.local? && @target_account.activitypub? + create_reject_notification(follow) if @target_account.local? && !@source_account.local? && @source_account.activitypub? UnmergeWorker.perform_async(@target_account.id, @source_account.id) follow end @@ -42,7 +42,6 @@ class UnfollowService < BaseService end def create_reject_notification(follow) - # Rejecting an already-existing follow request ActivityPub::DeliveryWorker.perform_async(build_reject_json(follow), follow.target_account_id, follow.account.inbox_url) end diff --git a/app/views/about/more.html.haml b/app/views/about/more.html.haml index 54e039519..9eeff3b25 100644 --- a/app/views/about/more.html.haml +++ b/app/views/about/more.html.haml @@ -42,5 +42,7 @@ = mail_to @instance_presenter.site_contact_email, nil, title: @instance_presenter.site_contact_email .column-3 + = render 'application/flashes' + .box-widget .rich-formatting= @instance_presenter.extended_description || t('about.extended_description_html') diff --git a/app/views/accounts/_moved.html.haml b/app/views/accounts/_moved.html.haml index 7a777bfea..02fd7bf42 100644 --- a/app/views/accounts/_moved.html.haml +++ b/app/views/accounts/_moved.html.haml @@ -3,10 +3,10 @@ .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)])), 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.acct)])), ActivityPub::TagManager.instance.url_for(moved_to_account), class: 'mention')) .moved-account-widget__card - = link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'me noopener' do + = link_to ActivityPub::TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'me noopener' do .detailed-status__display-avatar .account__avatar-overlay .account__avatar-overlay-base{ style: "background-image: url('#{moved_to_account.avatar.url(:original)}')" } diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml index a78a110fa..428f4d259 100644 --- a/app/views/accounts/show.html.haml +++ b/app/views/accounts/show.html.haml @@ -39,12 +39,12 @@ - else .activity-stream.activity-stream--under-tabs - if params[:page].to_i.zero? - = render partial: 'stream_entries/status', collection: @pinned_statuses, as: :status, locals: { pinned: true } + = render partial: 'statuses/status', collection: @pinned_statuses, as: :status, locals: { pinned: true } - if @newer_url .entry= link_to_more @newer_url - = render partial: 'stream_entries/status', collection: @statuses, as: :status + = render partial: 'statuses/status', collection: @statuses, as: :status - if @older_url .entry= link_to_more @older_url diff --git a/app/views/admin/accounts/_account.html.haml b/app/views/admin/accounts/_account.html.haml index eba3ad804..b057d3e42 100644 --- a/app/views/admin/accounts/_account.html.haml +++ b/app/views/admin/accounts/_account.html.haml @@ -19,4 +19,4 @@ = table_link_to 'times', t('admin.accounts.reject'), reject_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:reject, account.user) - else = table_link_to 'circle', t('admin.accounts.web'), web_path("accounts/#{account.id}") - = table_link_to 'globe', t('admin.accounts.public'), TagManager.instance.url_for(account) + = table_link_to 'globe', t('admin.accounts.public'), ActivityPub::TagManager.instance.url_for(account) diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 76dbf4388..54cf9af5d 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -53,6 +53,8 @@ = feature_hint(link_to(t('admin.dashboard.keybase'), edit_admin_settings_path), @keybase_integration) %li = feature_hint(link_to(t('admin.dashboard.feature_relay'), admin_relays_path), @relay_enabled) + %li + = feature_hint(link_to(t('admin.dashboard.feature_spam_check'), edit_admin_settings_path), @spam_check_enabled) .dashboard__widgets__versions %div diff --git a/app/views/admin/reports/_status.html.haml b/app/views/admin/reports/_status.html.haml index cdb914a03..e1068b3e9 100644 --- a/app/views/admin/reports/_status.html.haml +++ b/app/views/admin/reports/_status.html.haml @@ -19,7 +19,7 @@ = react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.proper.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } .detailed-status__meta - = link_to TagManager.instance.url_for(status), class: 'detailed-status__datetime', target: stream_link_target, rel: 'noopener' do + = link_to ActivityPub::TagManager.instance.url_for(status), class: 'detailed-status__datetime', target: stream_link_target, rel: 'noopener' do %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) · - if status.reblog? diff --git a/app/views/admin/settings/edit.html.haml b/app/views/admin/settings/edit.html.haml index 60d6c51f4..d3705a48f 100644 --- a/app/views/admin/settings/edit.html.haml +++ b/app/views/admin/settings/edit.html.haml @@ -84,6 +84,9 @@ .fields-group = f.input :show_replies_in_public_timelines, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_replies_in_public_timelines.title'), hint: t('admin.settings.show_replies_in_public_timelines.desc_html') + .fields-group + = f.input :spam_check_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.spam_check_enabled.title'), hint: t('admin.settings.spam_check_enabled.desc_html') + %hr.spacer/ .fields-group diff --git a/app/views/application/_card.html.haml b/app/views/application/_card.html.haml index e6059b035..00254c40c 100644 --- a/app/views/application/_card.html.haml +++ b/app/views/application/_card.html.haml @@ -1,4 +1,4 @@ -- account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account) +- account_url = local_assigns[:admin] ? admin_account_path(account.id) : ActivityPub::TagManager.instance.url_for(account) .card.h-card = link_to account_url, target: '_blank', rel: 'noopener' do diff --git a/app/views/authorize_interactions/_post_follow_actions.html.haml b/app/views/authorize_interactions/_post_follow_actions.html.haml index 561c60137..dd71160e2 100644 --- a/app/views/authorize_interactions/_post_follow_actions.html.haml +++ b/app/views/authorize_interactions/_post_follow_actions.html.haml @@ -1,4 +1,4 @@ .post-follow-actions %div= link_to t('authorize_follow.post_follow.web'), web_url("accounts/#{@resource.id}"), class: 'button button--block' - %div= link_to t('authorize_follow.post_follow.return'), TagManager.instance.url_for(@resource), class: 'button button--block' + %div= link_to t('authorize_follow.post_follow.return'), ActivityPub::TagManager.instance.url_for(@resource), class: 'button button--block' %div= t('authorize_follow.post_follow.close') diff --git a/app/views/remote_interaction/new.html.haml b/app/views/remote_interaction/new.html.haml index c8c08991f..2cc0fcb93 100644 --- a/app/views/remote_interaction/new.html.haml +++ b/app/views/remote_interaction/new.html.haml @@ -7,7 +7,7 @@ .public-layout .activity-stream.activity-stream--highlighted - = render 'stream_entries/status', status: @status + = render 'statuses/status', status: @status = simple_form_for @remote_follow, as: :remote_follow, url: remote_interaction_path(@status) do |f| = render 'shared/error_messages', object: @remote_follow diff --git a/app/views/remote_unfollows/_card.html.haml b/app/views/remote_unfollows/_card.html.haml deleted file mode 100644 index 9abcfd37e..000000000 --- a/app/views/remote_unfollows/_card.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -.account-card - .detailed-status__display-name - %div - = image_tag account.avatar.url(:original), alt: '', width: 48, height: 48, class: 'avatar' - - %span.display-name - - account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account) - = link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do - %strong.emojify= display_name(account, custom_emojify: true) - %span @#{account.acct} - - - if account.note? - .account__header__content.emojify= Formatter.instance.simplified_format(account) diff --git a/app/views/remote_unfollows/_post_follow_actions.html.haml b/app/views/remote_unfollows/_post_follow_actions.html.haml deleted file mode 100644 index 2a9c062e9..000000000 --- a/app/views/remote_unfollows/_post_follow_actions.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -.post-follow-actions - %div= link_to t('authorize_follow.post_follow.web'), web_url("accounts/#{@account.id}"), class: 'button button--block' - %div= link_to t('authorize_follow.post_follow.return'), TagManager.instance.url_for(@account), class: 'button button--block' - %div= t('authorize_follow.post_follow.close') diff --git a/app/views/remote_unfollows/error.html.haml b/app/views/remote_unfollows/error.html.haml deleted file mode 100644 index cb63f02be..000000000 --- a/app/views/remote_unfollows/error.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -.form-container - .flash-message#error_explanation - = t('remote_unfollow.error') diff --git a/app/views/remote_unfollows/success.html.haml b/app/views/remote_unfollows/success.html.haml deleted file mode 100644 index b007eedc7..000000000 --- a/app/views/remote_unfollows/success.html.haml +++ /dev/null @@ -1,10 +0,0 @@ -- content_for :page_title do - = t('remote_unfollow.title', acct: @account.acct) - -.form-container - .follow-prompt - %h2= t('remote_unfollow.unfollowed') - - = render 'application/card', account: @account - - = render 'post_follow_actions' diff --git a/app/views/stream_entries/_attachment_list.html.haml b/app/views/statuses/_attachment_list.html.haml index d9706f47b..d9706f47b 100644 --- a/app/views/stream_entries/_attachment_list.html.haml +++ b/app/views/statuses/_attachment_list.html.haml diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml index 2d417d011..cd315981c 100644 --- a/app/views/stream_entries/_detailed_status.html.haml +++ b/app/views/statuses/_detailed_status.html.haml @@ -1,6 +1,6 @@ .detailed-status.detailed-status--flex .p-author.h-card - = link_to TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do + = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do .detailed-status__display-avatar - if current_account&.user&.setting_auto_play_gif || autoplay = image_tag status.account.avatar_original_url, width: 48, height: 48, alt: '', class: 'account__avatar u-photo' @@ -24,21 +24,20 @@ = Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay) - if status.preloadable_poll = react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do - = render partial: 'stream_entries/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay } + = render partial: 'statuses/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay } - if !status.media_attachments.empty? - if status.media_attachments.first.video? - video = status.media_attachments.first = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 670, height: 380, detailed: true, inline: true, alt: video.description do - = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments } + = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - else = react_component :media_gallery, height: 380, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, 'reduceMotion': current_account&.user&.setting_reduce_motion, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do - = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments } + = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - elsif status.preview_card = react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json .detailed-status__meta - - if user_signed_in? && @account.id == status.account_id - if status.sharekey.present? = link_to "#{TagManager.instance.url_for(status)}?key=#{status.sharekey}", class: 'detailed-status__link', title: 'Right-click or long-press to copy share link with key', target: stream_link_target, rel: 'noopener' do @@ -46,7 +45,6 @@ · = link_to "#{TagManager.instance.url_for(status)}?rekey=1", class: 'detailed-status__link', title: 'Generate a new share key', target: stream_link_target, rel: 'noopener' do = fa_icon('user-plus') - · - if status.sharekey.present? = link_to "#{TagManager.instance.url_for(status)}?rekey=0", class: 'detailed-status__link', title: 'Revoke share key', target: stream_link_target, rel: 'noopener' do = fa_icon('user-times') diff --git a/app/views/stream_entries/_og_description.html.haml b/app/views/statuses/_og_description.html.haml index a7b18424d..a7b18424d 100644 --- a/app/views/stream_entries/_og_description.html.haml +++ b/app/views/statuses/_og_description.html.haml diff --git a/app/views/stream_entries/_og_image.html.haml b/app/views/statuses/_og_image.html.haml index 67f9274b6..67f9274b6 100644 --- a/app/views/stream_entries/_og_image.html.haml +++ b/app/views/statuses/_og_image.html.haml diff --git a/app/views/stream_entries/_poll.html.haml b/app/views/statuses/_poll.html.haml index ba34890df..ba34890df 100644 --- a/app/views/stream_entries/_poll.html.haml +++ b/app/views/statuses/_poll.html.haml diff --git a/app/views/stream_entries/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml index 96633b636..0affb1568 100644 --- a/app/views/stream_entries/_simple_status.html.haml +++ b/app/views/statuses/_simple_status.html.haml @@ -1,11 +1,11 @@ .status .status__info - = link_to TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', target: stream_link_target, rel: 'noopener' do + = link_to ActivityPub::TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', target: stream_link_target, rel: 'noopener' do %time.time-ago{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) %data.dt-published{ value: status.created_at.to_time.iso8601 } .p-author.h-card - = link_to TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener' do + = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener' do .status__avatar %div - if current_account&.user&.setting_auto_play_gif || autoplay @@ -28,16 +28,16 @@ = Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay) - if status.preloadable_poll = react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do - = render partial: 'stream_entries/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay } + = render partial: 'statuses/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay } - if !status.media_attachments.empty? - if status.media_attachments.first.video? - video = status.media_attachments.first = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description do - = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments } + = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - else = react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do - = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments } + = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - elsif status.preview_card = react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json @@ -54,9 +54,9 @@ = fa_icon 'reply-all fw' .status__action-bar__counter__label= obscured_counter status.replies_count = link_to remote_interaction_path(status, key: @sharekey, type: :reblog), class: 'status__action-bar-button icon-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do - - if status.public_visibility? || status.unlisted_visibility? + - if status.distributable? = fa_icon 'repeat fw' - - elsif status.private_visibility? + - elsif status.private_visibility? || status.limited_visibility? = fa_icon 'lock fw' - else = fa_icon 'envelope fw' diff --git a/app/views/stream_entries/_status.html.haml b/app/views/statuses/_status.html.haml index 3098b4f8d..8ea7f0774 100644 --- a/app/views/stream_entries/_status.html.haml +++ b/app/views/statuses/_status.html.haml @@ -17,9 +17,9 @@ - if status.reply? && include_threads - if @next_ancestor .entry{ class: entry_classes } - = link_to_more TagManager.instance.url_for(@next_ancestor) + = link_to_more ActivityPub::TagManager.instance.url_for(@next_ancestor) - = render partial: 'stream_entries/status', collection: @ancestors, as: :status, locals: { is_predecessor: true, direct_reply_id: status.in_reply_to_id }, autoplay: autoplay + = render partial: 'statuses/status', collection: @ancestors, as: :status, locals: { is_predecessor: true, direct_reply_id: status.in_reply_to_id }, autoplay: autoplay .entry{ class: entry_classes } @@ -28,7 +28,7 @@ .status__prepend-icon-wrapper %i.status__prepend-icon.fa.fa-fw.fa-repeat %span - = link_to TagManager.instance.url_for(status.account), class: 'status__display-name muted' do + = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name muted' do %bdi %strong.emojify= display_name(status.account, custom_emojify: true) = t('stream_entries.reblogged') @@ -39,18 +39,18 @@ %span = t('stream_entries.pinned') - = render (centered ? 'stream_entries/detailed_status' : 'stream_entries/simple_status'), status: status.proper, autoplay: autoplay + = render (centered ? 'statuses/detailed_status' : 'statuses/simple_status'), status: status.proper, autoplay: autoplay - if include_threads - if @since_descendant_thread_id .entry{ class: entry_classes } = link_to_more short_account_status_url(status.account.username, status, max_descendant_thread_id: @since_descendant_thread_id + 1) - @descendant_threads.each do |thread| - = render partial: 'stream_entries/status', collection: thread[:statuses], as: :status, locals: { is_successor: true, parent_id: status.id }, autoplay: autoplay + = render partial: 'statuses/status', collection: thread[:statuses], as: :status, locals: { is_successor: true, parent_id: status.id }, autoplay: autoplay - if thread[:next_status] .entry{ class: entry_classes } - = link_to_more TagManager.instance.url_for(thread[:next_status]) + = link_to_more ActivityPub::TagManager.instance.url_for(thread[:next_status]) - if @next_descendant_thread .entry{ class: entry_classes } = link_to_more short_account_status_url(status.account.username, status, since_descendant_thread_id: @max_descendant_thread_id - 1) diff --git a/app/views/statuses/embed.html.haml b/app/views/statuses/embed.html.haml new file mode 100644 index 000000000..6f2ec646f --- /dev/null +++ b/app/views/statuses/embed.html.haml @@ -0,0 +1,3 @@ +- cache @status do + .activity-stream.activity-stream--headless + = render 'status', status: @status, centered: true, autoplay: @autoplay diff --git a/app/views/statuses/show.html.haml b/app/views/statuses/show.html.haml new file mode 100644 index 000000000..704e37a3d --- /dev/null +++ b/app/views/statuses/show.html.haml @@ -0,0 +1,24 @@ +- content_for :page_title do + = t('statuses.title', name: display_name(@account), quote: truncate(@status.spoiler_text.presence || @status.text, length: 50, omission: '…', escape: false)) + +- content_for :header_tags do + - if @account.user&.setting_noindex + %meta{ name: 'robots', content: 'noindex' }/ + + %link{ rel: 'alternate', type: 'application/json+oembed', href: api_oembed_url(url: short_account_status_url(@account, @status), format: 'json') }/ + %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@status) }/ + + = opengraph 'og:site_name', site_title + = opengraph 'og:type', 'article' + = opengraph 'og:title', "#{display_name(@account)} (@#{@account.local_username_and_domain})" + = opengraph 'og:url', short_account_status_url(@account, @status) + + = render 'og_description', activity: @status + = render 'og_image', activity: @status, account: @account + +.grid + .column-0 + .activity-stream.h-entry + = render partial: 'status', locals: { status: @status, include_threads: true } + .column-1 + = render 'application/sidebar' diff --git a/app/views/stream_entries/embed.html.haml b/app/views/stream_entries/embed.html.haml deleted file mode 100644 index 4871c101e..000000000 --- a/app/views/stream_entries/embed.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -- cache @stream_entry.activity do - .activity-stream.activity-stream--headless - = render "stream_entries/#{@type}", @type.to_sym => @stream_entry.activity, centered: true, autoplay: @autoplay diff --git a/app/views/stream_entries/show.html.haml b/app/views/stream_entries/show.html.haml deleted file mode 100644 index 5fd8f7a69..000000000 --- a/app/views/stream_entries/show.html.haml +++ /dev/null @@ -1,24 +0,0 @@ -- content_for :page_title do - = t('statuses.title', name: display_name(@account), quote: truncate(@stream_entry.activity.spoiler_text.presence || @stream_entry.activity.text, length: 50, omission: '…', escape: false)) - -- content_for :header_tags do - - if @account.user&.setting_noindex - %meta{ name: 'robots', content: 'noindex' }/ - - %link{ rel: 'alternate', type: 'application/json+oembed', href: api_oembed_url(url: account_stream_entry_url(@account, @stream_entry), format: 'json') }/ - %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@stream_entry.activity) }/ - - = opengraph 'og:site_name', site_title - = opengraph 'og:type', 'article' - = opengraph 'og:title', "#{display_name(@account)} (@#{@account.local_username_and_domain})" - = opengraph 'og:url', short_account_status_url(@account, @stream_entry.activity) - - = render 'stream_entries/og_description', activity: @stream_entry.activity - = render 'stream_entries/og_image', activity: @stream_entry.activity, account: @account - -.grid - .column-0 - .activity-stream.h-entry - = render partial: "stream_entries/#{@type}", locals: { @type.to_sym => @stream_entry.activity, include_threads: true } - .column-1 - = render 'application/sidebar' diff --git a/app/views/well_known/webfinger/show.xml.ruby b/app/views/well_known/webfinger/show.xml.ruby index 4eb303eef..0f16d9e67 100644 --- a/app/views/well_known/webfinger/show.xml.ruby +++ b/app/views/well_known/webfinger/show.xml.ruby @@ -4,24 +4,37 @@ doc << Ox::Element.new('XRD').tap do |xrd| xrd['xmlns'] = 'http://docs.oasis-open.org/ns/xri/xrd-1.0' xrd << (Ox::Element.new('Subject') << @account.to_webfinger_s) - xrd << (Ox::Element.new('Alias') << short_account_url(@account)) - xrd << (Ox::Element.new('Alias') << account_url(@account)) - xrd << Ox::Element.new('Link').tap do |link| - link['rel'] = 'http://webfinger.net/rel/profile-page' - link['type'] = 'text/html' - link['href'] = short_account_url(@account) - end - xrd << Ox::Element.new('Link').tap do |link| - link['rel'] = 'self' - link['type'] = 'application/activity+json' - link['href'] = account_url(@account) - end + if @account.instance_actor? + xrd << (Ox::Element.new('Alias') << instance_actor_url) + + xrd << Ox::Element.new('Link').tap do |link| + link['rel'] = 'http://webfinger.net/rel/profile-page' + link['type'] = 'text/html' + link['href'] = about_more_url(instance_actor: true) + end + + xrd << Ox::Element.new('Link').tap do |link| + link['rel'] = 'self' + link['type'] = 'application/activity+json' + link['href'] = instance_actor_url + end + else + xrd << (Ox::Element.new('Alias') << short_account_url(@account)) + xrd << (Ox::Element.new('Alias') << account_url(@account)) + + xrd << Ox::Element.new('Link').tap do |link| + link['rel'] = 'http://webfinger.net/rel/profile-page' + link['type'] = 'text/html' + link['href'] = short_account_url(@account) + end - xrd << Ox::Element.new('Link').tap do |link| - link['rel'] = 'magic-public-key' - link['href'] = "data:application/magic-public-key,#{@account.magic_key}" + xrd << Ox::Element.new('Link').tap do |link| + link['rel'] = 'self' + link['type'] = 'application/activity+json' + link['href'] = account_url(@account) + end end end diff --git a/app/workers/activitypub/delivery_worker.rb b/app/workers/activitypub/delivery_worker.rb index 5e4c391f0..03d2c1187 100644 --- a/app/workers/activitypub/delivery_worker.rb +++ b/app/workers/activitypub/delivery_worker.rb @@ -2,6 +2,7 @@ class ActivityPub::DeliveryWorker include Sidekiq::Worker + include JsonLdHelper STOPLIGHT_FAILURE_THRESHOLD = 10 STOPLIGHT_COOLDOWN = 60 @@ -17,27 +18,35 @@ class ActivityPub::DeliveryWorker @json = json @source_account = Account.find(source_account_id) @inbox_url = inbox_url + @host = Addressable::URI.parse(inbox_url).normalized_site + @performed = false perform_request - - failure_tracker.track_success! - rescue => e - failure_tracker.track_failure! - raise e.class, "Delivery failed for #{inbox_url}: #{e.message}", e.backtrace[0] + ensure + if @performed + failure_tracker.track_success! + else + failure_tracker.track_failure! + end end private - def build_request - request = Request.new(:post, @inbox_url, body: @json) - request.on_behalf_of(@source_account, :uri, sign_with: @options[:sign_with]) - request.add_headers(HEADERS) + def build_request(http_client) + Request.new(:post, @inbox_url, body: @json, http_client: http_client).tap do |request| + request.on_behalf_of(@source_account, :uri, sign_with: @options[:sign_with]) + request.add_headers(HEADERS) + end end def perform_request light = Stoplight(@inbox_url) do - build_request.perform do |response| - raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) + request_pool.with(@host) do |http_client| + build_request(http_client).perform do |response| + raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) + + @performed = true + end end end diff --git a/app/workers/after_remote_follow_request_worker.rb b/app/workers/after_remote_follow_request_worker.rb index 84eb6ade2..ce9c65834 100644 --- a/app/workers/after_remote_follow_request_worker.rb +++ b/app/workers/after_remote_follow_request_worker.rb @@ -5,27 +5,5 @@ class AfterRemoteFollowRequestWorker sidekiq_options queue: 'pull', retry: 5 - attr_reader :follow_request - - def perform(follow_request_id) - @follow_request = FollowRequest.find(follow_request_id) - process_follow_service if processing_required? - rescue ActiveRecord::RecordNotFound - true - end - - private - - def process_follow_service - follow_request.destroy - FollowService.new.call(follow_request.account, updated_account.acct) - end - - def processing_required? - !updated_account.nil? && !updated_account.locked? - end - - def updated_account - @_updated_account ||= FetchRemoteAccountService.new.call(follow_request.target_account.remote_url) - end + def perform(follow_request_id); end end diff --git a/app/workers/after_remote_follow_worker.rb b/app/workers/after_remote_follow_worker.rb index edab83f85..d9719f2bf 100644 --- a/app/workers/after_remote_follow_worker.rb +++ b/app/workers/after_remote_follow_worker.rb @@ -5,27 +5,5 @@ class AfterRemoteFollowWorker sidekiq_options queue: 'pull', retry: 5 - attr_reader :follow - - def perform(follow_id) - @follow = Follow.find(follow_id) - process_follow_service if processing_required? - rescue ActiveRecord::RecordNotFound - true - end - - private - - def process_follow_service - follow.destroy - FollowService.new.call(follow.account, updated_account.acct) - end - - def updated_account - @_updated_account ||= FetchRemoteAccountService.new.call(follow.target_account.remote_url) - end - - def processing_required? - !updated_account.nil? && updated_account.locked? - end + def perform(follow_id); end end diff --git a/app/workers/maintenance/uncache_preview_worker.rb b/app/workers/maintenance/uncache_preview_worker.rb new file mode 100644 index 000000000..810ffd8cc --- /dev/null +++ b/app/workers/maintenance/uncache_preview_worker.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class Maintenance::UncachePreviewWorker + include Sidekiq::Worker + + sidekiq_options queue: 'pull' + + def perform(preview_card_id) + preview_card = PreviewCard.find(preview_card_id) + + return if preview_card.image.blank? + + preview_card.image.destroy + preview_card.save + rescue ActiveRecord::RecordNotFound + true + end +end diff --git a/app/workers/scheduler/preview_cards_cleanup_scheduler.rb b/app/workers/scheduler/preview_cards_cleanup_scheduler.rb new file mode 100644 index 000000000..2b38792f0 --- /dev/null +++ b/app/workers/scheduler/preview_cards_cleanup_scheduler.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class Scheduler::PreviewCardsCleanupScheduler + include Sidekiq::Worker + + sidekiq_options unique: :until_executed, retry: 0 + + def perform + Maintenance::UncachePreviewWorker.push_bulk(recent_link_preview_cards.pluck(:id)) + Maintenance::UncachePreviewWorker.push_bulk(older_preview_cards.pluck(:id)) + end + + private + + def recent_link_preview_cards + PreviewCard.where(type: :link).where('updated_at < ?', 1.month.ago) + end + + def older_preview_cards + PreviewCard.where('updated_at < ?', 6.months.ago) + end +end |